Skip to content

feat: 去中心化中继、单文件中继、Nostr/MQTT、界面简化与文件内自定义中继 - #6

Merged
Freecode100Year merged 5 commits into
mainfrom
feat/decentralized-relays
Oct 30, 2026
Merged

Freecode100Year merged 5 commits into
mainfrom
feat/decentralized-relays

Conversation

@Freecode100Year

Copy link
Copy Markdown
Owner

概要

一个分支完成三步:去中心化中继、降低中继部署门槛、接入外部协议。另外包括界面文字改为大白话,以及持有房间文件的人可以在文件里自定义中继。

⚠️ 本分支建立在 #5 之上,包含它的提交。只合并本 PR 即可一次并入全部改动;先合并 #5 的话,这里的 diff 会自动缩小。

1. 去中心化房间(version 3)

  • 中继写成 bc+wss://…、nostr+wss://… 或 mqtt+wss://…/mqtt,房间即为 version 3(1–5 个,可混用,但不能与经典 wss:// 混用)。经典 version 2 房间保持不变;「换中继」可以在两类之间互转,密钥不变。
  • html-room/mesh.js 把原来中继负责的事交给成员协商:
    • 入房:帧用 master 派生的 AES-GCM 密钥封装,并绑定 topic。
    • 编号:新成员先广播自己,其他人立即回应,之后认领最小空号;冲突时先认领者保留。
    • 在线名单:靠心跳推算。
    • 发送者:由封装内的编号标注,签名仍由 Group 层验证。
  • 每个帧同时发往全部中继,并按 IV 去重:只要有一个中继还通,房间就不会断,也不会出现成员分裂。
  • Node 服务器和 Cloudflare Worker 新增 /bc/<topic> 纯转发路径,限制帧大小、速率和每个 topic 的连接数,Origin 规则与 /hr/ 相同。

2. 更容易部署中继

  • relay/go:只用 Go 标准库的 bc 中继,单文件约 6 MB,覆盖 Windows、macOS、Linux、FreeBSD、Android 和 OpenWrt(mips/arm)。
    • -tunnel 通过 Cloudflare 临时隧道打印公网 bc+wss:// 地址,不需要域名、公网 IP、开端口或 root。
    • 另有 -allow-origin、-tls-cert 等参数,以及一个 Dockerfile。
  • scripts/relay-quickstart.sh:下载对应平台的二进制,强制校验 SHA-256;按需下载 cloudflared;也支持 --from-source。
  • .github/workflows/relay-binaries.yml:推送 tag 时构建 13 个平台并附加到 Release(需要推送一个 tag,quickstart 的下载地址才可用)。

3. 外部协议

  • Nostr:临时事件 kind 20111,标签 ["t", topic],每次会话使用一次性密钥做 BIP-340 签名(新增依赖 @noble/curves、@noble/hashes)。
  • MQTT 3.1.1 over WebSocket:QoS 0,主题 htmlroom/<topic>。

界面文字

  • 创建页和房间文件的所有文字改为大白话。
  • 中继设置收进折叠栏,主按钮高亮。
  • 两个页面都加了仓库链接。

文件内自定义中继

  • 新配置字段 custom: true:创建页默认勾选,取消勾选或 CLI 加 --strict 即关闭。
  • 开启的文件 CSP 为 wss: ws://localhost:* ws://127.0.0.1:* 加列出的中继。
  • 进房前可以填任意中继,只对这次打开有效,不改文件;密钥、口令和 roomId 不变。
  • 网页链接入口不显示该输入框。
  • 安全上的取舍写在 security-model.md。

测试

  • 单元测试:63 项通过。
  • 真实中继互通:本项目 Node 中继、Go 中继、会校验签名的 Nostr 中继、aedes MQTT;Worker 的 /bc/ 在 wrangler dev 下验证。
  • 浏览器:
    • mesh.mjs:3 名成员同时连 4 个中继,安全码一致,回执正常;逐个断开中继直到只剩 Nostr 仍能聊天;成员离开能及时看到;创建页一键生成去中心化房间。
    • custom-relay.mjs:在文件里填写中继,经典和去中心化两种都测了。
    • 原有浏览器测试与 Pages 测试全部通过。
  • Go 中继通过 go vet,可交叉编译到 10 个平台。

未验证

  • 没有连过真实的公共 Nostr 中继、公共 MQTT 代理,也没有跑过真实的 cloudflared(测试环境不能访问外网)。
  • 没有做真机测试。
  • npm audit 报的 undici 问题来自 wrangler 开发依赖,在本分支之前就已存在。

Generated by Claude Code

Room files gain a 更换中继 panel that re-emits the same room (master or
wrapped key untouched, no password needed) with a new relay list and exact
CSP connect-src. The hosted maker converts existing files, and the CLI gains
a retarget command. All three paths produce byte-identical output that
passes verify-room-file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PCUwNSXQdqfDSugmFo4qmM
1. Relay-agnostic transport (version 3 rooms)
   - Relay entries bc+wss://, nostr+wss://, mqtt+wss:// select version 3;
     classic wss:// rooms stay version 2, unchanged. Retarget converts
     between them with the same key, password and roomId.
   - html-room/mesh.js: members admit (AES-GCM frames under a master-derived
     key), number (announce, claim, earliest claim wins), list and attribute
     each other; relays only forward. Every frame goes to every relay and is
     de-duplicated by IV, so one surviving relay keeps the room together.
   - Node server and Cloudflare Worker serve /bc/<topic> plain broadcast.

2. Easier relays
   - relay/go: dependency-free Go broadcast relay, one ~6 MB binary for
     Windows, macOS, Linux, BSD, Android and OpenWrt routers; -tunnel prints
     a public bc+wss:// address via a Cloudflare quick tunnel (no domain,
     open port or root).
   - scripts/relay-quickstart.sh downloads it (SHA-256 enforced) and
     cloudflared; Relay binaries workflow publishes 13 platform builds.

3. External protocols
   - Nostr: ephemeral kind 20111 events tagged with the topic, signed with
     a per-session BIP-340 key (@noble/curves).
   - MQTT 3.1.1 over WebSocket, QoS 0, topic htmlroom/<topic>.

Tests: unit (parsing, sealing, packets, membership clashes), real relays
(Node, Go, signature-checking Nostr relay, aedes MQTT, Worker /bc/ under
wrangler dev), browser end-to-end over four relays with relay loss.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PCUwNSXQdqfDSugmFo4qmM
Rewrites every user-facing string in the room creator and the generated
index.html in everyday words, moves relay settings into a collapsed
section, highlights the main buttons, and links the repository
(https://github.com/Freecode100Year/htmlroom.git) from both pages.
Tests updated for the new wording.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PCUwNSXQdqfDSugmFo4qmM
Files carry an optional custom: true (on by default in the creation page
and CLI room; untick or --strict for exact relays only). Such files allow
connect-src wss: plus loopback ws, and show a relay box on the entry
screen; typed relays apply to that visit only and pick classic or
decentralized mode, with the same key, password and roomId. Web links
never show the box. Converter and CLI retarget keep or change the setting.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PCUwNSXQdqfDSugmFo4qmM
@Freecode100Year
Freecode100Year merged commit bbdd81f into main Oct 30, 2026
14 of 16 checks passed
@Freecode100Year

Copy link
Copy Markdown
Owner Author

已随 #8 并入 main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants