-
Notifications
You must be signed in to change notification settings - Fork 469
fix(desktop): gate notification content on Runtime Host privacy policy #5002
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1013,6 +1013,26 @@ registerNotificationsIpc({ | |
| locale: desktopLocale, | ||
| mainWindowController, | ||
| e2e: isE2e, | ||
| // Privacy state is Host-owned: the local settings copy never receives | ||
| // privacy updates, so the notification gate asks the authority instead | ||
| // of trusting the stale local copy (#4981). Any ready host holding | ||
| // incognito suppresses the banner; an unreachable authority does too. | ||
| privacyAuthority: { | ||
| isIncognitoActive: async () => { | ||
| const entries = runtimeHostManager?.entries() ?? []; | ||
| const ready = entries.filter( | ||
| (entry): entry is Extract<typeof entry, { readiness: 'ready' }> => | ||
| entry.readiness === 'ready', | ||
| ); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] Do not drop a reconnecting Host from the privacy decision A terminal event can already have been forwarded to the renderer when its Host disconnects; the renderer then invokes notifications:runEnded with the title/preview while the manager publishes that Host as reconnecting (runtime-host-desktop-manager.ts:1365-1370). This filter silently excludes its privacy authority. Executing this exact adapter with only a reconnecting Host returns false; a reconnecting private Host plus another ready non-private Host also returns false. Promise.all([]) does not reject, so resolveNotificationIncognito never reaches its fail-closed catch and the native banner can expose the content. The IPC payload has no originating Host identity, so another ready Host cannot authorize this message. Preserve a suppressing verdict when the originating privacy authority cannot be queried (and cover the real adapter readiness transition). |
||
| const verdicts = await Promise.all( | ||
| ready.map(async (entry) => | ||
| (await entry.candidate.client.queryRuntimePolicy()).policy.privacy | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Exclude unrelated guest policy failures from local notification decisions Normal supported path: mount a shared Session and then complete a turn in a local non-incognito Session. The actual adapter probe with a local false verdict and a ready guest rejecting policy returns raised=false. Scope the query to the notification's legitimate authority; do not grant guests whole-Host policy access or simply ignore failures of the source Host. A local + mounted-guest regression should preserve the local notification. 中文正常挂载共享 Session 后,guest 同样进入 ready entries,但其权限不包含 runtime.policy.query,因此 Promise.all 拒绝,所有普通本地通知也被当隐身取消。探针复现 raised=false。应按通知来源隔离权威,不给 guest 扩整机权限,也不能忽略来源 Host 的失败。 |
||
| .incognitoActive, | ||
| ), | ||
| ); | ||
| return verdicts.some((active) => active); | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| const sessionCopyOwnerProcessId = randomUUID(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P1] Do not turn a reconnecting privacy authority into a non-incognito verdict
Reasonable disconnect race: an incognito Host delivers a completed/error event, the renderer queues notifications:runEnded, and that Host enters reconnecting while the handler awaits local settings. This ready-only filter removes it before any policy query. With zero ready entries (or only an ordinary local Host remaining),
verdicts.somereturns false, so an unfocused window can display the queued private title/body. The query-error catch cannot help because the Host was never queried.The exact adapter/gate probe produces raised=true for zero-ready and local-ready + incognito-reconnecting cases. Keep a missing/unready relevant authority fail-closed; if needed pass the source scope through the existing notification IPC so the main process can resolve the right Host. Cover this actual boot decision, rather than only an injected resolver that throws.
中文
合理断连路径:隐身完成事件已触发通知 IPC,main 等待 settings 时 Host 变为 reconnecting,被 ready filter 排除,空 verdict 或仅普通本地 Host 都返回 false,后台窗口因此可展示私密标题/正文。未查询就不会触发 catch。探针确认 raised=true。相关权威缺失或未 ready 应保守抑制,必要时沿现有 IPC 传来源;测试应经过实际 boot adapter。