15 · 设备配对与 Push
设备配对解决“如何把已有身份安全带到新设备”,Push 解决“App 不在线时如何最小泄露地唤醒它”。两者都把秘密和短期凭证从普通 Relay 事件中隔离:配对使用短命 sidecar relay + ECDH/SAS;Push 使用独立 gateway、opaque capability、generation 与 durable outbox。
1. NIP-AB 配对角色
Source device Target device
has identity fresh install
│ │
├─ QR: source pubkey/session/relay/version
│ │
└──── ephemeral pair relay ─────────┘
encrypted state machineQR payload 不直接放长期私钥;它提供建立会话所需公开/临时材料。双方做 ECDH + HKDF,显示六位 SAS,用户人工确认两端一致后才继续传输身份材料。
2. Pairing 状态机
PairingSession 区分 source/target,限制:
- 消息必须按预期次序。
- session/peer/transcript 一致。
- 重复 event 去重。
- 固定总超时与连接超时。
- abort reason 可传播。
- 完成/失败/Drop 时秘密 zeroize。
SAS 使用 transcript hash 和 constant-time compare,防时序泄漏与中间人替换部分握手内容。
3. Pair relay
buzz-pair-relay 是专用 ephemeral relay,不应承载普通社区事件:
- 只允许 pairing kinds/严格 filters。
- 通过
ptag 定向投递。 - 连接约 120 秒超时。
- 有短窗口限流与 payload bounds。
- 会话结束后没有长期历史价值。
缩小协议面比在主 Relay 里加大量“if pairing”更容易审计。
4. Push 为什么独立 gateway
APNs .p8、team/key ID 等是高价值基础设施凭证。Buzz 把它们只交给 buzz-push-gateway:
client encrypted lease
│ kind 30350 / NIP-PL
▼
Buzz Relay DB + matcher + wake outbox
│ opaque capability / endpoint generation
▼
Push Gateway + its own PostgreSQL
│ sole APNs custody
▼
APNs → device wake-up普通 Relay 不需要看到 APNs token 明文,也不持有 provider signing key。
5. Lease 与 generation
Push lease 是 author-only、parameterized replaceable 事件。客户端更新 endpoint/filters 会产生新 generation:
- Relay 只为当前 generation 匹配事件。
- outbox job claim 带 claim ID/lease。
- worker 真正发送前再次 revalidate community、endpoint、generation。
- provider 报 token 无效时只 disable 精确 generation,不能误伤用户刚更新的新 endpoint。
这解决典型竞态:旧 job 在队列里等待期间,用户重新注册了设备。
6. Durable outbox
Push 不能使用 Redis best-effort fan-out,因为 App 离线时恰恰需要可靠唤醒。事件 commit 后 matcher 把 wake 写入 PostgreSQL outbox;worker 使用 FOR UPDATE SKIP LOCKED/claim lease 并行领取:
Pending → Claimed(generation, claim_id, expires)
→ Sent
→ Retry(next_attempt)
→ Disabled/Dead崩溃 worker 的 claim 到期后可被重新领取;发送端必须幂等/容忍重复,因为网络超时时无法总判断 APNs 是否已接收。
7. Gateway 自己的权威数据库
Gateway 维护与 Relay 不同的表:加密 APNs token、delegation/grant、App Attest 状态、replay 与 quota。这样即使 Relay DB 泄露,也只得到 opaque capability;要实际推送还需 gateway 的加密材料与 provider credential。
8. App Attest 与授权
iOS 注册路径可用 App Attest 证明请求来自合法应用实例。delegation/grant 将“用户签名身份”映射到“可注册某 endpoint 的设备凭证”。Gateway 还做:
- 请求防重放。
- endpoint/token quota。
- provider 错误分类与 backoff。
- 只有确定 token 永久无效时禁用。
9. 最小泄露通知
Push payload 应只包含唤醒/opaque routing 信息,正文回到 App 后从 Relay 拉取并通过正常权限门。把私密消息全文放进 APNs 会扩大 Apple/锁屏/日志暴露面,也绕开事件读取权限变化。
10. 完成度
配对: core crypto/state machine、sidecar relay、CLI 与 Desktop/Mobile 接线基础存在。
Push 服务端: lease、matcher、outbox、claim/revalidate、独立 gateway、App Attest/provider 主链完整。
产品闭环: 仍依赖真实 APNs 凭证、gateway 独立数据库、客户端 entitlement/注册/delegation 与生产监控。根 README 的“Push pending”更像交付状态,不代表服务器代码为空。
11. 源码入口
crates/buzz-core/src/pairing/:ECDH/HKDF/SAS 与状态机。crates/buzz-pair-relay/src/:ephemeral relay。crates/buzz-pairing-cli/src/:配对命令行流程。docs/nips/NIP-PL.md:Push lease 规范。crates/buzz-db/src/push.rs:lease/outbox/claim/generation fence。crates/buzz-push-gateway/src/:App Attest、APNs、授权与存储。docs/push-gateway-deployment.md:部署与密钥轮换边界。