95. 社交协议生态补齐方案 (Social Protocol Parity v1.0)
状态: ✅ 已落地 (v5.0.2.10, 2026-04-16) 日期: 2026-04-16 作用范围:
desktop-app-vue/src/main/social/、desktop-app-vue/src/renderer/pages/social/、packages/cli/src/commands/、packages/session-core/lib/nostr-crypto.js关联文档: 18. 社交 AI 系统 · 43. IPC 域分割与懒加载 · 用户指南: docs/guides/SOCIAL_PROTOCOLS_GUIDE.md
落地概览 (2026-04-16)
| Phase | 协议 / 模块 | 落地位置 | 测试 |
|---|---|---|---|
| 0 (前置) | BIP-340 schnorr + NIP-19 bech32 | packages/session-core/lib/nostr-crypto.js | packages/session-core/__tests__/nostr-crypto.test.js (21) |
| 1 | NIP-04 加密 DM | nostr-bridge.js publishDirectMessage / decryptDirectMessage + IPC nostr:publish-dm / nostr:decrypt-dm + CLI nostr dm / dm-decrypt | tests/unit/social/nostr-bridge-nips.test.js (15) |
| 2 | NIP-09 删除 | publishDeletion + IPC nostr:publish-deletion + CLI nostr delete | 同上 + nostr-bridge-ipc.test.js (23) |
| 3 | NIP-25 表态 | publishReaction + IPC nostr:publish-reaction + CLI nostr react | 同上 |
| 4 | Matrix Threads | matrix-bridge.js (m.thread) + CLI matrix thread send/list/roots | __tests__/unit/matrix-bridge.test.js |
| 5 | Matrix Spaces | m.space.child state event + CLI matrix space create/add-child/children/list | 同上 |
| 补 | ActivityPub C2S | activitypub-bridge.js + CLI activitypub ... (alias ap) | __tests__/unit/activitypub-bridge.test.js |
| 补 | Social Graph | social-graph.js (typed directed edges + EventBus) + CLI social graph ... | __tests__/unit/social-graph.test.js (36) |
| 补 | Topic Classifier | topic-classifier.js (zh/ja/en 语言检测 + 8 主题词典) + CLI social analyze/detect-lang | __tests__/unit/topic-classifier.test.js (32) |
IPC 通道总数: Nostr 6 → 10 (新增 publish-dm / decrypt-dm / publish-deletion / publish-reaction)。 加密实现: x-only-pubkey ECDH (pubkey 前缀 0x02) + AES-256-CBC + 每条消息 fresh 16-byte IV。 签名实现: Desktop 和 CLI 共享 @chainlesschain/session-core/nostr-crypto — @noble/curves schnorr + @scure/base bech32,不再是 placeholder。 CLI 门槛: 所有命令 headless,不依赖 Desktop GUI;用户入门见 docs/guides/SOCIAL_PROTOCOLS_GUIDE.md。
1. 概述
1.1 背景
docs/design/modules/18_社交AI系统.md:1092-1105 列出 8 项未来扩展。本方案聚焦其中 5 项同构的"协议生态补齐":
- Nostr: NIP-04(加密 DM)、NIP-09(事件删除)、NIP-25(表态 / Reactions)
- Matrix: Spaces(类 Discord 服务器分组)、Threads(消息线程回复)
相较于 ML 主题分类 / ActivityPub C2S 需要从零构建标签体系或协议栈,这 5 项都是在现有 Nostr NIP-01 + Matrix Bridge 之上做增量扩展,风险低、用户感知强。
1.2 现状差距
| 维度 | 现状 | 差距 | Phase |
|---|---|---|---|
Nostr kind 4 加密 DM | 事件常量已声明,content 未加密 | NIP-04 ECDH+AES-CBC 未实现 | 1 |
Nostr kind 5 删除 | 常量已声明,无逻辑 | 订阅端 tombstone 过滤缺失 | 2 |
Nostr kind 7 表态 | 常量已声明,无逻辑 | 不支持对事件 +/-/emoji | 3 |
| Nostr 签名 | nostr-bridge.js 签名字段为 placeholder | 需真正 schnorr 签名 + id 哈希 | 1(前置) |
| Matrix Spaces | 无 | m.space.child state event + 层级加载 | 4 |
| Matrix Threads | 无 | m.thread relation + 回复视图 | 5 |
1.3 重要前提:先修复"模拟层"再谈 NIP / Spaces
当前 matrix-bridge.js:126 的 login 无实际 homeserver 调用;nostr-bridge.js 的签名字段和 NIP-19 bech32 都是简化版。本方案要求先把 Nostr 签名链路补成真 schnorr(复用 core-blockchain/crypto 已有的 secp256k1),Matrix 同步引入 matrix-js-sdk 真客户端替换模拟器。若不做这一步,NIP-04/09/25 与 Spaces/Threads 都只是"假实现"。
成本: 前置模拟→真实替换约 3–4 天;若决定仍沿用模拟器,标注 Phase 0 为 "Skipped" 并在每个 phase 末尾加"signatures simulated"警告。
1.4 架构视图
┌──────────────────────────────────────────────────────────────┐
│ Renderer: NostrBridgePage.vue / MatrixBridgePage.vue │
│ + 新增 Tab: DM / Reactions / Spaces / Threads │
├──────────────────────────────────────────────────────────────┤
│ Pinia: nostrBridge.ts / matrixBridge.ts (增 state) │
├──────────────────────────────────────────────────────────────┤
│ IPC: 6 Nostr + 5 Matrix → 12 Nostr + 10 Matrix │
├──────────────────────────────────────────────────────────────┤
│ Main: nostr-bridge.js / matrix-bridge.js (扩事件处理) │
│ + nostr-nip04.js (ECDH + AES-CBC) │
│ + matrix-spaces.js (m.space.child 管理) │
│ + matrix-threads.js (m.thread relation 索引) │
├──────────────────────────────────────────────────────────────┤
│ DB: +nostr_reactions +nostr_deletions │
│ +matrix_spaces +matrix_space_children +matrix_threads │
└──────────────────────────────────────────────────────────────┘2. 实施方案
Phase 0: 签名链路真实化(前置)
工作量: SMALL | 风险: LOW(复用现有 secp256k1)
nostr-bridge.js:将 eventid = sha256(serialized)、sig = schnorr_sign(id, privkey)接入- 依赖:
android-app/core-blockchain/.../WalletCoreAdapter.kt的 secp256k1 已验证;Desktop 侧引noble-secp256k1或现有 BouncyCastle Web 绑定 nostr-identity.js的 npub/nsec 改为真 NIP-19 bech32(bech32npm 包 +@scure/base)
- 依赖:
- 测试: 对照 nostr protocol test vectors 20 条验证
Phase 1: NIP-04 加密 DM
工作量: MEDIUM | 落地文件:
desktop-app-vue/src/main/social/nostr-nip04.js[新增]encrypt(plaintext, theirPubHex, myPrivHex)→${base64(ciphertext)}?iv=${base64(iv)}decrypt(content, theirPubHex, myPrivHex)→ plaintext- ECDH:
secp256k1.getSharedSecret→ 取 x 坐标 32 字节作为 AES key AES-256-CBC+ 随机 16 字节 IV(使用crypto.randomBytes)
nostr-bridge.js:publishDM({toPub, plaintext})→ encrypts → publishes kind 4 with["p", toPub]tag- 订阅 kind 4 回调时按
ptag 匹配自己的 pubkey → 自动 decrypt →decrypted_content字段回传
nostr_events表新增decrypted_content TEXT(与 matrix_events 对齐)- IPC 新增:
nostr:publish-dm、nostr:get-dms(按对端 pubkey 过滤) - CLI 新增:
chainlesschain nostr dm <pub> <text>、chainlesschain nostr dms [--from <pub>]
Phase 2: NIP-09 事件删除
工作量: SMALL | 落地:
nostr-bridge.js::deleteEvent(eventId, reason?)→ publishes kind 5 with["e", eventId]tag- 订阅路径新增
_applyDeletions():- kind 5 到达时,写入
nostr_deletions(event_id, deleted_by_pubkey, reason, created_at)表 getEvents()查询时 LEFT JOIN 过滤:WHERE event_id NOT IN (SELECT event_id FROM nostr_deletions WHERE deleted_by_pubkey = nostr_events.pubkey)- 安全关键: 只认可事件作者本人发的删除(
deleted_by == event.pubkey),避免他人冒充删除
- kind 5 到达时,写入
- IPC 新增:
nostr:delete-event - CLI 新增:
chainlesschain nostr delete <event-id> [--reason ...]
Phase 3: NIP-25 Reactions
工作量: SMALL | 落地:
nostr-bridge.js::react(eventId, reaction)→ kind 7,content∈{"+", "-", emoji}, tags:[["e", id], ["p", authorPub]]nostr_reactions(event_id, reactor_pubkey, reaction, created_at)表 + UNIQUE(event_id, reactor_pubkey)(同人只算最新一条)- 订阅 kind 7 时按对应被反应事件聚合计数
getEventReactions(eventId)返回{"+": 12, "-": 2, "❤️": 5}聚合- IPC 新增:
nostr:react、nostr:get-reactions - CLI 新增:
chainlesschain nostr react <event-id> <+|-|emoji>
Phase 4: Matrix Spaces
工作量: MEDIUM | 落地:
desktop-app-vue/src/main/social/matrix-spaces.js[新增]createSpace({name, topic, visibility})→ POST/createRoomwithcreation_content: {type: "m.space"}addChildToSpace(spaceId, childRoomId, suggested=false)→ PUT statem.space.childwithvia: [homeserver]listSpaceChildren(spaceId)→ 读取 space 的 state events,递归(上限 3 层防环)
- DB 表新增
matrix_spaces(room_id PK, name, topic, visibility, created_at)+matrix_space_children(parent_id, child_id, suggested, order, added_at, PK(parent, child)) - IPC 新增:
matrix:create-space、matrix:list-spaces、matrix:add-space-child、matrix:list-space-children - Renderer:
MatrixBridgePage.vue新增 Space 侧栏(树状展示),点击 space 节点过滤 room 列表 - CLI 新增:
chainlesschain matrix space create/list/add-child/children
Phase 5: Matrix Threads
工作量: MEDIUM | 落地:
desktop-app-vue/src/main/social/matrix-threads.js[新增]- 发送线程回复:消息 content 加
"m.relates_to": {"rel_type": "m.thread", "event_id": rootId} listThreadReplies(rootId)→ 本地查询matrix_events.content.m.relates_to.rel_type = "m.thread"过滤- 可选:
/rooms/{id}/relations/{rootId}/m.thread真 homeserver 查询(MSC3440)
- 发送线程回复:消息 content 加
- DB 新增
matrix_threads(root_event_id PK, room_id, last_reply_at, reply_count)(聚合视图,非真源)- 每次
sendMessage如带 thread relation → 自动 UPSERT 这张表
- 每次
- IPC 新增:
matrix:send-thread-reply、matrix:list-thread-replies、matrix:list-threads(房间内所有线程根事件) - Renderer:
MatrixBridgePage.vue聊天视图消息悬浮出现 "Reply in thread" → 右侧抽屉打开 thread 视图 - CLI 新增:
chainlesschain matrix thread reply <room> <root-id> <text>、matrix thread list <room>
3. 测试计划
| Phase | 单测 | 集成 | 目标 |
|---|---|---|---|
| 0 | 15 | 3 | schnorr 签名 + NIP-19 bech32 与官方 test vectors 一致 |
| 1 | 12 | 2 | NIP-04 加解密往返;DM 订阅过滤;错误 pubkey 解密失败 |
| 2 | 8 | 2 | 非作者删除不生效;订阅端过滤;删除后重新订阅仍隐藏 |
| 3 | 10 | 2 | 聚合计数;同人多次反应只算最新;删除反应 |
| 4 | 14 | 3 | space 创建 / child 加入 / 树状渲染 / 3 层环检测 |
| 5 | 12 | 3 | thread relation 写入 + 查询 / 聚合表 UPSERT / 根事件列表 |
| 合计 | 71 | 15 | 追加 ~86 tests |
4. IPC / CLI / Renderer 增量
| 层 | 数量变化 |
|---|---|
| IPC 通道 | Nostr 6→12(+6)· Matrix 5→10(+5)(命名遵循 domain:action 惯例) |
| CLI 子命令 | Nostr +4 · Matrix +6 |
| DB 表 | +5:nostr_reactions · nostr_deletions · matrix_spaces · matrix_space_children · matrix_threads |
| Vue 页面 | NostrBridgePage.vue +2 Tab(DM / Reactions)· MatrixBridgePage.vue +Space 侧栏 + Thread 抽屉 |
5. 里程碑
| 里程碑 | 预估 | 内容 |
|---|---|---|
| M0 | +3d | Phase 0 签名真实化 + test vectors 通过 |
| M1 | +3d | NIP-04 落地 + 加密 DM 往返跑通 |
| M2 | +1d | NIP-09 删除 |
| M3 | +1d | NIP-25 反应 |
| M4 | +4d | Matrix Spaces(含 UI) |
| M5 | +3d | Matrix Threads(含 UI) |
| 合计 | ~15 工作日 | 2026-04-16 起算 ≈ 2026-05-09 完成 |
6. 风险与权衡
- 签名真实化成本被低估:若 Desktop 侧选
noble-secp256k1而非复用已有 BouncyCastle,需做 Node/Electron 兼容性验证。建议 Phase 0 先做 1 天 spike。 - Matrix 真 E2EE 不在本方案内:Spaces/Threads 仍基于模拟器或明文房间工作;真 Olm/Megolm 整合另列方案。
- NIP-04 已被社区视为 legacy(NIP-44 是新推荐)。本方案先补 NIP-04 保持生态兼容,NIP-44 可作为 Phase 1.5 增量。
- Spaces 层级递归:硬限 3 层 + 访问过的 room_id Set 去重,防止 space 自引用死循环。
7. 不做 / 延后
- ActivityPub C2S(与 Fediverse 搜索配套,独立方案)
- ML 主题分类 / 多语言支持("AI 增强"路线,另列方案)
- 真 Olm/Megolm E2EE(复杂度一个数量级以上)
- NIP-44(NIP-04 的继任者,待本方案验证稳定后作为 1.5 增量)
方案作者: AI Assistant (Claude) 审阅人: TBD
