Files
bear-cli/lib/bear_cli/api.ex
T
alex 870011f8a7 feat: 實作 bear CLI PAT 模式 MVP(login/whoami/token/logout/status)
- 新增 Elixir + Mix escript 專案(Req 0.5+、Jason)
- login --token <PAT>:以 PAT 驗證 /userinfo 後寫入憑證檔(0600)
- whoami:GET /userinfo 顯示身分 claims(支援 --json)
- token:印出 access token 供 pipe(--refresh 在 PAT 模式忽略)
- logout:清除本機憑證;status:純本機判定
- 憑證檔採原子寫入(rename)、0600、O_CREAT|O_EXCL 防 symlink
- 全域選項:--issuer/--config/--json/-v/-h/--version
- 29 個單元測試;mix precommit(compile --warnings-as-errors + format + test)
- 更新 README.md 與 docs/commands.md 反映 PAT 模式 MVP

Device Flow 登入待伺服器端 P1(bear 倉庫)完成後再接。issue #2
2026-08-31 11:14:12 +08:00

55 lines
1.6 KiB
Elixir
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
defmodule BearCli.Api do
@moduledoc """
Bear 伺服器 HTTP 介面(一律使用 `Req`)。
目前僅實作 PAT 模式所需的 `GET /userinfo`。
"""
@finch BearCli.Finch
@doc """
呼叫 `GET {issuer}/userinfo`(Bearer token)。
回傳:
- `{:ok, claims}` — 200,claims 為 JSON map
- `{:error, :unauthorized, description}` — 401
- `{:error, :server_error, status}` — 其他非 2xx
- `{:error, :network, reason}` — 傳輸層錯誤
"""
def userinfo(issuer, token) do
url = String.trim_trailing(issuer, "/") <> "/userinfo"
case Req.get(url,
headers: [authorization: "Bearer " <> token, accept: "application/json"],
retry: false,
finch: [name: @finch]
) do
{:ok, %Req.Response{status: 200, body: body}} ->
{:ok, decode_body(body)}
{:ok, %Req.Response{status: 401, body: body}} ->
{:error, :unauthorized, error_description(body)}
{:ok, %Req.Response{status: status}} ->
{:error, :server_error, status}
{:error, exception} ->
{:error, :network, Exception.message(exception)}
end
end
defp decode_body(%{} = body), do: body
defp decode_body(body) when is_binary(body), do: Jason.decode!(body)
defp decode_body(_), do: %{}
defp error_description(body) when is_binary(body) do
case Jason.decode(body) do
{:ok, %{"error_description" => desc}} when is_binary(desc) -> desc
{:ok, %{"error" => err}} when is_binary(err) -> err
_ -> "invalid_token"
end
end
defp error_description(_), do: "invalid_token"
end