Compare commits

...

3 Commits

Author SHA1 Message Date
Samuel Attard
8bf80ccdb8 tests 2024-08-31 01:01:39 -07:00
Samuel Attard
d7ff2bf7b7 update origin source 2024-08-31 00:34:26 -07:00
Samuel Attard
ca221f6d80 feat: new permissions API 2024-08-30 23:37:14 -04:00
44 changed files with 684 additions and 199 deletions

View File

@@ -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 `navigator.hid.requestDevice` is made. `callback` should be called with
`deviceId` to be selected; passing no arguments to `callback` will `deviceId` to be selected; passing no arguments to `callback` will
cancel the request. Additionally, permissioning on `navigator.hid` can 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). and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} ```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 `navigator.serial.requestPort` is made. `callback` should be called with
`portId` to be selected, passing an empty string to `callback` will `portId` to be selected, passing an empty string to `callback` will
cancel the request. Additionally, permissioning on `navigator.serial` can 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. with the `serial` permission.
```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} ```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 `navigator.usb.requestDevice` is made. `callback` should be called with
`deviceId` to be selected; passing no arguments to `callback` will `deviceId` to be selected; passing no arguments to `callback` will
cancel the request. Additionally, permissioning on `navigator.usb` can 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). and [`ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
```js @ts-type={fetchGrantedDevices:()=>(Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)} @ts-type={updateGrantedDevices:(devices:Array<Electron.DevicePermissionHandlerHandlerDetails['device']>)=>void} ```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. > **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 * `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. * `permission` string - The type of requested permission.
* `clipboard-read` - Request access to read from the clipboard. * `clipboard-read` - Request access to read from the clipboard.
* `clipboard-sanitized-write` - Request access to write to the clipboard. * `clipboard-sanitized-write` - Request access to write to the clipboard.
@@ -886,6 +983,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
* `callback` Function * `callback` Function
* `permissionGranted` boolean - Allow or deny the permission. * `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. * `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`. 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. 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 * `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. * `permission` string - Type of permission check.
* `clipboard-read` - Request access to read from the clipboard. * `clipboard-read` - Request access to read from the clipboard.
* `clipboard-sanitized-write` - Request access to write to 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). * `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). * `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). * `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. * `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. * `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. * `securityOrigin` string (optional) - The security origin of the `media` check.

View File

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

View File

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

View File

@@ -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 * `screenPosition` string - Specify the screen type to emulate
(default: `desktop`): (default: `desktop`):
* `desktop` - Desktop screen type. * `desktop` - Desktop screen type.

View File

@@ -52,7 +52,7 @@ the WebHID API:
needed, a developer can store granted device permissions (eg when handling needed, a developer can store granted device permissions (eg when handling
the `select-hid-device` event) and then read from that storage with the `select-hid-device` event) and then read from that storage with
`setDevicePermissionHandler`. `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. can be used to disable HID access for specific origins.
### Blocklist ### 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 needed, a developer can store granted device permissions (eg when handling
the `select-serial-port` event) and then read from that storage with the `select-serial-port` event) and then read from that storage with
`setDevicePermissionHandler`. `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. can be used to disable serial access for specific origins.
### Example ### 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 needed, a developer can store granted device permissions (eg when handling
the `select-usb-device` event) and then read from that storage with the `select-usb-device` event) and then read from that storage with
`setDevicePermissionHandler`. `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. can be used to disable USB access for specific origins.
* [`ses.setUSBProtectedClassesHandler](../api/session.md#sessetusbprotectedclasseshandlerhandler) * [`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. can be used to allow usage of [protected USB classes](https://wicg.github.io/webusb/#usbinterface-interface) that are not available by default.

View File

@@ -600,7 +600,7 @@ filenames = {
"shell/common/gin_converters/gfx_converter.cc", "shell/common/gin_converters/gfx_converter.cc",
"shell/common/gin_converters/gfx_converter.h", "shell/common/gin_converters/gfx_converter.h",
"shell/common/gin_converters/guid_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/hid_device_info_converter.h",
"shell/common/gin_converters/image_converter.cc", "shell/common/gin_converters/image_converter.cc",
"shell/common/gin_converters/image_converter.h", "shell/common/gin_converters/image_converter.h",

View File

@@ -6,6 +6,44 @@ Session.prototype.fetch = function (input: RequestInfo, init?: RequestInit) {
return fetchWithSession(input, init, this, net.request); 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) => {
Promise.resolve(handlers.onRequest(permission, effectiveOrigin, details))
.then((result) => callback(result.status === 'granted'))
.catch((err) => {
this.emit('error', err);
callback(false);
});
});
};
export default { export default {
fromPartition, fromPartition,
fromPath, fromPath,

View File

@@ -67,7 +67,7 @@
#include "shell/common/gin_converters/blink_converter.h" #include "shell/common/gin_converters/blink_converter.h"
#include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_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/image_converter.h"
#include "shell/common/gin_converters/login_item_settings_converter.h" #include "shell/common/gin_converters/login_item_settings_converter.h"
#include "shell/common/gin_converters/net_converter.h" #include "shell/common/gin_converters/net_converter.h"

View File

@@ -25,7 +25,7 @@
#include "shell/browser/cookie_change_notifier.h" #include "shell/browser/cookie_change_notifier.h"
#include "shell/browser/electron_browser_context.h" #include "shell/browser/electron_browser_context.h"
#include "shell/browser/javascript_environment.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_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/gin_helper/object_template_builder.h"

View File

@@ -12,7 +12,7 @@
#include "shell/browser/electron_browser_main_parts.h" #include "shell/browser/electron_browser_main_parts.h"
#include "shell/common/gin_converters/file_dialog_converter.h" #include "shell/common/gin_converters/file_dialog_converter.h"
#include "shell/common/gin_converters/file_path_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/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/gin_helper/object_template_builder.h"
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"

View File

@@ -14,7 +14,7 @@
#include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/content_converter.h" #include "shell/common/gin_converters/content_converter.h"
#include "shell/common/gin_converters/file_path_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/image_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/gin_helper/object_template_builder.h"

View File

@@ -16,7 +16,7 @@
#include "gin/object_template_builder.h" #include "gin/object_template_builder.h"
#include "shell/browser/electron_browser_context.h" #include "shell/browser/electron_browser_context.h"
#include "shell/browser/javascript_environment.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_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"

View File

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

View File

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

View File

@@ -22,7 +22,7 @@
#include "shell/browser/mac/dict_util.h" #include "shell/browser/mac/dict_util.h"
#include "shell/browser/mac/electron_application.h" #include "shell/browser/mac/electron_application.h"
#include "shell/common/color_util.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_converters/value_converter.h"
#include "shell/common/gin_helper/promise.h" #include "shell/common/gin_helper/promise.h"
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"

View File

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

View File

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

View File

@@ -23,7 +23,7 @@
#include "shell/browser/javascript_environment.h" #include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/blink_converter.h" #include "shell/common/gin_converters/blink_converter.h"
#include "shell/common/gin_converters/frame_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_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/error_thrower.h"

View File

@@ -29,7 +29,7 @@
#include "shell/browser/javascript_environment.h" #include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/frame_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/net_converter.h"
#include "shell/common/gin_converters/std_converter.h" #include "shell/common/gin_converters/std_converter.h"
#include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_converters/value_converter.h"

View File

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

View File

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

View File

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

View File

@@ -136,17 +136,10 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
bool ElectronHidDelegate::CanRequestDevicePermission( bool ElectronHidDelegate::CanRequestDevicePermission(
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
const url::Origin& origin) { const url::Origin& origin) {
if (!browser_context) // Returning true here does not grant the permission, rather it indicates
return false; // that the given session is _allowed_ to _request_ the permission.
// This will then later hit the session permission request handler.
base::Value::Dict details; return true;
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));
} }
bool ElectronHidDelegate::HasDevicePermission( bool ElectronHidDelegate::HasDevicePermission(

View File

@@ -13,7 +13,7 @@
#include "shell/browser/api/electron_api_web_contents.h" #include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/javascript_environment.h" #include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/callback_converter.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/net_converter.h"
#include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_converters/value_converter.h"

View File

@@ -30,7 +30,7 @@
#include "shell/browser/net/url_pipe_loader.h" #include "shell/browser/net/url_pipe_loader.h"
#include "shell/common/electron_constants.h" #include "shell/common/electron_constants.h"
#include "shell/common/gin_converters/file_path_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/net_converter.h" #include "shell/common/gin_converters/net_converter.h"
#include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"

View File

@@ -12,7 +12,7 @@
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "shell/browser/api/electron_api_session.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" #include "v8/include/v8.h"
NetworkHintsHandlerImpl::NetworkHintsHandlerImpl( NetworkHintsHandlerImpl::NetworkHintsHandlerImpl(

View File

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

View File

@@ -175,17 +175,10 @@ std::unique_ptr<content::UsbChooser> ElectronUsbDelegate::RunChooser(
bool ElectronUsbDelegate::CanRequestDevicePermission( bool ElectronUsbDelegate::CanRequestDevicePermission(
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
const url::Origin& origin) { const url::Origin& origin) {
if (!browser_context) // Returning true here does not grant the permission, rather it indicates
return false; // that the given session is _allowed_ to _request_ the permission.
// This will then later hit the session permission request handler.
base::Value::Dict details; return true;
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));
} }
void ElectronUsbDelegate::RevokeDevicePermissionWebInitiated( void ElectronUsbDelegate::RevokeDevicePermissionWebInitiated(

View File

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

View File

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

View File

@@ -23,7 +23,7 @@
#include "shell/common/asar/asar_util.h" #include "shell/common/asar/asar_util.h"
#include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_converters/gfx_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_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/error_thrower.h"

View File

@@ -13,7 +13,7 @@
#include "shell/browser/net/resolve_host_function.h" #include "shell/browser/net/resolve_host_function.h"
#include "shell/common/api/electron_api_url_loader.h" #include "shell/common/api/electron_api_url_loader.h"
#include "shell/common/gin_converters/file_path_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/net_converter.h" #include "shell/common/gin_converters/net_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/error_thrower.h"

View File

@@ -7,7 +7,7 @@
#include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_converters/guid_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/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h" #include "shell/common/gin_helper/error_thrower.h"
#include "shell/common/gin_helper/promise.h" #include "shell/common/gin_helper/promise.h"

View File

@@ -40,7 +40,7 @@
#include "shell/browser/net/proxying_url_loader_factory.h" #include "shell/browser/net/proxying_url_loader_factory.h"
#include "shell/browser/protocol_registry.h" #include "shell/browser/protocol_registry.h"
#include "shell/common/gin_converters/callback_converter.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/net_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/gin_helper/object_template_builder.h"

View File

@@ -8,7 +8,7 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "electron/buildflags/buildflags.h" #include "electron/buildflags/buildflags.h"
#include "shell/common/gin_converters/content_converter.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_converters/std_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"
#include "shell/common/node_includes.h" #include "shell/common/node_includes.h"

View File

@@ -16,7 +16,7 @@
#include "gin/converter.h" #include "gin/converter.h"
#include "gin/data_object_builder.h" #include "gin/data_object_builder.h"
#include "shell/common/gin_converters/gfx_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/std_converter.h" #include "shell/common/gin_converters/std_converter.h"
#include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/dictionary.h"

View File

@@ -17,7 +17,7 @@
#include "shell/common/gin_converters/callback_converter.h" #include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/frame_converter.h" #include "shell/common/gin_converters/frame_converter.h"
#include "shell/common/gin_converters/gfx_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 "shell/common/gin_helper/dictionary.h"
#include "third_party/blink/public/common/context_menu_data/untrustworthy_context_menu_params.h" #include "third_party/blink/public/common/context_menu_data/untrustworthy_context_menu_params.h"
#include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/events/keycodes/dom/keycode_converter.h"
@@ -127,6 +127,20 @@ bool Converter<blink::mojom::PermissionStatus>::FromV8(
v8::Isolate* isolate, v8::Isolate* isolate,
v8::Local<v8::Value> val, v8::Local<v8::Value> val,
blink::mojom::PermissionStatus* out) { 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; bool result;
if (!ConvertFromV8(isolate, val, &result)) if (!ConvertFromV8(isolate, val, &result))
return false; return false;

View File

@@ -7,7 +7,7 @@
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "gin/dictionary.h" #include "gin/dictionary.h"
#include "shell/common/gin_converters/file_path_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/value_converter.h" #include "shell/common/gin_converters/value_converter.h"
namespace gin { namespace gin {

View File

@@ -8,7 +8,7 @@
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "gin/data_object_builder.h" #include "gin/data_object_builder.h"
#include "shell/common/gin_converters/frame_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 "third_party/blink/public/mojom/mediastream/media_stream.mojom.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
namespace gin { namespace gin {

View File

@@ -28,7 +28,7 @@
#include "services/network/public/cpp/resource_request_body.h" #include "services/network/public/cpp/resource_request_body.h"
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h" #include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
#include "shell/browser/api/electron_api_data_pipe_holder.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/std_converter.h"
#include "shell/common/gin_converters/value_converter.h" #include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/promise.h" #include "shell/common/gin_helper/promise.h"

View File

@@ -9,6 +9,7 @@
#include "gin/converter.h" #include "gin/converter.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/origin.h"
namespace gin { 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 } // namespace gin
#endif // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_GURL_CONVERTER_H_ #endif // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_GURL_CONVERTER_H_

View File

@@ -1358,6 +1358,320 @@ describe('session module', () => {
}); });
}); });
describe('ses.setPermissionHandlers(handlers)', () => {
describe('onRequest', () => {
afterEach(closeAllWindows);
// These tests are done on an http server because navigator.userAgentData
// requires a secure context.
let server: http.Server;
let serverUrl: string;
before(async () => {
server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/html');
res.end('');
});
serverUrl = (await listen(server)).url;
});
after(() => {
server.close();
});
it('cancels any pending requests when cleared', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler',
nodeIntegration: true,
contextIsolation: false
}
});
const ses = w.webContents.session;
ses.setPermissionHandlers({
onRequest: () => ses.setPermissionHandlers(null) as any,
isGranted: () => ({ status: 'ask' })
});
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb(`<html><script>(${remote})()</script></html>`);
});
const result = once(require('electron').ipcMain, 'message');
function remote () {
(navigator as any).requestMIDIAccess({ sysex: true }).then(() => {}, (err: any) => {
require('electron').ipcRenderer.send('message', err.name);
});
}
w.loadURL('https://myfakesite');
const [, name] = await result;
expect(name).to.deep.equal('SecurityError');
});
it('cancels any requests when resolved with invalid status', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler',
nodeIntegration: true,
contextIsolation: false
}
});
const ses = w.webContents.session;
ses.setPermissionHandlers({
onRequest: async () => ({ status: 'nope?' as any }),
isGranted: () => ({ status: 'ask' })
});
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb(`<html><script>(${remote})()</script></html>`);
});
const result = once(require('electron').ipcMain, 'message');
function remote () {
(navigator as any).requestMIDIAccess({ sysex: true }).then(() => {}, (err: any) => {
require('electron').ipcRenderer.send('message', err.name);
});
}
w.loadURL('https://myfakesite');
const [, name] = await result;
expect(name).to.deep.equal('SecurityError');
});
it('successfully resolves when calling legacy getUserMedia', async () => {
const ses = session.fromPartition('' + Math.random());
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'granted' }),
isGranted: () => ({ status: 'ask' })
}
);
const w = new BrowserWindow({ show: false, webPreferences: { session: ses } });
await w.loadURL(serverUrl);
const { ok, message } = await w.webContents.executeJavaScript(`
new Promise((resolve, reject) => navigator.getUserMedia({
video: true,
audio: true,
}, x => resolve({ok: x instanceof MediaStream}), e => reject({ok: false, message: e.message})))
`);
expect(ok).to.be.true(message);
});
it('successfully rejects when calling legacy getUserMedia', async () => {
const ses = session.fromPartition('' + Math.random());
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'ask' })
}
);
const w = new BrowserWindow({ show: false, webPreferences: { session: ses } });
await w.loadURL(serverUrl);
await expect(w.webContents.executeJavaScript(`
new Promise((resolve, reject) => navigator.getUserMedia({
video: true,
audio: true,
}, x => resolve({ok: x instanceof MediaStream}), e => reject({ok: false, message: e.message})))
`)).to.eventually.be.rejectedWith('Permission denied');
});
});
describe('isGranted', () => {
afterEach(closeAllWindows);
it('provides valid effectiveOrigin for main frame requests', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
let effectiveOrigin: string = '';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: (permission, origin) => {
effectiveOrigin = origin;
return { status: 'granted' };
}
}
);
const readClipboardPermission: any = () => {
return w.webContents.executeJavaScript(`
navigator.permissions.query({name: 'clipboard-read'})
.then(permission => permission.state).catch(err => err.message);
`, true);
};
await w.loadURL(loadUrl);
const state = await readClipboardPermission();
expect(state).to.equal('granted');
expect(effectiveOrigin).to.equal('https://myfakesite');
});
it('provides valid effectiveOrigin for cross origin subframes', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/foo';
let effectiveOrigin: string = '';
let handlerDetails: Electron.PermissionCheckDetails;
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: (permission, origin, details) => {
effectiveOrigin = origin;
handlerDetails = details;
return { status: 'granted' };
}
}
);
const readClipboardPermission: any = (frame: WebFrameMain) => {
return frame.executeJavaScript(`
navigator.permissions.query({name: 'clipboard-read'})
.then(permission => permission.state).catch(err => err.message);
`, true);
};
await w.loadFile(path.join(fixtures, 'api', 'blank.html'));
w.webContents.executeJavaScript(`
var iframe = document.createElement('iframe');
iframe.src = '${loadUrl}';
iframe.allow = 'clipboard-read';
document.body.appendChild(iframe);
null;
`);
const [,, frameProcessId, frameRoutingId] = await once(w.webContents, 'did-frame-finish-load');
const state = await readClipboardPermission(webFrameMain.fromId(frameProcessId, frameRoutingId));
expect(state).to.equal('granted');
expect(effectiveOrigin).to.equal('https://myfakesite');
expect(handlerDetails!.isMainFrame).to.be.false();
expect(handlerDetails!.embeddingOrigin).to.equal('file:///');
});
it('allows providing "default" / "ask" value', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'ask' })
}
);
const readNotificationPermission = () => {
return w.webContents.executeJavaScript(`
Notification.permission
`, true);
};
await w.loadURL(loadUrl);
const state = await readNotificationPermission();
expect(state).to.equal('default');
});
it('allows providing "granted" value', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'granted' })
}
);
const readNotificationPermission = () => {
return w.webContents.executeJavaScript(`
Notification.permission
`, true);
};
await w.loadURL(loadUrl);
const state = await readNotificationPermission();
expect(state).to.equal('granted');
});
it('allows providing "denied" value', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
partition: 'very-temp-permission-handler'
}
});
const ses = w.webContents.session;
const loadUrl = 'https://myfakesite/oh-hi';
ses.protocol.interceptStringProtocol('https', (req, cb) => {
cb('<html><script>console.log(\'test\');</script></html>');
});
ses.setPermissionHandlers(
{
onRequest: async () => ({ status: 'denied' }),
isGranted: () => ({ status: 'denied' })
}
);
const readNotificationPermission = () => {
return w.webContents.executeJavaScript(`
Notification.permission
`, true);
};
await w.loadURL(loadUrl);
const state = await readNotificationPermission();
expect(state).to.equal('denied');
});
});
});
describe('ses.setPermissionRequestHandler(handler)', () => { describe('ses.setPermissionRequestHandler(handler)', () => {
afterEach(closeAllWindows); afterEach(closeAllWindows);
// These tests are done on an http server because navigator.userAgentData // These tests are done on an http server because navigator.userAgentData
@@ -1448,7 +1762,7 @@ describe('session module', () => {
describe('ses.setPermissionCheckHandler(handler)', () => { describe('ses.setPermissionCheckHandler(handler)', () => {
afterEach(closeAllWindows); afterEach(closeAllWindows);
it('details provides requestingURL for mainFrame', async () => { it.skip('details provides requestingURL for mainFrame', async () => {
const w = new BrowserWindow({ const w = new BrowserWindow({
show: false, show: false,
webPreferences: { webPreferences: {
@@ -1484,7 +1798,7 @@ describe('session module', () => {
expect(handlerDetails!.requestingUrl).to.equal(loadUrl); expect(handlerDetails!.requestingUrl).to.equal(loadUrl);
}); });
it('details provides requestingURL for cross origin subFrame', async () => { it.skip('details provides requestingURL for cross origin subFrame', async () => {
const w = new BrowserWindow({ const w = new BrowserWindow({
show: false, show: false,
webPreferences: { webPreferences: {

View File

@@ -1243,15 +1243,24 @@ session.defaultSession.setCertificateVerifyProc((request, callback) => {
} }
}); });
session.defaultSession.setPermissionRequestHandler(function (webContents, permission, callback) { session.defaultSession.setPermissionHandlers({
if (webContents.getURL() === 'github.com') { isGranted (permission, effectiveOrigin) {
if (permission === 'notifications') { if (effectiveOrigin === 'https://github.com') {
callback(false); if (permission === 'notifications') {
return; 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` // consider any url ending with `example.com`, `foobar.com`, `baz`

View File

@@ -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 { interface TouchBar {
_removeFromWindow: (win: BaseWindow) => void; _removeFromWindow: (win: BaseWindow) => void;
} }