Skip to content

feat(webview/gmeet): native cam/mic/screenshare + keep Meet routing in-app (#1022) - #1054

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
oxoxDev:feat/1022-gmeet-parity-audit
Apr 30, 2026
Merged

senamakel merged 4 commits into
tinyhumansai:mainfrom
oxoxDev:feat/1022-gmeet-parity-audit

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Apr 30, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Embedded Google Meet now matches stock Chrome for cam, mic, screenshare, captions, in-call chat, reactions, raise-hand, session persistence, and hangup-return UX.
  • Per-origin Browser.grantPermissions for meet.google.com adds audioCapture / videoCapture / displayCapture / clipboardReadWrite so getUserMedia succeeds without Meet's "Use microphone and camera" consent dialog.
  • Two routing leaks closed: (a) post-account-pick workspace.google.com marketing redirect → rewritten to meet.google.com/; (b) "Start now" / room-popup → kept in-app via parent navigation instead of leaking to system Chrome.
  • 6 new unit tests (origin_host_is accept/reject + 4 popup-routing cases). Manual smoke logged in docs/qa/GMEET-PARITY.md (15-row matrix, 11 ✅).
  • Two follow-ups filed before opening this PR: Ingest Google Meet caption transcripts via memory_doc_ingest #1052 (caption transcript ingestion feature) and Google Meet background effects fail in CEF ("something went wrong") #1053 (background effects CEF runtime gap).

Problem

Surfaced during the #1022 parity audit smoke against pnpm dev:app:

  1. Cam/mic gap — Gmeet's pre-call greenroom showed its own "Use microphone and camera" consent dialog and clicking it was a no-op. Root cause: Browser.grantPermissions for the gmeet CDP session granted only notifications (added by fix(webview/slack): scanner spawn + notifications + post-pushState target match (#1016) #1028 for Slack), so getUserMedia returned NotAllowedError and Gmeet's web client fell back to its own consent UI which the embedded view couldn't satisfy.
  2. Workspace marketing leak — after the user picked an account in the in-app sign-in flow, Google's edge SSR-redirected to workspace.google.com/products/meet/.... provider_allowed_hosts("google-meet") lists a bare google.com suffix (webview_accounts/mod.rs:108-113); url_is_internal matches workspace.google.com against .google.com so the navigation committed and the user landed on the Workspace marketing page instead of Meet.
  3. "Start now" leak — clicking "Start an instant meeting" / "New meeting" calls window.open(meet.google.com/<roomid>). 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 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_host predicate. This PR documents the dependency in docs/qa/GMEET-PARITY.md and stays out of that surface.

Solution

Per-origin Meet permission grant — cdp/session.rs

Extends Browser.grantPermissions to dispatch a per-provider permission set. Default for every embedded provider is ["notifications"]. For meet.google.com (matched via the new origin_host_is(origin, host) helper) it additionally grants audioCapture, videoCapture, displayCapture, clipboardReadWrite. Origin-scoped so Slack / WhatsApp / Telegram / Discord / Browserscan grants are unaffected.

Workspace marketing rewrite — webview_accounts/mod.rs::on_navigation

Pre-intercept inside the existing on_navigation closure. For the google-meet provider, if the navigation host is workspace.google.com (or any subdomain), the original navigation is cancelled and the embedded parent is navigated to https://meet.google.com/. Logged for diagnostics.

Room-popup parent navigation — popup_should_navigate_parent

Extends the existing gmeet branch (which already handled the Google auth popup) to also match meet.google.com hosts. 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.md

Mirrors the GMAIL-PARITY.md shape: 15-row acceptance matrix pre-filled from the smoke run, hardcoded constants table, smoke procedure, CDP-migration sketch, sign-off block.

Submission Checklist

  • Tests added or updated — 2 unit tests for origin_host_is (accept/reject) + 4 unit tests for popup_should_navigate_parent (gmeet room popup, gmeet landing popup, workspace not navigating parent, unrelated link not navigating parent).
  • N/A: this PR delivers a webview-parity audit row already tracked in docs/qa/GMEET-PARITY.md, not a new TEST-COVERAGE-MATRIX feature row, so no matrix sync applies.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related.
  • No new external network dependencies introduced — same Meet origin as the existing webview; mock backend untouched.
  • N/A: parity work for an already-shipping webview surface — covered by the [Feature] webview: Google Meet — full end-to-end parity with native app #1022 audit dossier (docs/qa/GMEET-PARITY.md); no new release-cut surface added.
  • Linked issue closed via Closes #NNN in the ## Related section.

Impact

  • Desktop only — CEF runtime + Tauri shell. No frontend / web / CLI changes.
  • Permission grants — origin-scoped to 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).
  • Routing changes — gmeet-specific. The workspace rewrite only fires for workspace.google.com (and subdomains) when the active provider is google-meet. The room-popup parent-nav only fires for meet.google.com hosts when the active provider is google-meet.
  • Performance — no new background tasks. One additional Browser.grantPermissions argument list at session attach.
  • Security — no new origins, no new JS injection, no new credential surfaces. Permission grants are origin-scoped via CDP and tied to the per-account CEF profile.
  • Migration — none.

Related

Summary by CodeRabbit

  • New Features

    • Google Meet popups and navigation now remain within the app instead than opening externally.
    • Automatic permission grants for audio capture, video capture, and screen sharing on Google Meet.
  • Bug Fixes

    • Improved handling of Google Meet landing page redirects within the webview.
  • Documentation

    • Added Google Meet webview compatibility testing matrix.

oxoxDev added 4 commits April 30, 2026 20:04
…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.
@oxoxDev
oxoxDev requested a review from a team April 30, 2026 14:42
@coderabbitai

coderabbitai Bot commented Apr 30, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The 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

Cohort / File(s) Summary
CDP Permission Grants
app/src-tauri/src/cdp/session.rs
Builds permission list dynamically for Browser.grantPermissions: always grants notifications, and additionally grants audioCapture, videoCapture, displayCapture, clipboardReadWrite when origin host matches meet.google.com. Adds case-insensitive origin_host_is helper with port-tolerance and includes unit tests.
Meet Popup & Redirect Handling
app/src-tauri/src/webview_accounts/mod.rs
Intercepts Google Meet popups to prevent external-browser routing; popup_should_navigate_parent returns Some(url) for google-meet popups targeting meet.google.com. Detects workspace.google.com redirects during navigation commits and asynchronously cancels/replaces them with redirect to https://meet.google.com/. Includes new navigation-decision tests.
QA Parity Documentation
docs/qa/GMEET-PARITY.md
Introduces comprehensive Google Meet webview parity audit matrix covering auth, landing, meeting creation/join, media, screenshare, captions, chat, reactions, lifecycle, and hangup flows. Documents observed behaviors, links to existing child issues (#1046, #1052, #1053), enumerates code-level gaps, includes constants reference, and sketches CDP-based caption extraction migration path.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A rabbit hops through Meet with glee,
Permissions granted, cam and mic are free,
No pesky popups, no workspace waylay,
Just Google Meet, where we video all day! 📹✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially addresses linked issues: it implements permission grants for media features and fixes routing leaks for #1022 and #1035, but does not implement transcript ingestion or caption extraction that are core acceptance criteria. Implement memory_doc_ingest for caption transcript persistence and harden caption extraction logic to fully satisfy #1022 acceptance criteria beyond permission grants.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: granting native camera/microphone/screenshare permissions and keeping Google Meet routing in-app.
Out of Scope Changes check ✅ Passed All changes are scoped to Google Meet webview parity: permission grants, routing fixes, tests, and documentation align with #1022 and #1035 objectives without introducing unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between a225bd9 and 0dbaaa7.

📒 Files selected for processing (3)
  • app/src-tauri/src/cdp/session.rs
  • app/src-tauri/src/webview_accounts/mod.rs
  • docs/qa/GMEET-PARITY.md

Comment on lines +1466 to +1469
log::info!(
"[webview-accounts] gmeet workspace marketing redirect intercepted ({}); rewriting parent to https://meet.google.com/",
url
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Comment thread docs/qa/GMEET-PARITY.md
## Sign-off

- Tester: oxoxDev
- Result: 11 ✅ / 0 ⚠️ / 2 ❌ (one blocked on #1046, one deferred to #1053) / 1 ⏭️ deferred to #1052 / 1 ❌ blocked on #1046

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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).

@senamakel
senamakel merged commit 8c65f10 into tinyhumansai:main Apr 30, 2026
15 checks passed
oxoxDev added a commit to oxoxDev/openhuman that referenced this pull request May 1, 2026
…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.
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix Google Meet webview landing page and post-2FA auth refresh [Feature] webview: Google Meet — full end-to-end parity with native app

2 participants