Skip to content

fix(v3): handle getUserMedia via a cross-platform Permissions map (Linux + Windows)#5567

Merged
leaanthony merged 6 commits into
masterfrom
fix/linux-usermedia-permission-5552
Jun 13, 2026
Merged

fix(v3): handle getUserMedia via a cross-platform Permissions map (Linux + Windows)#5567
leaanthony merged 6 commits into
masterfrom
fix/linux-usermedia-permission-5552

Conversation

@leaanthony

@leaanthony leaanthony commented Jun 10, 2026

Copy link
Copy Markdown
Member

Description

On Linux, navigator.mediaDevices.getUserMedia() always rejected with NotAllowedError: WebKitGTK denies any permission request with no handler attached, and Wails never attached one (#5552).

Rather than hardcode a blanket grant, this adds a declarative, cross-platform permission policy and wires both Linux and Windows to it.

API

app.Window.NewWithOptions(application.WebviewWindowOptions{
    Permissions: map[application.PermissionType]application.Permission{
        application.PermissionMicrophone: application.PermissionAllow,
        application.PermissionCamera:     application.PermissionDeny,
    },
})
  • PermissionType (uint8): Microphone, Camera, Geolocation, Notifications, ClipboardRead.
  • Permission (uint8): PermissionDefault (0), PermissionAllow (1), PermissionDeny (2) — values deliberately match the WebView2 permission-state ABI so the Windows backend needs no value translation.

PermissionDefault (the unset/zero value) means use the platform's native handling: the OS/webview prompt on macOS (TCC) and Windows (WebView2). Linux/WebKitGTK has no prompt mechanism, so PermissionDefault allows media capture (preserving the getUserMedia fix) and denies other capabilities; PermissionDeny turns media off.

Implementation

  • Linux (WebKitGTK, gtk3 + gtk4): the permission-request handler reads the map and allows/denies per the requested device types (audio → Microphone, video → Camera). Shared decision helper across both backends; tiny C wrappers expose webkit_user_media_permission_is_for_audio_device/_video_device.
  • Windows (WebView2): the cross-platform map is applied via SetPermission (translating kinds). The pre-existing Windows.Permissions map still works and overrides individual kinds.
  • macOS already defers to TCC; wiring WKUIDelegate to the map is a sensible follow-up.

Verification

End-to-end on Linux (Ubuntu, WebKitGTK 4.1, gtk3) with WebKit mock capture devices so the result depends only on the grant:

Permissions getUserMedia({audio:true})
unset / default GRANTED
{Microphone: PermissionDeny} NotAllowedError

(PermissionAllow takes the same handler branch as the proven default.) Builds pass for darwin, windows (CGO_ENABLED=0), and linux gtk3+gtk4; the gtk3 pkg/application suite passes under xvfb.

Fixes #5552

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code follows the general coding style of this project
  • I have updated v3/UNRELEASED_CHANGELOG.md

Summary by CodeRabbit

  • Bug Fixes

    • getUserMedia no longer fails with NotAllowedError on Linux; camera and microphone permission requests are now handled and honored, aligned with Windows behavior.
  • New Features

    • Per-window web permission controls added (camera, microphone, geolocation, notifications, clipboard read) with Default/Allow/Deny policies; on Linux camera/microphone default to allowed unless explicitly denied.

…quests

On Linux, navigator.mediaDevices.getUserMedia() always rejected with
NotAllowedError because WebKitGTK denies any permission request that no
permission-request signal handler claims, and Wails never connected one.
Applications had no way to intercept the request themselves, so camera
and microphone access was impossible — even with full OS-level access to
the devices.

Connect permission-request in both the GTK3 (webkit2gtk-4.1) and GTK4
(webkitgtk-6.0) backends and allow WebKitUserMediaPermissionRequest.
This matches the other platforms: Windows grants all WebView2
permissions by default (WindowOptions.Windows.Permissions can override),
and macOS defers to the OS-level prompt. All other permission kinds
return FALSE, keeping WebKit's default handling (deny).

Verified end-to-end on Linux (Ubuntu, WebKitGTK 4.1) under xvfb with
WebKit mock capture devices: getUserMedia({audio:true}) fails with
NotAllowedError on master and returns a live stream with this change.
gtk3 + gtk4 builds and the pkg/application test suite pass.

Fixes #5552
Copilot AI review requested due to automatic review settings June 10, 2026 21:52
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a Permissions API and per-window permission resolution, C/Go helpers and callbacks to detect WebKit user-media requests, GTK3/GTK4 handlers that allow or deny camera/microphone requests via allowMediaCapture, and Windows mapping to apply the same cross-platform permission options.

Changes

Linux user-media permission handling

Layer / File(s) Summary
Permission API and Linux resolution
v3/pkg/application/webview_window_options.go, v3/pkg/application/permissions_linux.go
Adds PermissionType/Permission and WebviewWindowOptions.Permissions; implements resolvePermission and allowMediaCapture for per-window media-capture decisions on Linux.
C/Go permission-request interop contracts
v3/pkg/application/linux_cgo.h, v3/pkg/application/linux_cgo.c, v3/pkg/application/linux_cgo_gtk3.go
Declares the exported handlePermissionRequest callback and adds C helper wrappers (is_user_media_permission_request, is_user_media_for_audio, is_user_media_for_video) to classify WebKit permission requests across the C/Go boundary.
GTK4 permission request handler
v3/pkg/application/linux_cgo.go
Connects WebKit permission-request to handlePermissionRequest; handler defers non-user-media, evaluates audio/video needs, calls allowMediaCapture, then webkit_permission_request_allow/deny.
GTK3 permission request handler
v3/pkg/application/linux_cgo_gtk3.go
Adds the GTK3 extern, C helper wrappers, exported handlePermissionRequest implementation, and wires the webview's permission-request signal to handle user-media similarly to GTK4.
Windows permission mapping
v3/pkg/application/webview_window_windows.go
Adds crossPermissionToWebView2Kind and applies cross-platform Permissions into WebView2 during Chromium setup before Windows-specific overrides; global allow is applied only when no per-kind policy exists.
CHANGELOG
v3/UNRELEASED_CHANGELOG.md
Documents the Fixed entry explaining Linux getUserMedia NotAllowedError fix and permission defaults/deny behavior (references #5552).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

Enhancement, go, Windows, Linux, v3-alpha, size:L

Poem

🐰 I hopped through C, Go, and GTK,
To wake webcams and let mics sing,
Signals caught where silence lay,
Permissions flipped to light the way,
The rabbit smiles — media's spring!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'fix(v3): handle getUserMedia via a cross-platform Permissions map (Linux + Windows)' clearly and concisely summarizes the main change: adding cross-platform permission handling for getUserMedia on Linux and Windows via a new Permissions map API.
Description check ✅ Passed The PR description comprehensively covers the issue (#5552), the API design (Permissions map with PermissionType and Permission constants), implementation details (Linux handler, Windows SetPermission), verification (Ubuntu/WebKitGTK end-to-end testing), and the changelog update.
Linked Issues check ✅ Passed All objectives from #5552 are met: WebKitGTK permission-request is now handled (#5552), getUserMedia works on Linux with PermissionDefault allowing media capture, and a supported cross-platform API (Permissions map) is provided for granular permission control.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #5552: Linux permission handler, Windows permission mapping, cross-platform PermissionType/Permission types, changelog update, and helper functions—with no extraneous modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/linux-usermedia-permission-5552

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 and usage tips.

Copilot AI 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.

Pull request overview

This PR fixes Linux (GTK3 + GTK4) WebKitGTK behavior where navigator.mediaDevices.getUserMedia() is always denied because Wails wasn’t handling WebKit’s permission-request signal. It connects the signal and allows user-media permission requests so camera/microphone access works on Linux, and documents the fix in the v3 unreleased changelog.

Changes:

  • Connect WebKitGTK permission-request signal for both GTK3 (webkit2gtk-4.1) and GTK4 (webkitgtk-6.0) backends.
  • Add a handler that allows WebKitUserMediaPermissionRequest (camera/microphone) and leaves other permission types to WebKit default handling.
  • Update v3/UNRELEASED_CHANGELOG.md with the Linux getUserMedia fix entry.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
v3/UNRELEASED_CHANGELOG.md Documents the Linux getUserMedia permission handling fix.
v3/pkg/application/linux_cgo.h Declares the new permission-request callback and a C wrapper for the user-media permission macro (GTK4 path).
v3/pkg/application/linux_cgo.go GTK4 backend: wires up permission-request and implements the Go callback to allow user-media requests.
v3/pkg/application/linux_cgo.c GTK4 backend: implements the C wrapper for WEBKIT_IS_USER_MEDIA_PERMISSION_REQUEST.
v3/pkg/application/linux_cgo_gtk3.go GTK3 backend: wires up permission-request, adds a local macro wrapper, and implements the Go callback to allow user-media requests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread v3/pkg/application/linux_cgo.go Outdated
Comment thread v3/pkg/application/linux_cgo_gtk3.go Outdated

@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: 1

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

Inline comments:
In `@v3/pkg/application/linux_cgo.go`:
- Around line 1507-1519: handlePermissionRequest currently unconditionally
grants any C.WebKitUserMediaPermissionRequest; change it to inspect the
requesting origin and only allow if it matches a trusted origin list or an
app-provided policy callback. Specifically: inside handlePermissionRequest (and
the GTK3 mirror), detect user-media requests via
C.is_user_media_permission_request(request), then obtain the request origin/URI
from the WebKit request or associated WebView (use the existing C/WebKit
accessor functions available in this file), validate that origin against a
hardcoded allow-list (e.g., wails://, localhost) or invoke an exported Go
permission callback (e.g., onPermissionRequest or similar app policy function)
which returns allow/deny, and only call
C.webkit_permission_request_allow(request) when validation returns allow;
otherwise return FALSE to deny. Ensure the new logic defaults to deny if origin
cannot be determined or callback is not provided, and replicate the same change
in the GTK3 mirror implementation.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 183770a4-dde1-4d27-a9b6-43e552fefe37

📥 Commits

Reviewing files that changed from the base of the PR and between 43309dd and afceeb1.

📒 Files selected for processing (5)
  • v3/UNRELEASED_CHANGELOG.md
  • v3/pkg/application/linux_cgo.c
  • v3/pkg/application/linux_cgo.go
  • v3/pkg/application/linux_cgo.h
  • v3/pkg/application/linux_cgo_gtk3.go

Comment on lines +1507 to +1519
//export handlePermissionRequest
func handlePermissionRequest(wv *C.WebKitWebView, request *C.WebKitPermissionRequest, data C.uintptr_t) C.gboolean {
// WebKitGTK denies any permission request nobody handles, so without this
// getUserMedia always fails with NotAllowedError. Grant camera/microphone
// access to match the other platforms: Windows grants all permissions by
// default and macOS defers to the OS-level prompt. Returning FALSE for
// everything else keeps WebKit's default handling (deny).
if C.is_user_media_permission_request(request) != 0 {
C.webkit_permission_request_allow(request)
return C.gboolean(1)
}
return C.gboolean(0)
}

@coderabbitai coderabbitai Bot Jun 10, 2026

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 | 🏗️ Heavy lift

Scope user-media auto-grant to trusted origins (or a configurable app policy).

handlePermissionRequest currently allows every WebKitUserMediaPermissionRequest unconditionally. Because apps can load arbitrary URLs, this can silently grant camera/microphone access to remote content. Please gate allow-listing to trusted app origins (e.g., wails:///localhost) or expose a permission callback and default-deny otherwise. The GTK3 mirror should enforce the same policy.

🔧 Suggested direction
 func handlePermissionRequest(wv *C.WebKitWebView, request *C.WebKitPermissionRequest, data C.uintptr_t) C.gboolean {
-	if C.is_user_media_permission_request(request) != 0 {
-		C.webkit_permission_request_allow(request)
-		return C.gboolean(1)
-	}
+	if C.is_user_media_permission_request(request) != 0 {
+		if uri := C.webkit_web_view_get_uri(wv); uri != nil {
+			current := C.GoString(uri)
+			if strings.HasPrefix(current, "wails://") ||
+				strings.HasPrefix(current, "http://localhost") ||
+				strings.HasPrefix(current, "https://localhost") {
+				C.webkit_permission_request_allow(request)
+				return C.gboolean(1)
+			}
+		}
+	}
 	return C.gboolean(0)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//export handlePermissionRequest
func handlePermissionRequest(wv *C.WebKitWebView, request *C.WebKitPermissionRequest, data C.uintptr_t) C.gboolean {
// WebKitGTK denies any permission request nobody handles, so without this
// getUserMedia always fails with NotAllowedError. Grant camera/microphone
// access to match the other platforms: Windows grants all permissions by
// default and macOS defers to the OS-level prompt. Returning FALSE for
// everything else keeps WebKit's default handling (deny).
if C.is_user_media_permission_request(request) != 0 {
C.webkit_permission_request_allow(request)
return C.gboolean(1)
}
return C.gboolean(0)
}
//export handlePermissionRequest
func handlePermissionRequest(wv *C.WebKitWebView, request *C.WebKitPermissionRequest, data C.uintptr_t) C.gboolean {
// WebKitGTK denies any permission request nobody handles, so without this
// getUserMedia always fails with NotAllowedError. Grant camera/microphone
// access to match the other platforms: Windows grants all permissions by
// default and macOS defers to the OS-level prompt. Returning FALSE for
// everything else keeps WebKit's default handling (deny).
if C.is_user_media_permission_request(request) != 0 {
if uri := C.webkit_web_view_get_uri(wv); uri != nil {
current := C.GoString(uri)
if strings.HasPrefix(current, "wails://") ||
strings.HasPrefix(current, "http://localhost") ||
strings.HasPrefix(current, "https://localhost") {
C.webkit_permission_request_allow(request)
return C.gboolean(1)
}
}
}
return C.gboolean(0)
}
🤖 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 `@v3/pkg/application/linux_cgo.go` around lines 1507 - 1519,
handlePermissionRequest currently unconditionally grants any
C.WebKitUserMediaPermissionRequest; change it to inspect the requesting origin
and only allow if it matches a trusted origin list or an app-provided policy
callback. Specifically: inside handlePermissionRequest (and the GTK3 mirror),
detect user-media requests via C.is_user_media_permission_request(request), then
obtain the request origin/URI from the WebKit request or associated WebView (use
the existing C/WebKit accessor functions available in this file), validate that
origin against a hardcoded allow-list (e.g., wails://, localhost) or invoke an
exported Go permission callback (e.g., onPermissionRequest or similar app policy
function) which returns allow/deny, and only call
C.webkit_permission_request_allow(request) when validation returns allow;
otherwise return FALSE to deny. Ensure the new logic defaults to deny if origin
cannot be determined or callback is not provided, and replicate the same change
in the GTK3 mirror implementation.

✅ Addressed in commit 1538d94

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed by the rework: the unconditional camera/microphone grant has been replaced with a cross-platform WebviewWindowOptions.Permissions map (map[PermissionType]Permission), honored on Linux (WebKitGTK) and Windows (WebView2). Camera/mic default to allowed on Linux only because WebKitGTK has no native prompt (preserving the getUserMedia fix), and can be turned off per-kind with PermissionDeny. See the updated PR description.

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.

@leaanthony, thanks for the detailed explanation. The rework is a solid improvement — the unconditional grant is now replaced by allowMediaCapture, which consults the per-window Permissions map (map[PermissionType]Permission). The Linux-defaulting-to-allow behavior for user-media is well-motivated (WebKitGTK has no native OS-level prompt), and developers can opt out on a per-kind basis with PermissionDeny. The GTK3 mirror was updated consistently too. This fully addresses the original concern. ✅


🧠 Learnings used
Learnt from: symball
Repo: wailsapp/wails PR: 4853
File: v2/internal/system/system.go:128-152
Timestamp: 2026-01-04T08:01:00.038Z
Learning: In v2/internal/system/system.go, shared functions like checkLibrary are defined without build tags but are only invoked from platform-specific files (system_linux.go, system_windows.go, system_darwin.go) that have build constraints. Reviewers should ensure there are no runtime OS checks in system.go and that platform-specific behavior is controlled via build tags. If runtime switches exist, remove them in favor of compile-time platform constraints to reduce overhead and improve correctness.

Learnt from: leaanthony
Repo: wailsapp/wails PR: 4906
File: v3/internal/setupwizard/wizard_windows.go:93-94
Timestamp: 2026-01-26T01:56:49.314Z
Learning: Ensure the Go toolchain minimum version for Wails v3 is 1.25+. Update go.mod to reflect 1.25+ and validate that setup wizard checks enforce Go 1.25+ at release time. Align any CI/go-version checks, documentation, and release notes with this requirement; this guideline applies to all Go files under the v3 module, not just the wizard.

@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: 1

♻️ Duplicate comments (1)
v3/pkg/application/permissions_linux.go (1)

20-41: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

PermissionDefault currently auto-grants mic/camera for any loaded origin.

allowMediaCapture defaults to allow and has no requester-origin input, and handlePermissionRequest in v3/pkg/application/linux_cgo.go only passes window ID/device flags. So remote web content loaded in a window can inherit camera/microphone access unless app code explicitly sets deny rules. Please scope default-allow to trusted app origins (or require explicit PermissionAllow for non-app origins).

🤖 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 `@v3/pkg/application/permissions_linux.go` around lines 20 - 41, The current
allowMediaCapture(windowID,uint,needAudio,needVideo) implicitly treats
PermissionDefault as allowed for any origin; change it to require explicit
PermissionAllow for non-app origins by (1) adding a requester origin parameter
to allowMediaCapture (e.g., allowMediaCapture(windowID uint, origin string,
needAudio, needVideo bool) ) and modify its inner allows() so that
resolvePermission is consulted and PermissionDefault is treated as allowed only
for trusted app origins (check origin against app origin list) and treated as
deny for other origins; (2) update the caller handlePermissionRequest in
linux_cgo.go to pass the request origin into allowMediaCapture; and (3) if
resolvePermission signature needs origin info, extend resolvePermission to
accept origin and use it when determining PermissionDefault behavior. Ensure
PermissionAllow and PermissionDeny semantics remain unchanged and only
PermissionDefault handling is scoped to app-origin trust.
🤖 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.

Inline comments:
In `@v3/pkg/application/webview_window_windows.go`:
- Around line 2104-2109: Remove the unconditional global allow so per-kind
permission states work: delete the call to
chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow) (which sets
e.globalPermission and causes PermissionRequested to always use Allow), and rely
solely on the existing per-kind loop that calls
chromium.SetPermission(crossPermissionToWebView2Kind(permission),
edge.CoreWebView2PermissionState(state)); leave the
crossPermissionToWebView2Kind/SetPermission logic intact so
PermissionDefault/Deny are respected.

---

Duplicate comments:
In `@v3/pkg/application/permissions_linux.go`:
- Around line 20-41: The current
allowMediaCapture(windowID,uint,needAudio,needVideo) implicitly treats
PermissionDefault as allowed for any origin; change it to require explicit
PermissionAllow for non-app origins by (1) adding a requester origin parameter
to allowMediaCapture (e.g., allowMediaCapture(windowID uint, origin string,
needAudio, needVideo bool) ) and modify its inner allows() so that
resolvePermission is consulted and PermissionDefault is treated as allowed only
for trusted app origins (check origin against app origin list) and treated as
deny for other origins; (2) update the caller handlePermissionRequest in
linux_cgo.go to pass the request origin into allowMediaCapture; and (3) if
resolvePermission signature needs origin info, extend resolvePermission to
accept origin and use it when determining PermissionDefault behavior. Ensure
PermissionAllow and PermissionDeny semantics remain unchanged and only
PermissionDefault handling is scoped to app-origin trust.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0859e3b5-e82d-4ae5-be06-f793aa3b5aa2

📥 Commits

Reviewing files that changed from the base of the PR and between afceeb1 and 1538d94.

📒 Files selected for processing (7)
  • v3/pkg/application/linux_cgo.c
  • v3/pkg/application/linux_cgo.go
  • v3/pkg/application/linux_cgo.h
  • v3/pkg/application/linux_cgo_gtk3.go
  • v3/pkg/application/permissions_linux.go
  • v3/pkg/application/webview_window_options.go
  • v3/pkg/application/webview_window_windows.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • v3/pkg/application/linux_cgo.h
  • v3/pkg/application/linux_cgo_gtk3.go

Comment thread v3/pkg/application/webview_window_windows.go
…nux + Windows)

Replaces the unconditional camera/microphone grant on Linux with a
declarative, cross-platform policy. A new
WebviewWindowOptions.Permissions map[PermissionType]Permission lets apps
allow/deny capabilities per kind:

  Permissions: map[application.PermissionType]application.Permission{
      application.PermissionMicrophone: application.PermissionDeny,
  }

PermissionType (uint8): Microphone, Camera, Geolocation, Notifications,
ClipboardRead. Permission (uint8): Default=0, Allow=1, Deny=2 — values
kept in step with the WebView2 permission-state ABI so the Windows
backend needs no value translation.

Linux (WebKitGTK, gtk3 + gtk4): the permission-request handler now reads
the map and allows/denies per the requested device types (audio→
Microphone, video→Camera). WebKitGTK has no native prompt, so
PermissionDefault allows media capture — preserving the getUserMedia fix
from #5552 — while PermissionDeny turns it off.

Windows (WebView2): the cross-platform map is applied via SetPermission
(translating kinds); the existing Windows.Permissions map still works and
overrides individual kinds.

Verified on Linux (Ubuntu, WebKitGTK 4.1, gtk3, mock capture devices):
default → getUserMedia GRANTED, PermissionDeny → NotAllowedError. Builds:
darwin, windows (CGO_ENABLED=0), and linux gtk3+gtk4; gtk3 pkg/application
suite passes under xvfb.

Fixes #5552
@leaanthony leaanthony force-pushed the fix/linux-usermedia-permission-5552 branch from 1538d94 to c7e8e77 Compare June 13, 2026 04:16
@leaanthony leaanthony changed the title fix(v3/linux): allow getUserMedia by handling WebKitGTK permission requests fix(v3): handle getUserMedia via a cross-platform Permissions map (Linux + Windows) Jun 13, 2026
…ions map

WebView2's PermissionRequested handler checks the global permission
before the per-kind map, and setupChromium unconditionally called
SetGlobalPermission(Allow). That made both the new cross-platform
Permissions map and the pre-existing Windows.Permissions map dead on
Windows: a configured PermissionDeny was silently ignored because every
request resolved to the global Allow first.

Only set the blanket allow-all when no per-kind policy is configured, so
unconfigured apps keep their previous auto-allow behaviour while apps
that set Permissions actually have them honoured (unset kinds fall
through to PermissionDefault → the platform's native prompt).

Surfaced by review on #5567.
@leaanthony leaanthony merged commit f085aa9 into master Jun 13, 2026
14 of 15 checks passed
@leaanthony leaanthony deleted the fix/linux-usermedia-permission-5552 branch June 13, 2026 11:09

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment on lines +154 to +159
// Permissions controls how capability requests (camera, microphone, …)
// from the web content are handled, per PermissionType. Unset entries use
// PermissionDefault. Cross-platform; see the Permission constants for the
// per-platform meaning of the default.
Permissions map[PermissionType]Permission

Comment on lines +284 to +289
// PermissionDefault uses the platform's native handling and is the zero
// value. On macOS (TCC) and Windows (WebView2) this presents the OS/webview
// permission prompt to the user. Linux/WebKitGTK has no prompt mechanism,
// so media capture (camera/microphone) is allowed — restoring getUserMedia
// for app content — and other capabilities are denied.
PermissionDefault Permission = iota
Comment on lines +265 to +294
// PermissionType identifies a capability that web content can request from
// the webview (camera, microphone, …). It is the cross-platform equivalent of
// the platform-specific permission-kind enums.
type PermissionType uint8

const (
PermissionMicrophone PermissionType = iota
PermissionCamera
PermissionGeolocation
PermissionNotifications
PermissionClipboardRead
)

// Permission is the policy applied to a PermissionType. The values are kept in
// step with the native WebView2 permission-state ABI (Default=0, Allow=1,
// Deny=2) so the Windows backend needs no translation.
type Permission uint8

const (
// PermissionDefault uses the platform's native handling and is the zero
// value. On macOS (TCC) and Windows (WebView2) this presents the OS/webview
// permission prompt to the user. Linux/WebKitGTK has no prompt mechanism,
// so media capture (camera/microphone) is allowed — restoring getUserMedia
// for app content — and other capabilities are denied.
PermissionDefault Permission = iota
// PermissionAllow grants the capability without prompting.
PermissionAllow
// PermissionDeny denies the capability without prompting.
PermissionDeny
)
leaanthony added a commit that referenced this pull request Jun 13, 2026
…5567) (#5592)

* docs: add Web Permissions guide and options reference (#5567)

PR #5567 added a cross-platform Permissions map to WebviewWindowOptions
but shipped with no documentation. This adds:

- New page: features/windows/permissions.mdx — full developer guide
  covering PermissionType/Permission API, per-platform behaviour
  (Linux WebKitGTK default-allow quirk, Windows prompt vs blanket-grant
  change, macOS TCC deferral), common patterns, Windows-specific override,
  and troubleshooting section

- Updated: features/windows/options.mdx — Permissions field added to
  the struct summary and a dedicated section with type reference and the
  Windows breaking-change callout

- Updated: astro.config.mjs sidebar — Web Permissions entry added
  between Window Options and Multiple Windows

* docs: rename 'Web Permissions' to 'Permissions'

* docs: clarify macOS permissions behaviour, remove WKUIDelegate jargon

* docs: remove PR reference from permissions example

* docs: fix Linux permissions accuracy per Copilot review

- Linux only handles camera/microphone; geolocation/notifications/clipboard
  remain unimplemented and always denied — table, matrix and patterns updated
- Removed implication that non-media capabilities can be allowed on Linux
- Added Linux-specific troubleshooting entry for unimplemented types
- Clarified PermissionAllow Linux caveat in options.mdx
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.

[v3][Linux][GTK3] getUserMedia is denied by default because WebKitGTK permission-request is not handled

2 participants