feat: 實作管理端指令群 jwks/accounts/audit-logs(issue #12)
- docs/commands.md 新增 §3.8 jwks、§3.9 accounts、§3.10 audit-logs 規格 - Api 新增 jwks/accounts/audit-logs 端點(共用 api_request) - 新增 Jwks/Accounts/AuditLogs/Admin 模組;CLI 接線三個指令群 - 403 → 退出碼 8 提示需 admin;一次性密碼只在成功當下輸出 - 測試 100 例全綠(fake API 注入,比照 cli_test.exs);基於含 PR #15 的最新 main
This commit is contained in:
@@ -6,6 +6,8 @@ defmodule BearCli.Api do
|
||||
- App 管理 API `/api/v1/apps`(alterminal/bear#28;PAT Bearer、admin 限定)。
|
||||
- 個人自助 API `/api/v1/profile*`(alterminal/bear#35;PAT Bearer、
|
||||
任何有效帳號):profile/密碼/email/sessions/PAT/MFA。
|
||||
- 管理端 API `/api/v1/jwks`/`/api/v1/accounts`/`/api/v1/audit-logs`
|
||||
(alterminal/bear#36; PAT Bearer, admin only).
|
||||
"""
|
||||
|
||||
@finch BearCli.Finch
|
||||
@@ -265,4 +267,85 @@ defmodule BearCli.Api do
|
||||
{:error, :network, Exception.message(exception)}
|
||||
end
|
||||
end
|
||||
|
||||
@doc "`GET /api/v1/jwks`: list all keys (active and inactive), newest first (no pagination)."
|
||||
def jwks_list(issuer, token) do
|
||||
api_request(issuer, token, :get, "/api/v1/jwks")
|
||||
end
|
||||
|
||||
@doc """
|
||||
`POST /api/v1/jwks`: create a new signing key. attrs: `%{"kid" => "...", "alg" => "RS256"}`
|
||||
(`alg` optional; RS256/384/512, ES256/384/512). Key material is never serialized.
|
||||
"""
|
||||
def jwks_create(issuer, token, attrs) do
|
||||
api_request(issuer, token, :post, "/api/v1/jwks", json: attrs)
|
||||
end
|
||||
|
||||
@doc "`GET /api/v1/jwks/{id}`: single key (public metadata only)."
|
||||
def jwks_get(issuer, token, id) do
|
||||
api_request(issuer, token, :get, "/api/v1/jwks/" <> URI.encode(id))
|
||||
end
|
||||
|
||||
@doc "`POST /api/v1/jwks/{id}/toggle`: switch key between active and inactive."
|
||||
def jwks_toggle(issuer, token, id) do
|
||||
api_request(issuer, token, :post, "/api/v1/jwks/" <> URI.encode(id) <> "/toggle", json: %{})
|
||||
end
|
||||
|
||||
# -- Accounts API (alterminal/bear#46; PAT Bearer, admin only) --
|
||||
|
||||
@doc """
|
||||
`GET /api/v1/accounts`: paginated list (newest first; per_page max 100).
|
||||
Returns `{:ok, %{"data" => [accounts], "page" => n, "per_page" => n, "total" => n}}`.
|
||||
"""
|
||||
def accounts_list(issuer, token, params \\ []) do
|
||||
api_request(issuer, token, :get, "/api/v1/accounts", params: params)
|
||||
end
|
||||
|
||||
@doc """
|
||||
`POST /api/v1/accounts`: create an account directly (no email verification).
|
||||
attrs: `%{"email" => "...", "hash_password" => "<plaintext>", "role" => "user|admin"}`
|
||||
(`role` optional, default `user`).
|
||||
"""
|
||||
def accounts_create(issuer, token, attrs) do
|
||||
api_request(issuer, token, :post, "/api/v1/accounts", json: attrs)
|
||||
end
|
||||
|
||||
@doc "`GET /api/v1/accounts/{id}`: single account (no credential fields)."
|
||||
def accounts_get(issuer, token, id) do
|
||||
api_request(issuer, token, :get, "/api/v1/accounts/" <> URI.encode(id))
|
||||
end
|
||||
|
||||
@doc """
|
||||
`PUT /api/v1/accounts/{id}`: update role; attrs: `%{"role" => "user|admin"}`.
|
||||
"""
|
||||
def accounts_update_role(issuer, token, id, attrs) do
|
||||
api_request(issuer, token, :put, "/api/v1/accounts/" <> URI.encode(id), json: attrs)
|
||||
end
|
||||
|
||||
@doc """
|
||||
`PUT /api/v1/accounts/{id}/password`: admin sets a new password (no old password
|
||||
needed); attrs: `%{"hash_password" => "<plaintext>"}`.
|
||||
"""
|
||||
def accounts_set_password(issuer, token, id, attrs) do
|
||||
api_request(issuer, token, :put, "/api/v1/accounts/" <> URI.encode(id) <> "/password",
|
||||
json: attrs
|
||||
)
|
||||
end
|
||||
|
||||
@doc "`DELETE /api/v1/accounts/{id}`: hard-delete an account (admin path). Returns `{:ok, %{}}` (204 empty)."
|
||||
def accounts_delete(issuer, token, id) do
|
||||
api_request(issuer, token, :delete, "/api/v1/accounts/" <> URI.encode(id))
|
||||
end
|
||||
|
||||
# -- Audit logs API (alterminal/bear#46; PAT Bearer, admin only) --
|
||||
|
||||
@doc """
|
||||
`GET /api/v1/audit-logs`: paginated list (newest first). params: `page:` /
|
||||
`per_page:` (max 200) / `category:` filter. Returns `{:ok, %{"data" => [entries],
|
||||
"page" => n, "per_page" => n, "total" => n, "total_pages" => n,
|
||||
"emails" => %{id => email}}}`.
|
||||
"""
|
||||
def audit_logs_list(issuer, token, params \\ []) do
|
||||
api_request(issuer, token, :get, "/api/v1/audit-logs", params: params)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user