Repository navigation
feat(webview/gmeet): native cam/mic/screenshare + keep Meet routing in-app (#1022) - #1054
Conversation
…google.com (tinyhumansai#1022) Embedded Google Meet was stuck on "Use microphone and camera" consent dialog and `getUserMedia()` calls returned `NotAllowedError` because `Browser.grantPermissions` for the gmeet CDP session only granted `notifications` (added by tinyhumansai#1028 for Slack). Confirmed during the tinyhumansai#1022 parity audit smoke — clicking "Use microphone and camera" was a no-op, and "Continue without microphone and camera" was the only path that landed the user in a meeting (with no AV). Extend the per-origin grant to cover Google Meet's full permission set: - `audioCapture` / `videoCapture` — getUserMedia for the cam/mic preview and in-call streams. Without these the consent dialog stays up forever even when the OS-level permission is granted. - `displayCapture` — getDisplayMedia for the "Present now" / screenshare send flow. - `clipboardReadWrite` — Meet's "Copy meeting link" button. Origin-scoped to `https://meet.google.com` only (via the new `origin_host_is` helper) so other providers' grants are unaffected: Slack still gets only `notifications`; WhatsApp / Telegram / Discord keep their current single-permission grant. Verified end-to-end against staging Meet: - Cam/mic preview renders in the pre-call greenroom - In-call cam, mic, screenshare-send, screenshare-receive, captions, reactions, raise-hand, in-call chat, hangup-return all work - Background effects still fail with "something went wrong" (CEF runtime gap — filed as tinyhumansai#1053) Adds two unit tests for `origin_host_is`: canonical-origin accept set (scheme/port/case insensitivity) and reject set (different host, subdomain mismatch, non-http schemes).
…om popup parent-nav (tinyhumansai#1022) Two related leaks that were sending parts of the Google Meet flow out to the user's system browser, both surfaced during the tinyhumansai#1022 parity audit smoke. **1. workspace.google.com marketing-page redirect** After the user picked an account in the in-app sign-in flow, Google's edge would SSR-redirect to `workspace.google.com/products/meet/...`. `provider_allowed_hosts("google-meet")` lists a bare `google.com` suffix which `url_is_internal` matches against `workspace.google.com`, so the navigation committed and the user landed on the Workspace marketing page instead of Meet. `on_navigation` now intercepts `workspace.google.com` (and any subdomain) for the `google-meet` provider and replaces the parent's URL with the canonical `https://meet.google.com/` entry point. The original navigation is cancelled. Logged for diagnostics. **2. "Start now" / new-room popup leak** Clicking "Start an instant meeting" / "New meeting" calls `window.open(https://meet.google.com/<roomid>)` to launch the room. The default `on_new_window` chain had no in-app handler for gmeet's own host (`popup_should_navigate_parent` only matched the Google auth popup, `popup_should_stay_in_app` is slack/zoom-only) so the URL fell through to `open_in_system_browser` and the meeting opened in Chrome — the user lost their session entirely. Extend `popup_should_navigate_parent` for the `google-meet` provider to also match `meet.google.com` hosts. The popup is denied and the embedded parent is navigated into the room URL, so the meeting stays in the same in-app tab the user clicked from. **Tests** Four new `webview_accounts::tests::*` cases covering the popup branch: - `gmeet_room_popup_navigates_parent` — meet.google.com/<roomid> is matched and the parent is navigated. - `gmeet_landing_popup_navigates_parent` — bare meet.google.com works too (covers the post-hangup "back to Meet home" UX). - `gmeet_workspace_popup_does_not_navigate_parent` — workspace marketing falls through to the on_navigation rewrite (and external fallback if it ever arrives via window.open). - `gmeet_unrelated_popup_does_not_navigate_parent` — third-party links still route to the user's default browser. The on_navigation rewrite is exercised end-to-end in the audit smoke documented in `docs/qa/GMEET-PARITY.md` row 2.
15-row matrix mirroring `docs/qa/GMAIL-PARITY.md` shape, pre-filled from the smoke run against staging Meet: - ✅ rows 2-12 + 14 (landing, start-now, join, cam/mic preview + in-call, screenshare send + receive, captions, in-call chat, reactions, session persistence, hangup return UX) - ❌ row 1 Auth — blocked on PR tinyhumansai#1046 (Google SSO ccTLD predicate); rebases away once tinyhumansai#1046 merges - ⏭️ row 13 Captions ingestion → memory_doc_ingest — feature deferred to tinyhumansai#1052 - ❌ row 15 Background effects — Chromium runtime gates absent in CEF; filed at tinyhumansai#1053 Includes the pre-audit code-level gaps, CDP-migration sketch, hardcoded constants table, and sign-off block.
📝 WalkthroughWalkthroughThe changes implement Google Meet-specific webview optimizations: dynamic CDP permission grants for meet.google.com (notifications, audio/video capture, display capture, clipboard), popup navigation interception to retain Meet sessions in-webview, and workspace.google.com redirect detection with automatic redirection to canonical meet.google.com. A comprehensive QA parity checklist is added. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Review rate limit: 4/5 reviews remaining, refill in 12 minutes. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src-tauri/src/webview_accounts/mod.rs`:
- Around line 1466-1469: The log call in the webview-accounts module currently
logs the full `url` (see the log::info! that reports "gmeet workspace marketing
redirect intercepted"), which may include sensitive query/fragment data; to fix,
parse or sanitize `url` before logging (e.g., create `redacted_url` by using
url::Url::parse(&url) and clearing query/fragment or by taking the part before
'?' and '#'), then replace `url` in the log::info! call with `redacted_url` so
only the safe path/host is recorded.
In `@docs/qa/GMEET-PARITY.md`:
- Line 75: The result tally in the GMEET-PARITY sign-off line double-counts the
same blocked item `#1046`; update the summary string in docs/qa/GMEET-PARITY.md
(the "Result: 11 ✅ / 0 ⚠️ / 2 ❌ ..." line) to remove the duplicate "1 ❌ blocked
on `#1046`" entry so the counts add up consistently (e.g., consolidate to a single
"2 ❌ (one blocked on `#1046`, one deferred to `#1053`)" or adjust counts so the
totals match the listed breakdown).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cb45b5fa-12f2-40ed-b1ac-24a407577dbe
📒 Files selected for processing (3)
app/src-tauri/src/cdp/session.rsapp/src-tauri/src/webview_accounts/mod.rsdocs/qa/GMEET-PARITY.md
| log::info!( | ||
| "[webview-accounts] gmeet workspace marketing redirect intercepted ({}); rewriting parent to https://meet.google.com/", | ||
| url | ||
| ); |
There was a problem hiding this comment.
Redact redirected URL before logging
Line 1467 logs the full URL. This path can carry query/fragment data, so logging raw values risks persisting sensitive auth/navigation artifacts. Log a redacted version instead.
Suggested patch
- log::info!(
- "[webview-accounts] gmeet workspace marketing redirect intercepted ({}); rewriting parent to https://meet.google.com/",
- url
- );
+ log::info!(
+ "[webview-accounts] gmeet workspace marketing redirect intercepted ({}); rewriting parent to https://meet.google.com/",
+ redact_navigation_url(url)
+ );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/src-tauri/src/webview_accounts/mod.rs` around lines 1466 - 1469, The log
call in the webview-accounts module currently logs the full `url` (see the
log::info! that reports "gmeet workspace marketing redirect intercepted"), which
may include sensitive query/fragment data; to fix, parse or sanitize `url`
before logging (e.g., create `redacted_url` by using url::Url::parse(&url) and
clearing query/fragment or by taking the part before '?' and '#'), then replace
`url` in the log::info! call with `redacted_url` so only the safe path/host is
recorded.
| ## Sign-off | ||
|
|
||
| - Tester: oxoxDev | ||
| - Result: 11 ✅ / 0 ⚠️ / 2 ❌ (one blocked on #1046, one deferred to #1053) / 1 ⏭️ deferred to #1052 / 1 ❌ blocked on #1046 |
There was a problem hiding this comment.
Fix inconsistent verdict tally in sign-off
Line 75 appears to double-count the #1046 blocked item (2 ❌ ... plus another 1 ❌ blocked on #1046``). Please normalize to a single consistent breakdown so totals are unambiguous.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/qa/GMEET-PARITY.md` at line 75, The result tally in the GMEET-PARITY
sign-off line double-counts the same blocked item `#1046`; update the summary
string in docs/qa/GMEET-PARITY.md (the "Result: 11 ✅ / 0 ⚠️ / 2 ❌ ..." line) to
remove the duplicate "1 ❌ blocked on `#1046`" entry so the counts add up
consistently (e.g., consolidate to a single "2 ❌ (one blocked on `#1046`, one
deferred to `#1053`)" or adjust counts so the totals match the listed breakdown).
…inyhumansai#1074) Slack Huddles use the same getUserMedia/getDisplayMedia surface as Google Meet — without browser-level permission grants for audioCapture, videoCapture, displayCapture and clipboardReadWrite, the huddle pre-flight sees an empty enumerateDevices() and the join button silently no-ops. Mirrors the gmeet pattern from tinyhumansai#1054. Origin-scoped to app.slack.com so nothing leaks to other providers sharing the CEF browser process. The huddle popup paint lifecycle bug is tracked separately (still ❌ on the tinyhumansai#1016 audit) — granting these perms now means the moment the paint bug clears, the huddle is functional immediately rather than needing a follow-up perms wire-up. Test: origin_host_is_matches_app_slack_com_for_huddle_grant locks the host gate so a future refactor can't silently widen / narrow the set of origins that receive media perms.
Summary
Browser.grantPermissionsformeet.google.comaddsaudioCapture/videoCapture/displayCapture/clipboardReadWritesogetUserMediasucceeds without Meet's "Use microphone and camera" consent dialog.workspace.google.commarketing redirect → rewritten tomeet.google.com/; (b) "Start now" / room-popup → kept in-app via parent navigation instead of leaking to system Chrome.origin_host_isaccept/reject + 4 popup-routing cases). Manual smoke logged indocs/qa/GMEET-PARITY.md(15-row matrix, 11 ✅).Problem
Surfaced during the #1022 parity audit smoke against
pnpm dev:app:Browser.grantPermissionsfor the gmeet CDP session granted onlynotifications(added by fix(webview/slack): scanner spawn + notifications + post-pushState target match (#1016) #1028 for Slack), sogetUserMediareturnedNotAllowedErrorand Gmeet's web client fell back to its own consent UI which the embedded view couldn't satisfy.workspace.google.com/products/meet/....provider_allowed_hosts("google-meet")lists a baregoogle.comsuffix (webview_accounts/mod.rs:108-113);url_is_internalmatchesworkspace.google.comagainst.google.comso the navigation committed and the user landed on the Workspace marketing page instead of Meet.window.open(meet.google.com/<roomid>). The defaulton_new_windowchain had no in-app handler for gmeet's own host (popup_should_navigate_parentonly matched the Google auth popup;popup_should_stay_in_appis slack/zoom-only), so the URL fell through toopen_in_system_browserand the meeting opened in Chrome — the user lost the in-app session entirely.A fourth gap surfaced during smoke (auth post-2FA refresh, audit row 1) but is fixed by PR #1046's
is_google_sso_hostpredicate. This PR documents the dependency indocs/qa/GMEET-PARITY.mdand stays out of that surface.Solution
Per-origin Meet permission grant —
cdp/session.rsExtends
Browser.grantPermissionsto dispatch a per-provider permission set. Default for every embedded provider is["notifications"]. Formeet.google.com(matched via the neworigin_host_is(origin, host)helper) it additionally grantsaudioCapture,videoCapture,displayCapture,clipboardReadWrite. Origin-scoped so Slack / WhatsApp / Telegram / Discord / Browserscan grants are unaffected.Workspace marketing rewrite —
webview_accounts/mod.rs::on_navigationPre-intercept inside the existing
on_navigationclosure. For thegoogle-meetprovider, if the navigation host isworkspace.google.com(or any subdomain), the original navigation is cancelled and the embedded parent is navigated tohttps://meet.google.com/. Logged for diagnostics.Room-popup parent navigation —
popup_should_navigate_parentExtends the existing gmeet branch (which already handled the Google auth popup) to also match
meet.google.comhosts. The popup is denied and the embedded parent is navigated into the room URL, so "Start now" / room-link clicks stay in the same in-app tab the user clicked from.Audit dossier —
docs/qa/GMEET-PARITY.mdMirrors the
GMAIL-PARITY.mdshape: 15-row acceptance matrix pre-filled from the smoke run, hardcoded constants table, smoke procedure, CDP-migration sketch, sign-off block.Submission Checklist
origin_host_is(accept/reject) + 4 unit tests forpopup_should_navigate_parent(gmeet room popup, gmeet landing popup, workspace not navigating parent, unrelated link not navigating parent).docs/qa/GMEET-PARITY.md, not a newTEST-COVERAGE-MATRIXfeature row, so no matrix sync applies.## Related.docs/qa/GMEET-PARITY.md); no new release-cut surface added.Closes #NNNin the## Relatedsection.Impact
https://meet.google.com. No other provider's permission set changes. Permissions are limited to the four Meet actually exercises during a call (audio capture, video capture, display capture for screenshare, clipboard for copy-meeting-link).workspace.google.com(and subdomains) when the active provider isgoogle-meet. The room-popup parent-nav only fires formeet.google.comhosts when the active provider isgoogle-meet.Browser.grantPermissionsargument list at session attach.Related
Browser.grantPermissionsinfra reused)is_google_sso_hostpredicate keeps the post-passwordSetSIDhop in-app and CEF lands cookies natively. No additional change needed in this PR.[Feature] Gmeet caption transcript ingestion via memory_doc_ingest(replaces current log-only handler atwebview_accounts/mod.rs:2219-2247)[Bug] Gmeet background effects fail in CEF — "something went wrong"(Chromium runtime gates absent in CEF for MediaPipe segmentation pipeline)GMEET-PARITY.mdCDP-migration section)Summary by CodeRabbit
New Features
Bug Fixes
Documentation