
Seal v0.2.3
点对点、端到端加密聊天。没有收件箱。没有可恢复的账户。没有人窃听——包括我们自己。
消息通过 libp2p 在节点之间直接传输,并在离开你的设备之前使用 Signal 风格的 Olm/Megolm 协议(通过 vodozemac)加密。唯一涉及的服务器是一个小型目录,帮助节点找到彼此的当前地址。它永远看不到消息内容,而且可以用一条命令清除。
有关实际防护的内容以及方式,请参阅 docs/THREAT_MODEL.md 和
docs/SECURITY.md。
Contents
截图
首次运行 —— 只需选择一个名称;无需其他设置。
会话 —— 群组栏、联系人列表和端到端加密聊天面板。
设置 —— 麦克风灵敏度、按键通话、登录时启动、网络可达性。
功能特性
- 始终端到端加密 —— 每条消息在离开你的设备之前,都会使用 Olm(1:1) 或 Megolm(群组)进行密封,采用 vodozemac 的双棘轮(Double-Ratchet)式方案: 每条消息都有自己独立的密钥。
- 永远没有收件箱 —— 消息通过点对点直接连接 (libp2p:QUIC/TCP + Noise,支持中继和 NAT 打洞)传输。如果接收方离线,消息会在本地等待并重试——绝不会排队存储在任何其他人的基础设施上。
- 目录,而非数据库 —— 唯一涉及的服务器
(
crates/directory-server)仅将用户 ID 映射到当前网络地址, 除此之外不做任何事情。它在结构上无法读取消息内容: 其Cargo.toml甚至不依赖任何知道如何读取消息内容的 crate。 - 一台设备,多个账户 —— 完全独立的身份(密钥、 联系人、消息),无需重启即可切换。
- 支持真实成员变更的群组 —— 每个群组都有文本和语音频道; 移除某人会轮换群组密钥,使其无法读取此后发送的任何内容。
- 内置语音 —— 通过系统级快捷键进行按键通话(适用于任何应用,而不仅仅是 Seal),可调节麦克风灵敏度,并可选变声器。
- 无元数据的附件 —— 图片在发送前会剥离 EXIF 数据(GPS 位置、 相机/设备信息),默认开启。
- 真正的紧急按钮 —— 设置 → 数据与隐私可立即且不可逆地删除本设备上的所有密钥、联系人和消息,而不会对你联系过的任何人产生任何影响。
- 如果需要,登录时启动 —— 默认开启,在设置中一键切换。
- 一套代码库,三个平台 —— 通过 Tauri 在 macOS、Windows 和 Linux 上提供原生窗口。
工作原理
这个应用中有两种身份,它们被刻意分开:
- 你的聊天身份 是 vodozemac 在你首次打开应用时在本地生成的 Ed25519/Curve25519 密钥对(
identity::Identity)。你的公开“用户 ID”就是该密钥的指纹(wire_proto::user_id_from_ed25519)。任何服务器都无法签发或吊销它,因为它的创建过程不涉及任何服务器。 - 你的网络身份 是一个单独的 libp2p 密钥对(
PeerId),仅用于传输层。它可以在重启之间变化,而完全不影响你的聊天身份;两者仅通过你自行签名的在线状态记录绑定在一起。
找到某人并真正与他们交谈是两个不同的步骤:``` ┌────────────────────────┐ │ directory server │ │ (axum + one SQLite │ │ file: users, │ │ presence, group │ │ rosters. Never │ │ message content.) │ └─────────┬───────────────┘ 1. "where is bob │ 2. "here's my current right now?" │ address" (signed, │ expires in minutes) ┌─────────┴───────────────┐ ▼ ▼ ┌───────┐ 3. direct libp2p ┌───────┐ │ alice │◄──── connection ────►│ bob │ └───────┘ (Noise + Olm/ └───────┘ Megolm encrypted)
1. Alice 通过 Bob 的用户 ID 在目录中查找他。这会返回他的
公钥以及他最后通告的网络地址。这就是目录所持有的全部内容:
公钥、显示名称、组成员列表,
以及短期有效的地址通告
(`crates/directory-server`)。
2. Alice 直接通过 libp2p(QUIC 或 TCP+Noise,带中继 +
NAT 打洞,用于 NAT 后的对等方;参见 `crates/net`)呼叫 Bob。目录从
此刻起完全不再参与。
3. 实际消息会使用 **Olm**(用于 1:1 聊天)或
**Megolm**(用于群组,`crates/crypto-session`),这是一种 Double-Ratchet 风格
方案,每条消息在放到该 libp2p 连接之前
都有自己的密钥。没有服务器端收件箱:如果 Bob 离线,
消息会在本地等待并重试,而不是存储在任何其他人的
基础设施上。
以上所有内容均由 `crates/core` 的 `AppService` 编排,它
是 Tauri 应用的 Rust 后端(`apps/desktop/src-tauri`)实际调用的对象;
UI 从不直接与网络通信。
## 项目布局```
crates/
wire-proto shared signed-request types for the directory API
identity vodozemac identity, OS-keychain key management
storage local encrypted store (contacts, messages, groups)
net libp2p transport + directory HTTP client
crypto-session Olm (1:1) / Megolm (group) session management
core orchestrates the above into `AppService` / `ChatNode`
directory-server the one server component (axum + SQLite)
apps/desktop the Tauri + React app
scripts/ build + backend-deployment scripts (§2, §5)
1. 前置要求
你在每个平台上都需要 Rust 和 Node.js,此外还需要 Tauri 用于构建原生窗口的、特定于平台的
工具链。storage 和 directory-server 还会从源码捆绑编译 SQLite,这需要一个普通的 C 编译器(本项目中
任何地方都不需要 OpenSSL 或其他原生加密库)。
所有平台通用: