- 新增 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
85 lines
2.1 KiB
Elixir
85 lines
2.1 KiB
Elixir
defmodule BearCli.Config do
|
||
@moduledoc """
|
||
設定檔與憑證檔的路徑及讀取。
|
||
|
||
設定優先序:CLI flag > 環境變數(`BEAR_ISSUER`)> 設定檔 > 內建預設。
|
||
"""
|
||
|
||
@default_issuer "https://alterminal.com"
|
||
|
||
@doc "內建預設 issuer。"
|
||
def default_issuer, do: @default_issuer
|
||
|
||
@doc """
|
||
設定檔路徑:`~/.config/bear/config.json`(可用 `BEAR_CONFIG` 覆寫)。
|
||
"""
|
||
def config_path do
|
||
System.get_env("BEAR_CONFIG") || Path.join(config_home(), "config.json")
|
||
end
|
||
|
||
@doc """
|
||
憑證檔路徑:`~/.local/state/bear/credentials.json`(可用 `BEAR_CREDENTIALS` 覆寫)。
|
||
"""
|
||
def credentials_path do
|
||
System.get_env("BEAR_CREDENTIALS") || Path.join(state_home(), "credentials.json")
|
||
end
|
||
|
||
defp config_home do
|
||
base =
|
||
System.get_env("XDG_CONFIG_HOME") ||
|
||
Path.join(System.user_home!(), ".config")
|
||
|
||
Path.join(base, "bear")
|
||
end
|
||
|
||
defp state_home do
|
||
base =
|
||
System.get_env("XDG_STATE_HOME") ||
|
||
Path.join(System.user_home!(), ".local/state")
|
||
|
||
Path.join(base, "bear")
|
||
end
|
||
|
||
@doc """
|
||
讀取設定檔,回傳 `{:ok, map}` 或 `:error`(檔案不存在/JSON 損毀)。
|
||
"""
|
||
def read_config(path \\ config_path()) do
|
||
case File.read(path) do
|
||
{:ok, content} -> Jason.decode(content)
|
||
{:error, _} -> :error
|
||
end
|
||
end
|
||
|
||
@doc """
|
||
解析最終 issuer,依序取第一個非空白值:
|
||
|
||
1. `cli_issuer`(`--issuer` flag)
|
||
2. `BEAR_ISSUER` 環境變數
|
||
3. 設定檔的 `issuer` 欄位(讀自 `config_path_override` 或預設路徑)
|
||
4. 內建預設 `https://alterminal.com`
|
||
"""
|
||
def resolve_issuer(cli_issuer, config_path_override \\ nil) do
|
||
path = config_path_override || config_path()
|
||
|
||
config =
|
||
case read_config(path) do
|
||
{:ok, map} when is_map(map) -> map
|
||
_ -> %{}
|
||
end
|
||
|
||
Enum.find(
|
||
[
|
||
cli_issuer,
|
||
System.get_env("BEAR_ISSUER"),
|
||
config["issuer"],
|
||
@default_issuer
|
||
],
|
||
&(not blank?(&1))
|
||
)
|
||
end
|
||
|
||
defp blank?(nil), do: true
|
||
defp blank?(""), do: true
|
||
defp blank?(_), do: false
|
||
end
|