Files
bear-cli/README.md
T
iris 62fd6b730e feat: 實作個人自助指令群 profile/password/email/sessions/tokens/mfa(issue #11)
- lib/bear_cli/self_service.ex:六個子群組(profile show/set、password change、
  email change、sessions list/revoke/revoke-others、tokens list/create/revoke、
  mfa status/setup/disable/recovery-codes),對接 alterminal/bear#38 的
  /api/v1/profile* JSON API(PAT Bearer、任何有效帳號)
- 敏感輸入(密碼/驗證碼)互動提示讀取,非 TTY → 退出碼 2;
  一次性明文(PAT 明文、recovery codes)僅於成功當下輸出
- mfa setup:otpauth URI 本地生成 ASCII QR(新增 eqrcode 依賴),
  確認走 /mfa/setup/confirm(依 #38 實作)
- Api 模組新增 profile 系列端點與 429 分流;CLI 分派接上六個指令群組
- docs/commands.md §3.7 對齊 #38 實際 API(sessions 欄位、tokens create
  無 --scope、mfa setup/confirm、email 需重帶 new_email);§7/§8/§9 與
  README 同步更新
- 測試 50 例(fake API 注入):解析、輸出、退出碼、互動輸入、錯誤分流;
  mix precommit 全綠(114 passed)
2026-09-09 22:50:53 +08:00

130 lines
7.1 KiB
Markdown
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.
# 🐻 Bear CLI
**Bear CLI** 是 [澳特科技](https://alterminal.com)(Alter Technology)單點登入系統 [Bear](https://gitea.alterminal.com/alterminal/bear) 的**終端機(CLI)客戶端**:讓使用者在 Linux 終端機以 Bear 帳號登入(Device Flow 或個人存取權杖)、查詢身分、取得 Token,作為 SSO 的終端入口。
> **狀態:已實作 PAT 模式 MVP(Elixir + Req,issue #6)+ App 管理(#10)+ 個人自助指令群(#11)**。`login --token <PAT>`、`whoami`、`token`、`logout`、`status`、`apps`、`profile`/`password`/`email`/`sessions`/`tokens`/`mfa` 已可用;Device Authorization Grant(RFC 8628)登入待伺服器端 P1(bear 倉庫)完成後再接。
> 伺服器端採用的 OIDC **Device Authorization Grant(RFC 8628)** 方向,詳見 bear 倉庫的設計文件 `docs/cli-feature-plan.md`(issue #17)。
> Bear 已支援**個人存取權杖(Personal Access Token,PAT)**;CLI 規劃以其作為完全免瀏覽器的替代登入方式(見下文)。
---
## 為什麼需要 CLI
Bear 目前所有流程都依賴「瀏覽器」:登入 `/login`、儀表板 Launch、Relying Party 走 Authorization Code Flow + PKCE。但**終端機沒有瀏覽器可互動**,無法完成 `redirect_uri` 回跳,因此需要一個為「無瀏覽器/輸入受限裝置」設計的登入流程,讓 `bear` 指令也能以 OIDC 身分登入並取用 Token。此外,Bear 現已支援**個人存取權杖(PAT)**,CLI 亦可直接以 PAT 登入,完全免瀏覽器,適合 CI/腳本/一次性使用。
---
## 指令總覽
| 指令 | 說明 | 階段 |
|------|------|------|
| `bear login` | 啟動 Device Flow 登入;或 `--token <PAT>` 以個人存取權杖登入 | P2 |
| `bear whoami` | 顯示目前登入身分(`GET /userinfo`) | P2 |
| `bear token [--refresh]` | 印出 access token(過期自動 refresh),供 pipe 給其他工具 | P2 |
| `bear logout` | 撤銷 refresh token(`POST /revoke`) | P2 |
| `bear status` | 顯示登入狀態與 token 剩餘效期 | P2 |
| `bear apps list/show/create/update/rotate-secret/toggle` | App 管理(需 bear App 管理 JSON API,PAT 登入、admin 限定) | P3(✅ 已實作) |
| `bear profile show/set` | 個人資料檢視/更新(需 bear 個人自助 JSON API) | P3(✅ 已實作) |
| `bear password change` | 變更密碼(互動輸入,不進 shell history) | P3(✅ 已實作) |
| `bear email change --new EMAIL` | 變更 email(雙向驗證碼流程) | P3(✅ 已實作) |
| `bear sessions list/revoke/revoke-others` | 管理網頁 session | P3(✅ 已實作) |
| `bear tokens list/create/revoke` | 管理 PAT(create 一次性顯示明文) | P3(✅ 已實作) |
| `bear mfa status/setup/disable/recovery-codes` | TOTP 兩因子管理 | P3(✅ 已實作) |
完整指令規格(選項、行為、輸出、退出碼)見 [`docs/commands.md`](docs/commands.md)。
---
## 實作狀態(PAT 模式 MVP)
目前已實作**個人存取權杖(PAT)模式**的最小可用版本(issue #6 骨架部分):
| 指令 | 狀態 |
|------|------|
| `bear login --token <PAT>` | ✅ 已實作(PAT 模式;Device Flow 待伺服器端 P1) |
| `bear whoami` | ✅ 已實作(`GET /userinfo`,Bearer PAT;支援 `BEAR_TOKEN` 環境變數) |
| `bear token` | ✅ 已實作(印出 PAT;`--refresh` 為用法錯誤) |
| `bear logout` | ✅ 已實作(清除本機憑證;PAT 需至網頁撤銷) |
| `bear status` | ✅ 已實作(純本機判定,顯示 PAT/環境變數模式) |
| `bear apps` | ✅ 已實作(`list`/`show`/`create`/`update`/`rotate-secret`/`toggle`;issue #10,對接 alterminal/bear#28 的 `/api/v1/apps` JSON API,admin PAT 限定) |
| `bear profile`/`password`/`email`/`sessions`/`tokens`/`mfa` | ✅ 已實作(issue #11,對接 alterminal/bear#38 的 `/api/v1/profile*` JSON API,任何有效 PAT 皆可):`profile show/set`、`password change`、`email change --new`、`sessions list/revoke/revoke-others`、`tokens list/create/revoke`、`mfa status/setup/disable/recovery-codes`。規格見 `docs/commands.md` §3.7 |
### 建置與執行
```bash
mix deps.get # 安裝依賴(Req、Jason)
mix test # 跑單元測試
mix escript.build # 產生單檔可執行 `bear`
./bear --help
./bear login --token <PAT> --issuer https://alterminal.com
```
> 發行格式目前採 `mix escript`(目標機需 Erlang);self-contained release(bakeware/burrito)仍為待定方向(見 `docs/commands.md` §7)。
---
## 全域選項
| 選項 | 說明 | 預設 |
|------|------|------|
| `--issuer URL` | Bear(OIDC Provider)位址 | `https://alterminal.com` |
| `--config PATH` | 設定檔路徑 | `~/.config/bear/config.json` |
| `--json` | 機器可讀輸出(JSON) | — |
| `-v, --verbose` | 顯示詳細日誌 | — |
| `-h, --help` | 顯示說明 | — |
| `--version` | 顯示版本 | — |
---
## 登入流程(`bear login`,示意)
### Device Flow(預設)
```
$ bear login
正在向 https://alterminal.com 註冊裝置...
請在瀏覽器開啟:https://alterminal.com/device
輸入代碼:ABCD-EFGH
(等待授權中...)
已登入:alice@example.com
```
登入後,CLI 將 refresh token 寫入本機憑證檔(0600),access token 僅做短命快取。
### 個人存取權杖(PAT,免瀏覽器)
```
$ bear login --token <PAT>
已登入:alice@example.com
```
以 PAT 登入不產生 refresh token;CLI 直接將該 PAT 寫入憑證檔(0600)作為憑證,適合 CI/腳本等無瀏覽器情境。
---
## 憑證與設定檔
| 檔 | 路徑 | 內容 | 權限 |
|----|------|------|------|
| 設定 | `~/.config/bear/config.json` | `issuer`、`client_id`、`scope` | 0644 |
| 憑證 | `~/.local/state/bear/credentials.json` | Device Flow:`refresh_token`+快取 `access_token`/`expires_at`;PAT:直接存 `access_token`(無 refresh) | **0600** |
---
## 里程碑
| 階段 | 內容 |
|------|------|
| **P1 伺服器:Device Flow** | `device_codes` 資料表、`POST /device_authorization`、`GET/POST /device` 授權頁、token 端點 `device_code` grant、Discovery 更新(於 bear 倉庫) |
| **P2 CLI 登入** | 本倉庫實作 `login`(Device Flow 或 `--token <PAT>`)/`whoami`/`token`/`logout`/`status`、憑證儲存 0600 |
| **P3 進階** | `bear apps` 管理指令群(依賴 bear App 管理 JSON API)、個人自助指令群 `profile`/`password`/`email`/`sessions`/`tokens`/`mfa`(依賴 bear 個人自助 JSON API,#11)、QR 顯示、系統 keyring、發行二進位 |
---
## 技術方向(規劃)
- **語言**:Elixir(與 Bear 主專案一致),HTTP 一律使用 `Req`。
- **發行**:`mix escript`(單檔可執行)或 `mix release` 自包含二進位(待定)。
- **安全**:device_code 只存 SHA-256 雜湊、user_code 限流、憑證檔 0600、token 與 PAT 一律不入 log/commit;一次性明文(`apps` 的 client_secret、`tokens create` 的 PAT、`mfa` 的 recovery codes)僅在成功當下顯示一次;密碼與驗證碼一律互動輸入、不回顧。