Browse Source

feat: new permissions API

Samuel Attard 7 months ago
parent
commit
ca221f6d80
43 changed files with 360 additions and 196 deletions
  1. 106 8
      docs/api/session.md
  2. 5 0
      docs/api/structures/permission-check-result.md
  3. 3 0
      docs/api/structures/permission-request-response.md
  4. 2 2
      docs/api/web-contents.md
  5. 3 3
      docs/tutorial/devices.md
  6. 1 1
      filenames.gni
  7. 38 0
      lib/browser/api/session.ts
  8. 1 1
      shell/browser/api/electron_api_app.cc
  9. 1 1
      shell/browser/api/electron_api_cookies.cc
  10. 1 1
      shell/browser/api/electron_api_download_item.cc
  11. 1 1
      shell/browser/api/electron_api_menu.cc
  12. 1 1
      shell/browser/api/electron_api_service_worker_context.cc
  13. 14 12
      shell/browser/api/electron_api_session.cc
  14. 1 1
      shell/browser/api/electron_api_session.h
  15. 1 1
      shell/browser/api/electron_api_system_preferences_mac.mm
  16. 6 4
      shell/browser/api/electron_api_web_contents.cc
  17. 2 0
      shell/browser/api/electron_api_web_contents.h
  18. 1 1
      shell/browser/api/electron_api_web_frame_main.cc
  19. 1 1
      shell/browser/api/electron_api_web_request.cc
  20. 41 48
      shell/browser/electron_permission_manager.cc
  21. 36 29
      shell/browser/electron_permission_manager.h
  22. 2 2
      shell/browser/file_system_access/file_system_access_permission_context.cc
  23. 4 11
      shell/browser/hid/electron_hid_delegate.cc
  24. 1 1
      shell/browser/login_handler.cc
  25. 1 1
      shell/browser/net/electron_url_loader_factory.cc
  26. 1 1
      shell/browser/network_hints_handler_impl.cc
  27. 4 5
      shell/browser/serial/electron_serial_delegate.cc
  28. 4 11
      shell/browser/usb/electron_usb_delegate.cc
  29. 19 26
      shell/browser/web_contents_permission_helper.cc
  30. 5 5
      shell/browser/web_contents_permission_helper.h
  31. 1 1
      shell/common/api/electron_api_native_image.cc
  32. 1 1
      shell/common/api/electron_api_net.cc
  33. 1 1
      shell/common/api/electron_api_shell.cc
  34. 1 1
      shell/common/api/electron_api_url_loader.cc
  35. 1 1
      shell/common/api/electron_api_v8_util.cc
  36. 1 1
      shell/common/gin_converters/blink_converter.cc
  37. 15 1
      shell/common/gin_converters/content_converter.cc
  38. 1 1
      shell/common/gin_converters/extension_converter.cc
  39. 1 1
      shell/common/gin_converters/media_converter.cc
  40. 1 1
      shell/common/gin_converters/net_converter.cc
  41. 8 0
      shell/common/gin_converters/url_converters.h
  42. 16 7
      spec/ts-smoke/electron/main.ts
  43. 5 0
      typings/internal-electron.d.ts

+ 106 - 8
docs/api/session.md

@@ -276,7 +276,7 @@ Emitted when a HID device needs to be selected when a call to
 `navigator.hid.requestDevice` is made. `callback` should be called with
 `deviceId` to be selected; passing no arguments to `callback` will
 cancel the request.  Additionally, permissioning on `navigator.hid` can
-be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler)
+be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler-deprecated)
 and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
 
 ```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)}
@@ -382,7 +382,7 @@ Emitted when a serial port needs to be selected when a call to
 `navigator.serial.requestPort` is made. `callback` should be called with
 `portId` to be selected, passing an empty string to `callback` will
 cancel the request.  Additionally, permissioning on `navigator.serial` can
-be managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler)
+be managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler-deprecated)
 with the `serial` permission.
 
 ```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)}
@@ -525,7 +525,7 @@ Emitted when a USB device needs to be selected when a call to
 `navigator.usb.requestDevice` is made. `callback` should be called with
 `deviceId` to be selected; passing no arguments to `callback` will
 cancel the request.  Additionally, permissioning on `navigator.usb` can
-be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler)
+be further managed by using [`ses.setPermissionCheckHandler(handler)`](#sessetpermissioncheckhandlerhandler-deprecated)
 and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
 
 ```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} @ts-type={updateGrantedDevices:(devices:Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)=>void}
@@ -858,10 +858,107 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
 
 > **NOTE:** The result of this procedure is cached by the network service.
 
-#### `ses.setPermissionRequestHandler(handler)`
+#### `ses.setPermissionHandlers(permissionHandlers)`
+
+* `permissionHandlers` Object | null
+  * `isGranted` Function\<[PermissionCheckResult](structures/permission-check-result.md)>
+    * `permission` string - Type of permission check.
+      * `clipboard-read` - Request access to read from the clipboard.
+      * `clipboard-sanitized-write` - Request access to write to the clipboard.
+      * `geolocation` - Access the user's geolocation data via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
+      * `fullscreen` - Control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API).
+      * `hid` - Access the HID protocol to manipulate HID devices via the [WebHID API](https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API).
+      * `idle-detection` - Access the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector).
+      * `media` - Access to media devices such as camera, microphone and speakers.
+      * `mediaKeySystem` - Access to DRM protected content.
+      * `midi` - Enable MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
+      * `midiSysex` - Use system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
+      * `notifications` - Configure and display desktop notifications to the user with the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification).
+      * `openExternal` - Open links in external applications.
+      * `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
+      * `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API).
+      * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
+      * `top-level-storage-access` -  Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
+      * `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
+    * `effectiveOrigin` string - The origin of the URL of the permission check, you should use this origin to perform security checks on whether to accept or deny this permission check. You may augment checks with additional information, but this is the primary source of truth you should rely on.
+    * `permissionCheckDetails` Object - Some properties are only available on certain permission types.
+      * `embeddingOrigin` string (optional) - The origin of the frame embedding the frame that made the permission check.  Only set for cross-origin sub frames making permission checks.
+      * `securityOrigin` string (optional) _Deprecated_ - The security origin of the `media` check. This value is identical to `effectiveOrigin`, use that value instead.
+      * `mediaType` string (optional) - The type of media access being requested, can be `video`, `audio` or `unknown`
+      * `isMainFrame` boolean (optional) - Whether the frame making the request is the main frame. This value is `undefined` in cases where the request is coming from a background worker and therefore is not related to a specific frame.
+  * `onRequest` Function\<Promise\<[PermissionRequestResponse](structures/permission-request-response.md)\>\>
+    * `permission` string - The type of requested permission.
+      * `clipboard-read` - Request access to read from the clipboard.
+      * `clipboard-sanitized-write` - Request access to write to the clipboard.
+      * `display-capture` - Request access to capture the screen via the [Screen Capture API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Capture_API).
+      * `fullscreen` - Request control of the app's fullscreen state via the [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API).
+      * `geolocation` - Request access to the user's location via the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
+      * `idle-detection` - Request access to the user's idle state via the [IdleDetector API](https://developer.mozilla.org/en-US/docs/Web/API/IdleDetector).
+      * `media` -  Request access to media devices such as camera, microphone and speakers.
+      * `mediaKeySystem` - Request access to DRM protected content.
+      * `midi` - Request MIDI access in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
+      * `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
+      * `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification)
+      * `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
+      * `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
+      * `openExternal` - Request to open links in external applications.
+      * `speaker-selection` - Request to enumerate and select audio output devices via the [speaker-selection permissions policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy/speaker-selection).
+      * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
+      * `top-level-storage-access` -  Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
+      * `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
+      * `unknown` - An unrecognized permission request.
+      * `fileSystem` - Request access to read, write, and file management capabilities using the [File System API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API).
+    * `effectiveOrigin` String - The origin of the URL of the permission check, you should use this origin to perform security checks on whether to accept or deny this permission check. You may augment checks with additional information, but this is the primary source of truth you should rely on.
+    * `permissionRequestDetails` [PermissionRequest](structures/permission-request.md)  | [FilesystemPermissionRequest](structures/filesystem-permission-request.md) | [MediaAccessPermissionRequest](structures/media-access-permission-request.md) | [OpenExternalPermissionRequest](structures/open-external-permission-request.md) - Additional information about the permission being requested.
+
+<!--
+STUFF
+
+Sets the handler which can be used to respond to permission requests for the `session`.
+Calling `callback(true)` will allow the permission and `callback(false)` will reject it.
+To clear the handler, call `setPermissionRequestHandler(null)`.  Please note that
+you must also implement `setPermissionCheckHandler` to get complete permission handling.
+Most web APIs do a permission check and then make a permission request if the check is denied.
+
+```js
+const { session } = require('electron')
+session.fromPartition('some-partition').setPermissionRequestHandler((webContents, permission, callback) => {
+  if (webContents.getURL() === 'some-host' && permission === 'notifications') {
+    return callback(false) // denied.
+  }
+
+  callback(true)
+})
+```
+
+#### `ses.setPermissionCheckHandler(handler)`
+
+* `handler` 
+
+Sets the handler which can be used to respond to permission checks for the `session`.
+Returning `true` will allow the permission and `false` will reject it.  Please note that
+you must also implement `setPermissionRequestHandler` to get complete permission handling.
+Most web APIs do a permission check and then make a permission request if the check is denied.
+To clear the handler, call `setPermissionCheckHandler(null)`.
+
+```js
+const { session } = require('electron')
+const url = require('url')
+session.fromPartition('some-partition').setPermissionCheckHandler((webContents, permission, requestingOrigin) => {
+  if (new URL(requestingOrigin).hostname === 'some-host' && permission === 'notifications') {
+    return true // granted
+  }
+
+  return false // denied
+})
+```
+
+-->
+
+#### `ses.setPermissionRequestHandler(handler)` _Deprecated_
 
 * `handler` Function | null
-  * `webContents` [WebContents](web-contents.md) - WebContents requesting the permission.  Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin.
+  * `webContents` [WebContents](web-contents.md) - WebContents requesting the permission.  Please note that if the request comes from a subframe you should use `effectiveOrigin` to check the request origin.
   * `permission` string - The type of requested permission.
     * `clipboard-read` - Request access to read from the clipboard.
     * `clipboard-sanitized-write` - Request access to write to the clipboard.
@@ -886,6 +983,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
   * `callback` Function
     * `permissionGranted` boolean - Allow or deny the permission.
   * `details` [PermissionRequest](structures/permission-request.md)  | [FilesystemPermissionRequest](structures/filesystem-permission-request.md) | [MediaAccessPermissionRequest](structures/media-access-permission-request.md) | [OpenExternalPermissionRequest](structures/open-external-permission-request.md) - Additional information about the permission being requested.
+  * `effectiveOrigin` string - The origin of the URL of the permission check, you should use this origin to perform security checks on whether to accept or deny this permission check. You may augment checks with additional information, but this is the primary source of truth you should rely on.
 
 Sets the handler which can be used to respond to permission requests for the `session`.
 Calling `callback(true)` will allow the permission and `callback(false)` will reject it.
@@ -904,10 +1002,10 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
 })
 ```
 
-#### `ses.setPermissionCheckHandler(handler)`
+#### `ses.setPermissionCheckHandler(handler)` _Deprecated_
 
 * `handler` Function\<boolean> | null
-  * `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission.  Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin.  All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`.  You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
+  * `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission.  Please note that if the request comes from a subframe you should use `effectiveOrigin` to check the request origin.  All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`.  You should use `embeddingOrigin` and `effectiveOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
   * `permission` string - Type of permission check.
     * `clipboard-read` - Request access to read from the clipboard.
     * `clipboard-sanitized-write` - Request access to write to the clipboard.
@@ -926,7 +1024,7 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
     * `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
     * `top-level-storage-access` -  Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
     * `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
-  * `requestingOrigin` string - The origin URL of the permission check
+  * `effectiveOrigin` string - The origin URL of the permission check
   * `details` Object - Some properties are only available on certain permission types.
     * `embeddingOrigin` string (optional) - The origin of the frame embedding the frame that made the permission check.  Only set for cross-origin sub frames making permission checks.
     * `securityOrigin` string (optional) - The security origin of the `media` check.

+ 5 - 0
docs/api/structures/permission-check-result.md

@@ -0,0 +1,5 @@
+# PermissionCheckResult Object
+
+* `status` string - Can be `granted`, `denied` or `ask`. Controls whether the permission check should be approved. Granted and Denied have their implied effects, `ask` will result in a permission request being fired to your permission request handler.
+
+Note: For media permission checks `ask` is equivilant to `granted`.

+ 3 - 0
docs/api/structures/permission-request-response.md

@@ -0,0 +1,3 @@
+# PermissionRequestResponse Object
+
+* `status` string - Can be `granted` or `denied`. Controls whether the permission should be granted.

+ 2 - 2
docs/api/web-contents.md

@@ -2034,9 +2034,9 @@ ipcRenderer.on('port', (e, msg) => {
 })
 ```
 
-#### `contents.enableDeviceEmulation(parameters)`
+#### `contents.enableDeviceEmulation(deviceEmulationParameters)`
 
-* `parameters` Object
+* `deviceEmulationParameters` Object
   * `screenPosition` string - Specify the screen type to emulate
       (default: `desktop`):
     * `desktop` - Desktop screen type.

+ 3 - 3
docs/tutorial/devices.md

@@ -52,7 +52,7 @@ the WebHID API:
   needed, a developer can store granted device permissions (eg when handling
   the `select-hid-device` event) and then read from that storage with
   `setDevicePermissionHandler`.
-* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
+* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler-deprecated)
   can be used to disable HID access for specific origins.
 
 ### Blocklist
@@ -101,7 +101,7 @@ There are several additional APIs for working with the Web Serial API:
   needed, a developer can store granted device permissions (eg when handling
   the `select-serial-port` event) and then read from that storage with
   `setDevicePermissionHandler`.
-* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
+* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler-deprecated)
   can be used to disable serial access for specific origins.
 
 ### Example
@@ -140,7 +140,7 @@ Electron provides several APIs for working with the WebUSB API:
   needed, a developer can store granted device permissions (eg when handling
   the `select-usb-device` event) and then read from that storage with
   `setDevicePermissionHandler`.
-* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
+* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler-deprecated)
   can be used to disable USB access for specific origins.
 * [`ses.setUSBProtectedClassesHandler](../api/session.md#sessetusbprotectedclasseshandlerhandler)
   can be used to allow usage of [protected USB classes](https://wicg.github.io/webusb/#usbinterface-interface) that are not available by default.

+ 1 - 1
filenames.gni

@@ -600,7 +600,7 @@ filenames = {
     "shell/common/gin_converters/gfx_converter.cc",
     "shell/common/gin_converters/gfx_converter.h",
     "shell/common/gin_converters/guid_converter.h",
-    "shell/common/gin_converters/gurl_converter.h",
+    "shell/common/gin_converters/url_converters.h",
     "shell/common/gin_converters/hid_device_info_converter.h",
     "shell/common/gin_converters/image_converter.cc",
     "shell/common/gin_converters/image_converter.h",

+ 38 - 0
lib/browser/api/session.ts

@@ -6,6 +6,44 @@ Session.prototype.fetch = function (input: RequestInfo, init?: RequestInit) {
   return fetchWithSession(input, init, this, net.request);
 };
 
+Session.prototype.setPermissionCheckHandler = function (handler) {
+  if (!handler) return this._setPermissionCheckHandler(handler);
+
+  return this._setPermissionCheckHandler((...args) => {
+    if (handler(...args)) return 'granted';
+    return 'denied';
+  });
+};
+
+Session.prototype.setPermissionRequestHandler = function (handler) {
+  if (!handler) return this._setPermissionRequestHandler(handler);
+
+  return this._setPermissionRequestHandler((wc, perm, cb: any, d, eo) => {
+    return handler(wc, perm, (granted) => cb(granted ? 'granted' : 'denied'), d, eo);
+  });
+};
+
+Session.prototype.setPermissionHandlers = function (handlers) {
+  if (!handlers) {
+    this._setPermissionCheckHandler(null);
+    this._setPermissionRequestHandler(null);
+    return;
+  }
+
+  this._setPermissionCheckHandler((_, permission, effectiveOrigin, details) => {
+    return handlers.isGranted(permission, effectiveOrigin, details).status;
+  });
+
+  this._setPermissionRequestHandler((_, permission, callback, details, effectiveOrigin) => {
+    handlers.onRequest(permission, effectiveOrigin, details)
+      .then((result) => callback(result.status === 'granted'))
+      .catch((err) => {
+        this.emit('error', err);
+        callback(false);
+      });
+  });
+};
+
 export default {
   fromPartition,
   fromPath,

+ 1 - 1
shell/browser/api/electron_api_app.cc

@@ -67,7 +67,7 @@
 #include "shell/common/gin_converters/blink_converter.h"
 #include "shell/common/gin_converters/callback_converter.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/image_converter.h"
 #include "shell/common/gin_converters/login_item_settings_converter.h"
 #include "shell/common/gin_converters/net_converter.h"

+ 1 - 1
shell/browser/api/electron_api_cookies.cc

@@ -25,7 +25,7 @@
 #include "shell/browser/cookie_change_notifier.h"
 #include "shell/browser/electron_browser_context.h"
 #include "shell/browser/javascript_environment.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/object_template_builder.h"

+ 1 - 1
shell/browser/api/electron_api_download_item.cc

@@ -12,7 +12,7 @@
 #include "shell/browser/electron_browser_main_parts.h"
 #include "shell/common/gin_converters/file_dialog_converter.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/object_template_builder.h"
 #include "shell/common/node_includes.h"

+ 1 - 1
shell/browser/api/electron_api_menu.cc

@@ -14,7 +14,7 @@
 #include "shell/common/gin_converters/callback_converter.h"
 #include "shell/common/gin_converters/content_converter.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/image_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/object_template_builder.h"

+ 1 - 1
shell/browser/api/electron_api_service_worker_context.cc

@@ -16,7 +16,7 @@
 #include "gin/object_template_builder.h"
 #include "shell/browser/electron_browser_context.h"
 #include "shell/browser/javascript_environment.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/node_includes.h"

+ 14 - 12
shell/browser/api/electron_api_session.cc

@@ -77,9 +77,10 @@
 #include "shell/common/gin_converters/callback_converter.h"
 #include "shell/common/gin_converters/content_converter.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/media_converter.h"
 #include "shell/common/gin_converters/net_converter.h"
+#include "shell/common/gin_converters/optional_converter.h"
 #include "shell/common/gin_converters/usb_protected_classes_converter.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
@@ -846,36 +847,37 @@ void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
       browser_context()->GetPermissionControllerDelegate());
   if (val->IsNull()) {
     permission_manager->SetPermissionRequestHandler(
-        ElectronPermissionManager::RequestHandler());
+        ElectronPermissionManager::OnRequestHandler());
     return;
   }
-  auto handler = std::make_unique<ElectronPermissionManager::RequestHandler>();
+  auto handler = std::make_unique<ElectronPermissionManager::OnRequestHandler>();
   if (!gin::ConvertFromV8(args->isolate(), val, handler.get())) {
     args->ThrowTypeError("Must pass null or function");
     return;
   }
   permission_manager->SetPermissionRequestHandler(base::BindRepeating(
-      [](ElectronPermissionManager::RequestHandler* handler,
+      [](ElectronPermissionManager::OnRequestHandler* handler,
          content::WebContents* web_contents,
          blink::PermissionType permission_type,
          ElectronPermissionManager::StatusCallback callback,
-         const base::Value& details) {
+         const base::Value& details,
+         const url::Origin& effective_origin) {
         handler->Run(web_contents, permission_type, std::move(callback),
-                     details);
+                     details, effective_origin);
       },
       base::Owned(std::move(handler))));
 }
 
-void Session::SetPermissionCheckHandler(v8::Local<v8::Value> val,
+void Session::SetPermissionIsGrantedHandler(v8::Local<v8::Value> val,
                                         gin::Arguments* args) {
-  ElectronPermissionManager::CheckHandler handler;
+  ElectronPermissionManager::IsGrantedHandler handler;
   if (!(val->IsNull() || gin::ConvertFromV8(args->isolate(), val, &handler))) {
     args->ThrowTypeError("Must pass null or function");
     return;
   }
   auto* permission_manager = static_cast<ElectronPermissionManager*>(
       browser_context()->GetPermissionControllerDelegate());
-  permission_manager->SetPermissionCheckHandler(handler);
+  permission_manager->SetPermissionIsGrantedHandler(handler);
 }
 
 void Session::SetDisplayMediaRequestHandler(v8::Isolate* isolate,
@@ -1603,10 +1605,10 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
       .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
       .SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
       .SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
-      .SetMethod("setPermissionRequestHandler",
+      .SetMethod("_setPermissionRequestHandler",
                  &Session::SetPermissionRequestHandler)
-      .SetMethod("setPermissionCheckHandler",
-                 &Session::SetPermissionCheckHandler)
+      .SetMethod("_setPermissionCheckHandler",
+                 &Session::SetPermissionIsGrantedHandler)
       .SetMethod("setDisplayMediaRequestHandler",
                  &Session::SetDisplayMediaRequestHandler)
       .SetMethod("setDevicePermissionHandler",

+ 1 - 1
shell/browser/api/electron_api_session.h

@@ -119,7 +119,7 @@ class Session : public gin::Wrappable<Session>,
   void SetCertVerifyProc(v8::Local<v8::Value> proc, gin::Arguments* args);
   void SetPermissionRequestHandler(v8::Local<v8::Value> val,
                                    gin::Arguments* args);
-  void SetPermissionCheckHandler(v8::Local<v8::Value> val,
+  void SetPermissionIsGrantedHandler(v8::Local<v8::Value> val,
                                  gin::Arguments* args);
   void SetDevicePermissionHandler(v8::Local<v8::Value> val,
                                   gin::Arguments* args);

+ 1 - 1
shell/browser/api/electron_api_system_preferences_mac.mm

@@ -22,7 +22,7 @@
 #include "shell/browser/mac/dict_util.h"
 #include "shell/browser/mac/electron_application.h"
 #include "shell/common/color_util.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/promise.h"
 #include "shell/common/node_includes.h"

+ 6 - 4
shell/browser/api/electron_api_web_contents.cc

@@ -117,7 +117,7 @@
 #include "shell/common/gin_converters/file_path_converter.h"
 #include "shell/common/gin_converters/frame_converter.h"
 #include "shell/common/gin_converters/gfx_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/image_converter.h"
 #include "shell/common/gin_converters/net_converter.h"
 #include "shell/common/gin_converters/optional_converter.h"
@@ -1466,12 +1466,13 @@ void WebContents::OnRequestPointerLock(content::WebContents* web_contents,
 }
 
 void WebContents::RequestPointerLock(content::WebContents* web_contents,
+                                     content::RenderFrameHost* frame,
                                      bool user_gesture,
                                      bool last_unlocked_by_target) {
   auto* permission_helper =
       WebContentsPermissionHelper::FromWebContents(web_contents);
   permission_helper->RequestPointerLockPermission(
-      user_gesture, last_unlocked_by_target,
+      frame, user_gesture, last_unlocked_by_target,
       base::BindOnce(&WebContents::OnRequestPointerLock,
                      base::Unretained(this)));
 }
@@ -1493,11 +1494,12 @@ void WebContents::OnRequestKeyboardLock(content::WebContents* web_contents,
 }
 
 void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
+                                      content::RenderFrameHost* frame,
                                       bool esc_key_locked) {
   auto* permission_helper =
       WebContentsPermissionHelper::FromWebContents(web_contents);
   permission_helper->RequestKeyboardLockPermission(
-      esc_key_locked, base::BindOnce(&WebContents::OnRequestKeyboardLock,
+      frame, esc_key_locked, base::BindOnce(&WebContents::OnRequestKeyboardLock,
                                      base::Unretained(this)));
 }
 
@@ -1515,7 +1517,7 @@ bool WebContents::CheckMediaAccessPermission(
       content::WebContents::FromRenderFrameHost(render_frame_host);
   auto* permission_helper =
       WebContentsPermissionHelper::FromWebContents(web_contents);
-  return permission_helper->CheckMediaAccessPermission(security_origin, type);
+  return permission_helper->CheckMediaAccessPermission(render_frame_host, security_origin, type);
 }
 
 void WebContents::RequestMediaAccessPermission(

+ 2 - 0
shell/browser/api/electron_api_web_contents.h

@@ -614,6 +614,7 @@ class WebContents : public ExclusiveAccessContext,
                             bool last_unlocked_by_target,
                             bool allowed);
   void RequestPointerLock(content::WebContents* web_contents,
+                          content::RenderFrameHost* requesting_frame,
                           bool user_gesture,
                           bool last_unlocked_by_target) override;
   void LostPointerLock() override;
@@ -621,6 +622,7 @@ class WebContents : public ExclusiveAccessContext,
                              bool esc_key_locked,
                              bool allowed);
   void RequestKeyboardLock(content::WebContents* web_contents,
+                           content::RenderFrameHost* requesting_frame,
                            bool esc_key_locked) override;
   void CancelKeyboardLockRequest(content::WebContents* web_contents) override;
   bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,

+ 1 - 1
shell/browser/api/electron_api_web_frame_main.cc

@@ -23,7 +23,7 @@
 #include "shell/browser/javascript_environment.h"
 #include "shell/common/gin_converters/blink_converter.h"
 #include "shell/common/gin_converters/frame_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/error_thrower.h"

+ 1 - 1
shell/browser/api/electron_api_web_request.cc

@@ -29,7 +29,7 @@
 #include "shell/browser/javascript_environment.h"
 #include "shell/common/gin_converters/callback_converter.h"
 #include "shell/common/gin_converters/frame_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/net_converter.h"
 #include "shell/common/gin_converters/std_converter.h"
 #include "shell/common/gin_converters/value_converter.h"

+ 41 - 48
shell/browser/electron_permission_manager.cc

@@ -107,7 +107,7 @@ ElectronPermissionManager::ElectronPermissionManager() = default;
 ElectronPermissionManager::~ElectronPermissionManager() = default;
 
 void ElectronPermissionManager::SetPermissionRequestHandler(
-    const RequestHandler& handler) {
+    const OnRequestHandler& handler) {
   if (handler.is_null() && !pending_requests_.IsEmpty()) {
     for (PendingRequestsMap::iterator iter(&pending_requests_); !iter.IsAtEnd();
          iter.Advance()) {
@@ -117,12 +117,12 @@ void ElectronPermissionManager::SetPermissionRequestHandler(
     }
     pending_requests_.Clear();
   }
-  request_handler_ = handler;
+  on_request_handler_ = handler;
 }
 
-void ElectronPermissionManager::SetPermissionCheckHandler(
-    const CheckHandler& handler) {
-  check_handler_ = handler;
+void ElectronPermissionManager::SetPermissionIsGrantedHandler(
+    const IsGrantedHandler& handler) {
+  is_granted_handler_ = handler;
 }
 
 void ElectronPermissionManager::SetDevicePermissionHandler(
@@ -143,7 +143,7 @@ void ElectronPermissionManager::SetBluetoothPairingHandler(
 void ElectronPermissionManager::RequestPermissionWithDetails(
     blink::PermissionType permission,
     content::RenderFrameHost* render_frame_host,
-    const GURL& requesting_origin,
+    const url::Origin& effective_origin,
     bool user_gesture,
     base::Value::Dict details,
     StatusCallback response_callback) {
@@ -155,7 +155,7 @@ void ElectronPermissionManager::RequestPermissionWithDetails(
   RequestPermissionsWithDetails(
       render_frame_host,
       content::PermissionRequestDescription(permission, user_gesture,
-                                            requesting_origin),
+                                            effective_origin.GetURL()),
       std::move(details),
       base::BindOnce(PermissionRequestResponseCallbackWrapper,
                      std::move(response_callback)));
@@ -187,7 +187,7 @@ void ElectronPermissionManager::RequestPermissionsWithDetails(
     return;
   }
 
-  if (request_handler_.is_null()) {
+  if (on_request_handler_.is_null()) {
     std::vector<blink::mojom::PermissionStatus> statuses;
     for (auto& permission : permissions) {
       if (permission == blink::PermissionType::MIDI_SYSEX) {
@@ -205,8 +205,6 @@ void ElectronPermissionManager::RequestPermissionsWithDetails(
     return;
   }
 
-  auto* web_contents =
-      content::WebContents::FromRenderFrameHost(render_frame_host);
   int request_id = pending_requests_.Add(std::make_unique<PendingRequest>(
       render_frame_host, permissions, std::move(response_callback)));
 
@@ -219,7 +217,8 @@ void ElectronPermissionManager::RequestPermissionsWithDetails(
     const auto callback =
         base::BindRepeating(&ElectronPermissionManager::OnPermissionResponse,
                             base::Unretained(this), request_id, i);
-    request_handler_.Run(web_contents, permission, callback, dict_value);
+    // TODO: Fix origin
+    on_request_handler_.Run(nullptr, permission, callback, dict_value, render_frame_host->GetLastCommittedOrigin());
   }
 }
 
@@ -240,7 +239,7 @@ void ElectronPermissionManager::OnPermissionResponse(
 
 void ElectronPermissionManager::ResetPermission(
     blink::PermissionType permission,
-    const GURL& requesting_origin,
+    const GURL& effective_origin,
     const GURL& embedding_origin) {}
 
 void ElectronPermissionManager::RequestPermissionsFromCurrentDocument(
@@ -261,23 +260,21 @@ void ElectronPermissionManager::RequestPermissionsFromCurrentDocument(
 
 blink::mojom::PermissionStatus ElectronPermissionManager::GetPermissionStatus(
     blink::PermissionType permission,
-    const GURL& requesting_origin,
+    const GURL& effective_origin,
     const GURL& embedding_origin) {
   base::Value::Dict details;
   details.Set("embeddingOrigin", embedding_origin.spec());
-  bool granted = CheckPermissionWithDetails(permission, {}, requesting_origin,
+  return CheckPermissionWithDetails(permission, url::Origin::Create(effective_origin),
                                             std::move(details));
-  return granted ? blink::mojom::PermissionStatus::GRANTED
-                 : blink::mojom::PermissionStatus::DENIED;
 }
 
 content::PermissionResult
 ElectronPermissionManager::GetPermissionResultForOriginWithoutContext(
     blink::PermissionType permission,
-    const url::Origin& requesting_origin,
+    const url::Origin& effective_origin,
     const url::Origin& embedding_origin) {
   blink::mojom::PermissionStatus status = GetPermissionStatus(
-      permission, requesting_origin.GetURL(), embedding_origin.GetURL());
+      permission, effective_origin.GetURL(), embedding_origin.GetURL());
   return content::PermissionResult(
       status, content::PermissionStatusSource::UNSPECIFIED);
 }
@@ -294,24 +291,13 @@ void ElectronPermissionManager::CheckBluetoothDevicePair(
   }
 }
 
-bool ElectronPermissionManager::CheckPermissionWithDetails(
+blink::mojom::PermissionStatus ElectronPermissionManager::CheckPermissionWithDetails(
     blink::PermissionType permission,
-    content::RenderFrameHost* render_frame_host,
-    const GURL& requesting_origin,
+    const url::Origin& effective_origin,
     base::Value::Dict details) const {
-  if (check_handler_.is_null())
-    return true;
+  if (is_granted_handler_.is_null())
+    return blink::mojom::PermissionStatus::GRANTED;
 
-  auto* web_contents =
-      render_frame_host
-          ? content::WebContents::FromRenderFrameHost(render_frame_host)
-          : nullptr;
-  if (render_frame_host) {
-    details.Set("requestingUrl",
-                render_frame_host->GetLastCommittedURL().spec());
-  }
-  details.Set("isMainFrame",
-              render_frame_host && render_frame_host->GetParent() == nullptr);
   switch (permission) {
     case blink::PermissionType::AUDIO_CAPTURE:
       details.Set("mediaType", "audio");
@@ -322,8 +308,20 @@ bool ElectronPermissionManager::CheckPermissionWithDetails(
     default:
       break;
   }
-  return check_handler_.Run(web_contents, permission, requesting_origin,
-                            base::Value(std::move(details)));
+  return is_granted_handler_.Run(nullptr, permission, effective_origin,
+                            base::Value(std::move(details))).value_or(blink::mojom::PermissionStatus::DENIED);
+}
+
+blink::mojom::PermissionStatus ElectronPermissionManager::CheckPermissionWithDetailsAndFrame(blink::PermissionType permission,
+                                          const url::Origin& effective_origin,
+                                          content::RenderFrameHost* requesting_frame,
+                                          base::Value::Dict details) const {
+  details.Set("isMainFrame", requesting_frame->GetParent() == nullptr);
+  details.Set("embeddingOrigin",
+              content::PermissionUtil::GetLastCommittedOriginAsURL(
+                  requesting_frame->GetMainFrame())
+                  .spec());
+  return CheckPermissionWithDetails(permission, effective_origin, std::move(details));
 }
 
 bool ElectronPermissionManager::CheckDevicePermission(
@@ -384,15 +382,9 @@ ElectronPermissionManager::GetPermissionStatusForCurrentDocument(
     return blink::mojom::PermissionStatus::DENIED;
 
   base::Value::Dict details;
-  details.Set("embeddingOrigin",
-              content::PermissionUtil::GetLastCommittedOriginAsURL(
-                  render_frame_host->GetMainFrame())
-                  .spec());
-  bool granted = CheckPermissionWithDetails(
-      permission, render_frame_host,
-      render_frame_host->GetLastCommittedOrigin().GetURL(), std::move(details));
-  return granted ? blink::mojom::PermissionStatus::GRANTED
-                 : blink::mojom::PermissionStatus::DENIED;
+  return CheckPermissionWithDetailsAndFrame(
+      permission,
+      render_frame_host->GetLastCommittedOrigin(), render_frame_host, std::move(details));
 }
 
 blink::mojom::PermissionStatus
@@ -411,9 +403,10 @@ ElectronPermissionManager::GetPermissionStatusForEmbeddedRequester(
   if (render_frame_host->IsNestedWithinFencedFrame())
     return blink::mojom::PermissionStatus::DENIED;
 
-  return GetPermissionStatus(
-      permission, overridden_origin.GetURL(),
-      render_frame_host->GetLastCommittedOrigin().GetURL());
+  base::Value::Dict details;
+  return CheckPermissionWithDetailsAndFrame(
+      permission, overridden_origin,
+      render_frame_host, std::move(details));
 }
 
 ElectronPermissionManager::SubscriptionId
@@ -421,7 +414,7 @@ ElectronPermissionManager::SubscribeToPermissionStatusChange(
     blink::PermissionType permission,
     content::RenderProcessHost* render_process_host,
     content::RenderFrameHost* render_frame_host,
-    const GURL& requesting_origin,
+    const GURL& effective_origin,
     bool should_include_device_status,
     base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) {
   return SubscriptionId();

+ 36 - 29
shell/browser/electron_permission_manager.h

@@ -48,14 +48,15 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
   using StatusesCallback = base::OnceCallback<void(
       const std::vector<blink::mojom::PermissionStatus>&)>;
   using PairCallback = base::OnceCallback<void(base::Value::Dict)>;
-  using RequestHandler = base::RepeatingCallback<void(content::WebContents*,
+  using OnRequestHandler = base::RepeatingCallback<void(content::WebContents*,
                                                       blink::PermissionType,
                                                       StatusCallback,
-                                                      const base::Value&)>;
-  using CheckHandler =
-      base::RepeatingCallback<bool(content::WebContents*,
+                                                      const base::Value&,
+                                                      const url::Origin& effective_origin)>;
+  using IsGrantedHandler =
+      base::RepeatingCallback<std::optional<blink::mojom::PermissionStatus>(content::WebContents*,
                                    blink::PermissionType,
-                                   const GURL& requesting_origin,
+                                   const url::Origin& effective_origin,
                                    const base::Value&)>;
 
   using DeviceCheckHandler =
@@ -67,46 +68,52 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
   using BluetoothPairingHandler =
       base::RepeatingCallback<void(gin_helper::Dictionary, PairCallback)>;
 
-  void RequestPermissionWithDetails(blink::PermissionType permission,
-                                    content::RenderFrameHost* render_frame_host,
-                                    const GURL& requesting_origin,
-                                    bool user_gesture,
-                                    base::Value::Dict details,
-                                    StatusCallback response_callback);
-
-  // Handler to dispatch permission requests in JS.
-  void SetPermissionRequestHandler(const RequestHandler& handler);
-  void SetPermissionCheckHandler(const CheckHandler& handler);
+  // Handlers to dispatch permission requests in JS.
+  void SetPermissionRequestHandler(const OnRequestHandler& handler);
+  void SetPermissionIsGrantedHandler(const IsGrantedHandler& handler);
   void SetDevicePermissionHandler(const DeviceCheckHandler& handler);
   void SetProtectedUSBHandler(const ProtectedUSBHandler& handler);
   void SetBluetoothPairingHandler(const BluetoothPairingHandler& handler);
 
+  // Bluetooth permissions, maps to session.setBluetoothPairingHandler()
   void CheckBluetoothDevicePair(gin_helper::Dictionary details,
                                 PairCallback pair_callback) const;
 
-  bool CheckPermissionWithDetails(blink::PermissionType permission,
-                                  content::RenderFrameHost* render_frame_host,
-                                  const GURL& requesting_origin,
-                                  base::Value::Dict details) const;
-
+  // Device permissions, maps to session.setDevicePermissionHandler()
   bool CheckDevicePermission(blink::PermissionType permission,
                              const url::Origin& origin,
                              const base::Value& object,
                              ElectronBrowserContext* browser_context) const;
-
   void GrantDevicePermission(blink::PermissionType permission,
                              const url::Origin& origin,
                              const base::Value& object,
                              ElectronBrowserContext* browser_context) const;
-
   void RevokeDevicePermission(blink::PermissionType permission,
                               const url::Origin& origin,
                               const base::Value& object,
                               ElectronBrowserContext* browser_context) const;
 
+  // USB permissions, maps to session.setUSBProtectedClassesHandler()
   USBProtectedClasses CheckProtectedUSBClasses(
       const USBProtectedClasses& classes) const;
 
+  // Permission granted checks, maps to session.setPermissionHandlers({ isGranted })
+  blink::mojom::PermissionStatus CheckPermissionWithDetails(blink::PermissionType permission,
+                                  const url::Origin& effective_origin,
+                                  base::Value::Dict details) const;
+  blink::mojom::PermissionStatus CheckPermissionWithDetailsAndFrame(blink::PermissionType permission,
+                                          const url::Origin& effective_origin,
+                                          content::RenderFrameHost* requesting_frame,
+                                          base::Value::Dict details) const;
+
+  // Permission requests, maps to session.setPermissionHandlers({ onRequest })
+  void RequestPermissionWithDetails(blink::PermissionType permission,
+                                    content::RenderFrameHost* render_frame_host,
+                                    const url::Origin& effective_origin,
+                                    bool user_gesture,
+                                    base::Value::Dict details,
+                                    StatusCallback response_callback);
+
  protected:
   void OnPermissionResponse(int request_id,
                             int permission_id,
@@ -118,11 +125,11 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
       const content::PermissionRequestDescription& request_description,
       StatusesCallback callback) override;
   void ResetPermission(blink::PermissionType permission,
-                       const GURL& requesting_origin,
+                       const GURL& effective_origin,
                        const GURL& embedding_origin) override;
   blink::mojom::PermissionStatus GetPermissionStatus(
       blink::PermissionType permission,
-      const GURL& requesting_origin,
+      const GURL& effective_origin,
       const GURL& embedding_origin) override;
   void RequestPermissionsFromCurrentDocument(
       content::RenderFrameHost* render_frame_host,
@@ -132,7 +139,7 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
       override;
   content::PermissionResult GetPermissionResultForOriginWithoutContext(
       blink::PermissionType permission,
-      const url::Origin& requesting_origin,
+      const url::Origin& effective_origin,
       const url::Origin& embedding_origin) override;
   blink::mojom::PermissionStatus GetPermissionStatusForCurrentDocument(
       blink::PermissionType permission,
@@ -145,12 +152,12 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
   blink::mojom::PermissionStatus GetPermissionStatusForEmbeddedRequester(
       blink::PermissionType permission,
       content::RenderFrameHost* render_frame_host,
-      const url::Origin& requesting_origin) override;
+      const url::Origin& effective_origin) override;
   SubscriptionId SubscribeToPermissionStatusChange(
       blink::PermissionType permission,
       content::RenderProcessHost* render_process_host,
       content::RenderFrameHost* render_frame_host,
-      const GURL& requesting_origin,
+      const GURL& effective_origin,
       bool should_include_device_status,
       base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback)
       override;
@@ -166,8 +173,8 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
       base::Value::Dict details,
       StatusesCallback callback);
 
-  RequestHandler request_handler_;
-  CheckHandler check_handler_;
+  OnRequestHandler on_request_handler_;
+  IsGrantedHandler is_granted_handler_;
   DeviceCheckHandler device_permission_handler_;
   ProtectedUSBHandler protected_usb_handler_;
   BluetoothPairingHandler bluetooth_pairing_handler_;

+ 2 - 2
shell/browser/file_system_access/file_system_access_permission_context.cc

@@ -295,8 +295,8 @@ class FileSystemAccessPermissionContext::PermissionGrantImpl
       return;
     }
 
-    auto origin = rfh->GetLastCommittedOrigin().GetURL();
-    if (url::Origin::Create(origin) != origin_) {
+    auto origin = rfh->GetLastCommittedOrigin();
+    if (origin != origin_) {
       // Third party iframes are not allowed to request more permissions.
       std::move(callback).Run(PermissionRequestOutcome::kThirdPartyContext);
       return;

+ 4 - 11
shell/browser/hid/electron_hid_delegate.cc

@@ -136,17 +136,10 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
 bool ElectronHidDelegate::CanRequestDevicePermission(
     content::BrowserContext* browser_context,
     const url::Origin& origin) {
-  if (!browser_context)
-    return false;
-
-  base::Value::Dict details;
-  details.Set("securityOrigin", origin.GetURL().spec());
-  auto* permission_manager = static_cast<ElectronPermissionManager*>(
-      browser_context->GetPermissionControllerDelegate());
-  return permission_manager->CheckPermissionWithDetails(
-      static_cast<blink::PermissionType>(
-          WebContentsPermissionHelper::PermissionType::HID),
-      nullptr, origin.GetURL(), std::move(details));
+  // Returning true here does not grant the permission, rather it indicates
+  // that the given session is _allowed_ to _request_ the permission.
+  // This will then later hit the session permission request handler.
+  return true;
 }
 
 bool ElectronHidDelegate::HasDevicePermission(

+ 1 - 1
shell/browser/login_handler.cc

@@ -13,7 +13,7 @@
 #include "shell/browser/api/electron_api_web_contents.h"
 #include "shell/browser/javascript_environment.h"
 #include "shell/common/gin_converters/callback_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/net_converter.h"
 #include "shell/common/gin_converters/value_converter.h"
 

+ 1 - 1
shell/browser/net/electron_url_loader_factory.cc

@@ -30,7 +30,7 @@
 #include "shell/browser/net/url_pipe_loader.h"
 #include "shell/common/electron_constants.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/net_converter.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"

+ 1 - 1
shell/browser/network_hints_handler_impl.cc

@@ -12,7 +12,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "shell/browser/api/electron_api_session.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "v8/include/v8.h"
 
 NetworkHintsHandlerImpl::NetworkHintsHandlerImpl(

+ 4 - 5
shell/browser/serial/electron_serial_delegate.cc

@@ -48,11 +48,10 @@ std::unique_ptr<content::SerialChooser> ElectronSerialDelegate::RunChooser(
 
 bool ElectronSerialDelegate::CanRequestPortPermission(
     content::RenderFrameHost* frame) {
-  auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
-  auto* permission_helper =
-      WebContentsPermissionHelper::FromWebContents(web_contents);
-  return permission_helper->CheckSerialAccessPermission(
-      web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin());
+  // Returning true here does not grant the permission, rather it indicates
+  // that the given session is _allowed_ to _request_ the permission.
+  // This will then later hit the session permission request handler.
+  return true;
 }
 
 bool ElectronSerialDelegate::HasPortPermission(

+ 4 - 11
shell/browser/usb/electron_usb_delegate.cc

@@ -175,17 +175,10 @@ std::unique_ptr<content::UsbChooser> ElectronUsbDelegate::RunChooser(
 bool ElectronUsbDelegate::CanRequestDevicePermission(
     content::BrowserContext* browser_context,
     const url::Origin& origin) {
-  if (!browser_context)
-    return false;
-
-  base::Value::Dict details;
-  details.Set("securityOrigin", origin.GetURL().spec());
-  auto* permission_manager = static_cast<ElectronPermissionManager*>(
-      browser_context->GetPermissionControllerDelegate());
-  return permission_manager->CheckPermissionWithDetails(
-      static_cast<blink::PermissionType>(
-          WebContentsPermissionHelper::PermissionType::USB),
-      nullptr, origin.GetURL(), std::move(details));
+  // Returning true here does not grant the permission, rather it indicates
+  // that the given session is _allowed_ to _request_ the permission.
+  // This will then later hit the session permission request handler.
+  return true;
 }
 
 void ElectronUsbDelegate::RevokeDevicePermissionWebInitiated(

+ 19 - 26
shell/browser/web_contents_permission_helper.cc

@@ -206,34 +206,24 @@ WebContentsPermissionHelper::~WebContentsPermissionHelper() = default;
 
 void WebContentsPermissionHelper::RequestPermission(
     content::RenderFrameHost* requesting_frame,
+    const url::Origin& origin,
     blink::PermissionType permission,
     base::OnceCallback<void(bool)> callback,
     bool user_gesture,
     base::Value::Dict details) {
   auto* permission_manager = static_cast<ElectronPermissionManager*>(
       web_contents_->GetBrowserContext()->GetPermissionControllerDelegate());
-  auto origin = web_contents_->GetLastCommittedURL();
   permission_manager->RequestPermissionWithDetails(
       permission, requesting_frame, origin, false, std::move(details),
       base::BindOnce(&OnPermissionResponse, std::move(callback)));
 }
 
-bool WebContentsPermissionHelper::CheckPermission(
-    blink::PermissionType permission,
-    base::Value::Dict details) const {
-  auto* rfh = web_contents_->GetPrimaryMainFrame();
-  auto* permission_manager = static_cast<ElectronPermissionManager*>(
-      web_contents_->GetBrowserContext()->GetPermissionControllerDelegate());
-  auto origin = web_contents_->GetLastCommittedURL();
-  return permission_manager->CheckPermissionWithDetails(permission, rfh, origin,
-                                                        std::move(details));
-}
-
 void WebContentsPermissionHelper::RequestFullscreenPermission(
     content::RenderFrameHost* requesting_frame,
     base::OnceCallback<void(bool)> callback) {
   RequestPermission(
       requesting_frame,
+      requesting_frame->GetLastCommittedOrigin(),
       static_cast<blink::PermissionType>(PermissionType::FULLSCREEN),
       std::move(callback));
 }
@@ -259,8 +249,9 @@ void WebContentsPermissionHelper::RequestMediaAccessPermission(
 
   // The permission type doesn't matter here, AUDIO_CAPTURE/VIDEO_CAPTURE
   // are presented as same type in content_converter.h.
-  RequestPermission(content::RenderFrameHost::FromID(request.render_process_id,
-                                                     request.render_frame_id),
+  auto* frame = content::RenderFrameHost::FromID(request.render_process_id,
+                                                     request.render_frame_id);
+  RequestPermission(frame, request.url_origin,
                     blink::PermissionType::AUDIO_CAPTURE, std::move(callback),
                     false, std::move(details));
 }
@@ -268,16 +259,18 @@ void WebContentsPermissionHelper::RequestMediaAccessPermission(
 void WebContentsPermissionHelper::RequestWebNotificationPermission(
     content::RenderFrameHost* requesting_frame,
     base::OnceCallback<void(bool)> callback) {
-  RequestPermission(requesting_frame, blink::PermissionType::NOTIFICATIONS,
+  RequestPermission(requesting_frame, requesting_frame->GetLastCommittedOrigin(), blink::PermissionType::NOTIFICATIONS,
                     std::move(callback));
 }
 
 void WebContentsPermissionHelper::RequestPointerLockPermission(
+    content::RenderFrameHost* frame,
     bool user_gesture,
     bool last_unlocked_by_target,
     base::OnceCallback<void(content::WebContents*, bool, bool, bool)>
         callback) {
-  RequestPermission(web_contents_->GetPrimaryMainFrame(),
+  RequestPermission(frame,
+                    frame->GetLastCommittedOrigin(),
                     blink::PermissionType::POINTER_LOCK,
                     base::BindOnce(std::move(callback), web_contents_,
                                    user_gesture, last_unlocked_by_target),
@@ -285,10 +278,12 @@ void WebContentsPermissionHelper::RequestPointerLockPermission(
 }
 
 void WebContentsPermissionHelper::RequestKeyboardLockPermission(
+    content::RenderFrameHost* requesting_frame,
     bool esc_key_locked,
     base::OnceCallback<void(content::WebContents*, bool, bool)> callback) {
   RequestPermission(
-      web_contents_->GetPrimaryMainFrame(),
+      requesting_frame,
+      requesting_frame->GetLastCommittedOrigin(),
       blink::PermissionType::KEYBOARD_LOCK,
       base::BindOnce(std::move(callback), web_contents_, esc_key_locked));
 }
@@ -302,29 +297,27 @@ void WebContentsPermissionHelper::RequestOpenExternalPermission(
   details.Set("externalURL", url.spec());
   RequestPermission(
       requesting_frame,
+      requesting_frame->GetLastCommittedOrigin(),
       static_cast<blink::PermissionType>(PermissionType::OPEN_EXTERNAL),
       std::move(callback), user_gesture, std::move(details));
 }
 
 bool WebContentsPermissionHelper::CheckMediaAccessPermission(
+    content::RenderFrameHost* requesting_frame,
     const url::Origin& security_origin,
     blink::mojom::MediaStreamType type) const {
   base::Value::Dict details;
+  // Deprecated
   details.Set("securityOrigin", security_origin.GetURL().spec());
   details.Set("mediaType", MediaStreamTypeToString(type));
   auto blink_type = type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE
                         ? blink::PermissionType::AUDIO_CAPTURE
                         : blink::PermissionType::VIDEO_CAPTURE;
-  return CheckPermission(blink_type, std::move(details));
-}
 
-bool WebContentsPermissionHelper::CheckSerialAccessPermission(
-    const url::Origin& embedding_origin) const {
-  base::Value::Dict details;
-  details.Set("securityOrigin", embedding_origin.GetURL().spec());
-  return CheckPermission(
-      static_cast<blink::PermissionType>(PermissionType::SERIAL),
-      std::move(details));
+  auto* permission_manager = static_cast<ElectronPermissionManager*>(
+      web_contents_->GetBrowserContext()->GetPermissionControllerDelegate());
+  return permission_manager->CheckPermissionWithDetailsAndFrame(blink_type, security_origin, requesting_frame,
+                                                        std::move(details)) != blink::mojom::PermissionStatus::DENIED;
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(WebContentsPermissionHelper);

+ 5 - 5
shell/browser/web_contents_permission_helper.h

@@ -41,11 +41,13 @@ class WebContentsPermissionHelper
   void RequestMediaAccessPermission(const content::MediaStreamRequest& request,
                                     content::MediaResponseCallback callback);
   void RequestPointerLockPermission(
+      content::RenderFrameHost* frame,
       bool user_gesture,
       bool last_unlocked_by_target,
       base::OnceCallback<void(content::WebContents*, bool, bool, bool)>
           callback);
   void RequestKeyboardLockPermission(
+      content::RenderFrameHost* requesting_frame,
       bool esc_key_locked,
       base::OnceCallback<void(content::WebContents*, bool, bool)> callback);
   void RequestWebNotificationPermission(
@@ -57,23 +59,21 @@ class WebContentsPermissionHelper
                                      const GURL& url);
 
   // Synchronous Checks
-  bool CheckMediaAccessPermission(const url::Origin& security_origin,
+  bool CheckMediaAccessPermission(content::RenderFrameHost* requesting_frame,
+                                  const url::Origin& security_origin,
                                   blink::mojom::MediaStreamType type) const;
-  bool CheckSerialAccessPermission(const url::Origin& embedding_origin) const;
 
  private:
   explicit WebContentsPermissionHelper(content::WebContents* web_contents);
   friend class content::WebContentsUserData<WebContentsPermissionHelper>;
 
   void RequestPermission(content::RenderFrameHost* requesting_frame,
+                         const url::Origin& origin,
                          blink::PermissionType permission,
                          base::OnceCallback<void(bool)> callback,
                          bool user_gesture = false,
                          base::Value::Dict details = {});
 
-  bool CheckPermission(blink::PermissionType permission,
-                       base::Value::Dict details) const;
-
   // TODO(clavin): refactor to use the WebContents provided by the
   // WebContentsUserData base class instead of storing a duplicate ref
   raw_ptr<content::WebContents> web_contents_;

+ 1 - 1
shell/common/api/electron_api_native_image.cc

@@ -23,7 +23,7 @@
 #include "shell/common/asar/asar_util.h"
 #include "shell/common/gin_converters/file_path_converter.h"
 #include "shell/common/gin_converters/gfx_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/error_thrower.h"

+ 1 - 1
shell/common/api/electron_api_net.cc

@@ -13,7 +13,7 @@
 #include "shell/browser/net/resolve_host_function.h"
 #include "shell/common/api/electron_api_url_loader.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/net_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/error_thrower.h"

+ 1 - 1
shell/common/api/electron_api_shell.cc

@@ -7,7 +7,7 @@
 #include "shell/common/gin_converters/callback_converter.h"
 #include "shell/common/gin_converters/file_path_converter.h"
 #include "shell/common/gin_converters/guid_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/error_thrower.h"
 #include "shell/common/gin_helper/promise.h"

+ 1 - 1
shell/common/api/electron_api_url_loader.cc

@@ -40,7 +40,7 @@
 #include "shell/browser/net/proxying_url_loader_factory.h"
 #include "shell/browser/protocol_registry.h"
 #include "shell/common/gin_converters/callback_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/net_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/gin_helper/object_template_builder.h"

+ 1 - 1
shell/common/api/electron_api_v8_util.cc

@@ -8,7 +8,7 @@
 #include "base/run_loop.h"
 #include "electron/buildflags/buildflags.h"
 #include "shell/common/gin_converters/content_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/std_converter.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "shell/common/node_includes.h"

+ 1 - 1
shell/common/gin_converters/blink_converter.cc

@@ -16,7 +16,7 @@
 #include "gin/converter.h"
 #include "gin/data_object_builder.h"
 #include "shell/common/gin_converters/gfx_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/std_converter.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/dictionary.h"

+ 15 - 1
shell/common/gin_converters/content_converter.cc

@@ -17,7 +17,7 @@
 #include "shell/common/gin_converters/callback_converter.h"
 #include "shell/common/gin_converters/frame_converter.h"
 #include "shell/common/gin_converters/gfx_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_helper/dictionary.h"
 #include "third_party/blink/public/common/context_menu_data/untrustworthy_context_menu_params.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
@@ -127,6 +127,20 @@ bool Converter<blink::mojom::PermissionStatus>::FromV8(
     v8::Isolate* isolate,
     v8::Local<v8::Value> val,
     blink::mojom::PermissionStatus* out) {
+  std::string str_result;
+  if (ConvertFromV8(isolate, val, &str_result)) {
+    if (str_result == "granted") {
+      *out = blink::mojom::PermissionStatus::GRANTED;
+    } else if (str_result == "denied") {
+      *out = blink::mojom::PermissionStatus::DENIED;
+    } else if (str_result == "ask") {
+      *out = blink::mojom::PermissionStatus::ASK;
+    } else {
+      return false;
+    }
+    return true;
+  }
+
   bool result;
   if (!ConvertFromV8(isolate, val, &result))
     return false;

+ 1 - 1
shell/common/gin_converters/extension_converter.cc

@@ -7,7 +7,7 @@
 #include "extensions/common/extension.h"
 #include "gin/dictionary.h"
 #include "shell/common/gin_converters/file_path_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/value_converter.h"
 
 namespace gin {

+ 1 - 1
shell/common/gin_converters/media_converter.cc

@@ -8,7 +8,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "gin/data_object_builder.h"
 #include "shell/common/gin_converters/frame_converter.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 
 namespace gin {

+ 1 - 1
shell/common/gin_converters/net_converter.cc

@@ -28,7 +28,7 @@
 #include "services/network/public/cpp/resource_request_body.h"
 #include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
 #include "shell/browser/api/electron_api_data_pipe_holder.h"
-#include "shell/common/gin_converters/gurl_converter.h"
+#include "shell/common/gin_converters/url_converters.h"
 #include "shell/common/gin_converters/std_converter.h"
 #include "shell/common/gin_converters/value_converter.h"
 #include "shell/common/gin_helper/promise.h"

+ 8 - 0
shell/common/gin_converters/gurl_converter.h → shell/common/gin_converters/url_converters.h

@@ -9,6 +9,7 @@
 
 #include "gin/converter.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace gin {
 
@@ -30,6 +31,13 @@ struct Converter<GURL> {
   }
 };
 
+template <>
+struct Converter<url::Origin> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const url::Origin& val) {
+    return ConvertToV8(isolate, val.Serialize());
+  }
+};
+
 }  // namespace gin
 
 #endif  // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_GURL_CONVERTER_H_

+ 16 - 7
spec/ts-smoke/electron/main.ts

@@ -1243,15 +1243,24 @@ session.defaultSession.setCertificateVerifyProc((request, callback) => {
   }
 });
 
-session.defaultSession.setPermissionRequestHandler(function (webContents, permission, callback) {
-  if (webContents.getURL() === 'github.com') {
-    if (permission === 'notifications') {
-      callback(false);
-      return;
+session.defaultSession.setPermissionHandlers({
+  isGranted (permission, effectiveOrigin) {
+    if (effectiveOrigin === 'https://github.com') {
+      if (permission === 'notifications') {
+        return { status: 'granted' };
+      }
+    }
+    return { status: 'denied' };
+  },
+  onRequest: async function (permission, effectiveOrigin) {
+    if (effectiveOrigin === 'https://github.com') {
+      if (permission === 'notifications') {
+        return { status: 'denied' };
+      }
     }
-  }
 
-  callback(true);
+    return { status: 'granted' };
+  }
 });
 
 // consider any url ending with `example.com`, `foobar.com`, `baz`

+ 5 - 0
typings/internal-electron.d.ts

@@ -67,6 +67,11 @@ declare namespace Electron {
     }
   }
 
+  interface Session {
+    _setPermissionRequestHandler: (...args: Parameters<Electron.Session['setPermissionRequestHandler']>) => void;
+    _setPermissionCheckHandler: (fn: ((...args: Parameters<NonNullable<Parameters<Electron.Session['setPermissionCheckHandler']>[0]>>) => Electron.PermissionCheckResult['status']) | null) => void;
+  }
+
   interface TouchBar {
     _removeFromWindow: (win: BaseWindow) => void;
   }