Files
WebDrop/docs/account-channel-architecture.md
T
justme 58506f82de
ci/woodpecker/pr/web-build Pipeline failed
ci/woodpecker/pr/ci Pipeline was successful
docs: describe workspace signing boundaries
2026-10-14 04:06:29 +08:00

6.9 KiB

账号、设备、频道与加密的统一模型

本文件收束账号频道工作区的模型;密码学细节仍以 protocol.md 为准。临时 Share 是独立的对外发布功能,只复用文件传输和密码学,不作为频道成员模型。

领域边界

已确认的下一版规则

注册设置初始密码。密码和绑定的 Passkey 是账号认证/解锁入口,不要求旧设备批准新设备;Passkey 的 WebAuthn 验证由 .NET 10 官方组件完成。支持 PRF 时浏览器封装保险库解密凭据;PRF 输出不传给服务器。不支持 PRF 的 Passkey 可登录,资源解密仍需密码。绑定需重新验证密码,撤销后该凭据不能再创建会话。

Member 加入空间后自动获得默认频道的聊天读取/发言和文件读取/上传权,只能修改自己的内容,不能管理频道或邀请成员。其他频道单独授权;历史聊天和文件由 Owner 分别决定是否向新成员开放。历史选择在接受邀请时生效:关闭时分别轮换该数据域 epoch,仅给新成员当前 epoch;已获授权的成员保留历史访问。之后修改开关只影响后续邀请,不撤回已交付密钥。

Account 使用不可修改的 username 作为稳定身份,displayName/avatar 由后端个人资料接口管理。AccountDevice 是账号下的浏览器身份,具有独立登录 session、名称与撤销状态;每个空间的设备 S 独立生成。空间成员绑定账号与角色,不绑定某次登录或设备。

空间是成员管理与同步的边界,不是内容密钥边界。频道属于空间,分组归属空间,文件夹属于频道,资源归属由后端校验和保存。新空间与初始“常规”频道在同一事务中创建。每频道独立维护 chat 与 files 两个数据域及 epoch;分组仅组织频道,不创建密钥域。

模块互通

账号模块提供当前身份、个人资料、设备会话与解锁后的账号密钥。空间模块负责创建空间、初始频道、成员邀请与加入;频道模块负责频道、分组、文件夹和频道内的聊天/文件访问。权限、历史范围、epoch 和授权收件人由后端计算、持久化和校验。浏览器只根据服务端返回的授权计划生成密钥并进行封装;它不能选择或扩大授权集合。加密模块不读取 UI 或数据库,只提供账号密钥封装、随机对象密钥封装和帧加解密。Worker 是 API 与密码学之间的编排层,不是业务规则来源。

账号登录授权访问服务端;频道内容密钥授权解密内容。这两种能力分开校验,服务端不能通过登录 token 推出频道密钥。频道主的成员记录才是 owner 权限的最终依据,不能凭复制管理密钥冒充另一个账号。

密钥与多设备

账号邀请私钥保存在密码加密的保险库中,多台设备登录同一账号后解锁同一账号私钥。空间创建时生成空间访问凭据,Owner 凭据与 Owner 账号密钥包由后端原子存储;它们不再加密频道内容。频道 chat/files 域密钥在浏览器生成,并通过 Owner 账号 ECDH 公钥封装;服务端保存密文,获授权成员的账号可领取并在本机解封。

已加入成员的新设备只凭账号登录即可解封账号分发给该账号的数据域密钥,不需要邀请者在线,也不需要复制带内容密钥的链接。每个浏览器有独立设备登录凭据和独立空间终端 S;读取账号空间列表不占成员名额,实际打开空间才登记设备席位。同一账号在一个空间只占一个成员名额,设备数量不受成员上限影响。设备撤销会撤销其账号 sessions;账号空间成员身份及其人数名额保留,其他设备继续访问。

本机记住登录保存 session token、不可导出的保险库 CryptoKey 和加密保险库。勾选记住账号密码时,将填充资料用另一把不可导出的本机 AES-GCM 密钥加密保存;不保存 verifier。退出清除自动恢复 session,保留已选择保存的填充资料,明确清除时全部移除。登录态与本机资源数据库在同一启动屏障后恢复,避免先加载访客资源再切换账号。

文件目录与内容

频道、分组、目录和资源归属通过服务端结构接口管理,前端拉取快照并渲染。上传文件完成密文传输后提交资源归属;归属操作也保存在本机队列中,断网重试不丢失。文件名称、类型、大小继续保存在加密 file.published 元数据中,读取元数据不消耗下载次数;下载内容后校验元数据一致性。

不迁移旧加密结构或旧账户资料,不提供导入接口。新结构与新资料直接由后端管理,客户端不再处理结构控制记录。

空间访问凭据不再用于频道内容加密。每频道 chat/files 域各自生成随机 32 字节 epoch 密钥,按账号公钥封装;每个聊天条目、文件及加密发布元数据再独立生成随机对象密钥,由对应域密钥加密封装。对象封装的 AAD 绑定空间、频道、域、epoch 和 itemId。保留现有逐帧认证、FINAL、连续性、padding、ID/AAD 校验与持久化密文重试。下载逐块解密到本机临时存储,完整性和大小校验成功才交付文件;出错清除临时内容。OPFS 不可用时使用 Blob 回退并明确限制。

安全边界

频道域 epoch 与随机对象密钥允许新成员按设置只领取当前 epoch,服务端也会在写入时检查作者、频道授权及当前 epoch。WorkspaceChannel 是唯一频道聚合;Chat 与 FileGroup 是独立域,授权和密钥隔离,但共享对象帧存储。账号设备已具备根签证书和 FINAL 对象帧签名验证基础;频道结构命令、删除事件和成员/设备撤销后的域轮换仍未完成。已获得的历史密钥和明文无法被收回,因此不能声称已实现前向保密。

账号签名根公钥和根签名设备证书已有基础实现,首次从服务端获得的其他账号根公钥使用 TOFU 固定;首次密钥替换仍无法检测。频道结构、权限、作者归属和聊天/文件生命周期目前尚未改为签名事件,客户端尚未校验 Owner Capability 或事件签名。密钥透明性、授权/事件签名和成员撤销密钥轮换仍未完成,不能宣称已抵御主动恶意服务端。前端代码与运行终端仍是信任根。

账号昵称与设备名是不同概念,昵称不参与密钥派生。头像接受有大小上限的 PNG/JPEG/WebP,由后端管理,禁止第三方头像 URL 和可执行 SVG。聊天发送者由服务端条目作者和账号资料提供,不接受加密内容中的身份声明。

界面术语采用「空间 → 频道分组 → 频道 → 文件夹/聊天」。旧资源路由 /channels 和帧协议 threadId 保留,分别映射空间/频道;新结构接口使用 /spaces。账号保险库保存私钥和访问凭据,资料与结构不再由客户端合并同步。