Skip to content

feat(web): in-page API key settings (RFC-0029 revision, loopback-gated) - #153

Merged
eric8810 merged 3 commits into
masterfrom
feat/web-key-settings
Aug 17, 2026
Merged

feat(web): in-page API key settings (RFC-0029 revision, loopback-gated)#153
eric8810 merged 3 commits into
masterfrom
feat/web-key-settings

Conversation

@eric8810

Copy link
Copy Markdown
Contributor

RFC-0029 设计修订(决策 D4):网页内 provider key 设置替代"仅 env: 引用"。进 0.3.0(维护者裁决方案 B)。

动机

原设计要求用户先在 shell export 再启动控制台——对下载即用的本地工具是最/frustrating 的第一步。同类产品(OpenWebUI/LM Studio/各官方 Playground)均为网页内设置。

设计(安全模型)

  • Settings 页:provider 选择 + key 输入(password 框,提交即清空)+ "记住(落盘)"开关 + 已存列表(仅掩码)
  • 存储:默认仅内存;显式 remember 才写 ~/.config/aimux-web/keys.json0600,temp+rename 原子写,同目录无 EXDEV);启动加载,损坏文件静默忽略
  • 回环门控:绑定非环回(--host 0.0.0.0/LAN)时 PUT/DELETE 403、请求内明文维持拒绝、GET 返回 plaintext_entry:false 供前端禁用输入框——原决策担心的远程录入面被精确挡住
  • resolve 优先级(calls/cache_probe/replay 三处统一):请求显式 env:VAR > 请求明文(仅回环)> Settings 已存 key > provider 注册默认 env var
  • 泄漏面控制:GET 永不回明文(>8 字符 key 显示尾 4 位,≤8 只给长度);明文不进日志/错误/Debug/Recording(录制脱敏在 HTTP 层)

API

GET /api/settings/keys(掩码列表 + plaintext_entry)· PUT /api/settings/keys {provider,key,remember?} · DELETE /api/settings/keys/{provider}

文档

RFC-0029 决策表 D4 修订 + §5.5 Settings 与凭据(威胁模型);README 快速开始改为双路径(网页内 or env)。

评审

两轮独立评审:R1 安全核心全过(无明文泄漏面/回环判定 fail-closed/三调用方一致),4 条低危(空串视同 unset、掩码阈值 8、原子写、DELETE trim)已修;R2 CLEAN 的 3 个小尾巴(空分支测试、过时注释、tmp 并发碰撞)亦已修。22 测试全过,clippy -D warnings 干净,前端 build+vue-tsc 过,curl 真机冒烟(掩码/403/重启加载/0600)通过。

Maintainer-approved plan B for 0.3.0: the console previously accepted
only env:VAR references in wire.rs resolve_api_key, forcing a shell
export before first use. This adds a Settings page with provider
selection and a key entry point.

Backend:
- settings.rs KeyStore: per-provider keys in memory by default,
  explicit remember=true persists to ~/.config/aimux-web/keys.json
  (%APPDATA% on Windows) with 0600 perms, loaded at startup
- api/settings.rs: GET /api/settings/keys (masked hints only, last 4
  chars), PUT /api/settings/keys {provider, key, remember?},
  DELETE /api/settings/keys/{provider}
- loopback gating: bind host stored in AppState; non-loopback binds
  get 403 on PUT/DELETE and plaintext_entry:false on GET
- resolve_api_key now takes the provider name + KeyStore from all
  three callers (calls/cache_probe/replay): explicit spec (env: ref,
  or plaintext on loopback only) > stored key > provider env var

Frontend: Settings view (route /settings, nav entry) with provider
combobox, masked key list, remember switch; key-field hints in
Playground/Replay/CacheProbe point at Settings.

Docs: RFC-0029 decision table D4 + new §5.5 (threat model, priority);
README quick start makes env export optional.

No plaintext in logs, responses, or recordings; no new dependencies.
- empty/whitespace key spec resolves as unset (stored key / provider env
  fallback) instead of an empty key
- mask threshold raised to >8 chars so a short key never leaks in full
  through its own tail
- disk persistence writes via temp + rename — concurrent PUT(remember)
  snapshots interleave outside the lock and could tear the JSON in place
- DELETE trims the provider path segment, matching PUT
@eric8810 eric8810 added enhancement New feature or request priority:high High risk — should be fixed first area:ffi FFI / C ABI boundary (aimux-ffi) labels Aug 17, 2026
@eric8810
eric8810 merged commit e8fcd09 into master Aug 17, 2026
24 checks passed
@eric8810
eric8810 deleted the feat/web-key-settings branch August 17, 2026 04:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ffi FFI / C ABI boundary (aimux-ffi) enhancement New feature or request priority:high High risk — should be fixed first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant