Skip to content

ADR 0008:匿名账号 + 设备配对,去掉共享口令

This content is not available in your language yet.

  • 状态:已采纳(2026-09-29,YOUT-217)
  • 决策者:zhibo li
  • 取代:ADR 0006 第 1 条(/v1/* 只认一把共享口令)
  • 延续:ADR 0006(不做登录、服务端不存历史)、ADR 0007(端到端加密)

原来 server 只认一把共享口令,只适合“一台 server 只给一个人用”:

  • 公共云端没法用:口令不能发给用户,也不能写死在 App 里。写死等于所有人共用一把钥匙,server 分不清谁是谁,A 会收到 B 的来电,也能吊销 B 的电脑。
  • 私有化部署门槛高:用户要自己生成口令,再在 server、daemon、App 三处填成同一串。
  1. 账号是匿名的:只有一个 id,没有用户名、密码,也不做登录。
  2. 每台设备一把令牌:App、手机、daemon 各有自己的设备令牌(App oba_…,daemon 沿用 obm_…),server 只存 SHA-256,可以逐台移除。原来的 machines 表改名为 devices 并加上 account_id、kind,已配对的 daemon 令牌照常有效。
  3. 按账号隔离:来电、回复、电脑、投递状态、SSE 推送都只属于一个账号;别的账号的来电、设备一律当作不存在(404),同一个 Multica 任务在不同账号里各来一次电。
  4. 谁先装谁建账号,后来的设备配对加入:
    • 已有设备显示 6 位配对码(10 分钟、只能用一次)和二维码,新设备输码或扫码加入(POST /v1/pairing → POST /v1/pairing/redeem)。
    • 二维码 / 配对链接 outbrief://pair?server=…&code=…&key=obk1_… 同时带上端到端密钥,设备对设备传递,server 看不到;只输 6 位码拿不到密钥,要输加密口令(ADR 0007 的口令派生),或者改用扫码 / 粘贴配对链接。
    • 输错配对码、认领码按来源地址限流(10 分钟 10 次,全局 200 次),6 位码猜不出来。
  5. 谁能建账号取决于部署方式(GET /v1/server 的 signup):
    • 公共云端 OUTBRIEF_OPEN_SIGNUP=true:谁都能建(open),按来源地址限流(每小时 20 个,全局 500 个)。
    • 私有化部署(默认):没有任何账号时 server 每次启动在日志里打印一次性认领码(claim),第一个账号必须带上它;认领后不再允许建新账号(closed),其他设备只能用配对码加入。升级时迁移出的默认账号也算已认领。
  6. 没有 PC 客户端时,daemon 的设置经 server 转发:手机把「本机设置接口」的请求用端到端密钥加密,POST /v1/devices/:id/settings 经 daemon 的 WebSocket 转过去,daemon 解密、执行、把结果加密后原路返回。server 只按请求 id 对应,读不到内容(Multica 令牌、大模型 Key 也不经明文)。改端到端密钥不能走这条路。
  7. 配置只剩数据库地址:OUTBRIEF_DATABASE_URL(部署平台注入,本地默认连 docker 的 outbrief 库)、可选的 PORT、OUTBRIEF_OPEN_SIGNUP;不需要 .env。

私有化部署为什么不和云端走完全一样的逻辑

Section titled “私有化部署为什么不和云端走完全一样的逻辑”

设备、配对、隔离、端到端密钥这些在两种部署下是同一套代码,唯一的差别是“谁能创建账号”。私有化部署如果也开放注册:

  • 私有 server 为了让手机在外面能连上,地址通常是公网可达的。任何知道地址的人(扫端口、看到你的配置、日志外泄)都能注册账号,把你的 server 当免费中转站用,占你的数据库、带宽,甚至用它给别人“来电”。数据虽然按账号隔离、读不到你的内容,但机器和费用是你的。
  • 限流只能拖慢,不能阻止;私有部署也不该承担公网注册的风控。
  • 单人使用的 server 本来就不需要第二个账号,开放注册只有风险没有收益。

所以私有化部署默认关闭注册,用认领码确定“第一个人就是主人”,之后新设备都通过主人已有设备上的配对码加入。认领码只出现在 server 日志里,能看日志的就是部署的人,用户也不用自己生成、到处复制口令。

不采用“从本机(127.0.0.1)来的第一个请求免认领”:server 前面常有反向代理,代理转发来的请求在 server 看来都是本机地址,会把认领直接开放给所有人。

需要给家人各自独立的账号时,临时设 OUTBRIEF_OPEN_SIGNUP=true 重启,建完再关掉;只想共用来电的直接配对进同一个账号。

迁移(现有数据只有作者一个用户)

Section titled “迁移(现有数据只有作者一个用户)”
  • 迁移 012 在已有数据时建一个默认账号(created_via = migration),把所有来电、电脑挂到它下面;空库不建,启动后进入认领流程。
  • 已配对的 daemon 令牌(obm_…)不变,不用重新配对。
  • 桌面 App 升级后丢弃旧的共享口令,改由本机 daemon 引荐:App 用本机密钥文件 ~/.outbrief/local-api.key 请 daemon 生成一个配对码,再自己兑换成设备令牌,加入 daemon 所在的默认账号(server 不再认识共享口令,也就没法拿它换令牌)。手机等其他设备升级后重新扫码配对。
  • 桌面 App 不再用 GET 127.0.0.1:8790/e2e/key 配共享口令取密钥:本机设置接口改用只有本机用户能读的密钥文件鉴权。
  • /v1/auth/check、POST /v1/machines、GET/DELETE /v1/machines 删除,改为 /v1/me、/v1/devices。
  • server 的在线状态、限流、设置转发都在进程内存里,仍然只能跑一个实例(上线策略和以后的扩展路线见 ADR 0009)。