Skip to content

fix(electron): scope capture permissions to the HUD#740

Merged
meiiie merged 3 commits into
mainfrom
fix/electron-permission-policy
Jul 11, 2026
Merged

fix(electron): scope capture permissions to the HUD#740
meiiie merged 3 commits into
mainfrom
fix/electron-permission-policy

Conversation

@meiiie

@meiiie meiiie commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Description

Scopes Electron capture permissions to Recordly's actual HUD instead of the entire default session.

  • allows only media from the live HUD main frame
  • validates document and origin across Vite, loopback, and packaged file URLs
  • validates display frame ownership before desktop-source access
  • denies default HID, serial, and USB access

Motivation

The existing handlers granted media to every renderer regardless of window/origin, default-granted
HID/serial/USB, and ignored display-capture frame/origin details. A compromised non-recording
renderer could therefore request capabilities it does not need.

Electron 39 source review showed that requestingOrigin may be a full URL and HTTP origins may end
in /. Both forms work while hostname, port, credential, path, query, frame, and window lookalikes
are rejected.

Type of Change

  • Bug Fix

Related Issue(s)

No linked issue. Independent of draft PRs #737-#739.

Testing Guide

  • npx vitest --run electron/permissionPolicy.test.ts src/hooks/useScreenRecorder.test.ts: 103/103
  • npx biome lint electron/main.ts electron/permissionPolicy.ts electron/permissionPolicy.test.ts
  • npx tsc --noEmit --noUnusedLocals false
  • npm test -- --reporter=dot: 97/97 files, 891/891 tests
  • production renderer/main/preload build plus Electron-main normalize/smoke

Default tsc --noEmit retains only the baseline failure addressed by #737.

Risk / limits

Verified on Windows with unit, type, full-suite, and production-build gates. Physical devices and
packaged interactive capture were not run; macOS/Linux are source/policy-tested, not runtime-tested.
Async countdown and legacy desktop capture remain compatible: no user gesture or media subtype is
required.

Checklist

  • I have performed a self-review of my code.
  • No UI change; screenshots/video are not applicable.

Summary by CodeRabbit

  • Security Improvements

    • Added stricter URL and origin-based authorization for camera, microphone, and screen-capture requests.
    • Grants are limited to trusted HUD overlay main-frame contexts using validated document identity and strict windowType rules.
    • Screen-capture authorization now happens before resolving capture sources; unauthorized requests are denied immediately.
    • Device permissions are denied by default, and media permission checks are routed through the new policy logic.
  • Tests

    • Added permission-policy tests covering trusted/invalid URL variants, packaged and loopback contexts, main-frame enforcement, and edge-case metadata/origin matching.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ffebea97-4166-4baa-a5ce-9086607b2984

📥 Commits

Reviewing files that changed from the base of the PR and between 57cae3c and b9f66e1.

📒 Files selected for processing (1)
  • electron/permissionPolicy.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • electron/permissionPolicy.test.ts

📝 Walkthrough

Walkthrough

The change adds centralized URL-, origin-, frame-, and window-based authorization for Electron media and display capture requests. It integrates these checks into Electron handlers, denies device permissions by default, and adds comprehensive Vitest coverage.

Changes

Capture permission policy

Layer / File(s) Summary
Policy contracts and validation
electron/permissionPolicy.ts
Adds trusted-document URL, document identity, security-origin, media-permission, and display-capture validation.
Electron permission-handler integration
electron/main.ts
Builds trusted renderer bases, identifies the HUD window, applies authorization to media/display requests, and denies device permissions by default.
Permission-policy validation coverage
electron/permissionPolicy.test.ts
Tests trusted URLs, valid capture requests, origin variants, malformed inputs, and denial conditions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Renderer
  participant Electron
  participant PermissionPolicy
  participant DesktopCapturer
  Renderer->>Electron: Request media or display capture
  Electron->>PermissionPolicy: Validate HUD window, frame, URL, and origin
  PermissionPolicy-->>Electron: Grant or deny
  Electron->>DesktopCapturer: Resolve sources when authorized
  DesktopCapturer-->>Renderer: Capture sources or empty response
Loading

Possibly related PRs

Suggested labels: Checked

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change to Electron capture permissions.
Description check ✅ Passed The description covers the main template sections—purpose, motivation, type, issues, testing, risks, and checklist—with screenshots/video marked not applicable.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/electron-permission-policy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@meiiie meiiie marked this pull request as ready for review July 11, 2026 03:30

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

🧹 Nitpick comments (1)
electron/permissionPolicy.test.ts (1)

135-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add display-capture grant tests for loopback and remaining file-origin variants.

shouldGrantMediaPermission tests cover the packaged loopback renderer (lines 83-94) and all three Chromium file-origin forms "null", "file://", "file:///" (lines 96-111), but shouldGrantDisplayCapture only tests the dev HUD URL and the "file://" origin. The PR objectives state validation across "Vite, loopback, and packaged file URLs," so the loopback grant case and the additional file-origin forms should be covered here too.

Since both functions delegate to the same isSecurityOriginForDocument, the risk is low, but adding these cases ensures display-capture stays correct if the origin-validation path diverges in future refactors.

♻️ Suggested additional display-capture tests
 	it("accepts the exact packaged file HUD with an opaque origin", () => {
 		expect(
 			shouldGrantDisplayCapture(
 				makeRequest({ currentDocumentUrl: FILE_HUD_URL, securityOrigin: "file://" }),
 				TRUSTED_DOCUMENT_BASE_URLS,
 			),
 		).toBe(true);
 	});

+	it("accepts the packaged loopback renderer with its exact origin", () => {
+		expect(
+			shouldGrantDisplayCapture(
+				makeRequest({
+					currentDocumentUrl: PACKAGED_HUD_URL,
+					securityOrigin: "http://127.0.0.1:43127",
+				}),
+				TRUSTED_DOCUMENT_BASE_URLS,
+			),
+		).toBe(true);
+	});
+
+	it.each(["null", "file://", "file:///"])(
+		"accepts Chromium's packaged file origin form: %s",
+		(securityOrigin) => {
+			expect(
+				shouldGrantDisplayCapture(
+					makeRequest({ currentDocumentUrl: FILE_HUD_URL, securityOrigin }),
+					TRUSTED_DOCUMENT_BASE_URLS,
+				),
+			).toBe(true);
+		},
+	);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/permissionPolicy.test.ts` around lines 135 - 182, Add
display-capture grant coverage in the shouldGrantDisplayCapture test suite for
the packaged loopback renderer and file HUD using each remaining opaque origin
form: "null" and "file:///". Reuse makeRequest with the appropriate
loopback/file document URLs and securityOrigin values, asserting each request is
granted alongside the existing "file://" case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@electron/permissionPolicy.test.ts`:
- Around line 135-182: Add display-capture grant coverage in the
shouldGrantDisplayCapture test suite for the packaged loopback renderer and file
HUD using each remaining opaque origin form: "null" and "file:///". Reuse
makeRequest with the appropriate loopback/file document URLs and securityOrigin
values, asserting each request is granted alongside the existing "file://" case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6403e114-1bb7-40b4-b74f-bb4bf9a665cb

📥 Commits

Reviewing files that changed from the base of the PR and between 641d223 and 146dc6a.

📒 Files selected for processing (3)
  • electron/main.ts
  • electron/permissionPolicy.test.ts
  • electron/permissionPolicy.ts

@meiiie meiiie merged commit 3ae326a into main Jul 11, 2026
4 checks passed
@meiiie meiiie deleted the fix/electron-permission-policy branch July 11, 2026 03:38
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.

1 participant