feat(sharing): membership lifecycle v1.1 — invite/accept, revoke rotation, headless sync - #65
Open
yexiyue wants to merge 2 commits into
Open
feat(sharing): membership lifecycle v1.1 — invite/accept, revoke rotation, headless sync#65yexiyue wants to merge 2 commits into
yexiyue wants to merge 2 commits into
Conversation
…tion, headless sync Completes the sharing lifecycle on top of e2e-sharing-v1 (v0.5.0). Revocation now truly cuts off (fulfills e2e-sharing-v1's deferred 5.4): - revoke_member rotates the workspace key (keys::rotate_workspace_key: bump key_version + new self-Lockbox, history retained — lazy, no forward secrecy); remaining members re-fetch the new key reactively on the permission-op broadcast (coordinator -> full_sync::fetch_workspace_key). The removed device gets no new Lockbox so it cannot decrypt new content. - inbound gossip is gated on is_authorized(source) before decrypt, so a revoked device's broadcasts (doc + awareness) are dropped immediately. - the revoked device gets AppEvent::MemberRevoked, auto-unsubscribes, and is notified; already-synced content stays readable (threat model). Sharing is now invite->accept (not a silent owner-side grant): - WorkspaceRequest::ShareInvitation + ShareInvitationResult; AppCore:: invite_device blocks on the recipient's accept/decline (reusing pairing's request-response pending correlation) and only grants on accept. - ShareInvitationReceived event -> ShareInvitationDialog (notification queue); an "auto-accept invitations" preference (default off) skips the dialog for paired devices. Un-opened workspaces are now syncable (headless lazy-open): - AppCore::ensure_open_for_sync opens a member workspace sync-only (no gossip subscribe) on demand when an authorized peer lists/pulls it, so a workspace need not be open in a window to be discovered/synced. Still role-filtered. Refactor: extract the duplicated dialog countdown into useCountdown. core: 106 tests green, clippy clean, tsc/biome clean.
- blog e2e-encrypted-sharing: add section 10 "v1.1 续集" (invite/accept, revoke cutoff + key rotation, headless lazy-open) + fix Mermaid render (Box is a reserved sequenceDiagram keyword -> LB; drop the [..|..] frame text that broke parsing). - 11-threat-model: revocation is now two-stage (online cutoff + key rotation), invite consent, auto-accept opt-in, headless does not loosen the role gate. - 05-sharing: add "v1.1 实现增量" section.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
在
e2e-sharing-v1(v0.5.0,已发布)的加密内核之上,把分享的成员生命周期补全——四个驱动问题都来自真机双设备测试。OpenSpec change:sharing-v1-1(本地,openspec 目录 gitignore)。包含
Q1 撤销真切断(兑现 e2e-sharing-v1 延后的 5.4)
revoke_member发完Revokeop 后调keys::rotate_workspace_key(bumpkey_version+ 新 self-Lockbox,保留历史 = lazy,无前向保密);剩余成员在收到权限链广播时反应式重取新 key(coordinator→full_sync::fetch_workspace_key)。被移除设备拿不到新 Lockbox → 解不开新内容。is_authorized(source)预检 → 即时丢弃被移除设备的广播(doc + awareness)。AppEvent::MemberRevoked→ 自动退订 + 提示;旧的已同步内容仍可读(威胁模型物理边界)。Q2 分享改为「邀请 → 接受」握手
WorkspaceRequest::ShareInvitation+WorkspaceResponse::ShareInvitationResult;AppCore::invite_device阻塞等对方接受/拒绝(复用配对的 request-response pending 关联),接受后才grant_collaborator——未接受不授权。ShareInvitationReceived事件 →ShareInvitationDialog(走通知队列)。Q3 自动接受邀请设置
autoAcceptInvitations(默认关,持久化);开启后对已配对设备的邀请自动接受、不弹窗。Q4 未打开工作区可同步(headless 懒打开)
AppCore::ensure_open_for_sync:被授权对端ListWorkspaces/DocList/WorkspaceKey时,按需以 sync-only(不订阅 gossip) 打开本机未在窗口打开的工作区,使其可被发现/拉取。仍按role_of过滤,未授权看不到也拉不到。重构
useCountdownhook,去掉ShareInvitationDialog/PairingRequestDialog字节级重复的倒计时 effect。验证
rotation_cuts_off_old_version_holder);cargo clippy(core + 桌面)-D warnings干净;tsc+biome干净;桌面二进制链接成功。合并前建议两台真机过一遍:① owner 邀请 → B 弹窗接受 → 可同步;② owner 移除 B → B 在线即停 + 轮换后解不开新内容 + B 收到「已被移出」;③ 另一台设备能看到并拉取 A 未打开的工作区;④ 验证
invite_to_workspace的 request-response 超时窗口够用户响应(配对同款机制)。安全 / 边界(诚实声明)
key_version)永久可读、无法远程删除(任何 E2E 系统的物理边界)。在线切断不是密码学切断(对方仍持旧 key、能离线解已抓的旧密文)。不在本 PR(后续)