mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
41 Commits
v16.0.0-be
...
v17.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b2c46dfd6 | ||
|
|
4fd7c2adcd | ||
|
|
6db8d7918d | ||
|
|
e53bd1b72a | ||
|
|
d2425472df | ||
|
|
0e042ca64d | ||
|
|
6f684d564f | ||
|
|
e07d74cf29 | ||
|
|
2c10d0fe1b | ||
|
|
1193a37d8f | ||
|
|
2d111a4e25 | ||
|
|
22d683e3f8 | ||
|
|
abf6f1cf78 | ||
|
|
4da66b9d68 | ||
|
|
02d3e66bcb | ||
|
|
3b155f7391 | ||
|
|
80577a4f08 | ||
|
|
a5f1fbdc54 | ||
|
|
ecf191e71f | ||
|
|
104e0f3059 | ||
|
|
10d92e9f29 | ||
|
|
a758a2eab3 | ||
|
|
0f6560f1f7 | ||
|
|
265474882c | ||
|
|
68c738a177 | ||
|
|
98ac0ca52a | ||
|
|
c377fe4ba6 | ||
|
|
25d0963d9b | ||
|
|
2360012cad | ||
|
|
1a6a8f55af | ||
|
|
53bf308497 | ||
|
|
5e1fbc9025 | ||
|
|
d88e71f688 | ||
|
|
919fd0f28d | ||
|
|
da921e680f | ||
|
|
6aece4a83d | ||
|
|
77579614e0 | ||
|
|
e39a1d2ea0 | ||
|
|
68d3659f75 | ||
|
|
bb6dc99d9d | ||
|
|
38b810b2e3 |
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -8,9 +8,9 @@ body:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
|
||||
required: true
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -8,9 +8,9 @@ body:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
|
||||
required: true
|
||||
|
||||
@@ -7,9 +7,9 @@ body:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
|
||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -3,7 +3,7 @@
|
||||
Thank you for your Pull Request. Please provide a description above and review
|
||||
the requirements below.
|
||||
|
||||
Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTING.md
|
||||
Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
#### Checklist
|
||||
@@ -11,7 +11,7 @@ Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTIN
|
||||
|
||||
- [ ] PR description included and stakeholders cc'd
|
||||
- [ ] `npm test` passes
|
||||
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/master/docs/development/testing.md)
|
||||
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
|
||||
- [ ] relevant documentation is changed or added
|
||||
- [ ] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples).
|
||||
|
||||
|
||||
6
.github/config.yml
vendored
6
.github/config.yml
vendored
@@ -2,7 +2,7 @@
|
||||
newPRWelcomeComment: |
|
||||
💖 Thanks for opening this pull request! 💖
|
||||
|
||||
We use [semantic commit messages](https://github.com/electron/electron/blob/master/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix.
|
||||
We use [semantic commit messages](https://github.com/electron/electron/blob/main/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix.
|
||||
|
||||
Examples of commit messages with semantic prefixes:
|
||||
|
||||
@@ -12,9 +12,9 @@ newPRWelcomeComment: |
|
||||
|
||||
Things that will help get your PR across the finish line:
|
||||
|
||||
- Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/master/docs/development/coding-style.md).
|
||||
- Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/main/docs/development/coding-style.md).
|
||||
- Run `npm run lint` locally to catch formatting errors earlier.
|
||||
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/master/docs/styleguide.md).
|
||||
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/main/docs/styleguide.md).
|
||||
- Include tests when adding/changing behavior.
|
||||
- Include screenshots and animated GIFs whenever possible.
|
||||
|
||||
|
||||
1
BUILD.gn
1
BUILD.gn
@@ -379,6 +379,7 @@ source_set("electron_lib") {
|
||||
"//ppapi/shared_impl",
|
||||
"//printing/buildflags",
|
||||
"//services/device/public/cpp/geolocation",
|
||||
"//services/device/public/cpp/hid",
|
||||
"//services/device/public/mojom",
|
||||
"//services/proxy_resolver:lib",
|
||||
"//services/video_capture/public/mojom:constants",
|
||||
|
||||
@@ -36,7 +36,7 @@ Having the original text _as well as_ the translation can help mitigate translat
|
||||
|
||||
Responses to posted issues may or may not be in the original language.
|
||||
|
||||
**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project.
|
||||
**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project.
|
||||
|
||||
## [Pull Requests](https://electronjs.org/docs/development/pull-requests)
|
||||
|
||||
|
||||
2
DEPS
2
DEPS
@@ -17,7 +17,7 @@ vars = {
|
||||
'chromium_version':
|
||||
'95.0.4629.0',
|
||||
'node_version':
|
||||
'v16.9.1',
|
||||
'v16.10.0',
|
||||
'nan_version':
|
||||
# The following commit hash of NAN is v2.14.2 with *only* changes to the
|
||||
# test suite. This should be updated to a specific tag when one becomes
|
||||
|
||||
@@ -1 +1 @@
|
||||
16.0.0-nightly.20210922
|
||||
17.0.0-nightly.20211004
|
||||
@@ -1,7 +1,7 @@
|
||||
[](https://electronjs.org)
|
||||
|
||||
[](https://circleci.com/gh/electron/electron/tree/master)
|
||||
[](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/master)
|
||||
[](https://circleci.com/gh/electron/electron/tree/main)
|
||||
[](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main)
|
||||
[](https://discord.com/invite/electron)
|
||||
|
||||
:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪.
|
||||
@@ -16,7 +16,7 @@ Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
announcements.
|
||||
|
||||
This project adheres to the Contributor Covenant
|
||||
[code of conduct](https://github.com/electron/electron/tree/master/CODE_OF_CONDUCT.md).
|
||||
[code of conduct](https://github.com/electron/electron/tree/main/CODE_OF_CONDUCT.md).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behavior to [coc@electronjs.org](mailto:coc@electronjs.org).
|
||||
|
||||
@@ -97,6 +97,6 @@ and more can be found in the [support document](docs/tutorial/support.md#finding
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/electron/electron/blob/master/LICENSE)
|
||||
[MIT](https://github.com/electron/electron/blob/main/LICENSE)
|
||||
|
||||
When using the Electron or other GitHub logos, be sure to follow the [GitHub logo guidelines](https://github.com/logos).
|
||||
|
||||
@@ -10,7 +10,7 @@ Report security bugs in third-party modules to the person or team maintaining th
|
||||
|
||||
## The Electron Security Notification Process
|
||||
|
||||
For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md) Governance document.
|
||||
For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md) Governance document.
|
||||
|
||||
## Learning More About Security
|
||||
|
||||
|
||||
@@ -500,16 +500,6 @@ gets emitted.
|
||||
**Note:** Extra command line arguments might be added by Chromium,
|
||||
such as `--original-process-start-time`.
|
||||
|
||||
### Event: 'desktop-capturer-get-sources'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
|
||||
Calling `event.preventDefault()` will make it return empty sources.
|
||||
|
||||
## Methods
|
||||
|
||||
The `app` object has the following methods:
|
||||
@@ -1072,7 +1062,7 @@ indicates success while any other value indicates failure according to Chromium
|
||||
Linux.
|
||||
* `secureDnsMode` String (optional) - Can be "off", "automatic" or "secure".
|
||||
Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be
|
||||
performed. When "automatic", DoH lookups will be peformed first if DoH is
|
||||
performed. When "automatic", DoH lookups will be performed first if DoH is
|
||||
available, and insecure DNS lookups will be performed as a fallback. When
|
||||
"secure", only DoH lookups will be performed. Defaults to "automatic".
|
||||
* `secureDnsServers` String[] (optional) - A list of DNS-over-HTTP
|
||||
|
||||
@@ -61,12 +61,6 @@ throttling in one window, you can take the hack of
|
||||
|
||||
Forces the maximum disk space to be used by the disk cache, in bytes.
|
||||
|
||||
### --enable-api-filtering-logging
|
||||
|
||||
Enables caller stack logging for the following APIs (filtering events):
|
||||
|
||||
* `desktopCapturer.getSources()` / `desktop-capturer-get-sources`
|
||||
|
||||
### --enable-logging[=file]
|
||||
|
||||
Prints Chromium's logging to stderr (or a log file).
|
||||
|
||||
@@ -3,40 +3,49 @@
|
||||
> Access information about media sources that can be used to capture audio and
|
||||
> video from the desktop using the [`navigator.mediaDevices.getUserMedia`] API.
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
Process: [Main](../glossary.md#main-process)
|
||||
|
||||
The following example shows how to capture video from a desktop window whose
|
||||
title is `Electron`:
|
||||
|
||||
```javascript
|
||||
// In the renderer process.
|
||||
// In the main process.
|
||||
const { desktopCapturer } = require('electron')
|
||||
|
||||
desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
|
||||
for (const source of sources) {
|
||||
if (source.name === 'Electron') {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: source.id,
|
||||
minWidth: 1280,
|
||||
maxWidth: 1280,
|
||||
minHeight: 720,
|
||||
maxHeight: 720
|
||||
}
|
||||
}
|
||||
})
|
||||
handleStream(stream)
|
||||
} catch (e) {
|
||||
handleError(e)
|
||||
}
|
||||
mainWindow.webContents.send('SET_SOURCE', source.id)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
// In the preload script.
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
ipcRenderer.on('SET_SOURCE', async (event, sourceId) => {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: sourceId,
|
||||
minWidth: 1280,
|
||||
maxWidth: 1280,
|
||||
minHeight: 720,
|
||||
maxHeight: 720
|
||||
}
|
||||
}
|
||||
})
|
||||
handleStream(stream)
|
||||
} catch (e) {
|
||||
handleError(e)
|
||||
}
|
||||
})
|
||||
|
||||
function handleStream (stream) {
|
||||
const video = document.querySelector('video')
|
||||
|
||||
@@ -234,6 +234,7 @@ expanding and collapsing the dialog.
|
||||
* `title` String (optional) - Title of the message box, some platforms will not show it.
|
||||
* `detail` String (optional) - Extra information of the message.
|
||||
* `icon` ([NativeImage](native-image.md) | String) (optional)
|
||||
* `textWidth` Integer (optional) _macOS_ - Custom width of the text in the message box.
|
||||
* `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via
|
||||
the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the
|
||||
label. If no such labeled buttons exist and this option is not set, `0` will be used as the
|
||||
@@ -285,6 +286,7 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
|
||||
* `checkboxChecked` Boolean (optional) - Initial checked state of the
|
||||
checkbox. `false` by default.
|
||||
* `icon` [NativeImage](native-image.md) (optional)
|
||||
* `textWidth` Integer (optional) _macOS_ - Custom width of the text in the message box.
|
||||
* `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via
|
||||
the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the
|
||||
label. If no such labeled buttons exist and this option is not set, `0` will be used as the
|
||||
|
||||
@@ -180,6 +180,96 @@ Emitted when a hunspell dictionary file download fails. For details
|
||||
on the failure you should collect a netlog and inspect the download
|
||||
request.
|
||||
|
||||
#### Event: 'select-hid-device'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `deviceList` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
* `callback` Function
|
||||
* `deviceId` String | null (optional)
|
||||
|
||||
Emitted when a HID device needs to be selected when a call to
|
||||
`navigator.hid.requestDevice` is made. `callback` should be called with
|
||||
`deviceId` to be selected; passing no arguments to `callback` will
|
||||
cancel the request. Additionally, permissioning on `navigator.hid` can
|
||||
be further managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler)
|
||||
and [ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow()
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'hid') {
|
||||
// Add logic here to determine if permission should be given to allow HID selection
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'hid') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
})
|
||||
callback(selectedPort?.deviceId)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### Event: 'hid-device-added'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted when a new HID device becomes available. For example, when a new USB device is plugged in.
|
||||
|
||||
This event will only be emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired.
|
||||
|
||||
#### Event: 'hid-device-removed'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted when a HID device has been removed. For example, this event will fire when a USB device is unplugged.
|
||||
|
||||
This event will only be emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired.
|
||||
|
||||
#### Event: 'select-serial-port'
|
||||
|
||||
Returns:
|
||||
@@ -525,7 +615,7 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
|
||||
* `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.
|
||||
* `permission` String - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, or `serial`.
|
||||
* `permission` String - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, `hid`, or `serial`.
|
||||
* `requestingOrigin` String - The origin URL of the permission check
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
* `embeddingOrigin` String (optional) - The origin of the frame embedding the frame that made the permission check. Only set for cross-origin sub frames making permission checks.
|
||||
@@ -553,6 +643,71 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
|
||||
})
|
||||
```
|
||||
|
||||
#### `ses.setDevicePermissionHandler(handler)`
|
||||
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `details` Object
|
||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid`.
|
||||
* `origin` String - The origin URL of the device permission check.
|
||||
* `device` [HIDDevice](structures/hid-device.md) - the device that permission is being requested for.
|
||||
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
|
||||
|
||||
Sets the handler which can be used to respond to device permission checks for the `session`.
|
||||
Returning `true` will allow the device to be permitted and `false` will reject it.
|
||||
To clear the handler, call `setDevicePermissionHandler(null)`.
|
||||
This handler can be used to provide default permissioning to devices without first calling for permission
|
||||
to devices (eg via `navigator.hid.requestDevice`). If this handler is not defined, the default device
|
||||
permissions as granted through device selection (eg via `navigator.hid.requestDevice`) will be used.
|
||||
Additionally, the default behavior of Electron is to store granted device permision through the lifetime
|
||||
of the corresponding WebContents. If longer term storage is needed, a developer can store granted device
|
||||
permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow()
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'hid') {
|
||||
// Add logic here to determine if permission should be given to allow HID selection
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'hid') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
})
|
||||
callback(selectedPort?.deviceId)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### `ses.clearHostResolverCache()`
|
||||
|
||||
Returns `Promise<void>` - Resolves when the operation is complete.
|
||||
|
||||
8
docs/api/structures/hid-device.md
Normal file
8
docs/api/structures/hid-device.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# HIDDevice Object
|
||||
|
||||
* `deviceId` String - Unique identifier for the device.
|
||||
* `name` String - Name of the device.
|
||||
* `vendorId` Integer - The USB vendor ID.
|
||||
* `productId` Integer - The USB product ID.
|
||||
* `serialNumber` String (optional) - The USB device serial number.
|
||||
* `guid` String (optional) - Unique identifier for the HID interface. A device may have multiple HID interfaces.
|
||||
@@ -856,15 +856,6 @@ Returns:
|
||||
|
||||
Emitted when the renderer process sends a synchronous message via `ipcRenderer.sendSync()`.
|
||||
|
||||
#### Event: 'desktop-capturer-get-sources'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
|
||||
Calling `event.preventDefault()` will make it return empty sources.
|
||||
|
||||
#### Event: 'preferred-size-changed'
|
||||
|
||||
Returns:
|
||||
@@ -1827,7 +1818,8 @@ End subscribing for frame presentation events.
|
||||
#### `contents.startDrag(item)`
|
||||
|
||||
* `item` Object
|
||||
* `file` String[] | String - The path(s) to the file(s) being dragged.
|
||||
* `file` String - The path to the file being dragged.
|
||||
* `files` String[] (optional) - The paths to the files being dragged. (`files` will override `file` field)
|
||||
* `icon` [NativeImage](native-image.md) | String - The image must be
|
||||
non-empty on macOS.
|
||||
|
||||
|
||||
@@ -632,7 +632,7 @@ error.
|
||||
### API Changed: `shell.openItem` is now `shell.openPath`
|
||||
|
||||
The `shell.openItem` API has been replaced with an asynchronous `shell.openPath` API.
|
||||
You can see the original API proposal and reasoning [here](https://github.com/electron/governance/blob/master/wg-api/spec-documents/shell-openitem.md).
|
||||
You can see the original API proposal and reasoning [here](https://github.com/electron/governance/blob/main/wg-api/spec-documents/shell-openitem.md).
|
||||
|
||||
## Planned Breaking API Changes (8.0)
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ These guides are intended for people working on the Electron project itself.
|
||||
For guides on Electron app development, see
|
||||
[/docs/README.md](../README.md#guides-and-tutorials).
|
||||
|
||||
* [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md)
|
||||
* [Contributing to Electron](https://github.com/electron/electron/blob/master/CONTRIBUTING.md)
|
||||
* [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md)
|
||||
* [Contributing to Electron](https://github.com/electron/electron/blob/main/CONTRIBUTING.md)
|
||||
* [Issues](issues.md)
|
||||
* [Pull Requests](pull-requests.md)
|
||||
* [Documentation Styleguide](coding-style.md#documentation)
|
||||
|
||||
@@ -8,7 +8,7 @@ Example Use Case:
|
||||
* We need `VS15.9` and we have `VS15.7` installed; this would require us to update an Azure image.
|
||||
|
||||
1. Identify the image you wish to modify.
|
||||
* In [appveyor.yml](https://github.com/electron/electron/blob/master/appveyor.yml), the image is identified by the property *image*.
|
||||
* In [appveyor.yml](https://github.com/electron/electron/blob/main/appveyor.yml), the image is identified by the property *image*.
|
||||
* The names used correspond to the *"images"* defined for a build cloud, eg the [libcc-20 cloud](https://windows-ci.electronjs.org/build-clouds/8).
|
||||
* Find the image you wish to modify in the build cloud and make note of the **VHD Blob Path** for that image, which is the value for that corresponding key.
|
||||
* You will need this URI path to copy into a new image.
|
||||
|
||||
@@ -65,8 +65,8 @@ origin URLs.
|
||||
$ cd src/electron
|
||||
$ git remote remove origin
|
||||
$ git remote add origin https://github.com/electron/electron
|
||||
$ git checkout master
|
||||
$ git branch --set-upstream-to=origin/master
|
||||
$ git checkout main
|
||||
$ git branch --set-upstream-to=origin/main
|
||||
$ cd -
|
||||
```
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ you prefer a graphical interface.
|
||||
* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped.
|
||||
|
||||
```text
|
||||
command script import ~/electron/src/tools/lldb/lldbinit.py
|
||||
# e.g: ['~/electron/src/tools/lldb']
|
||||
script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>']
|
||||
script import lldbinit
|
||||
```
|
||||
|
||||
## Attaching to and Debugging Electron
|
||||
|
||||
@@ -72,4 +72,4 @@ to try NW.js.
|
||||
|
||||
[nwjs]: https://nwjs.io/
|
||||
[electron-modules]: https://www.npmjs.com/search?q=electron
|
||||
[node-bindings]: https://github.com/electron/electron/tree/master/lib/common
|
||||
[node-bindings]: https://github.com/electron/electron/tree/main/lib/common
|
||||
|
||||
@@ -45,10 +45,10 @@ Once you've built the project locally, you're ready to start making changes!
|
||||
### Step 3: Branch
|
||||
|
||||
To keep your development environment organized, create local branches to
|
||||
hold your work. These should be branched directly off of the `master` branch.
|
||||
hold your work. These should be branched directly off of the `main` branch.
|
||||
|
||||
```sh
|
||||
$ git checkout -b my-branch -t upstream/master
|
||||
$ git checkout -b my-branch -t upstream/main
|
||||
```
|
||||
|
||||
## Making Changes
|
||||
@@ -134,11 +134,11 @@ Once you have committed your changes, it is a good idea to use `git rebase`
|
||||
|
||||
```sh
|
||||
$ git fetch upstream
|
||||
$ git rebase upstream/master
|
||||
$ git rebase upstream/main
|
||||
```
|
||||
|
||||
This ensures that your working branch has the latest changes from `electron/electron`
|
||||
master.
|
||||
main.
|
||||
|
||||
### Step 7: Test
|
||||
|
||||
@@ -189,7 +189,7 @@ the requirements below.
|
||||
|
||||
Bug fixes and new features should include tests and possibly benchmarks.
|
||||
|
||||
Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTING.md
|
||||
Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
```
|
||||
|
||||
@@ -222,7 +222,7 @@ seem unfamiliar, refer to this
|
||||
#### Approval and Request Changes Workflow
|
||||
|
||||
All pull requests require approval from a
|
||||
[Code Owner](https://github.com/electron/electron/blob/master/.github/CODEOWNERS)
|
||||
[Code Owner](https://github.com/electron/electron/blob/main/.github/CODEOWNERS)
|
||||
of the area you modified in order to land. Whenever a maintainer reviews a pull
|
||||
request they may request changes. These may be small, such as fixing a typo, or
|
||||
may involve substantive changes. Such requests are intended to be helpful, but
|
||||
|
||||
17
docs/fiddles/features/web-bluetooth/index.html
Normal file
17
docs/fiddles/features/web-bluetooth/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Web Bluetooth API</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Web Bluetooth API</h1>
|
||||
|
||||
<button id="clickme">Test Bluetooth</button>
|
||||
|
||||
<p>Currently selected bluetooth device: <strong id="device-name""></strong></p>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
30
docs/fiddles/features/web-bluetooth/main.js
Normal file
30
docs/fiddles/features/web-bluetooth/main.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
|
||||
event.preventDefault()
|
||||
if (deviceList && deviceList.length > 0) {
|
||||
callback(deviceList[0].deviceId)
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
8
docs/fiddles/features/web-bluetooth/renderer.js
Normal file
8
docs/fiddles/features/web-bluetooth/renderer.js
Normal file
@@ -0,0 +1,8 @@
|
||||
async function testIt() {
|
||||
const device = await navigator.bluetooth.requestDevice({
|
||||
acceptAllDevices: true
|
||||
})
|
||||
document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}`
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click',testIt)
|
||||
21
docs/fiddles/features/web-hid/index.html
Normal file
21
docs/fiddles/features/web-hid/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>WebHID API</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebHID API</h1>
|
||||
|
||||
<button id="clickme">Test WebHID</button>
|
||||
|
||||
<h3>HID devices automatically granted access via <i>setDevicePermissionHandler</i></h3>
|
||||
<div id="granted-devices"></div>
|
||||
|
||||
<h3>HID devices automatically granted access via <i>select-hid-device</i></h3>
|
||||
<div id="granted-devices2"></div>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
50
docs/fiddles/features/web-hid/main.js
Normal file
50
docs/fiddles/features/web-hid/main.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
if (details.deviceList && details.deviceList.length > 0) {
|
||||
callback(details.deviceList[0].deviceId)
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('hid-device-added', (event, device) => {
|
||||
console.log('hid-device-added FIRED WITH', device)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('hid-device-removed', (event, device) => {
|
||||
console.log('hid-device-removed FIRED WITH', device)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'hid' && details.securityOrigin === 'file:///') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (details.deviceType === 'hid' && details.origin === 'file://') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
19
docs/fiddles/features/web-hid/renderer.js
Normal file
19
docs/fiddles/features/web-hid/renderer.js
Normal file
@@ -0,0 +1,19 @@
|
||||
async function testIt() {
|
||||
const grantedDevices = await navigator.hid.getDevices()
|
||||
let grantedDeviceList = ''
|
||||
grantedDevices.forEach(device => {
|
||||
grantedDeviceList += `<hr>${device.productName}</hr>`
|
||||
})
|
||||
document.getElementById('granted-devices').innerHTML = grantedDeviceList
|
||||
const grantedDevices2 = await navigator.hid.requestDevice({
|
||||
filters: []
|
||||
})
|
||||
|
||||
grantedDeviceList = ''
|
||||
grantedDevices2.forEach(device => {
|
||||
grantedDeviceList += `<hr>${device.productName}</hr>`
|
||||
})
|
||||
document.getElementById('granted-devices2').innerHTML = grantedDeviceList
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click',testIt)
|
||||
16
docs/fiddles/features/web-serial/index.html
Normal file
16
docs/fiddles/features/web-serial/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Web Serial API</title>
|
||||
<body>
|
||||
<h1>Web Serial API</h1>
|
||||
|
||||
<button id="clickme">Test Web Serial API</button>
|
||||
|
||||
<p>Matching Arduino Uno device: <strong id="device-name""></strong></p>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
54
docs/fiddles/features/web-serial/main.js
Normal file
54
docs/fiddles/features/web-serial/main.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||
event.preventDefault()
|
||||
if (portList && portList.length > 0) {
|
||||
callback(portList[0].portId)
|
||||
} else {
|
||||
callback('') //Could not find any matching devices
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('serial-port-added', (event, port) => {
|
||||
console.log('serial-port-added FIRED WITH', port)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('serial-port-removed', (event, port) => {
|
||||
console.log('serial-port-removed FIRED WITH', port)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'serial' && details.securityOrigin === 'file:///') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (details.deviceType === 'serial' && details.origin === 'file://') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
mainWindow.webContents.openDevTools()
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
19
docs/fiddles/features/web-serial/renderer.js
Normal file
19
docs/fiddles/features/web-serial/renderer.js
Normal file
@@ -0,0 +1,19 @@
|
||||
async function testIt() {
|
||||
const filters = [
|
||||
{ usbVendorId: 0x2341, usbProductId: 0x0043 },
|
||||
{ usbVendorId: 0x2341, usbProductId: 0x0001 }
|
||||
];
|
||||
try {
|
||||
const port = await navigator.serial.requestPort({filters});
|
||||
const portInfo = port.getInfo();
|
||||
document.getElementById('device-name').innerHTML = `vendorId: ${portInfo.usbVendorId} | productId: ${portInfo.usbProductId} `
|
||||
} catch (ex) {
|
||||
if (ex.name === 'NotFoundError') {
|
||||
document.getElementById('device-name').innerHTML = 'Device NOT found'
|
||||
} else {
|
||||
document.getElementById('device-name').innerHTML = ex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click',testIt)
|
||||
@@ -1,5 +1,5 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, shell } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
let mainWindow;
|
||||
|
||||
99
docs/tutorial/devices.md
Normal file
99
docs/tutorial/devices.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Device Access
|
||||
|
||||
Like Chromium based browsers, Electron provides access to device hardware
|
||||
through web APIs. For the most part these APIs work like they do in a browser,
|
||||
but there are some differences that need to be taken into account. The primary
|
||||
difference between Electron and browsers is what happens when device access is
|
||||
requested. In a browser, users are presented with a popup where they can grant
|
||||
access to an individual device. In Electron APIs are provided which can be
|
||||
used by a developer to either automatically pick a device or prompt users to
|
||||
pick a device via a developer created interface.
|
||||
|
||||
## Web Bluetooth API
|
||||
|
||||
The [Web Bluetooth API](https://web.dev/bluetooth/) can be used to communicate
|
||||
with bluetooth devices. In order to use this API in Electron, developers will
|
||||
need to handle the [`select-bluetooth-device` event on the webContents](../api/web-contents.md#event-select-bluetooth-device)
|
||||
associated with the device request.
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
the first available bluetooth device when the `Test Bluetooth` button is
|
||||
clicked.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/web-bluetooth'
|
||||
|
||||
```
|
||||
|
||||
## WebHID API
|
||||
|
||||
The [WebHID API](https://web.dev/hid/) can be used to access HID devices such
|
||||
as keyboards and gamepads. Electron provides several APIs for working with
|
||||
the WebHID API:
|
||||
|
||||
* The [`select-hid-device` event on the Session](../api/session.md#event-select-hid-device)
|
||||
can be used to select a HID device when a call to
|
||||
`navigator.hid.requestDevice` is made. Additionally the [`hid-device-added`](../api/session.md#event-hid-device-added)
|
||||
and [`hid-device-removed`](../api/session.md#event-hid-device-removed) events
|
||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||
`navigator.hid.requestDevice` process.
|
||||
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
can be used to provide default permissioning to devices without first calling
|
||||
for permission to devices via `navigator.hid.requestDevice`. Additionally,
|
||||
the default behavior of Electron is to store granted device permision through
|
||||
the lifetime of the corresponding WebContents. If longer term storage is
|
||||
needed, a developer can store granted device permissions (eg when handling
|
||||
the `select-hid-device` event) and then read from that storage with
|
||||
`setDevicePermissionHandler`.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable HID access for specific origins.
|
||||
|
||||
### Blocklist
|
||||
|
||||
By default Electron employs the same [blocklist](https://github.com/WICG/webhid/blob/main/blocklist.txt)
|
||||
used by Chromium. If you wish to override this behavior, you can do so by
|
||||
setting the `disable-hid-blocklist` flag:
|
||||
|
||||
```javascript
|
||||
app.commandLine.appendSwitch('disable-hid-blocklist')
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
HID devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
and through [`select-hid-device` event on the Session](../api/session.md#event-select-hid-device)
|
||||
when the `Test WebHID` button is clicked.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/web-hid'
|
||||
|
||||
```
|
||||
|
||||
## Web Serial API
|
||||
|
||||
The [Web Serial API](https://web.dev/serial/) can be used to access serial
|
||||
devices that are connected via serial port, USB, or Bluetooth. In order to use
|
||||
this API in Electron, developers will need to handle the
|
||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||
associated with the serial port request.
|
||||
|
||||
There are several additional APIs for working with the Web Serial API:
|
||||
|
||||
* The [`serial-port-added`](../api/session.md#event-serial-port-added)
|
||||
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
|
||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||
`navigator.serial.requestPort` process.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable serial access for specific origins.
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
the first available Arduino Uno serial device (if connected) through
|
||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||
when the `Test Web Serial` button is clicked.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/web-serial'
|
||||
|
||||
```
|
||||
@@ -51,4 +51,4 @@ Somewhere in the Electron binary there will be a sequence of bytes that look lik
|
||||
|
||||
To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
|
||||
|
||||
You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json5).
|
||||
You can view the current schema [here](https://github.com/electron/electron/blob/main/build/fuses/fuses.json5).
|
||||
|
||||
@@ -23,7 +23,7 @@ your responsibility to ensure that the code is not malicious.
|
||||
## Reporting Security Issues
|
||||
|
||||
For information on how to properly disclose an Electron vulnerability,
|
||||
see [SECURITY.md](https://github.com/electron/electron/tree/master/SECURITY.md)
|
||||
see [SECURITY.md](https://github.com/electron/electron/tree/main/SECURITY.md)
|
||||
|
||||
## Chromium Security Issues and Upgrades
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Finding Support
|
||||
|
||||
If you have a security concern,
|
||||
please see the [security document](https://github.com/electron/electron/tree/master/SECURITY.md).
|
||||
please see the [security document](https://github.com/electron/electron/tree/main/SECURITY.md).
|
||||
|
||||
If you're looking for programming help,
|
||||
for answers to questions,
|
||||
@@ -26,7 +26,7 @@ you can interact with the community in these locations:
|
||||
* [`electron-pl`](https://electronpl.github.io) *(Poland)*
|
||||
|
||||
If you'd like to contribute to Electron,
|
||||
see the [contributing document](https://github.com/electron/electron/blob/master/CONTRIBUTING.md).
|
||||
see the [contributing document](https://github.com/electron/electron/blob/main/CONTRIBUTING.md).
|
||||
|
||||
If you've found a bug in a [supported version](#supported-versions) of Electron,
|
||||
please report it with the [issue tracker](../development/issues.md).
|
||||
@@ -50,15 +50,15 @@ as the 4.2.x series are supported. We only support the latest minor release
|
||||
for each stable release series. This means that in the case of a security fix
|
||||
6.1.x will receive the fix, but we will not release a new version of 6.0.x.
|
||||
|
||||
The latest stable release unilaterally receives all fixes from `master`,
|
||||
The latest stable release unilaterally receives all fixes from `main`,
|
||||
and the version prior to that receives the vast majority of those fixes
|
||||
as time and bandwidth warrants. The oldest supported release line will receive
|
||||
only security fixes directly.
|
||||
|
||||
All supported release lines will accept external pull requests to backport
|
||||
fixes previously merged to `master`, though this may be on a case-by-case
|
||||
fixes previously merged to `main`, though this may be on a case-by-case
|
||||
basis for some older supported lines. All contested decisions around release
|
||||
line backports will be resolved by the [Releases Working Group](https://github.com/electron/governance/tree/master/wg-releases) as an agenda item at their weekly meeting the week the backport PR is raised.
|
||||
line backports will be resolved by the [Releases Working Group](https://github.com/electron/governance/tree/main/wg-releases) as an agenda item at their weekly meeting the week the backport PR is raised.
|
||||
|
||||
When an API is changed or removed in a way that breaks existing functionality, the
|
||||
previous functionality will be supported for a minimum of two major versions when
|
||||
@@ -70,9 +70,9 @@ until the maintainers feel the maintenance burden is too high to continue doing
|
||||
|
||||
### Currently supported versions
|
||||
|
||||
* 17.x.y
|
||||
* 16.x.y
|
||||
* 15.x.y
|
||||
* 14.x.y
|
||||
* 13
|
||||
|
||||
### End-of-life
|
||||
|
||||
@@ -125,5 +125,7 @@
|
||||
</message>
|
||||
<message name="IDS_BADGE_UNREAD_NOTIFICATIONS" desc="The accessibility text which will be read by a screen reader when there are notifcatications">
|
||||
{UNREAD_NOTIFICATIONS, plural, =1 {1 Unread Notification} other {# Unread Notifications}}
|
||||
</message>
|
||||
</message>
|
||||
<message name="IDS_HID_CHOOSER_ITEM_WITHOUT_NAME" desc="User option displaying the device IDs for a Human Interface Device (HID) without a device name.">
|
||||
Unknown Device (<ph name="DEVICE_ID">$1<ex>1234:abcd</ex></ph>) </message>
|
||||
</grit-part>
|
||||
|
||||
@@ -84,6 +84,7 @@ auto_filenames = {
|
||||
"docs/api/structures/file-filter.md",
|
||||
"docs/api/structures/file-path-with-headers.md",
|
||||
"docs/api/structures/gpu-feature-status.md",
|
||||
"docs/api/structures/hid-device.md",
|
||||
"docs/api/structures/input-event.md",
|
||||
"docs/api/structures/io-counters.md",
|
||||
"docs/api/structures/ipc-main-event.md",
|
||||
@@ -141,7 +142,6 @@ auto_filenames = {
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
@@ -223,7 +223,6 @@ auto_filenames = {
|
||||
"lib/browser/api/web-contents.ts",
|
||||
"lib/browser/api/web-frame-main.ts",
|
||||
"lib/browser/default-menu.ts",
|
||||
"lib/browser/desktop-capturer.ts",
|
||||
"lib/browser/devtools.ts",
|
||||
"lib/browser/guest-view-manager.ts",
|
||||
"lib/browser/guest-window-manager.ts",
|
||||
@@ -270,7 +269,6 @@ auto_filenames = {
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/exports/electron.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
@@ -308,7 +306,6 @@ auto_filenames = {
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/exports/electron.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
|
||||
@@ -387,6 +387,14 @@ filenames = {
|
||||
"shell/browser/font/electron_font_access_delegate.h",
|
||||
"shell/browser/font_defaults.cc",
|
||||
"shell/browser/font_defaults.h",
|
||||
"shell/browser/hid/electron_hid_delegate.cc",
|
||||
"shell/browser/hid/electron_hid_delegate.h",
|
||||
"shell/browser/hid/hid_chooser_context.cc",
|
||||
"shell/browser/hid/hid_chooser_context.h",
|
||||
"shell/browser/hid/hid_chooser_context_factory.cc",
|
||||
"shell/browser/hid/hid_chooser_context_factory.h",
|
||||
"shell/browser/hid/hid_chooser_controller.cc",
|
||||
"shell/browser/hid/hid_chooser_controller.h",
|
||||
"shell/browser/javascript_environment.cc",
|
||||
"shell/browser/javascript_environment.h",
|
||||
"shell/browser/lib/bluetooth_chooser.cc",
|
||||
|
||||
@@ -1,5 +1,72 @@
|
||||
import { getSourcesImpl } from '@electron/internal/browser/desktop-capturer';
|
||||
const { createDesktopCapturer } = process._linkedBinding('electron_browser_desktop_capturer');
|
||||
|
||||
export async function getSources (options: Electron.SourcesOptions) {
|
||||
return getSourcesImpl(null, options);
|
||||
const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);
|
||||
|
||||
let currentlyRunning: {
|
||||
options: ElectronInternal.GetSourcesOptions;
|
||||
getSources: Promise<ElectronInternal.GetSourcesResult[]>;
|
||||
}[] = [];
|
||||
|
||||
// |options.types| can't be empty and must be an array
|
||||
function isValid (options: Electron.SourcesOptions) {
|
||||
const types = options ? options.types : undefined;
|
||||
return Array.isArray(types);
|
||||
}
|
||||
|
||||
export async function getSources (args: Electron.SourcesOptions) {
|
||||
if (!isValid(args)) throw new Error('Invalid options');
|
||||
|
||||
const captureWindow = args.types.includes('window');
|
||||
const captureScreen = args.types.includes('screen');
|
||||
|
||||
const { thumbnailSize = { width: 150, height: 150 } } = args;
|
||||
const { fetchWindowIcons = false } = args;
|
||||
|
||||
const options = {
|
||||
captureWindow,
|
||||
captureScreen,
|
||||
thumbnailSize,
|
||||
fetchWindowIcons
|
||||
};
|
||||
|
||||
for (const running of currentlyRunning) {
|
||||
if (deepEqual(running.options, options)) {
|
||||
// If a request is currently running for the same options
|
||||
// return that promise
|
||||
return running.getSources;
|
||||
}
|
||||
}
|
||||
|
||||
const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
|
||||
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer();
|
||||
|
||||
const stopRunning = () => {
|
||||
if (capturer) {
|
||||
delete capturer._onerror;
|
||||
delete capturer._onfinished;
|
||||
capturer = null;
|
||||
}
|
||||
// Remove from currentlyRunning once we resolve or reject
|
||||
currentlyRunning = currentlyRunning.filter(running => running.options !== options);
|
||||
};
|
||||
|
||||
capturer._onerror = (error: string) => {
|
||||
stopRunning();
|
||||
reject(error);
|
||||
};
|
||||
|
||||
capturer._onfinished = (sources: Electron.DesktopCapturerSource[]) => {
|
||||
stopRunning();
|
||||
resolve(sources);
|
||||
};
|
||||
|
||||
capturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons);
|
||||
});
|
||||
|
||||
currentlyRunning.push({
|
||||
options,
|
||||
getSources
|
||||
});
|
||||
|
||||
return getSources;
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ const messageBox = (sync: boolean, window: BrowserWindow | null, options?: Messa
|
||||
defaultId = -1,
|
||||
detail = '',
|
||||
icon = null,
|
||||
textWidth = 0,
|
||||
noLink = false,
|
||||
message = '',
|
||||
title = '',
|
||||
@@ -225,7 +226,8 @@ const messageBox = (sync: boolean, window: BrowserWindow | null, options?: Messa
|
||||
detail,
|
||||
checkboxLabel,
|
||||
checkboxChecked,
|
||||
icon
|
||||
icon,
|
||||
textWidth
|
||||
};
|
||||
|
||||
if (sync) {
|
||||
|
||||
@@ -666,9 +666,9 @@ WebContents.prototype._init = function () {
|
||||
postBody
|
||||
};
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
|
||||
// if attempting to use this API with the deprecated window.open event,
|
||||
// if attempting to use this API with the deprecated new-window event,
|
||||
// windowOpenOverriddenOptions will always return null. This ensures
|
||||
// short-term backwards compatibility until window.open is removed.
|
||||
// short-term backwards compatibility until new-window is removed.
|
||||
const parsedFeatures = parseFeatures(rawFeatures);
|
||||
const overriddenFeatures: BrowserWindowConstructorOptions = {
|
||||
...parsedFeatures.options,
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
const { createDesktopCapturer } = process._linkedBinding('electron_browser_desktop_capturer');
|
||||
|
||||
const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);
|
||||
|
||||
let currentlyRunning: {
|
||||
options: ElectronInternal.GetSourcesOptions;
|
||||
getSources: Promise<ElectronInternal.GetSourcesResult[]>;
|
||||
}[] = [];
|
||||
|
||||
// |options.types| can't be empty and must be an array
|
||||
function isValid (options: Electron.SourcesOptions) {
|
||||
const types = options ? options.types : undefined;
|
||||
return Array.isArray(types);
|
||||
}
|
||||
|
||||
export const getSourcesImpl = (sender: Electron.WebContents | null, args: Electron.SourcesOptions) => {
|
||||
if (!isValid(args)) throw new Error('Invalid options');
|
||||
|
||||
const captureWindow = args.types.includes('window');
|
||||
const captureScreen = args.types.includes('screen');
|
||||
|
||||
const { thumbnailSize = { width: 150, height: 150 } } = args;
|
||||
const { fetchWindowIcons = false } = args;
|
||||
|
||||
const options = {
|
||||
captureWindow,
|
||||
captureScreen,
|
||||
thumbnailSize,
|
||||
fetchWindowIcons
|
||||
};
|
||||
|
||||
for (const running of currentlyRunning) {
|
||||
if (deepEqual(running.options, options)) {
|
||||
// If a request is currently running for the same options
|
||||
// return that promise
|
||||
return running.getSources;
|
||||
}
|
||||
}
|
||||
|
||||
const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
|
||||
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer();
|
||||
|
||||
const stopRunning = () => {
|
||||
if (capturer) {
|
||||
delete capturer._onerror;
|
||||
delete capturer._onfinished;
|
||||
capturer = null;
|
||||
}
|
||||
// Remove from currentlyRunning once we resolve or reject
|
||||
currentlyRunning = currentlyRunning.filter(running => running.options !== options);
|
||||
if (sender) {
|
||||
sender.removeListener('destroyed', stopRunning);
|
||||
}
|
||||
};
|
||||
|
||||
capturer._onerror = (error: string) => {
|
||||
stopRunning();
|
||||
reject(error);
|
||||
};
|
||||
|
||||
capturer._onfinished = (sources: Electron.DesktopCapturerSource[]) => {
|
||||
stopRunning();
|
||||
resolve(sources);
|
||||
};
|
||||
|
||||
capturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons);
|
||||
|
||||
// If the WebContents is destroyed before receiving result, just remove the
|
||||
// reference to emit and the capturer itself so that it never dispatches
|
||||
// back to the renderer
|
||||
if (sender) {
|
||||
sender.once('destroyed', stopRunning);
|
||||
}
|
||||
});
|
||||
|
||||
currentlyRunning.push({
|
||||
options,
|
||||
getSources
|
||||
});
|
||||
|
||||
return getSources;
|
||||
};
|
||||
@@ -1,30 +1,9 @@
|
||||
import { app } from 'electron/main';
|
||||
import type { WebContents } from 'electron/main';
|
||||
import { clipboard } from 'electron/common';
|
||||
import * as fs from 'fs';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import type * as desktopCapturerModule from '@electron/internal/browser/desktop-capturer';
|
||||
|
||||
const eventBinding = process._linkedBinding('electron_browser_event');
|
||||
|
||||
const emitCustomEvent = function (contents: WebContents, eventName: string, ...args: any[]) {
|
||||
const event = eventBinding.createWithSender(contents);
|
||||
|
||||
app.emit(eventName, event, contents, ...args);
|
||||
contents.emit(eventName, event, ...args);
|
||||
|
||||
return event;
|
||||
};
|
||||
|
||||
const logStack = function (contents: WebContents, code: string, stack: string) {
|
||||
if (stack) {
|
||||
console.warn(`WebContents (${contents.id}): ${code}`, stack);
|
||||
}
|
||||
};
|
||||
|
||||
// Implements window.close()
|
||||
ipcMainInternal.on(IPC_MESSAGES.BROWSER_WINDOW_CLOSE, function (event) {
|
||||
const window = event.sender.getOwnerBrowserWindow();
|
||||
@@ -58,22 +37,6 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, function (event, me
|
||||
return (clipboard as any)[method](...args);
|
||||
});
|
||||
|
||||
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
|
||||
const desktopCapturer = require('@electron/internal/browser/desktop-capturer') as typeof desktopCapturerModule;
|
||||
|
||||
ipcMainInternal.handle(IPC_MESSAGES.DESKTOP_CAPTURER_GET_SOURCES, async function (event, options: Electron.SourcesOptions, stack: string) {
|
||||
logStack(event.sender, 'desktopCapturer.getSources()', stack);
|
||||
const customEvent = emitCustomEvent(event.sender, 'desktop-capturer-get-sources');
|
||||
|
||||
if (customEvent.defaultPrevented) {
|
||||
console.error('Blocked desktopCapturer.getSources()');
|
||||
return [];
|
||||
}
|
||||
|
||||
return await desktopCapturer.getSourcesImpl(event.sender, options);
|
||||
});
|
||||
}
|
||||
|
||||
const getPreloadScript = async function (preloadPath: string) {
|
||||
let preloadSrc = null;
|
||||
let preloadError = null;
|
||||
|
||||
@@ -28,6 +28,4 @@ export const enum IPC_MESSAGES {
|
||||
INSPECTOR_CONFIRM = 'INSPECTOR_CONFIRM',
|
||||
INSPECTOR_CONTEXT_MENU = 'INSPECTOR_CONTEXT_MENU',
|
||||
INSPECTOR_SELECT_FILE = 'INSPECTOR_SELECT_FILE',
|
||||
|
||||
DESKTOP_CAPTURER_GET_SOURCES = 'DESKTOP_CAPTURER_GET_SOURCES',
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import deprecate from '@electron/internal/common/api/deprecate';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
|
||||
|
||||
const enableStacks = hasSwitch('enable-api-filtering-logging');
|
||||
|
||||
function getCurrentStack () {
|
||||
const target = {};
|
||||
if (enableStacks) {
|
||||
Error.captureStackTrace(target, getCurrentStack);
|
||||
}
|
||||
return (target as any).stack;
|
||||
}
|
||||
|
||||
let warned = process.noDeprecation;
|
||||
export async function getSources (options: Electron.SourcesOptions) {
|
||||
if (!warned) {
|
||||
deprecate.log('The use of \'desktopCapturer.getSources\' in the renderer process is deprecated and will be removed. See https://www.electronjs.org/docs/breaking-changes#removed-desktopcapturergetsources-in-the-renderer for more details.');
|
||||
warned = true;
|
||||
}
|
||||
return await ipcRendererInternal.invoke(IPC_MESSAGES.DESKTOP_CAPTURER_GET_SOURCES, options, getCurrentStack());
|
||||
}
|
||||
@@ -5,10 +5,3 @@ export const rendererModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'ipcRenderer', loader: () => require('./ipc-renderer') },
|
||||
{ name: 'webFrame', loader: () => require('./web-frame') }
|
||||
];
|
||||
|
||||
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
|
||||
rendererModuleList.push({
|
||||
name: 'desktopCapturer',
|
||||
loader: () => require('@electron/internal/renderer/api/desktop-capturer')
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,10 +26,3 @@ export const moduleList: ElectronInternal.ModuleEntry[] = [
|
||||
private: true
|
||||
}
|
||||
];
|
||||
|
||||
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
|
||||
moduleList.push({
|
||||
name: 'desktopCapturer',
|
||||
loader: () => require('@electron/internal/renderer/api/desktop-capturer')
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "16.0.0-nightly.20210922",
|
||||
"version": "17.0.0-nightly.20211004",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,3 +3,4 @@ expose_aes-cfb.patch
|
||||
expose_des-ede3.patch
|
||||
fix_sync_evp_get_cipherbynid_and_evp_get_cipherbyname.patch
|
||||
add_maskhash_to_rsa_pss_params_st_for_compat.patch
|
||||
enable_x509_v_flag_trusted_first_flag.patch
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Juan Cruz Viotti <jv@jviotti.com>
|
||||
Date: Thu, 30 Sep 2021 13:39:23 -0400
|
||||
Subject: Enable X509_V_FLAG_TRUSTED_FIRST flag
|
||||
|
||||
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
|
||||
|
||||
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
|
||||
index 5a881d64c30076404cc800fff9e943bb0b30d2ac..29d5341efc8eb7ae6f90bdde5a8032e99f75c98e 100644
|
||||
--- a/crypto/x509/x509_vpm.c
|
||||
+++ b/crypto/x509/x509_vpm.c
|
||||
@@ -528,7 +528,7 @@ static const X509_VERIFY_PARAM default_table[] = {
|
||||
(char *)"default", /* X509 default parameters */
|
||||
0, /* Check time */
|
||||
0, /* internal flags */
|
||||
- 0, /* flags */
|
||||
+ X509_V_FLAG_TRUSTED_FIRST, /* flags */
|
||||
0, /* purpose */
|
||||
0, /* trust */
|
||||
100, /* depth */
|
||||
@@ -100,7 +100,6 @@ build_do_not_depend_on_packed_resource_integrity.patch
|
||||
refactor_restore_base_adaptcallbackforrepeating.patch
|
||||
hack_to_allow_gclient_sync_with_host_os_mac_on_linux_in_ci.patch
|
||||
don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch
|
||||
add_gin_wrappable_crash_key.patch
|
||||
logging_win32_only_create_a_console_if_logging_to_stderr.patch
|
||||
fix_media_key_usage_with_globalshortcuts.patch
|
||||
feat_expose_raw_response_headers_from_urlloader.patch
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: VerteDinde <khammond@slack-corp.com>
|
||||
Date: Thu, 15 Jul 2021 12:16:50 -0700
|
||||
Subject: chore: add gin::wrappable wrapperinfo crash key
|
||||
|
||||
This patch adds an additional crash key for gin::Wrappable, to help
|
||||
debug a crash that is occurring during garbage collection in SecondWeakCallback.
|
||||
|
||||
The crash seems to be due to a class that is holding a reference to
|
||||
gin::Wrappable even after being deleted. This added crash key compares
|
||||
the soon-to-be-deleted WrapperInfo with known WrapperInfo components to
|
||||
help determine where the crash originated from.
|
||||
|
||||
This patch should not be upstreamed, and can be removed in Electron 15 and
|
||||
beyond once we identify the cause of the crash.
|
||||
|
||||
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
|
||||
index c6059fdb0e0f74ee3ef78c5517634ed5a36f1b10..e16b2ec43b98c3b8724fd85085a33fe52a1e1979 100644
|
||||
--- a/gin/BUILD.gn
|
||||
+++ b/gin/BUILD.gn
|
||||
@@ -88,6 +88,10 @@ component("gin") {
|
||||
frameworks = [ "CoreFoundation.framework" ]
|
||||
}
|
||||
|
||||
+ if (!is_mas_build) {
|
||||
+ public_deps += [ "//components/crash/core/common:crash_key" ]
|
||||
+ }
|
||||
+
|
||||
configs += [
|
||||
"//tools/v8_context_snapshot:use_v8_context_snapshot",
|
||||
"//v8:external_startup_data",
|
||||
diff --git a/gin/wrappable.cc b/gin/wrappable.cc
|
||||
index fe07eb94a8e679859bba6d76ff0d6ee86bd0c67e..ecb0aa2c4ec57e1814f4c94194e775440f4e35ee 100644
|
||||
--- a/gin/wrappable.cc
|
||||
+++ b/gin/wrappable.cc
|
||||
@@ -8,6 +8,11 @@
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "gin/per_isolate_data.h"
|
||||
|
||||
+#if !defined(MAS_BUILD)
|
||||
+#include "components/crash/core/common/crash_key.h"
|
||||
+#include "electron/shell/common/crash_keys.h"
|
||||
+#endif
|
||||
+
|
||||
namespace gin {
|
||||
|
||||
WrappableBase::WrappableBase() = default;
|
||||
@@ -36,6 +41,15 @@ void WrappableBase::FirstWeakCallback(
|
||||
void WrappableBase::SecondWeakCallback(
|
||||
const v8::WeakCallbackInfo<WrappableBase>& data) {
|
||||
WrappableBase* wrappable = data.GetParameter();
|
||||
+
|
||||
+#if !defined(MAS_BUILD)
|
||||
+ WrapperInfo* wrapperInfo = static_cast<WrapperInfo*>(data.GetInternalField(0));
|
||||
+ std::string location = electron::crash_keys::GetCrashValueForGinWrappable(wrapperInfo);
|
||||
+
|
||||
+ static crash_reporter::CrashKeyString<32> crash_key("gin-wrappable-fatal.location");
|
||||
+ crash_reporter::ScopedCrashKeyString auto_clear(&crash_key, location);
|
||||
+#endif
|
||||
+
|
||||
delete wrappable;
|
||||
}
|
||||
|
||||
@@ -24,4 +24,4 @@ fix_account_for_debugger_agent_race_condition.patch
|
||||
add_should_read_node_options_from_env_option_to_disable_node_options.patch
|
||||
repl_fix_crash_when_sharedarraybuffer_disabled.patch
|
||||
fix_readbarrier_undefined_symbol_error_on_woa_arm64.patch
|
||||
fix_-wunreachable-code-return.patch
|
||||
fix_crash_creating_private_key_with_unsupported_algorithm.patch
|
||||
|
||||
@@ -21,7 +21,7 @@ index 1cc7da1ce15f43905ce607adcc1a23ed9d92948a..16af6aec3791df1363682f1ed024c522
|
||||
Isolate* isolate,
|
||||
const std::vector<std::string>& args,
|
||||
diff --git a/src/env.h b/src/env.h
|
||||
index b38a69fc06a189569524df767dbbbe5c1985aa20..6b22cc4aaaf59d309d1bcebfbb3710ceeafd13e6 100644
|
||||
index d31512ae37fba212a20cf306be46f7dfadeabd6a..8286ea06cc5c4e836921b06b37cf19d4508f4832 100644
|
||||
--- a/src/env.h
|
||||
+++ b/src/env.h
|
||||
@@ -1145,6 +1145,8 @@ class Environment : public MemoryRetainer {
|
||||
@@ -34,7 +34,7 @@ index b38a69fc06a189569524df767dbbbe5c1985aa20..6b22cc4aaaf59d309d1bcebfbb3710ce
|
||||
inline std::vector<double>* destroy_async_id_list();
|
||||
|
||||
diff --git a/src/node.cc b/src/node.cc
|
||||
index 6302bb925339d709a54151a8fc8b58f1a2253881..48a9eedfaf6350fc05fb104a1f44e85b75878f9a 100644
|
||||
index 788e61645a281197cb3a1f3acbae427ddae1ab23..5afd3541d52d275d55067ddb1c11a585214eff41 100644
|
||||
--- a/src/node.cc
|
||||
+++ b/src/node.cc
|
||||
@@ -882,7 +882,7 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
|
||||
@@ -47,10 +47,10 @@ index 6302bb925339d709a54151a8fc8b58f1a2253881..48a9eedfaf6350fc05fb104a1f44e85b
|
||||
ParseNodeOptionsEnvVar(node_options, errors);
|
||||
|
||||
diff --git a/src/node_worker.cc b/src/node_worker.cc
|
||||
index 3e3cb67d9e8c8b1ea867ff31d96a81709b47cc8d..679282e688258314fcd594bab7fd711cac2c9e48 100644
|
||||
index 16b7be36f284311f38583fa1df28a2945560b524..62a7dae080fad7e18863968dee22dbe4b461ab82 100644
|
||||
--- a/src/node_worker.cc
|
||||
+++ b/src/node_worker.cc
|
||||
@@ -457,6 +457,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -467,6 +467,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
||||
});
|
||||
|
||||
#ifndef NODE_WITHOUT_NODE_OPTIONS
|
||||
@@ -58,7 +58,7 @@ index 3e3cb67d9e8c8b1ea867ff31d96a81709b47cc8d..679282e688258314fcd594bab7fd711c
|
||||
MaybeLocal<String> maybe_node_opts =
|
||||
env_vars->Get(isolate, OneByteString(isolate, "NODE_OPTIONS"));
|
||||
Local<String> node_opts;
|
||||
@@ -487,6 +488,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -497,6 +498,7 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1781,7 +1781,7 @@ index 0000000000000000000000000000000000000000..d1d6b51e8c0c5bc6a5d09e217eb30483
|
||||
+ args = rebase_path(inputs + outputs, root_build_dir)
|
||||
+}
|
||||
diff --git a/src/node_version.h b/src/node_version.h
|
||||
index 48b8d9f22fb98d0733630eaea3194d746fba8a2f..a7a12564e4dd9320959d07fb4ab1527f942cf115 100644
|
||||
index a572d9b95853730a29a67349b46d47d6180586f3..888a95f93411a9168b75751e0af12c74fc5f0ba9 100644
|
||||
--- a/src/node_version.h
|
||||
+++ b/src/node_version.h
|
||||
@@ -89,7 +89,10 @@
|
||||
|
||||
@@ -8,7 +8,7 @@ modules from being used in the renderer process. This should be upstreamed as
|
||||
a customizable error message.
|
||||
|
||||
diff --git a/src/node_binding.cc b/src/node_binding.cc
|
||||
index 8b8389ae53608afedc9cc0ad2a6c8461b7aa893e..e79ddab7d73c6297ef1dc74b2a0ce469bf49e37c 100644
|
||||
index e323f76261f2028ef58da74066f9112d8a5a8df2..02d8566caffb86d05645fb602ca7b5c6b8c71aa9 100644
|
||||
--- a/src/node_binding.cc
|
||||
+++ b/src/node_binding.cc
|
||||
@@ -4,6 +4,7 @@
|
||||
@@ -19,7 +19,7 @@ index 8b8389ae53608afedc9cc0ad2a6c8461b7aa893e..e79ddab7d73c6297ef1dc74b2a0ce469
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
@@ -466,7 +467,12 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -472,7 +473,12 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
|
||||
if (mp->nm_context_register_func == nullptr) {
|
||||
if (env->force_context_aware()) {
|
||||
dlib->Close();
|
||||
|
||||
@@ -8,10 +8,10 @@ they use themselves as the entry point. We should try to upstream some form
|
||||
of this.
|
||||
|
||||
diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
|
||||
index 076eb528af016b9143985685bc6d1e7c14fa80e6..40370102a2f0b6e692761626653c232a77810fbc 100644
|
||||
index 9d2799c3c9ac3b216c2289ae4e037dd228844d23..5b31df1207d4417a6f9b784574e3779650ba21d2 100644
|
||||
--- a/lib/internal/bootstrap/pre_execution.js
|
||||
+++ b/lib/internal/bootstrap/pre_execution.js
|
||||
@@ -104,10 +104,12 @@ function patchProcessObject(expandArgv1) {
|
||||
@@ -105,10 +105,12 @@ function patchProcessObject(expandArgv1) {
|
||||
if (expandArgv1 && process.argv[1] &&
|
||||
!StringPrototypeStartsWith(process.argv[1], '-')) {
|
||||
// Expand process.argv[1] into a full path.
|
||||
|
||||
@@ -8,7 +8,7 @@ node modules will have different (wrong) ideas about how v8 structs are laid
|
||||
out in memory on 64-bit machines, and will summarily fail to work.
|
||||
|
||||
diff --git a/common.gypi b/common.gypi
|
||||
index 75fc36bc3c0eee65a6bb00ec31c79aabf3bb7dde..82722da38f0027626e204dd7a33f7bc5e070059d 100644
|
||||
index c222ed20be858544d454c59192889132eaa9e1ee..4f352dea639cc9ab8913b915d35df4edf4fb6a06 100644
|
||||
--- a/common.gypi
|
||||
+++ b/common.gypi
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
@@ -9,10 +9,10 @@ modules to sandboxed renderers.
|
||||
TODO(codebytere): remove and replace with a public facing API.
|
||||
|
||||
diff --git a/src/node_binding.cc b/src/node_binding.cc
|
||||
index 3c9776e655d0e458cdd3ab7c3adafff7de339cc5..8b8389ae53608afedc9cc0ad2a6c8461b7aa893e 100644
|
||||
index 050c5dff0ad5fc0692e348741b820762d40bd498..e323f76261f2028ef58da74066f9112d8a5a8df2 100644
|
||||
--- a/src/node_binding.cc
|
||||
+++ b/src/node_binding.cc
|
||||
@@ -608,6 +608,10 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -614,6 +614,10 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
args.GetReturnValue().Set(exports);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Environment on the V8 context of blink, so no new V8 context is created.
|
||||
As a result, a renderer process may have multiple Node Environments in it.
|
||||
|
||||
diff --git a/src/node.cc b/src/node.cc
|
||||
index 3ee25ebbd67a01d607456e5158c98ca2fdea396b..6302bb925339d709a54151a8fc8b58f1a2253881 100644
|
||||
index acf4f0fac03c0ba655d55bc832a37a816ac26a33..788e61645a281197cb3a1f3acbae427ddae1ab23 100644
|
||||
--- a/src/node.cc
|
||||
+++ b/src/node.cc
|
||||
@@ -139,6 +139,8 @@ using v8::Undefined;
|
||||
@@ -67,7 +67,7 @@ index 3ee25ebbd67a01d607456e5158c98ca2fdea396b..6302bb925339d709a54151a8fc8b58f1
|
||||
std::string tz;
|
||||
if (credentials::SafeGetenv("TZ", &tz) && !tz.empty()) {
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index 049163bf27cc7c1d6433b65becab0d7761491f09..09cb7a317cc46e88e5d214996dc87dc6e8730b1a 100644
|
||||
index 1f9afa558d0c8b7950a0f5862017e09a08118ec1..45de72bd94cf669ac2badf89d23164cb7022a5b3 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -213,6 +213,8 @@ namespace node {
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: feat: initialize asar support
|
||||
This patch initializes asar support in Node.js.
|
||||
|
||||
diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
|
||||
index 0906b35edc5ff38fb7730eba9cebcc0e472fe56c..076eb528af016b9143985685bc6d1e7c14fa80e6 100644
|
||||
index a4c73cba5481b3005474742483a554c93358c4e1..9d2799c3c9ac3b216c2289ae4e037dd228844d23 100644
|
||||
--- a/lib/internal/bootstrap/pre_execution.js
|
||||
+++ b/lib/internal/bootstrap/pre_execution.js
|
||||
@@ -76,6 +76,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
|
||||
@@ -77,6 +77,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
|
||||
assert(!CJSLoader.hasLoadedAnyUserCJSModule);
|
||||
loadPreloadModules();
|
||||
initializeFrozenIntrinsics();
|
||||
@@ -17,7 +17,7 @@ index 0906b35edc5ff38fb7730eba9cebcc0e472fe56c..076eb528af016b9143985685bc6d1e7c
|
||||
}
|
||||
|
||||
function patchProcessObject(expandArgv1) {
|
||||
@@ -482,6 +483,10 @@ function loadPreloadModules() {
|
||||
@@ -485,6 +486,10 @@ function loadPreloadModules() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Fri, 20 Aug 2021 22:41:11 -0700
|
||||
Subject: fix: -Wunreachable-code-return
|
||||
|
||||
Should be upstreamed.
|
||||
|
||||
Upstreamed in https://github.com/nodejs/node/pull/40034.
|
||||
|
||||
diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc
|
||||
index 612ce2b78b41badccbbce0616dffd86de042738f..c4a3322c6d972fc2052af75b79389c522924d9c5 100644
|
||||
--- a/src/inspector_agent.cc
|
||||
+++ b/src/inspector_agent.cc
|
||||
@@ -87,7 +87,6 @@ inline void* StartIoThreadMain(void* unused) {
|
||||
if (agent != nullptr)
|
||||
agent->RequestIoThreadStart();
|
||||
}
|
||||
- return nullptr;
|
||||
}
|
||||
|
||||
static int StartDebugSignalHandler() {
|
||||
diff --git a/src/node_url.cc b/src/node_url.cc
|
||||
index d7549e3bc05562d67bdef5aebf1fefa550b72eb6..d78cb7a3e1ceb075bd532e823a915b18f5a52afd 100644
|
||||
--- a/src/node_url.cc
|
||||
+++ b/src/node_url.cc
|
||||
@@ -600,7 +600,6 @@ std::string URLHost::ToString() const {
|
||||
case HostType::H_DOMAIN:
|
||||
case HostType::H_OPAQUE:
|
||||
return value_.domain_or_opaque;
|
||||
- break;
|
||||
case HostType::H_IPV4: {
|
||||
dest.reserve(15);
|
||||
uint32_t value = value_.ipv4;
|
||||
@@ -7,7 +7,7 @@ common.gypi is a file that's included in the node header bundle, despite
|
||||
the fact that we do not build node with gyp.
|
||||
|
||||
diff --git a/common.gypi b/common.gypi
|
||||
index 013f24b107408f757f4bdb950be519f61bc5358b..75fc36bc3c0eee65a6bb00ec31c79aabf3bb7dde 100644
|
||||
index 7bc2b3abf470193640b40824ffb17891088cabfb..c222ed20be858544d454c59192889132eaa9e1ee 100644
|
||||
--- a/common.gypi
|
||||
+++ b/common.gypi
|
||||
@@ -81,6 +81,23 @@
|
||||
|
||||
@@ -6,7 +6,7 @@ Subject: fix: add v8_enable_reverse_jsargs defines in common.gypi
|
||||
This can be removed once node upgrades V8 and inevitably has to do this exact same thing. Also hi node people if you are looking at this.
|
||||
|
||||
diff --git a/common.gypi b/common.gypi
|
||||
index 82722da38f0027626e204dd7a33f7bc5e070059d..f330d4e92a585d7d72e8322cebb5606fe7220e8c 100644
|
||||
index 4f352dea639cc9ab8913b915d35df4edf4fb6a06..63c7d2b1da5f1c83f02f856e0d14198bfed6787e 100644
|
||||
--- a/common.gypi
|
||||
+++ b/common.gypi
|
||||
@@ -65,6 +65,7 @@
|
||||
@@ -25,7 +25,7 @@ index 82722da38f0027626e204dd7a33f7bc5e070059d..f330d4e92a585d7d72e8322cebb5606f
|
||||
##### end V8 defaults #####
|
||||
|
||||
# When building native modules using 'npm install' with the system npm,
|
||||
@@ -384,6 +386,9 @@
|
||||
@@ -385,6 +387,9 @@
|
||||
['v8_enable_pointer_compression == 1 or v8_enable_31bit_smis_on_64bit_arch == 1', {
|
||||
'defines': ['V8_31BIT_SMIS_ON_64BIT_ARCH'],
|
||||
}],
|
||||
|
||||
@@ -36,11 +36,11 @@ index 523d252e08974a10f9a53fb46d3345669cec3380..5bf19a0dda42849159d954181058897c
|
||||
#endif
|
||||
|
||||
diff --git a/src/env-inl.h b/src/env-inl.h
|
||||
index 061897d95d8b5f61968c59260e609d7be724b88f..7c7ee3207089bf3e51db646a367bdd6deba18628 100644
|
||||
index 2b000ed9ace5f73bfe0e8cab3e83ce94804f9c55..a1690712c457534d70db777cb722537913f86a0e 100644
|
||||
--- a/src/env-inl.h
|
||||
+++ b/src/env-inl.h
|
||||
@@ -881,6 +881,10 @@ inline bool Environment::hide_console_windows() const {
|
||||
return flags_ & EnvironmentFlags::kHideConsoleWindows;
|
||||
@@ -891,6 +891,10 @@ inline bool Environment::no_global_search_paths() const {
|
||||
!options_->global_search_paths;
|
||||
}
|
||||
|
||||
+inline bool Environment::should_initialize_inspector() const {
|
||||
@@ -51,31 +51,31 @@ index 061897d95d8b5f61968c59260e609d7be724b88f..7c7ee3207089bf3e51db646a367bdd6d
|
||||
return emit_filehandle_warning_;
|
||||
}
|
||||
diff --git a/src/env.h b/src/env.h
|
||||
index 4fd5be8e15029b65d61982aa32eba2cd27957fce..b38a69fc06a189569524df767dbbbe5c1985aa20 100644
|
||||
index f055e6b45013d9f8c039c662981bfd54f08266f6..d31512ae37fba212a20cf306be46f7dfadeabd6a 100644
|
||||
--- a/src/env.h
|
||||
+++ b/src/env.h
|
||||
@@ -1202,6 +1202,7 @@ class Environment : public MemoryRetainer {
|
||||
inline bool owns_inspector() const;
|
||||
@@ -1204,6 +1204,7 @@ class Environment : public MemoryRetainer {
|
||||
inline bool tracks_unmanaged_fds() const;
|
||||
inline bool hide_console_windows() const;
|
||||
inline bool no_global_search_paths() const;
|
||||
+ inline bool should_initialize_inspector() const;
|
||||
inline uint64_t thread_id() const;
|
||||
inline worker::Worker* worker_context() const;
|
||||
Environment* worker_parent_env() const;
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index b7f3e97873ef90b635e0648639f1a287a0bd88fa..48e378079f6d05e7cc1141a8875450b125028789 100644
|
||||
index 364f789fbcbec8e3234961294698d8e69b04a310..85b5ac6a5a5cb5e4388a92a1d07c9afe17140a8c 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -409,7 +409,11 @@ enum Flags : uint64_t {
|
||||
// Set this flag to force hiding console windows when spawning child
|
||||
// processes. This is usually used when embedding Node.js in GUI programs on
|
||||
// Windows.
|
||||
- kHideConsoleWindows = 1 << 5
|
||||
+ kHideConsoleWindows = 1 << 5,
|
||||
@@ -420,7 +420,11 @@ enum Flags : uint64_t {
|
||||
// $HOME/.node_modules and $NODE_PATH. This is used by standalone apps that
|
||||
// do not expect to have their behaviors changed because of globally
|
||||
// installed modules.
|
||||
- kNoGlobalSearchPaths = 1 << 7
|
||||
+ kNoGlobalSearchPaths = 1 << 7,
|
||||
+ // Controls whether or not the Environment should call InitializeInspector.
|
||||
+ // This control is needed by embedders who may not want to initialize the V8
|
||||
+ // inspector in situations where it already exists.
|
||||
+ kNoInitializeInspector = 1 << 6
|
||||
+ kNoInitializeInspector = 1 << 8
|
||||
};
|
||||
} // namespace EnvironmentFlags
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Thu, 23 Sep 2021 12:29:23 +0200
|
||||
Subject: fix: crash creating private key with unsupported algorithm
|
||||
|
||||
This patch fixes an issue where some calls to crypto.createPrivateKey
|
||||
made with algorithms unsupported by BoringSSL cause a crash when invoking
|
||||
methods on their return values. This was happening because BoringSSL
|
||||
shims some algorithms but doesn't implement them and so attempted to
|
||||
created keys with them will fail (see https://source.chromium.org/chromium/chromium/src/+/main:third_party/boringssl/src/include/openssl/evp.h;l=835-837?q=ed448&ss=chromium)
|
||||
|
||||
Node.js returned false in initEdRaw (see: https://github.com/nodejs/node/blob/20cf47004e7801ede1588d2de8785c0100f6ab38/src/crypto/crypto_keys.cc#L1106)
|
||||
but then did nothing with the return value, meaning that if no pkey was
|
||||
created successfully that a key object was still returned but attempts
|
||||
to use the data_ field would crash the process as data_ was never
|
||||
assigned. This is fixed by checking the return value of initEdRaw at the
|
||||
JavaScript level and throwing an error if the function returns false.
|
||||
|
||||
This patch will be upstreamed in some form.
|
||||
|
||||
diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js
|
||||
index ce053fbb4b800a67adcd5642a6ef09f8f2a21ce6..1b0e4b8791cf422bba331b242cd7df29b18c9da8 100644
|
||||
--- a/lib/internal/crypto/keys.js
|
||||
+++ b/lib/internal/crypto/keys.js
|
||||
@@ -436,15 +436,19 @@ function getKeyObjectHandleFromJwk(key, ctx) {
|
||||
|
||||
const handle = new KeyObjectHandle();
|
||||
if (isPublic) {
|
||||
- handle.initEDRaw(
|
||||
+ if (!handle.initEDRaw(
|
||||
`NODE-${key.crv.toUpperCase()}`,
|
||||
keyData,
|
||||
- kKeyTypePublic);
|
||||
+ kKeyTypePublic)) {
|
||||
+ throw new Error('Failed to create key - unsupported algorithm');
|
||||
+ }
|
||||
} else {
|
||||
- handle.initEDRaw(
|
||||
+ if (!handle.initEDRaw(
|
||||
`NODE-${key.crv.toUpperCase()}`,
|
||||
keyData,
|
||||
- kKeyTypePrivate);
|
||||
+ kKeyTypePrivate)) {
|
||||
+ throw new Error('Failed to create key - unsupported algorithm');
|
||||
+ }
|
||||
}
|
||||
|
||||
return handle;
|
||||
@@ -10,6 +10,26 @@ This should be upstreamed in some form, though it may need to be tweaked
|
||||
before it's acceptable to upstream, as this patch comments out a couple
|
||||
of tests that upstream probably cares about.
|
||||
|
||||
diff --git a/test/parallel/test-crypto-async-sign-verify.js b/test/parallel/test-crypto-async-sign-verify.js
|
||||
index 4e3c32fdcd23fbe3e74bd5e624b739d224689f33..19d65aae7fa8ec9f9b907733ead17a208ed47909 100644
|
||||
--- a/test/parallel/test-crypto-async-sign-verify.js
|
||||
+++ b/test/parallel/test-crypto-async-sign-verify.js
|
||||
@@ -88,6 +88,7 @@ test('rsa_public.pem', 'rsa_private.pem', 'sha256', false,
|
||||
// ED25519
|
||||
test('ed25519_public.pem', 'ed25519_private.pem', undefined, true);
|
||||
// ED448
|
||||
+/*
|
||||
test('ed448_public.pem', 'ed448_private.pem', undefined, true);
|
||||
|
||||
// ECDSA w/ der signature encoding
|
||||
@@ -109,6 +110,7 @@ test('dsa_public.pem', 'dsa_private.pem', 'sha256',
|
||||
// DSA w/ ieee-p1363 signature encoding
|
||||
test('dsa_public.pem', 'dsa_private.pem', 'sha256', false,
|
||||
{ dsaEncoding: 'ieee-p1363' });
|
||||
+*/
|
||||
|
||||
// Test Parallel Execution w/ KeyObject is threadsafe in openssl3
|
||||
{
|
||||
diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js
|
||||
index 21c5af6cfe3e5eef64fc2d4dcc63c55b1d79ad51..b21eb4b97ad778304b3a4e8d549e109614350dfb 100644
|
||||
--- a/test/parallel/test-crypto-authenticated.js
|
||||
@@ -488,306 +508,6 @@ index af2146982c7a3bf7bd7527f44e4b17a3b605026e..f6b91f675cfea367c608892dee078b56
|
||||
|
||||
// Non-XOF hash functions should accept valid outputLength options as well.
|
||||
assert.strictEqual(crypto.createHash('sha224', { outputLength: 28 })
|
||||
diff --git a/test/parallel/test-crypto-key-objects.js b/test/parallel/test-crypto-key-objects.js
|
||||
index c2c47a9ce72f124c78f2743cf88ccd96d714fa1b..fcdbad0262fa1dd8a7858f255d0e5e45a470f72a 100644
|
||||
--- a/test/parallel/test-crypto-key-objects.js
|
||||
+++ b/test/parallel/test-crypto-key-objects.js
|
||||
@@ -307,11 +307,11 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
}, common.hasOpenSSL3 ? {
|
||||
message: 'error:1E08010C:DECODER routines::unsupported',
|
||||
} : {
|
||||
- message: 'error:0909006C:PEM routines:get_name:no start line',
|
||||
- code: 'ERR_OSSL_PEM_NO_START_LINE',
|
||||
- reason: 'no start line',
|
||||
- library: 'PEM routines',
|
||||
- function: 'get_name',
|
||||
+ message: /error:2007E073:BIO routines:BIO_new_mem_buf:null parameter|error:0900006e:PEM routines:OPENSSL_internal:NO_START_LINE/,
|
||||
+ code: /ERR_OSSL_BIO_NULL_PARAMETER|ERR_OSSL_PEM_NO_START_LINE/,
|
||||
+ reason: /null parameter|NO_START_LINE/,
|
||||
+ library: /BIO routines|PEM routines/,
|
||||
+ function: /BIO_new_mem_buf|OPENSSL_internal/,
|
||||
});
|
||||
|
||||
// This should not abort either: https://github.com/nodejs/node/issues/29904
|
||||
@@ -334,8 +334,8 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
message: /error:1E08010C:DECODER routines::unsupported/,
|
||||
library: 'DECODER routines'
|
||||
} : {
|
||||
- message: /asn1 encoding/,
|
||||
- library: 'asn1 encoding routines'
|
||||
+ message: /asn1 encoding|DECODE_ERROR/,
|
||||
+ library: /asn1 encoding routines|public key routines/
|
||||
});
|
||||
}
|
||||
|
||||
@@ -349,6 +349,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
d: 'wVK6M3SMhQh3NK-7GRrSV-BVWQx1FO5pW8hhQeu_NdA',
|
||||
kty: 'OKP'
|
||||
} },
|
||||
+/*
|
||||
{ private: fixtures.readKey('ed448_private.pem', 'ascii'),
|
||||
public: fixtures.readKey('ed448_public.pem', 'ascii'),
|
||||
keyType: 'ed448',
|
||||
@@ -380,6 +381,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
'S0jlSYJk',
|
||||
kty: 'OKP'
|
||||
} },
|
||||
+*/
|
||||
].forEach((info) => {
|
||||
const keyType = info.keyType;
|
||||
|
||||
@@ -421,7 +423,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
}
|
||||
}
|
||||
});
|
||||
-
|
||||
+/*
|
||||
[
|
||||
{ private: fixtures.readKey('ec_p256_private.pem', 'ascii'),
|
||||
public: fixtures.readKey('ec_p256_public.pem', 'ascii'),
|
||||
@@ -514,7 +516,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
}
|
||||
}
|
||||
});
|
||||
-
|
||||
+*/
|
||||
{
|
||||
// Reading an encrypted key without a passphrase should fail.
|
||||
assert.throws(() => createPrivateKey(privateDsa), common.hasOpenSSL3 ? {
|
||||
@@ -546,7 +548,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
}), {
|
||||
message: common.hasOpenSSL3 ?
|
||||
'error:1E08010C:DECODER routines::unsupported' :
|
||||
- /bad decrypt/
|
||||
+ /bad decrypt|error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT/
|
||||
});
|
||||
|
||||
const publicKey = createPublicKey(publicDsa);
|
||||
@@ -569,7 +571,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
() => privateKey.export({ format: 'jwk' }),
|
||||
{ code: 'ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE' });
|
||||
}
|
||||
-
|
||||
+/*
|
||||
{
|
||||
// Test RSA-PSS.
|
||||
{
|
||||
@@ -767,7 +769,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
+*/
|
||||
{
|
||||
// Exporting an encrypted private key requires a cipher
|
||||
const privateKey = createPrivateKey(privatePem);
|
||||
diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js
|
||||
index 09d43317426e712f60d4eba380cd4e044e3f3cf8..43c274b96fbb1c4d8398e2d32b625da21e85d6a6 100644
|
||||
--- a/test/parallel/test-crypto-keygen.js
|
||||
+++ b/test/parallel/test-crypto-keygen.js
|
||||
@@ -297,6 +297,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
}));
|
||||
}
|
||||
|
||||
+/*
|
||||
{
|
||||
// Test RSA-PSS.
|
||||
generateKeyPair('rsa-pss', {
|
||||
@@ -345,7 +346,9 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
testSignVerify(publicKey, privateKey);
|
||||
}));
|
||||
}
|
||||
+*/
|
||||
|
||||
+/*
|
||||
{
|
||||
// 'rsa-pss' should not add a RSASSA-PSS-params sequence by default.
|
||||
// Regression test for: https://github.com/nodejs/node/issues/39936
|
||||
@@ -368,7 +371,9 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
assert.strictEqual(spki[3], 11, spki.toString('hex'));
|
||||
}));
|
||||
}
|
||||
+*/
|
||||
|
||||
+/*
|
||||
{
|
||||
const privateKeyEncoding = {
|
||||
type: 'pkcs8',
|
||||
@@ -417,6 +422,9 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
});
|
||||
}));
|
||||
}
|
||||
+*/
|
||||
+
|
||||
+/*
|
||||
{
|
||||
// Test async DSA key object generation.
|
||||
generateKeyPair('dsa', {
|
||||
@@ -438,7 +446,9 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
});
|
||||
}));
|
||||
}
|
||||
+*/
|
||||
|
||||
+/*
|
||||
{
|
||||
// Test async elliptic curve key generation, e.g. for ECDSA, with a SEC1
|
||||
// private key.
|
||||
@@ -552,8 +562,10 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
||||
}));
|
||||
}
|
||||
+*/
|
||||
|
||||
{
|
||||
+ /*
|
||||
// Test async elliptic curve key generation, e.g. for ECDSA, with an encrypted
|
||||
// private key.
|
||||
generateKeyPair('ec', {
|
||||
@@ -590,9 +602,11 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
passphrase: 'top secret'
|
||||
});
|
||||
}));
|
||||
+ */
|
||||
|
||||
// Test async elliptic curve key generation, e.g. for ECDSA, with an encrypted
|
||||
// private key with paramEncoding explicit.
|
||||
+ /*
|
||||
generateKeyPair('ec', {
|
||||
namedCurve: 'P-256',
|
||||
paramEncoding: 'explicit',
|
||||
@@ -627,15 +641,16 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
passphrase: 'top secret'
|
||||
});
|
||||
}));
|
||||
+ */
|
||||
|
||||
// Test async elliptic curve key generation with 'jwk' encoding
|
||||
[
|
||||
- ['ec', ['P-384', 'P-256', 'P-521', 'secp256k1']],
|
||||
+ ['ec', ['P-384', 'P-256', 'P-521', /*'secp256k1'*/]],
|
||||
['rsa'],
|
||||
['ed25519'],
|
||||
- ['ed448'],
|
||||
+ // ['ed448'],
|
||||
['x25519'],
|
||||
- ['x448'],
|
||||
+ // ['x448'],
|
||||
].forEach((types) => {
|
||||
const [type, options] = types;
|
||||
switch (type) {
|
||||
@@ -738,6 +753,8 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
message: "The property 'options.paramEncoding' is invalid. " +
|
||||
"Received 'otherEncoding'"
|
||||
});
|
||||
+
|
||||
+ /*
|
||||
assert.throws(() => generateKeyPairSync('dsa', {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
@@ -751,6 +768,8 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
code: 'ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE',
|
||||
message: 'Unsupported JWK Key Type.'
|
||||
});
|
||||
+ */
|
||||
+
|
||||
assert.throws(() => generateKeyPairSync('ec', {
|
||||
namedCurve: 'secp224r1',
|
||||
publicKeyEncoding: {
|
||||
@@ -1089,6 +1108,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
}
|
||||
}
|
||||
|
||||
+/*
|
||||
// Test DSA parameters.
|
||||
{
|
||||
// Test invalid modulus lengths.
|
||||
@@ -1116,6 +1136,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
});
|
||||
}
|
||||
}
|
||||
+*/
|
||||
|
||||
// Test EC parameters.
|
||||
{
|
||||
@@ -1160,13 +1181,13 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
}));
|
||||
|
||||
generateKeyPair('ec', {
|
||||
- namedCurve: 'secp256k1',
|
||||
+ namedCurve: 'secp521r1',
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.deepStrictEqual(publicKey.asymmetricKeyDetails, {
|
||||
- namedCurve: 'secp256k1'
|
||||
+ namedCurve: 'secp521r1'
|
||||
});
|
||||
assert.deepStrictEqual(privateKey.asymmetricKeyDetails, {
|
||||
- namedCurve: 'secp256k1'
|
||||
+ namedCurve: 'secp521r1'
|
||||
});
|
||||
}));
|
||||
}
|
||||
@@ -1174,7 +1195,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
// Test EdDSA key generation.
|
||||
{
|
||||
if (!/^1\.1\.0/.test(process.versions.openssl)) {
|
||||
- ['ed25519', 'ed448', 'x25519', 'x448'].forEach((keyType) => {
|
||||
+ ['ed25519'/*, 'ed448', 'x25519', 'x448'*/].forEach((keyType) => {
|
||||
generateKeyPair(keyType, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
assert.strictEqual(publicKey.asymmetricKeyType, keyType);
|
||||
@@ -1188,6 +1209,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
}
|
||||
}
|
||||
|
||||
+/*
|
||||
// Test classic Diffie-Hellman key generation.
|
||||
{
|
||||
generateKeyPair('dh', {
|
||||
@@ -1300,6 +1322,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||
});
|
||||
}
|
||||
}
|
||||
+*/
|
||||
|
||||
// Test invalid key encoding types.
|
||||
{
|
||||
@@ -1500,6 +1523,7 @@ if (!common.hasOpenSSL3) {
|
||||
}, common.mustSucceed((publicKey, privateKey) => {
|
||||
assert.strictEqual(publicKey.type, 'public');
|
||||
|
||||
+ /*
|
||||
for (const passphrase of ['', Buffer.alloc(0)]) {
|
||||
const privateKeyObject = createPrivateKey({
|
||||
passphrase,
|
||||
@@ -1507,6 +1531,7 @@ if (!common.hasOpenSSL3) {
|
||||
});
|
||||
assert.strictEqual(privateKeyObject.asymmetricKeyType, 'rsa');
|
||||
}
|
||||
+ */
|
||||
|
||||
// Encrypting with an empty passphrase is not the same as not encrypting
|
||||
// the key, and not specifying a passphrase should fail when decoding it.
|
||||
diff --git a/test/parallel/test-crypto-padding-aes256.js b/test/parallel/test-crypto-padding-aes256.js
|
||||
index 14d853bdfd0a5dcc5bdb6e00cb20fdbeaabd2aff..3ae6fc47d4c6a8296a2c3c70daf464fad886a88d 100644
|
||||
--- a/test/parallel/test-crypto-padding-aes256.js
|
||||
+++ b/test/parallel/test-crypto-padding-aes256.js
|
||||
@@ -32,13 +32,13 @@ const key = Buffer.from('0123456789abcdef0123456789abcdef' +
|
||||
'0123456789abcdef0123456789abcdef', 'hex');
|
||||
|
||||
function encrypt(val, pad) {
|
||||
- const c = crypto.createCipheriv('aes256', key, iv);
|
||||
+ const c = crypto.createCipheriv('aes-256-cbc', key, iv);
|
||||
c.setAutoPadding(pad);
|
||||
return c.update(val, 'utf8', 'latin1') + c.final('latin1');
|
||||
}
|
||||
|
||||
function decrypt(val, pad) {
|
||||
- const c = crypto.createDecipheriv('aes256', key, iv);
|
||||
+ const c = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
||||
c.setAutoPadding(pad);
|
||||
return c.update(val, 'latin1', 'utf8') + c.final('utf8');
|
||||
}
|
||||
diff --git a/test/parallel/test-crypto-padding.js b/test/parallel/test-crypto-padding.js
|
||||
index f1f14b472997e76bb4100edb1c6cf4fc24d1074d..5057e3f9bc5bb78aceffa5e79530f8ceed84e6f7 100644
|
||||
--- a/test/parallel/test-crypto-padding.js
|
||||
@@ -1240,10 +960,10 @@ index 151eebd36c9765df086a020ba42920b2442b1b77..efe97ff2499cba909ac5500d827364fa
|
||||
}
|
||||
|
||||
diff --git a/test/parallel/test-webcrypto-export-import-rsa.js b/test/parallel/test-webcrypto-export-import-rsa.js
|
||||
index 04cf6388fc739d3eab0a8d47857590c7a9b84342..d111e697db652b98dd8a9eb7869b1a98ba6bca79 100644
|
||||
index ab7aa77394ac9989514b7a184900092bd6753996..b0104ac45867a923a8c651e01e8c6975a62f7c61 100644
|
||||
--- a/test/parallel/test-webcrypto-export-import-rsa.js
|
||||
+++ b/test/parallel/test-webcrypto-export-import-rsa.js
|
||||
@@ -480,6 +480,7 @@ const testVectors = [
|
||||
@@ -481,6 +481,7 @@ const testVectors = [
|
||||
await Promise.all(variations);
|
||||
})().then(common.mustCall());
|
||||
|
||||
@@ -1251,11 +971,14 @@ index 04cf6388fc739d3eab0a8d47857590c7a9b84342..d111e697db652b98dd8a9eb7869b1a98
|
||||
{
|
||||
const publicPem = fixtures.readKey('rsa_pss_public_2048.pem', 'ascii');
|
||||
const privatePem = fixtures.readKey('rsa_pss_private_2048.pem', 'ascii');
|
||||
@@ -521,3 +522,4 @@ const testVectors = [
|
||||
@@ -522,6 +523,7 @@ const testVectors = [
|
||||
assert.strictEqual(jwk.alg, 'PS256');
|
||||
})().then(common.mustCall());
|
||||
}
|
||||
+*/
|
||||
|
||||
{
|
||||
const ecPublic = crypto.createPublicKey(
|
||||
diff --git a/test/parallel/test-webcrypto-wrap-unwrap.js b/test/parallel/test-webcrypto-wrap-unwrap.js
|
||||
index 1094845c73e14313860ad476fb7baba2a11b5af4..51972b4b34b191ac59145889dbf2da5c0d407dbe 100644
|
||||
--- a/test/parallel/test-webcrypto-wrap-unwrap.js
|
||||
|
||||
@@ -22,7 +22,7 @@ index 0fb750c5abbe00740f2095ec397c823e26666199..523d252e08974a10f9a53fb46d334566
|
||||
int thread_pool_size,
|
||||
node::tracing::TracingController* tracing_controller) {
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index 09cb7a317cc46e88e5d214996dc87dc6e8730b1a..b7f3e97873ef90b635e0648639f1a287a0bd88fa 100644
|
||||
index 45de72bd94cf669ac2badf89d23164cb7022a5b3..364f789fbcbec8e3234961294698d8e69b04a310 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -118,6 +118,7 @@ namespace node {
|
||||
@@ -33,7 +33,7 @@ index 09cb7a317cc46e88e5d214996dc87dc6e8730b1a..b7f3e97873ef90b635e0648639f1a287
|
||||
class TracingController;
|
||||
|
||||
}
|
||||
@@ -488,6 +489,8 @@ NODE_EXTERN v8::MaybeLocal<v8::Value> PrepareStackTraceCallback(
|
||||
@@ -499,6 +500,8 @@ NODE_EXTERN v8::MaybeLocal<v8::Value> PrepareStackTraceCallback(
|
||||
NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env);
|
||||
NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env);
|
||||
|
||||
|
||||
@@ -222,10 +222,10 @@ index 7cb4513f9ad0eaadd055b169520ae1e5073b7e2d..50a6663966cdb147a702df21240fa449
|
||||
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "could not generate prime");
|
||||
return Nothing<bool>();
|
||||
diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc
|
||||
index 1bbf9a1753e4e2d82c55c4187489c22867d1d9bb..585af1674e129dc4d1c918d29fe9915bac8b4163 100644
|
||||
index d2307c33f5de8733b1343225a3fe6a700d1f51e4..fd31caa1355cd7be98992411b9cda2dbb500f211 100644
|
||||
--- a/src/crypto/crypto_rsa.cc
|
||||
+++ b/src/crypto/crypto_rsa.cc
|
||||
@@ -566,7 +566,7 @@ Maybe<bool> GetRsaKeyDetail(
|
||||
@@ -580,7 +580,7 @@ Maybe<bool> GetRsaKeyDetail(
|
||||
// In that case, RSA_get0_pss_params does not return nullptr but all fields
|
||||
// of the returned RSA_PSS_PARAMS will be set to nullptr.
|
||||
|
||||
@@ -234,7 +234,7 @@ index 1bbf9a1753e4e2d82c55c4187489c22867d1d9bb..585af1674e129dc4d1c918d29fe9915b
|
||||
if (params != nullptr) {
|
||||
int hash_nid = NID_sha1;
|
||||
int mgf_nid = NID_mgf1;
|
||||
@@ -607,10 +607,11 @@ Maybe<bool> GetRsaKeyDetail(
|
||||
@@ -621,10 +621,11 @@ Maybe<bool> GetRsaKeyDetail(
|
||||
}
|
||||
|
||||
if (params->saltLength != nullptr) {
|
||||
@@ -250,21 +250,8 @@ index 1bbf9a1753e4e2d82c55c4187489c22867d1d9bb..585af1674e129dc4d1c918d29fe9915b
|
||||
}
|
||||
|
||||
if (target
|
||||
diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc
|
||||
index 7846df17ffbe8b5ea3a685c46f73b5d28ad64b1f..2bf12b8b4a7e16adf9c1f58d72ae4f59a0b2b2a4 100644
|
||||
--- a/src/crypto/crypto_sig.cc
|
||||
+++ b/src/crypto/crypto_sig.cc
|
||||
@@ -110,7 +110,7 @@ unsigned int GetBytesOfRS(const ManagedEVPPKey& pkey) {
|
||||
if (base_id == EVP_PKEY_DSA) {
|
||||
const DSA* dsa_key = EVP_PKEY_get0_DSA(pkey.get());
|
||||
// Both r and s are computed mod q, so their width is limited by that of q.
|
||||
- bits = BN_num_bits(DSA_get0_q(dsa_key));
|
||||
+ bits = BN_num_bits(dsa_key->q);
|
||||
} else if (base_id == EVP_PKEY_EC) {
|
||||
const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
|
||||
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);
|
||||
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
|
||||
index f18304cd655842e999a39659315c4eb3ce1c0c6e..1aed0e7e88460cea63950f71dac502829d662cff 100644
|
||||
index 7e0c8ba3eb60db88af8ba75e41e593dab86d2714..5c528c810256872c76dc7ba5a673d28652c405e1 100644
|
||||
--- a/src/crypto/crypto_util.cc
|
||||
+++ b/src/crypto/crypto_util.cc
|
||||
@@ -491,24 +491,14 @@ Maybe<bool> Decorate(Environment* env, Local<Object> obj,
|
||||
|
||||
@@ -40,7 +40,7 @@ index 5bf19a0dda42849159d954181058897c45d280fd..03078ff3869fcd17101f1cdaf77f725d
|
||||
|
||||
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index 48e378079f6d05e7cc1141a8875450b125028789..22e095804bca9d73d22707169c5aff2b13994344 100644
|
||||
index 85b5ac6a5a5cb5e4388a92a1d07c9afe17140a8c..4201c0d0460b032721ef42a26d79c38a9ee20c24 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -313,7 +313,8 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
|
||||
@@ -53,7 +53,7 @@ index 48e378079f6d05e7cc1141a8875450b125028789..22e095804bca9d73d22707169c5aff2b
|
||||
};
|
||||
|
||||
enum IsolateSettingsFlags {
|
||||
@@ -498,7 +499,8 @@ NODE_EXTERN node::tracing::Agent* CreateAgent();
|
||||
@@ -509,7 +510,8 @@ NODE_EXTERN node::tracing::Agent* CreateAgent();
|
||||
NODE_DEPRECATED("Use MultiIsolatePlatform::Create() instead",
|
||||
NODE_EXTERN MultiIsolatePlatform* CreatePlatform(
|
||||
int thread_pool_size,
|
||||
|
||||
@@ -7,3 +7,6 @@ do_not_export_private_v8_symbols_on_windows.patch
|
||||
fix_build_deprecated_attirbute_for_older_msvc_versions.patch
|
||||
fix_disable_implies_dcheck_for_node_stream_array_buffers.patch
|
||||
cppgc-js_support_eager_traced_value_in_ephemeron_pairs.patch
|
||||
regexp_add_a_currently_failing_cctest_for_irregexp_reentrancy.patch
|
||||
regexp_allow_reentrant_irregexp_execution.patch
|
||||
regexp_remove_the_stack_parameter_from_regexp_matchers.patch
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jakob Gruber <jgruber@chromium.org>
|
||||
Date: Mon, 6 Sep 2021 08:29:33 +0200
|
||||
Subject: Add a (currently failing) cctest for irregexp reentrancy
|
||||
|
||||
The test should be enabled once reentrancy is supported.
|
||||
|
||||
Bug: v8:11382
|
||||
Change-Id: Ifb90d8a6fd8bf9f05e9ca2405d4e04e013ce7ee3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3138201
|
||||
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
|
||||
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
|
||||
Reviewed-by: Patrick Thier <pthier@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#76667}
|
||||
|
||||
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
|
||||
index 0a6626ce332ae3ad3e49cb99404646c22c866b71..9c28520ed56998173c105b9d8a2ca3c4489b916e 100644
|
||||
--- a/test/cctest/cctest.status
|
||||
+++ b/test/cctest/cctest.status
|
||||
@@ -136,6 +136,9 @@
|
||||
'test-strings/Traverse': [PASS, HEAVY],
|
||||
'test-swiss-name-dictionary-csa/DeleteAtBoundaries': [PASS, HEAVY],
|
||||
'test-swiss-name-dictionary-csa/SameH2': [PASS, HEAVY],
|
||||
+
|
||||
+ # TODO(v8:11382): Reenable once irregexp is reentrant.
|
||||
+ 'test-regexp/RegExpInterruptReentrantExecution': [FAIL],
|
||||
}], # ALWAYS
|
||||
|
||||
##############################################################################
|
||||
@@ -670,6 +673,9 @@
|
||||
|
||||
# Instruction cache flushing is disabled in jitless mode.
|
||||
'test-icache/*': [SKIP],
|
||||
+
|
||||
+ # Tests generated irregexp code.
|
||||
+ 'test-regexp/RegExpInterruptReentrantExecution': [SKIP],
|
||||
}], # lite_mode or variant == jitless
|
||||
|
||||
##############################################################################
|
||||
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
||||
index dc5e2ea50898fbf684f5f4655d8b50982d4ebbbd..f7cbc54499464acf1a7de45251a6118340ec51fd 100644
|
||||
--- a/test/cctest/test-api.cc
|
||||
+++ b/test/cctest/test-api.cc
|
||||
@@ -21734,10 +21734,6 @@ TEST(RegExpInterruptAndMakeSubjectTwoByteExternal) {
|
||||
// experimental engine.
|
||||
i::FLAG_enable_experimental_regexp_engine_on_excessive_backtracks = false;
|
||||
RegExpInterruptTest test;
|
||||
- // We want to be stuck regexp execution, so no fallback to linear-time
|
||||
- // engine.
|
||||
- // TODO(mbid,v8:10765): Find a way to test interrupt support of the
|
||||
- // experimental engine.
|
||||
test.RunTest(RegExpInterruptTest::MakeSubjectTwoByteExternal);
|
||||
}
|
||||
|
||||
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
|
||||
index 27204f7f519229cc4c21a10dd0a44222d4b6edd6..2692748e623d3d52780ff89a97f4300bcd981cbd 100644
|
||||
--- a/test/cctest/test-regexp.cc
|
||||
+++ b/test/cctest/test-regexp.cc
|
||||
@@ -2346,6 +2346,50 @@ TEST(UnicodePropertyEscapeCodeSize) {
|
||||
}
|
||||
}
|
||||
|
||||
+namespace {
|
||||
+
|
||||
+struct RegExpExecData {
|
||||
+ i::Isolate* isolate;
|
||||
+ i::Handle<i::JSRegExp> regexp;
|
||||
+ i::Handle<i::String> subject;
|
||||
+};
|
||||
+
|
||||
+i::Handle<i::Object> RegExpExec(const RegExpExecData* d) {
|
||||
+ return i::RegExp::Exec(d->isolate, d->regexp, d->subject, 0,
|
||||
+ d->isolate->regexp_last_match_info())
|
||||
+ .ToHandleChecked();
|
||||
+}
|
||||
+
|
||||
+void ReenterRegExp(v8::Isolate* isolate, void* data) {
|
||||
+ RegExpExecData* d = static_cast<RegExpExecData*>(data);
|
||||
+ i::Handle<i::Object> result = RegExpExec(d);
|
||||
+ CHECK(result->IsNull());
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+
|
||||
+// Tests reentrant irregexp calls.
|
||||
+TEST(RegExpInterruptReentrantExecution) {
|
||||
+ CHECK(!i::FLAG_jitless);
|
||||
+ i::FLAG_regexp_tier_up = false; // Enter irregexp, not the interpreter.
|
||||
+
|
||||
+ LocalContext context;
|
||||
+ v8::Isolate* isolate = context->GetIsolate();
|
||||
+ v8::HandleScope scope(isolate);
|
||||
+
|
||||
+ RegExpExecData d;
|
||||
+ d.isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
+ d.regexp = v8::Utils::OpenHandle(
|
||||
+ *v8::RegExp::New(context.local(), v8_str("(a*)*x"), v8::RegExp::kNone)
|
||||
+ .ToLocalChecked());
|
||||
+ d.subject = v8::Utils::OpenHandle(*v8_str("aaaa"));
|
||||
+
|
||||
+ isolate->RequestInterrupt(&ReenterRegExp, &d);
|
||||
+
|
||||
+ i::Handle<i::Object> result = RegExpExec(&d);
|
||||
+ CHECK(result->IsNull());
|
||||
+}
|
||||
+
|
||||
#undef CHECK_PARSE_ERROR
|
||||
#undef CHECK_SIMPLE
|
||||
#undef CHECK_MIN_MAX
|
||||
1736
patches/v8/regexp_allow_reentrant_irregexp_execution.patch
Normal file
1736
patches/v8/regexp_allow_reentrant_irregexp_execution.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,397 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jakob Gruber <jgruber@chromium.org>
|
||||
Date: Wed, 22 Sep 2021 14:42:48 +0200
|
||||
Subject: Remove the `stack` parameter from regexp matchers
|
||||
|
||||
The argument is no longer in use.
|
||||
|
||||
Bug: v8:11382
|
||||
Change-Id: I7febc7fe7ef17ae462c700f0dba3ca1beade3021
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3173681
|
||||
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
|
||||
Reviewed-by: Patrick Thier <pthier@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#77017}
|
||||
|
||||
diff --git a/src/builtins/builtins-regexp-gen.cc b/src/builtins/builtins-regexp-gen.cc
|
||||
index 6e4307b404405c4c78614a956c64b4a86f5fe0fe..6c2d3b44a39a6bcce4e48ac621b21f54371e9b6f 100644
|
||||
--- a/src/builtins/builtins-regexp-gen.cc
|
||||
+++ b/src/builtins/builtins-regexp-gen.cc
|
||||
@@ -436,8 +436,6 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
// External constants.
|
||||
TNode<ExternalReference> isolate_address =
|
||||
ExternalConstant(ExternalReference::isolate_address(isolate()));
|
||||
- TNode<ExternalReference> regexp_stack_memory_top_address = ExternalConstant(
|
||||
- ExternalReference::address_of_regexp_stack_memory_top_address(isolate()));
|
||||
TNode<ExternalReference> static_offsets_vector_address = ExternalConstant(
|
||||
ExternalReference::address_of_static_offsets_vector(isolate()));
|
||||
|
||||
@@ -606,26 +604,18 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
MachineType arg5_type = type_int32;
|
||||
TNode<Int32T> arg5 = SmiToInt32(register_count);
|
||||
|
||||
- // Argument 6: Start (high end) of backtracking stack memory area. This
|
||||
- // argument is ignored in the interpreter.
|
||||
- TNode<RawPtrT> stack_top = UncheckedCast<RawPtrT>(
|
||||
- Load(MachineType::Pointer(), regexp_stack_memory_top_address));
|
||||
+ // Argument 6: Indicate that this is a direct call from JavaScript.
|
||||
+ MachineType arg6_type = type_int32;
|
||||
+ TNode<Int32T> arg6 = Int32Constant(RegExp::CallOrigin::kFromJs);
|
||||
|
||||
- MachineType arg6_type = type_ptr;
|
||||
- TNode<RawPtrT> arg6 = stack_top;
|
||||
+ // Argument 7: Pass current isolate address.
|
||||
+ MachineType arg7_type = type_ptr;
|
||||
+ TNode<ExternalReference> arg7 = isolate_address;
|
||||
|
||||
- // Argument 7: Indicate that this is a direct call from JavaScript.
|
||||
- MachineType arg7_type = type_int32;
|
||||
- TNode<Int32T> arg7 = Int32Constant(RegExp::CallOrigin::kFromJs);
|
||||
-
|
||||
- // Argument 8: Pass current isolate address.
|
||||
- MachineType arg8_type = type_ptr;
|
||||
- TNode<ExternalReference> arg8 = isolate_address;
|
||||
-
|
||||
- // Argument 9: Regular expression object. This argument is ignored in native
|
||||
+ // Argument 8: Regular expression object. This argument is ignored in native
|
||||
// irregexp code.
|
||||
- MachineType arg9_type = type_tagged;
|
||||
- TNode<JSRegExp> arg9 = regexp;
|
||||
+ MachineType arg8_type = type_tagged;
|
||||
+ TNode<JSRegExp> arg8 = regexp;
|
||||
|
||||
// TODO(v8:11880): avoid roundtrips between cdc and code.
|
||||
TNode<RawPtrT> code_entry = LoadCodeObjectEntry(code);
|
||||
@@ -640,8 +630,7 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
std::make_pair(arg1_type, arg1), std::make_pair(arg2_type, arg2),
|
||||
std::make_pair(arg3_type, arg3), std::make_pair(arg4_type, arg4),
|
||||
std::make_pair(arg5_type, arg5), std::make_pair(arg6_type, arg6),
|
||||
- std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8),
|
||||
- std::make_pair(arg9_type, arg9)));
|
||||
+ std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8)));
|
||||
|
||||
// Check the result.
|
||||
// We expect exactly one result since we force the called regexp to behave
|
||||
diff --git a/src/regexp/arm/regexp-macro-assembler-arm.cc b/src/regexp/arm/regexp-macro-assembler-arm.cc
|
||||
index 10766db4cf1d41ad0fee0754c6eaeebe46ace500..6e79ffd8adf8417c356bb36e1dbb2d0bfc290858 100644
|
||||
--- a/src/regexp/arm/regexp-macro-assembler-arm.cc
|
||||
+++ b/src/regexp/arm/regexp-macro-assembler-arm.cc
|
||||
@@ -38,14 +38,12 @@ namespace internal {
|
||||
* Each call to a public method should retain this convention.
|
||||
*
|
||||
* The stack will have the following structure:
|
||||
- * - fp[56] Address regexp (address of the JSRegExp object; unused in
|
||||
+ * - fp[52] Address regexp (address of the JSRegExp object; unused in
|
||||
* native code, passed to match signature of
|
||||
* the interpreter)
|
||||
- * - fp[52] Isolate* isolate (address of the current isolate)
|
||||
- * - fp[48] direct_call (if 1, direct call from JavaScript code,
|
||||
+ * - fp[48] Isolate* isolate (address of the current isolate)
|
||||
+ * - fp[44] direct_call (if 1, direct call from JavaScript code,
|
||||
* if 0, call through the runtime system).
|
||||
- * - fp[44] stack_area_base (high end of the memory area to use as
|
||||
- * backtracking stack).
|
||||
* - fp[40] capture array size (may fit multiple sets of matches)
|
||||
* - fp[36] int* capture_array (int[num_saved_registers_], for output).
|
||||
* --- sp when called ---
|
||||
@@ -82,7 +80,6 @@ namespace internal {
|
||||
* Address end,
|
||||
* int* capture_output_array,
|
||||
* int num_capture_registers,
|
||||
- * byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate,
|
||||
* Address regexp);
|
||||
diff --git a/src/regexp/arm/regexp-macro-assembler-arm.h b/src/regexp/arm/regexp-macro-assembler-arm.h
|
||||
index a76f9dea70264d79d57ebd6c60b100bc9e0a499d..5aad6c1d85d574f4db307b6edcdda89ed25d5ca8 100644
|
||||
--- a/src/regexp/arm/regexp-macro-assembler-arm.h
|
||||
+++ b/src/regexp/arm/regexp-macro-assembler-arm.h
|
||||
@@ -91,15 +91,13 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
|
||||
static const int kFramePointer = 0;
|
||||
|
||||
// Above the frame pointer - Stored registers and stack passed parameters.
|
||||
- // Register 4..11.
|
||||
static const int kStoredRegisters = kFramePointer;
|
||||
// Return address (stored from link register, read into pc on return).
|
||||
static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize;
|
||||
// Stack parameters placed by caller.
|
||||
static const int kRegisterOutput = kReturnAddress + kPointerSize;
|
||||
static const int kNumOutputRegisters = kRegisterOutput + kPointerSize;
|
||||
- static const int kStackHighEnd = kNumOutputRegisters + kPointerSize;
|
||||
- static const int kDirectCall = kStackHighEnd + kPointerSize;
|
||||
+ static const int kDirectCall = kNumOutputRegisters + kPointerSize;
|
||||
static const int kIsolate = kDirectCall + kPointerSize;
|
||||
|
||||
// Below the frame pointer.
|
||||
diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/src/regexp/arm64/regexp-macro-assembler-arm64.cc
|
||||
index 6192461fa32879469d56d36fb788b5de33038d77..4611a323afacb5accfb3886581879e60eb1c9f12 100644
|
||||
--- a/src/regexp/arm64/regexp-macro-assembler-arm64.cc
|
||||
+++ b/src/regexp/arm64/regexp-macro-assembler-arm64.cc
|
||||
@@ -66,14 +66,12 @@ namespace internal {
|
||||
* ^^^^^^^^^ fp ^^^^^^^^^
|
||||
* - fp[-8] direct_call 1 => Direct call from JavaScript code.
|
||||
* 0 => Call through the runtime system.
|
||||
- * - fp[-16] stack_base High end of the memory area to use as
|
||||
- * the backtracking stack.
|
||||
- * - fp[-24] output_size Output may fit multiple sets of matches.
|
||||
- * - fp[-32] input Handle containing the input string.
|
||||
- * - fp[-40] success_counter
|
||||
+ * - fp[-16] output_size Output may fit multiple sets of matches.
|
||||
+ * - fp[-24] input Handle containing the input string.
|
||||
+ * - fp[-32] success_counter
|
||||
* ^^^^^^^^^^^^^ From here and downwards we store 32 bit values ^^^^^^^^^^^^^
|
||||
- * - fp[-44] register N Capture registers initialized with
|
||||
- * - fp[-48] register N + 1 non_position_value.
|
||||
+ * - fp[-40] register N Capture registers initialized with
|
||||
+ * - fp[-44] register N + 1 non_position_value.
|
||||
* ... The first kNumCachedRegisters (N) registers
|
||||
* ... are cached in x0 to x7.
|
||||
* ... Only positions must be stored in the first
|
||||
@@ -95,7 +93,6 @@ namespace internal {
|
||||
* Address end,
|
||||
* int* capture_output_array,
|
||||
* int num_capture_registers,
|
||||
- * byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate,
|
||||
* Address regexp);
|
||||
@@ -750,11 +747,10 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
|
||||
// x3: byte* input_end
|
||||
// x4: int* output array
|
||||
// x5: int output array size
|
||||
- // x6: Address stack_base
|
||||
- // x7: int direct_call
|
||||
-
|
||||
- // sp[8]: address of the current isolate
|
||||
- // sp[0]: secondary link/return address used by native call
|
||||
+ // x6: int direct_call
|
||||
+ // x7: Isolate* isolate
|
||||
+ //
|
||||
+ // sp[0]: secondary link/return address used by native call
|
||||
|
||||
// Tell the system that we have a stack frame. Because the type is MANUAL, no
|
||||
// code is generated.
|
||||
diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.h b/src/regexp/arm64/regexp-macro-assembler-arm64.h
|
||||
index 204ee68dc868142693e9959170c71df3f72f97ce..f3869a72b631f9fb42b275d2edd8f3cfe1cfd8bb 100644
|
||||
--- a/src/regexp/arm64/regexp-macro-assembler-arm64.h
|
||||
+++ b/src/regexp/arm64/regexp-macro-assembler-arm64.h
|
||||
@@ -102,16 +102,12 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
|
||||
// Callee-saved registers (x19-x28).
|
||||
static const int kNumCalleeSavedRegisters = 10;
|
||||
static const int kCalleeSavedRegisters = kReturnAddress + kSystemPointerSize;
|
||||
- // Stack parameter placed by caller.
|
||||
- // It is placed above the FP, LR and the callee-saved registers.
|
||||
- static const int kIsolate =
|
||||
- kCalleeSavedRegisters + kNumCalleeSavedRegisters * kSystemPointerSize;
|
||||
|
||||
// Below the frame pointer.
|
||||
// Register parameters stored by setup code.
|
||||
- static const int kDirectCall = -kSystemPointerSize;
|
||||
- static const int kStackHighEnd = kDirectCall - kSystemPointerSize;
|
||||
- static const int kOutputSize = kStackHighEnd - kSystemPointerSize;
|
||||
+ static const int kIsolate = -kSystemPointerSize;
|
||||
+ static const int kDirectCall = kIsolate - kSystemPointerSize;
|
||||
+ static const int kOutputSize = kDirectCall - kSystemPointerSize;
|
||||
static const int kInput = kOutputSize - kSystemPointerSize;
|
||||
// When adding local variables remember to push space for them in
|
||||
// the frame in GetCode.
|
||||
diff --git a/src/regexp/experimental/experimental.cc b/src/regexp/experimental/experimental.cc
|
||||
index c05a010d06f34405128ffb9a9d67d86a20fcb83d..c3d701715aa88be3f5a8009319a09b032c85f4ad 100644
|
||||
--- a/src/regexp/experimental/experimental.cc
|
||||
+++ b/src/regexp/experimental/experimental.cc
|
||||
@@ -192,8 +192,7 @@ int32_t ExperimentalRegExp::ExecRaw(Isolate* isolate,
|
||||
int32_t ExperimentalRegExp::MatchForCallFromJs(
|
||||
Address subject, int32_t start_position, Address input_start,
|
||||
Address input_end, int* output_registers, int32_t output_register_count,
|
||||
- Address backtrack_stack, RegExp::CallOrigin call_origin, Isolate* isolate,
|
||||
- Address regexp) {
|
||||
+ RegExp::CallOrigin call_origin, Isolate* isolate, Address regexp) {
|
||||
DCHECK(FLAG_enable_experimental_regexp_engine);
|
||||
DCHECK_NOT_NULL(isolate);
|
||||
DCHECK_NOT_NULL(output_registers);
|
||||
diff --git a/src/regexp/experimental/experimental.h b/src/regexp/experimental/experimental.h
|
||||
index 5987fb4d7732f47c5f31cc0fab7b11e252c864f8..cdc683e97e901bd3e63332a04f69c6d31f964931 100644
|
||||
--- a/src/regexp/experimental/experimental.h
|
||||
+++ b/src/regexp/experimental/experimental.h
|
||||
@@ -34,7 +34,6 @@ class ExperimentalRegExp final : public AllStatic {
|
||||
Address input_start, Address input_end,
|
||||
int* output_registers,
|
||||
int32_t output_register_count,
|
||||
- Address backtrack_stack,
|
||||
RegExp::CallOrigin call_origin,
|
||||
Isolate* isolate, Address regexp);
|
||||
static MaybeHandle<Object> Exec(
|
||||
diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/src/regexp/ia32/regexp-macro-assembler-ia32.cc
|
||||
index 51d63b2531e2bc85fb115de23d7b6a6f40b36f11..8369b88e22c300890fe4ddb1bbba62093e8b23d8 100644
|
||||
--- a/src/regexp/ia32/regexp-macro-assembler-ia32.cc
|
||||
+++ b/src/regexp/ia32/regexp-macro-assembler-ia32.cc
|
||||
@@ -40,8 +40,6 @@ namespace internal {
|
||||
* - Isolate* isolate (address of the current isolate)
|
||||
* - direct_call (if 1, direct call from JavaScript code, if 0
|
||||
* call through the runtime system)
|
||||
- * - stack_area_base (high end of the memory area to use as
|
||||
- * backtracking stack)
|
||||
* - capture array size (may fit multiple sets of matches)
|
||||
* - int* capture_array (int[num_saved_registers_], for output).
|
||||
* - end of input (address of end of string)
|
||||
@@ -74,7 +72,6 @@ namespace internal {
|
||||
* Address end,
|
||||
* int* capture_output_array,
|
||||
* int num_capture_registers,
|
||||
- * byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate
|
||||
* Address regexp);
|
||||
diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.h b/src/regexp/ia32/regexp-macro-assembler-ia32.h
|
||||
index 861795da900d91111386e4f8e660f7f94ea46a33..01914a6b8b5abb96a4eec8d844e2d1aea7cbf231 100644
|
||||
--- a/src/regexp/ia32/regexp-macro-assembler-ia32.h
|
||||
+++ b/src/regexp/ia32/regexp-macro-assembler-ia32.h
|
||||
@@ -105,8 +105,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
|
||||
// one set of capture results. For the case of non-global regexp, we ignore
|
||||
// this value.
|
||||
static const int kNumOutputRegisters = kRegisterOutput + kSystemPointerSize;
|
||||
- static const int kStackHighEnd = kNumOutputRegisters + kSystemPointerSize;
|
||||
- static const int kDirectCall = kStackHighEnd + kSystemPointerSize;
|
||||
+ static const int kDirectCall = kNumOutputRegisters + kSystemPointerSize;
|
||||
static const int kIsolate = kDirectCall + kSystemPointerSize;
|
||||
// Below the frame pointer - local stack variables.
|
||||
// When adding local variables remember to push space for them in
|
||||
diff --git a/src/regexp/regexp-interpreter.cc b/src/regexp/regexp-interpreter.cc
|
||||
index f9a959d2582a25cd60a97453e696f8f1f0560ce8..a2f23f78c308162240c5adf8904e732ce3bf6159 100644
|
||||
--- a/src/regexp/regexp-interpreter.cc
|
||||
+++ b/src/regexp/regexp-interpreter.cc
|
||||
@@ -1111,7 +1111,7 @@ IrregexpInterpreter::Result IrregexpInterpreter::MatchInternal(
|
||||
// builtin.
|
||||
IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs(
|
||||
Address subject, int32_t start_position, Address, Address,
|
||||
- int* output_registers, int32_t output_register_count, Address,
|
||||
+ int* output_registers, int32_t output_register_count,
|
||||
RegExp::CallOrigin call_origin, Isolate* isolate, Address regexp) {
|
||||
DCHECK_NOT_NULL(isolate);
|
||||
DCHECK_NOT_NULL(output_registers);
|
||||
diff --git a/src/regexp/regexp-interpreter.h b/src/regexp/regexp-interpreter.h
|
||||
index a4d79184b08963598bbc42a91541c8df695bf4c5..e9dedd781b5b83d4017f8b2bd4353f1d57013a67 100644
|
||||
--- a/src/regexp/regexp-interpreter.h
|
||||
+++ b/src/regexp/regexp-interpreter.h
|
||||
@@ -36,9 +36,8 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic {
|
||||
// RETRY is returned if a retry through the runtime is needed (e.g. when
|
||||
// interrupts have been scheduled or the regexp is marked for tier-up).
|
||||
//
|
||||
- // Arguments input_start, input_end and backtrack_stack are
|
||||
- // unused. They are only passed to match the signature of the native irregex
|
||||
- // code.
|
||||
+ // Arguments input_start and input_end are unused. They are only passed to
|
||||
+ // match the signature of the native irregex code.
|
||||
//
|
||||
// Arguments output_registers and output_register_count describe the results
|
||||
// array, which will contain register values of all captures if SUCCESS is
|
||||
@@ -47,7 +46,6 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic {
|
||||
Address input_start, Address input_end,
|
||||
int* output_registers,
|
||||
int32_t output_register_count,
|
||||
- Address backtrack_stack,
|
||||
RegExp::CallOrigin call_origin,
|
||||
Isolate* isolate, Address regexp);
|
||||
|
||||
diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc
|
||||
index 1f5875afb8850da4136da6633d5b0ad9f52803e3..ced89ad4386b9d037851529f098c8aa111f2a478 100644
|
||||
--- a/src/regexp/regexp-macro-assembler.cc
|
||||
+++ b/src/regexp/regexp-macro-assembler.cc
|
||||
@@ -306,23 +306,21 @@ int NativeRegExpMacroAssembler::Execute(
|
||||
String input, // This needs to be the unpacked (sliced, cons) string.
|
||||
int start_offset, const byte* input_start, const byte* input_end,
|
||||
int* output, int output_size, Isolate* isolate, JSRegExp regexp) {
|
||||
- // Ensure that the minimum stack has been allocated.
|
||||
RegExpStackScope stack_scope(isolate);
|
||||
- Address stack_base = stack_scope.stack()->memory_top();
|
||||
|
||||
bool is_one_byte = String::IsOneByteRepresentationUnderneath(input);
|
||||
Code code = FromCodeT(CodeT::cast(regexp.Code(is_one_byte)));
|
||||
RegExp::CallOrigin call_origin = RegExp::CallOrigin::kFromRuntime;
|
||||
|
||||
- using RegexpMatcherSig = int(
|
||||
- Address input_string, int start_offset, const byte* input_start,
|
||||
- const byte* input_end, int* output, int output_size, Address stack_base,
|
||||
- int call_origin, Isolate* isolate, Address regexp);
|
||||
+ using RegexpMatcherSig =
|
||||
+ // NOLINTNEXTLINE(readability/casting)
|
||||
+ int(Address input_string, int start_offset, const byte* input_start,
|
||||
+ const byte* input_end, int* output, int output_size, int call_origin,
|
||||
+ Isolate* isolate, Address regexp);
|
||||
|
||||
auto fn = GeneratedCode<RegexpMatcherSig>::FromCode(code);
|
||||
- int result =
|
||||
- fn.Call(input.ptr(), start_offset, input_start, input_end, output,
|
||||
- output_size, stack_base, call_origin, isolate, regexp.ptr());
|
||||
+ int result = fn.Call(input.ptr(), start_offset, input_start, input_end,
|
||||
+ output, output_size, call_origin, isolate, regexp.ptr());
|
||||
DCHECK_GE(result, SMALLEST_REGEXP_RESULT);
|
||||
|
||||
if (result == EXCEPTION && !isolate->has_pending_exception()) {
|
||||
diff --git a/src/regexp/x64/regexp-macro-assembler-x64.cc b/src/regexp/x64/regexp-macro-assembler-x64.cc
|
||||
index abcbed18aaa9bdc4a497962714bffde74d581173..e4bff5dafa9f12c14805c72e51f973252b97a5a7 100644
|
||||
--- a/src/regexp/x64/regexp-macro-assembler-x64.cc
|
||||
+++ b/src/regexp/x64/regexp-macro-assembler-x64.cc
|
||||
@@ -47,14 +47,12 @@ namespace internal {
|
||||
* Each call to a C++ method should retain these registers.
|
||||
*
|
||||
* The stack will have the following content, in some order, indexable from the
|
||||
- * frame pointer (see, e.g., kStackHighEnd):
|
||||
+ * frame pointer (see, e.g., kDirectCall):
|
||||
* - Address regexp (address of the JSRegExp object; unused in native
|
||||
* code, passed to match signature of interpreter)
|
||||
* - Isolate* isolate (address of the current isolate)
|
||||
* - direct_call (if 1, direct call from JavaScript code, if 0 call
|
||||
* through the runtime system)
|
||||
- * - stack_area_base (high end of the memory area to use as
|
||||
- * backtracking stack)
|
||||
* - capture array size (may fit multiple sets of matches)
|
||||
* - int* capture_array (int[num_saved_registers_], for output).
|
||||
* - end of input (address of end of string)
|
||||
@@ -85,7 +83,6 @@ namespace internal {
|
||||
* Address end,
|
||||
* int* capture_output_array,
|
||||
* int num_capture_registers,
|
||||
- * byte* stack_area_base,
|
||||
* bool direct_call = false,
|
||||
* Isolate* isolate,
|
||||
* Address regexp);
|
||||
@@ -849,8 +846,6 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
|
||||
}
|
||||
|
||||
// Initialize backtrack stack pointer.
|
||||
- // TODO(jgruber): Remove the kStackHighEnd parameter (and others like
|
||||
- // kIsolate).
|
||||
LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
|
||||
|
||||
__ jmp(&start_label_);
|
||||
diff --git a/src/regexp/x64/regexp-macro-assembler-x64.h b/src/regexp/x64/regexp-macro-assembler-x64.h
|
||||
index 74a3c95b06c771078ab03e6787e5912315421bb2..6f89ba9f8cf45430dc0edc7f2241a9aca34324c0 100644
|
||||
--- a/src/regexp/x64/regexp-macro-assembler-x64.h
|
||||
+++ b/src/regexp/x64/regexp-macro-assembler-x64.h
|
||||
@@ -108,9 +108,8 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
|
||||
// this value. NumOutputRegisters is passed as 32-bit value. The upper
|
||||
// 32 bit of this 64-bit stack slot may contain garbage.
|
||||
static const int kNumOutputRegisters = kRegisterOutput + kSystemPointerSize;
|
||||
- static const int kStackHighEnd = kNumOutputRegisters + kSystemPointerSize;
|
||||
// DirectCall is passed as 32 bit int (values 0 or 1).
|
||||
- static const int kDirectCall = kStackHighEnd + kSystemPointerSize;
|
||||
+ static const int kDirectCall = kNumOutputRegisters + kSystemPointerSize;
|
||||
static const int kIsolate = kDirectCall + kSystemPointerSize;
|
||||
#else
|
||||
// In AMD64 ABI Calling Convention, the first six integer parameters
|
||||
@@ -121,13 +120,12 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
|
||||
static const int kInputStart = kStartIndex - kSystemPointerSize;
|
||||
static const int kInputEnd = kInputStart - kSystemPointerSize;
|
||||
static const int kRegisterOutput = kInputEnd - kSystemPointerSize;
|
||||
-
|
||||
// For the case of global regular expression, we have room to store at least
|
||||
// one set of capture results. For the case of non-global regexp, we ignore
|
||||
// this value.
|
||||
static const int kNumOutputRegisters = kRegisterOutput - kSystemPointerSize;
|
||||
- static const int kStackHighEnd = kFrameAlign;
|
||||
- static const int kDirectCall = kStackHighEnd + kSystemPointerSize;
|
||||
+
|
||||
+ static const int kDirectCall = kFrameAlign;
|
||||
static const int kIsolate = kDirectCall + kSystemPointerSize;
|
||||
#endif
|
||||
|
||||
@@ -232,9 +232,8 @@ def remove_patch_filename(patch):
|
||||
def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
if patch_range is None:
|
||||
patch_range, num_patches = guess_base_commit(repo)
|
||||
sys.stderr.write(
|
||||
"Exporting {} patches in {} since {}\n".format(num_patches, repo, patch_range[0:7])
|
||||
)
|
||||
sys.stderr.write("Exporting {} patches in {} since {}\n".format(
|
||||
num_patches, repo, patch_range[0:7]))
|
||||
patch_data = format_patch(repo, patch_range)
|
||||
patches = split_patches(patch_data)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from util import SRC_DIR
|
||||
from lib.util import SRC_DIR
|
||||
|
||||
PYYAML_LIB_DIR = os.path.join(SRC_DIR, 'third_party', 'pyyaml', 'lib')
|
||||
sys.path.append(PYYAML_LIB_DIR)
|
||||
|
||||
@@ -29,11 +29,25 @@ const IS_WINDOWS = process.platform === 'win32';
|
||||
|
||||
function spawnAndCheckExitCode (cmd, args, opts) {
|
||||
opts = Object.assign({ stdio: 'inherit' }, opts);
|
||||
const status = childProcess.spawnSync(cmd, args, opts).status;
|
||||
if (status) process.exit(status);
|
||||
const { error, status, signal } = childProcess.spawnSync(cmd, args, opts);
|
||||
if (error) {
|
||||
// the subsprocess failed or timed out
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
if (status === null) {
|
||||
// the subprocess terminated due to a signal
|
||||
console.error(signal);
|
||||
process.exit(1);
|
||||
}
|
||||
if (status !== 0) {
|
||||
// `status` is an exit code
|
||||
process.exit(status);
|
||||
}
|
||||
}
|
||||
|
||||
function cpplint (args) {
|
||||
args.unshift(`--project_root=${SOURCE_ROOT}`);
|
||||
const result = childProcess.spawnSync(IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py', args, { encoding: 'utf8', shell: true });
|
||||
// cpplint.py writes EVERYTHING to stderr, including status messages
|
||||
if (result.stderr) {
|
||||
@@ -91,7 +105,7 @@ const LINTERS = [{
|
||||
const rcfile = path.join(DEPOT_TOOLS, 'pylintrc');
|
||||
const args = ['--rcfile=' + rcfile, ...filenames];
|
||||
const env = Object.assign({ PYTHONPATH: path.join(SOURCE_ROOT, 'script') }, process.env);
|
||||
spawnAndCheckExitCode('pylint.py', args, { env });
|
||||
spawnAndCheckExitCode('pylint', args, { env });
|
||||
}
|
||||
}, {
|
||||
key: 'javascript',
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
"abort/test-abort-backtrace",
|
||||
"async-hooks/test-crypto-pbkdf2",
|
||||
"async-hooks/test-crypto-randomBytes",
|
||||
"message/source_map_throw_catch",
|
||||
"message/source_map_throw_first_tick",
|
||||
"message/source_map_throw_set_immediate",
|
||||
"message/v8_warning",
|
||||
"parallel/test-assert",
|
||||
"parallel/test-bootstrap-modules",
|
||||
"parallel/test-buffer-backing-arraybuffer",
|
||||
"parallel/test-buffer-constructor-node-modules-paths",
|
||||
@@ -18,7 +13,6 @@
|
||||
"parallel/test-cluster-shared-handle-bind-privileged-port",
|
||||
"parallel/test-code-cache",
|
||||
"parallel/test-crypto-aes-wrap",
|
||||
"parallel/test-crypto-async-sign-verify",
|
||||
"parallel/test-crypto-authenticated-stream",
|
||||
"parallel/test-crypto-certificate",
|
||||
"parallel/test-crypto-des3-wrap",
|
||||
@@ -27,36 +21,23 @@
|
||||
"parallel/test-crypto-engine",
|
||||
"parallel/test-crypto-fips",
|
||||
"parallel/test-crypto-hkdf.js",
|
||||
"parallel/test-crypto-keygen",
|
||||
"parallel/test-crypto-keygen-deprecation",
|
||||
"parallel/test-crypto-key-objects",
|
||||
"parallel/test-crypto-padding-aes256",
|
||||
"parallel/test-crypto-secure-heap",
|
||||
"parallel/test-debug-args",
|
||||
"parallel/test-debug-usage",
|
||||
"parallel/test-debugger-pid",
|
||||
"parallel/test-domain-abort-on-uncaught",
|
||||
"parallel/test-domain-with-abort-on-uncaught-exception",
|
||||
"parallel/test-finalization-group-error",
|
||||
"parallel/test-freeze-intrinsics",
|
||||
"parallel/test-fs-utimes-y2K38",
|
||||
"parallel/test-gc-tls-external-memory",
|
||||
"parallel/test-http2-clean-output",
|
||||
"parallel/test-http2-reset-flood",
|
||||
"parallel/test-https-agent-session-reuse",
|
||||
"parallel/test-https-options-boolean-check",
|
||||
"parallel/test-inspector-inspect-brk-node",
|
||||
"parallel/test-inspector-multisession-ws",
|
||||
"parallel/test-inspector-port-zero-cluster",
|
||||
"parallel/test-inspector-tracing-domain",
|
||||
"parallel/test-inspector-vm-global-accessors-getter-sideeffect",
|
||||
"parallel/test-inspector-vm-global-accessors-sideeffects",
|
||||
"parallel/test-module-loading-globalpaths",
|
||||
"parallel/test-module-run-main-monkey-patch",
|
||||
"parallel/test-module-version",
|
||||
"parallel/test-openssl-ca-options",
|
||||
"parallel/test-policy-integrity",
|
||||
"parallel/test-process-env-allowed-flags-are-documented",
|
||||
"parallel/test-process-external-stdio-close",
|
||||
"parallel/test-process-external-stdio-close-spawn",
|
||||
"parallel/test-process-versions",
|
||||
"parallel/test-readline-interface",
|
||||
"parallel/test-repl",
|
||||
"parallel/test-repl-harmony",
|
||||
"parallel/test-repl-pretty-custom-stack",
|
||||
@@ -134,14 +115,8 @@
|
||||
"parallel/test-trace-events-v8",
|
||||
"parallel/test-trace-events-vm",
|
||||
"parallel/test-trace-events-worker-metadata",
|
||||
"parallel/test-util-inspect",
|
||||
"parallel/test-v8-coverage",
|
||||
"parallel/test-v8-flags",
|
||||
"parallel/test-v8-untrusted-code-mitigations",
|
||||
"parallel/test-vm-module-basic",
|
||||
"parallel/test-vm-parse-abort-on-uncaught-exception",
|
||||
"parallel/test-vm-sigint-existing-handler",
|
||||
"parallel/test-vm-timeout",
|
||||
"parallel/test-webcrypto-derivebits-hkdf",
|
||||
"parallel/test-webcrypto-derivebits-node-dh",
|
||||
"parallel/test-webcrypto-ed25519-ed448",
|
||||
@@ -153,17 +128,8 @@
|
||||
"parallel/test-webcrypto-sign-verify-node-dsa",
|
||||
"parallel/test-webcrypto-x25519-x448",
|
||||
"parallel/test-whatwg-encoding-custom-textdecoder",
|
||||
"parallel/test-worker-message-channel",
|
||||
"parallel/test-worker-message-port",
|
||||
"parallel/test-worker-message-port-transfer-duplicate",
|
||||
"parallel/test-worker-message-port-transfer-target",
|
||||
"parallel/test-worker-resource-limits",
|
||||
"parallel/test-worker-sharedarraybuffer-from-worker-thread",
|
||||
"parallel/test-worker-stdio",
|
||||
"parallel/test-worker-workerdata-messageport",
|
||||
"parallel/test-zlib-unused-weak",
|
||||
"pseudo-tty/test-set-raw-mode-reset-process-exit",
|
||||
"pseudo-tty/test-set-raw-mode-reset-signal",
|
||||
"report/test-report-fatal-error",
|
||||
"report/test-report-getreport",
|
||||
"report/test-report-signal",
|
||||
@@ -172,13 +138,7 @@
|
||||
"report/test-report-uv-handles",
|
||||
"report/test-report-worker",
|
||||
"report/test-report-writereport",
|
||||
"sequential/test-inspector-contexts",
|
||||
"sequential/test-inspector-port-zero",
|
||||
"sequential/test-inspector-resource-name-to-url",
|
||||
"sequential/test-inspector-stress-http",
|
||||
"sequential/test-perf-hooks",
|
||||
"sequential/test-tls-connect",
|
||||
"sequential/test-vm-timeout-rethrow",
|
||||
"sequential/test-worker-prof",
|
||||
"wpt/test-encoding",
|
||||
"wpt/test-webcrypto"
|
||||
|
||||
@@ -135,7 +135,7 @@ def main():
|
||||
json.load(f) # Make sure it's not an empty file
|
||||
print("Using existing mtime cache for patches")
|
||||
return 0
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
|
||||
@@ -100,7 +100,8 @@ def main():
|
||||
# Upload libcxx_objects.zip for linux only
|
||||
libcxx_objects = get_zip_name('libcxx-objects', ELECTRON_VERSION)
|
||||
libcxx_objects_zip = os.path.join(OUT_DIR, libcxx_objects)
|
||||
shutil.copy2(os.path.join(OUT_DIR, 'libcxx_objects.zip'), libcxx_objects_zip)
|
||||
shutil.copy2(os.path.join(OUT_DIR, 'libcxx_objects.zip'),
|
||||
libcxx_objects_zip)
|
||||
upload_electron(release, libcxx_objects_zip, args)
|
||||
|
||||
# Upload headers.zip and abi_headers.zip as non-platform specific
|
||||
|
||||
@@ -48,7 +48,8 @@ def main():
|
||||
# FIXME: Enable after ELECTRON_ENABLE_LOGGING works again
|
||||
# env['ELECTRON_ENABLE_LOGGING'] = 'true'
|
||||
testargs = [electron, test_path]
|
||||
if sys.platform != 'linux' and (platform.machine() == 'ARM64' or os.environ.get('TARGET_ARCH') == 'arm64'):
|
||||
if sys.platform != 'linux' and (platform.machine() == 'ARM64' or
|
||||
os.environ.get('TARGET_ARCH') == 'arm64'):
|
||||
testargs.append('--disable-accelerated-video-decode')
|
||||
subprocess.check_call(testargs, env=env)
|
||||
except subprocess.CalledProcessError as e:
|
||||
|
||||
@@ -39,10 +39,7 @@ void BrowserWindow::OverrideNSWindowContentView(
|
||||
|
||||
void BrowserWindow::UpdateDraggableRegions(
|
||||
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
||||
if (window_->has_frame())
|
||||
return;
|
||||
|
||||
if (!web_contents())
|
||||
if (window_->has_frame() || !web_contents())
|
||||
return;
|
||||
|
||||
// All ControlRegionViews should be added as children of the WebContentsView,
|
||||
@@ -78,8 +75,13 @@ void BrowserWindow::UpdateDraggableRegions(
|
||||
DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
|
||||
}
|
||||
|
||||
// Draggable regions on BrowserViews are independent from those of
|
||||
// BrowserWindows, so if a BrowserView with different draggable regions than
|
||||
// the BrowserWindow it belongs to is superimposed on top of that window, the
|
||||
// draggable regions of the BrowserView take precedence over those of the
|
||||
// BrowserWindow.
|
||||
for (NativeBrowserView* view : window_->browser_views()) {
|
||||
view->UpdateDraggableRegions(drag_exclude_rects);
|
||||
view->UpdateDraggableRegions(view->GetDraggableRegions());
|
||||
}
|
||||
|
||||
// Create and add a ControlRegionView for each region that needs to be
|
||||
|
||||
@@ -236,13 +236,11 @@ std::u16string Menu::GetToolTipAt(int index) const {
|
||||
return model_->GetToolTipAt(index);
|
||||
}
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
std::u16string Menu::GetAcceleratorTextAtForTesting(int index) const {
|
||||
ui::Accelerator accelerator;
|
||||
model_->GetAcceleratorAtWithParams(index, true, &accelerator);
|
||||
return accelerator.GetShortcutText();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Menu::IsItemCheckedAt(int index) const {
|
||||
return model_->IsItemCheckedAt(index);
|
||||
@@ -297,9 +295,7 @@ v8::Local<v8::ObjectTemplate> Menu::FillObjectTemplate(
|
||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||
.SetMethod("popupAt", &Menu::PopupAt)
|
||||
.SetMethod("closePopupAt", &Menu::ClosePopupAt)
|
||||
#if DCHECK_IS_ON()
|
||||
.SetMethod("getAcceleratorTextAt", &Menu::GetAcceleratorTextAtForTesting)
|
||||
#endif
|
||||
.SetMethod("_getAcceleratorTextAt", &Menu::GetAcceleratorTextAtForTesting)
|
||||
#if defined(OS_MAC)
|
||||
.SetMethod("_getUserAcceleratorAt", &Menu::GetUserAcceleratorAt)
|
||||
#endif
|
||||
|
||||
@@ -79,9 +79,7 @@ class Menu : public gin::Wrappable<Menu>,
|
||||
int positioning_item,
|
||||
base::OnceClosure callback) = 0;
|
||||
virtual void ClosePopupAt(int32_t window_id) = 0;
|
||||
#if DCHECK_IS_ON()
|
||||
virtual std::u16string GetAcceleratorTextAtForTesting(int index) const;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<ElectronMenuModel> model_;
|
||||
Menu* parent_ = nullptr;
|
||||
|
||||
@@ -34,9 +34,7 @@ class MenuMac : public Menu {
|
||||
int positioning_item,
|
||||
base::OnceClosure callback);
|
||||
void ClosePopupAt(int32_t window_id) override;
|
||||
#if DCHECK_IS_ON()
|
||||
std::u16string GetAcceleratorTextAtForTesting(int index) const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class Menu;
|
||||
|
||||
@@ -170,7 +170,6 @@ void MenuMac::ClosePopupAt(int32_t window_id) {
|
||||
std::move(close_popup));
|
||||
}
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
std::u16string MenuMac::GetAcceleratorTextAtForTesting(int index) const {
|
||||
// A least effort to get the real shortcut text of NSMenuItem, the code does
|
||||
// not need to be perfect since it is test only.
|
||||
@@ -206,7 +205,6 @@ std::u16string MenuMac::GetAcceleratorTextAtForTesting(int index) const {
|
||||
text += key;
|
||||
return text;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MenuMac::ClosePopupOnUI(int32_t window_id) {
|
||||
auto controller = popup_controllers_.find(window_id);
|
||||
|
||||
@@ -644,6 +644,18 @@ void Session::SetPermissionCheckHandler(v8::Local<v8::Value> val,
|
||||
permission_manager->SetPermissionCheckHandler(handler);
|
||||
}
|
||||
|
||||
void Session::SetDevicePermissionHandler(v8::Local<v8::Value> val,
|
||||
gin::Arguments* args) {
|
||||
ElectronPermissionManager::DeviceCheckHandler handler;
|
||||
if (!(val->IsNull() || gin::ConvertFromV8(args->isolate(), val, &handler))) {
|
||||
args->ThrowTypeError("Must pass null or function");
|
||||
return;
|
||||
}
|
||||
auto* permission_manager = static_cast<ElectronPermissionManager*>(
|
||||
browser_context()->GetPermissionControllerDelegate());
|
||||
permission_manager->SetDevicePermissionHandler(handler);
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> Session::ClearHostResolverCache(gin::Arguments* args) {
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
gin_helper::Promise<void> promise(isolate);
|
||||
@@ -1148,6 +1160,8 @@ gin::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
|
||||
&Session::SetPermissionRequestHandler)
|
||||
.SetMethod("setPermissionCheckHandler",
|
||||
&Session::SetPermissionCheckHandler)
|
||||
.SetMethod("setDevicePermissionHandler",
|
||||
&Session::SetDevicePermissionHandler)
|
||||
.SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
|
||||
.SetMethod("clearAuthCache", &Session::ClearAuthCache)
|
||||
.SetMethod("allowNTLMCredentialsForDomains",
|
||||
|
||||
@@ -104,6 +104,8 @@ class Session : public gin::Wrappable<Session>,
|
||||
gin::Arguments* args);
|
||||
void SetPermissionCheckHandler(v8::Local<v8::Value> val,
|
||||
gin::Arguments* args);
|
||||
void SetDevicePermissionHandler(v8::Local<v8::Value> val,
|
||||
gin::Arguments* args);
|
||||
v8::Local<v8::Promise> ClearHostResolverCache(gin::Arguments* args);
|
||||
v8::Local<v8::Promise> ClearAuthCache();
|
||||
void AllowNTLMCredentialsForDomains(const std::string& domains);
|
||||
|
||||
@@ -918,6 +918,12 @@ void WebContents::InitWithWebContents(
|
||||
}
|
||||
|
||||
WebContents::~WebContents() {
|
||||
// clear out objects that have been granted permissions so that when
|
||||
// WebContents::RenderFrameDeleted is called as a result of WebContents
|
||||
// destruction it doesn't try to clear out a granted_devices_
|
||||
// on a destructed object.
|
||||
granted_devices_.clear();
|
||||
|
||||
if (!inspectable_web_contents_) {
|
||||
WebContentsDestroyed();
|
||||
return;
|
||||
@@ -947,18 +953,31 @@ WebContents::~WebContents() {
|
||||
// InspectableWebContents will be automatically destroyed.
|
||||
}
|
||||
|
||||
void WebContents::DeleteThisIfAlive() {
|
||||
// It is possible that the FirstWeakCallback has been called but the
|
||||
// SecondWeakCallback has not, in this case the garbage collection of
|
||||
// WebContents has already started and we should not |delete this|.
|
||||
// Calling |GetWrapper| can detect this corner case.
|
||||
auto* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Object> wrapper;
|
||||
if (!GetWrapper(isolate).ToLocal(&wrapper))
|
||||
return;
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WebContents::Destroy() {
|
||||
// The content::WebContents should be destroyed asyncronously when possible
|
||||
// as user may choose to destroy WebContents during an event of it.
|
||||
if (Browser::Get()->is_shutting_down() || IsGuest() ||
|
||||
type_ == Type::kBrowserView) {
|
||||
delete this;
|
||||
DeleteThisIfAlive();
|
||||
} else {
|
||||
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
[](base::WeakPtr<WebContents> contents) {
|
||||
if (contents)
|
||||
delete contents.get();
|
||||
contents->DeleteThisIfAlive();
|
||||
},
|
||||
GetWeakPtr()));
|
||||
}
|
||||
@@ -1427,6 +1446,12 @@ void WebContents::RenderFrameDeleted(
|
||||
// - Cross-origin navigation creates a new RFH in a separate process which
|
||||
// is swapped by content::RenderFrameHostManager.
|
||||
//
|
||||
|
||||
// clear out objects that have been granted permissions
|
||||
if (!granted_devices_.empty()) {
|
||||
granted_devices_.erase(render_frame_host->GetFrameTreeNodeId());
|
||||
}
|
||||
|
||||
// WebFrameMain::FromRenderFrameHost(rfh) will use the RFH's FrameTreeNode ID
|
||||
// to find an existing instance of WebFrameMain. During a cross-origin
|
||||
// navigation, the deleted RFH will be the old host which was swapped out. In
|
||||
@@ -3237,6 +3262,42 @@ v8::Local<v8::Promise> WebContents::TakeHeapSnapshot(
|
||||
return handle;
|
||||
}
|
||||
|
||||
void WebContents::GrantDevicePermission(
|
||||
const url::Origin& origin,
|
||||
const base::Value* device,
|
||||
content::PermissionType permissionType,
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
granted_devices_[render_frame_host->GetFrameTreeNodeId()][permissionType]
|
||||
[origin]
|
||||
.push_back(
|
||||
std::make_unique<base::Value>(device->Clone()));
|
||||
}
|
||||
|
||||
std::vector<base::Value> WebContents::GetGrantedDevices(
|
||||
const url::Origin& origin,
|
||||
content::PermissionType permissionType,
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
const auto& devices_for_frame_host_it =
|
||||
granted_devices_.find(render_frame_host->GetFrameTreeNodeId());
|
||||
if (devices_for_frame_host_it == granted_devices_.end())
|
||||
return {};
|
||||
|
||||
const auto& current_devices_it =
|
||||
devices_for_frame_host_it->second.find(permissionType);
|
||||
if (current_devices_it == devices_for_frame_host_it->second.end())
|
||||
return {};
|
||||
|
||||
const auto& origin_devices_it = current_devices_it->second.find(origin);
|
||||
if (origin_devices_it == current_devices_it->second.end())
|
||||
return {};
|
||||
|
||||
std::vector<base::Value> results;
|
||||
for (const auto& object : origin_devices_it->second)
|
||||
results.push_back(object->Clone());
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void WebContents::UpdatePreferredSize(content::WebContents* web_contents,
|
||||
const gfx::Size& pref_size) {
|
||||
Emit("preferred-size-changed", pref_size);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "content/common/frame.mojom.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/keyboard_event_processing_result.h"
|
||||
#include "content/public/browser/permission_type.h"
|
||||
#include "content/public/browser/render_widget_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
@@ -91,6 +92,11 @@ class OffScreenWebContentsView;
|
||||
|
||||
namespace api {
|
||||
|
||||
using DevicePermissionMap = std::map<
|
||||
int,
|
||||
std::map<content::PermissionType,
|
||||
std::map<url::Origin, std::vector<std::unique_ptr<base::Value>>>>>;
|
||||
|
||||
// Wrapper around the content::WebContents.
|
||||
class WebContents : public gin::Wrappable<WebContents>,
|
||||
public gin_helper::EventEmitterMixin<WebContents>,
|
||||
@@ -419,6 +425,21 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
electron::mojom::ElectronBrowser::DoGetZoomLevelCallback callback);
|
||||
void SetImageAnimationPolicy(const std::string& new_policy);
|
||||
|
||||
// Grants |origin| access to |device|.
|
||||
// To be used in place of ObjectPermissionContextBase::GrantObjectPermission.
|
||||
void GrantDevicePermission(const url::Origin& origin,
|
||||
const base::Value* device,
|
||||
content::PermissionType permissionType,
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
|
||||
// Returns the list of devices that |origin| has been granted permission to
|
||||
// access. To be used in place of
|
||||
// ObjectPermissionContextBase::GetGrantedObjects.
|
||||
std::vector<base::Value> GetGrantedDevices(
|
||||
const url::Origin& origin,
|
||||
content::PermissionType permissionType,
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
|
||||
private:
|
||||
// Does not manage lifetime of |web_contents|.
|
||||
WebContents(v8::Isolate* isolate, content::WebContents* web_contents);
|
||||
@@ -430,6 +451,9 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
WebContents(v8::Isolate* isolate, const gin_helper::Dictionary& options);
|
||||
~WebContents() override;
|
||||
|
||||
// Delete this if garbage collection has not started.
|
||||
void DeleteThisIfAlive();
|
||||
|
||||
// Creates a InspectableWebContents object and takes ownership of
|
||||
// |web_contents|.
|
||||
void InitWithWebContents(std::unique_ptr<content::WebContents> web_contents,
|
||||
@@ -762,6 +786,9 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
// Stores the frame thats currently in fullscreen, nullptr if there is none.
|
||||
content::RenderFrameHost* fullscreen_frame_ = nullptr;
|
||||
|
||||
// In-memory cache that holds objects that have been granted permissions.
|
||||
DevicePermissionMap granted_devices_;
|
||||
|
||||
base::WeakPtrFactory<WebContents> weak_factory_{this};
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebContents);
|
||||
|
||||
@@ -592,8 +592,7 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
|
||||
switches::kStandardSchemes, switches::kEnableSandbox,
|
||||
switches::kSecureSchemes, switches::kBypassCSPSchemes,
|
||||
switches::kCORSSchemes, switches::kFetchSchemes,
|
||||
switches::kServiceWorkerSchemes, switches::kEnableApiFilteringLogging,
|
||||
switches::kStreamingSchemes};
|
||||
switches::kServiceWorkerSchemes, switches::kStreamingSchemes};
|
||||
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
|
||||
kCommonSwitchNames,
|
||||
base::size(kCommonSwitchNames));
|
||||
@@ -1705,4 +1704,10 @@ device::GeolocationManager* ElectronBrowserClient::GetGeolocationManager() {
|
||||
#endif
|
||||
}
|
||||
|
||||
content::HidDelegate* ElectronBrowserClient::GetHidDelegate() {
|
||||
if (!hid_delegate_)
|
||||
hid_delegate_ = std::make_unique<ElectronHidDelegate>();
|
||||
return hid_delegate_.get();
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "services/metrics/public/cpp/ukm_source_id.h"
|
||||
#include "shell/browser/bluetooth/electron_bluetooth_delegate.h"
|
||||
#include "shell/browser/font/electron_font_access_delegate.h"
|
||||
#include "shell/browser/hid/electron_hid_delegate.h"
|
||||
#include "shell/browser/serial/electron_serial_delegate.h"
|
||||
#include "third_party/blink/public/mojom/badging/badging.mojom-forward.h"
|
||||
|
||||
@@ -96,6 +97,8 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
||||
|
||||
content::BluetoothDelegate* GetBluetoothDelegate() override;
|
||||
|
||||
content::HidDelegate* GetHidDelegate() override;
|
||||
|
||||
device::GeolocationManager* GetGeolocationManager() override;
|
||||
|
||||
protected:
|
||||
@@ -309,6 +312,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
||||
std::unique_ptr<ElectronSerialDelegate> serial_delegate_;
|
||||
std::unique_ptr<ElectronBluetoothDelegate> bluetooth_delegate_;
|
||||
std::unique_ptr<ElectronFontAccessDelegate> font_access_delegate_;
|
||||
std::unique_ptr<ElectronHidDelegate> hid_delegate_;
|
||||
|
||||
#if defined(OS_MAC)
|
||||
ElectronBrowserMainParts* browser_main_parts_ = nullptr;
|
||||
|
||||
@@ -17,9 +17,17 @@
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
#include "shell/browser/electron_browser_client.h"
|
||||
#include "shell/browser/electron_browser_main_parts.h"
|
||||
#include "shell/browser/hid/hid_chooser_context.h"
|
||||
#include "shell/browser/web_contents_permission_helper.h"
|
||||
#include "shell/browser/web_contents_preferences.h"
|
||||
#include "shell/common/gin_converters/content_converter.h"
|
||||
#include "shell/common/gin_converters/frame_converter.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/gin_helper/event_emitter_caller.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
@@ -117,6 +125,11 @@ void ElectronPermissionManager::SetPermissionCheckHandler(
|
||||
check_handler_ = handler;
|
||||
}
|
||||
|
||||
void ElectronPermissionManager::SetDevicePermissionHandler(
|
||||
const DeviceCheckHandler& handler) {
|
||||
device_permission_handler_ = handler;
|
||||
}
|
||||
|
||||
void ElectronPermissionManager::RequestPermission(
|
||||
content::PermissionType permission,
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
@@ -282,6 +295,71 @@ bool ElectronPermissionManager::CheckPermissionWithDetails(
|
||||
mutable_details);
|
||||
}
|
||||
|
||||
bool ElectronPermissionManager::CheckDevicePermission(
|
||||
content::PermissionType permission,
|
||||
const url::Origin& origin,
|
||||
const base::Value* device,
|
||||
content::RenderFrameHost* render_frame_host) const {
|
||||
auto* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||
api::WebContents* api_web_contents = api::WebContents::From(web_contents);
|
||||
if (device_permission_handler_.is_null()) {
|
||||
if (api_web_contents) {
|
||||
std::vector<base::Value> granted_devices =
|
||||
api_web_contents->GetGrantedDevices(origin, permission,
|
||||
render_frame_host);
|
||||
|
||||
for (const auto& granted_device : granted_devices) {
|
||||
if (permission ==
|
||||
static_cast<content::PermissionType>(
|
||||
WebContentsPermissionHelper::PermissionType::HID)) {
|
||||
if (device->FindIntKey(kHidVendorIdKey) !=
|
||||
granted_device.FindIntKey(kHidVendorIdKey) ||
|
||||
device->FindIntKey(kHidProductIdKey) !=
|
||||
granted_device.FindIntKey(kHidProductIdKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto* serial_number =
|
||||
granted_device.FindStringKey(kHidSerialNumberKey);
|
||||
const auto* device_serial_number =
|
||||
device->FindStringKey(kHidSerialNumberKey);
|
||||
|
||||
if (serial_number && device_serial_number &&
|
||||
*device_serial_number == *serial_number)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Object> details = gin::DataObjectBuilder(isolate)
|
||||
.Set("deviceType", permission)
|
||||
.Set("origin", origin.Serialize())
|
||||
.Set("device", device->Clone())
|
||||
.Set("frame", render_frame_host)
|
||||
.Build();
|
||||
return device_permission_handler_.Run(details);
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronPermissionManager::GrantDevicePermission(
|
||||
content::PermissionType permission,
|
||||
const url::Origin& origin,
|
||||
const base::Value* device,
|
||||
content::RenderFrameHost* render_frame_host) const {
|
||||
if (device_permission_handler_.is_null()) {
|
||||
auto* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||
api::WebContents* api_web_contents = api::WebContents::From(web_contents);
|
||||
if (api_web_contents)
|
||||
api_web_contents->GrantDevicePermission(origin, device, permission,
|
||||
render_frame_host);
|
||||
}
|
||||
}
|
||||
|
||||
blink::mojom::PermissionStatus
|
||||
ElectronPermissionManager::GetPermissionStatusForFrame(
|
||||
content::PermissionType permission,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "base/callback.h"
|
||||
#include "base/containers/id_map.h"
|
||||
#include "content/public/browser/permission_controller_delegate.h"
|
||||
#include "gin/dictionary.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
@@ -42,9 +43,13 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
|
||||
const GURL& requesting_origin,
|
||||
const base::Value&)>;
|
||||
|
||||
using DeviceCheckHandler =
|
||||
base::RepeatingCallback<bool(const v8::Local<v8::Object>&)>;
|
||||
|
||||
// Handler to dispatch permission requests in JS.
|
||||
void SetPermissionRequestHandler(const RequestHandler& handler);
|
||||
void SetPermissionCheckHandler(const CheckHandler& handler);
|
||||
void SetDevicePermissionHandler(const DeviceCheckHandler& handler);
|
||||
|
||||
// content::PermissionControllerDelegate:
|
||||
void RequestPermission(content::PermissionType permission,
|
||||
@@ -81,6 +86,16 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
|
||||
const GURL& requesting_origin,
|
||||
const base::DictionaryValue* details) const;
|
||||
|
||||
bool CheckDevicePermission(content::PermissionType permission,
|
||||
const url::Origin& origin,
|
||||
const base::Value* object,
|
||||
content::RenderFrameHost* render_frame_host) const;
|
||||
|
||||
void GrantDevicePermission(content::PermissionType permission,
|
||||
const url::Origin& origin,
|
||||
const base::Value* object,
|
||||
content::RenderFrameHost* render_frame_host) const;
|
||||
|
||||
protected:
|
||||
void OnPermissionResponse(int request_id,
|
||||
int permission_id,
|
||||
@@ -108,6 +123,7 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
|
||||
|
||||
RequestHandler request_handler_;
|
||||
CheckHandler check_handler_;
|
||||
DeviceCheckHandler device_permission_handler_;
|
||||
|
||||
PendingRequestsMap pending_requests_;
|
||||
|
||||
|
||||
163
shell/browser/hid/electron_hid_delegate.cc
Normal file
163
shell/browser/hid/electron_hid_delegate.cc
Normal file
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2021 Microsoft, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/hid/electron_hid_delegate.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "shell/browser/hid/hid_chooser_context.h"
|
||||
#include "shell/browser/hid/hid_chooser_context_factory.h"
|
||||
#include "shell/browser/hid/hid_chooser_controller.h"
|
||||
#include "shell/browser/web_contents_permission_helper.h"
|
||||
|
||||
namespace {
|
||||
|
||||
electron::HidChooserContext* GetChooserContext(
|
||||
content::RenderFrameHost* frame) {
|
||||
auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
|
||||
auto* browser_context = web_contents->GetBrowserContext();
|
||||
return electron::HidChooserContextFactory::GetForBrowserContext(
|
||||
browser_context);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace electron {
|
||||
|
||||
ElectronHidDelegate::ElectronHidDelegate() = default;
|
||||
|
||||
ElectronHidDelegate::~ElectronHidDelegate() = default;
|
||||
|
||||
std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
||||
content::HidChooser::Callback callback) {
|
||||
electron::HidChooserContext* chooser_context =
|
||||
GetChooserContext(render_frame_host);
|
||||
if (!device_observation_.IsObserving())
|
||||
device_observation_.Observe(chooser_context);
|
||||
|
||||
HidChooserController* controller = ControllerForFrame(render_frame_host);
|
||||
if (controller) {
|
||||
DeleteControllerForFrame(render_frame_host);
|
||||
}
|
||||
AddControllerForFrame(render_frame_host, std::move(filters),
|
||||
std::move(callback));
|
||||
|
||||
// Return a nullptr because the return value isn't used for anything, eg
|
||||
// there is no mechanism to cancel navigator.hid.requestDevice(). The return
|
||||
// value is simply used in Chromium to cleanup the chooser UI once the serial
|
||||
// service is destroyed.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ElectronHidDelegate::CanRequestDevicePermission(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
auto* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||
auto* permission_helper =
|
||||
WebContentsPermissionHelper::FromWebContents(web_contents);
|
||||
return permission_helper->CheckHIDAccessPermission(
|
||||
web_contents->GetMainFrame()->GetLastCommittedOrigin());
|
||||
}
|
||||
|
||||
bool ElectronHidDelegate::HasDevicePermission(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const device::mojom::HidDeviceInfo& device) {
|
||||
auto* chooser_context = GetChooserContext(render_frame_host);
|
||||
const auto& origin =
|
||||
render_frame_host->GetMainFrame()->GetLastCommittedOrigin();
|
||||
return chooser_context->HasDevicePermission(origin, device,
|
||||
render_frame_host);
|
||||
}
|
||||
|
||||
device::mojom::HidManager* ElectronHidDelegate::GetHidManager(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
auto* chooser_context = GetChooserContext(render_frame_host);
|
||||
return chooser_context->GetHidManager();
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::AddObserver(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
Observer* observer) {
|
||||
observer_list_.AddObserver(observer);
|
||||
auto* chooser_context = GetChooserContext(render_frame_host);
|
||||
if (!device_observation_.IsObserving())
|
||||
device_observation_.Observe(chooser_context);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::RemoveObserver(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
content::HidDelegate::Observer* observer) {
|
||||
observer_list_.RemoveObserver(observer);
|
||||
}
|
||||
|
||||
const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const std::string& guid) {
|
||||
auto* chooser_context = GetChooserContext(render_frame_host);
|
||||
return chooser_context->GetDeviceInfo(guid);
|
||||
}
|
||||
|
||||
bool ElectronHidDelegate::IsFidoAllowedForOrigin(const url::Origin& origin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnDeviceAdded(
|
||||
const device::mojom::HidDeviceInfo& device_info) {
|
||||
for (auto& observer : observer_list_)
|
||||
observer.OnDeviceAdded(device_info);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnDeviceRemoved(
|
||||
const device::mojom::HidDeviceInfo& device_info) {
|
||||
for (auto& observer : observer_list_)
|
||||
observer.OnDeviceRemoved(device_info);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnDeviceChanged(
|
||||
const device::mojom::HidDeviceInfo& device_info) {
|
||||
for (auto& observer : observer_list_)
|
||||
observer.OnDeviceChanged(device_info);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnHidManagerConnectionError() {
|
||||
device_observation_.Reset();
|
||||
|
||||
for (auto& observer : observer_list_)
|
||||
observer.OnHidManagerConnectionError();
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnHidChooserContextShutdown() {
|
||||
device_observation_.Reset();
|
||||
}
|
||||
|
||||
HidChooserController* ElectronHidDelegate::ControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
auto mapping = controller_map_.find(render_frame_host);
|
||||
return mapping == controller_map_.end() ? nullptr : mapping->second.get();
|
||||
}
|
||||
|
||||
HidChooserController* ElectronHidDelegate::AddControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
||||
content::HidChooser::Callback callback) {
|
||||
auto* web_contents =
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
||||
auto controller = std::make_unique<HidChooserController>(
|
||||
render_frame_host, std::move(filters), std::move(callback), web_contents,
|
||||
weak_factory_.GetWeakPtr());
|
||||
controller_map_.insert(
|
||||
std::make_pair(render_frame_host, std::move(controller)));
|
||||
return ControllerForFrame(render_frame_host);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::DeleteControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
controller_map_.erase(render_frame_host);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
84
shell/browser/hid/electron_hid_delegate.h
Normal file
84
shell/browser/hid/electron_hid_delegate.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_HID_ELECTRON_HID_DELEGATE_H_
|
||||
#define SHELL_BROWSER_HID_ELECTRON_HID_DELEGATE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/observer_list.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "content/public/browser/hid_delegate.h"
|
||||
#include "shell/browser/hid/hid_chooser_context.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class HidChooserController;
|
||||
|
||||
class ElectronHidDelegate : public content::HidDelegate,
|
||||
public HidChooserContext::DeviceObserver {
|
||||
public:
|
||||
ElectronHidDelegate();
|
||||
ElectronHidDelegate(ElectronHidDelegate&) = delete;
|
||||
ElectronHidDelegate& operator=(ElectronHidDelegate&) = delete;
|
||||
~ElectronHidDelegate() override;
|
||||
|
||||
// content::HidDelegate:
|
||||
std::unique_ptr<content::HidChooser> RunChooser(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
||||
content::HidChooser::Callback callback) override;
|
||||
bool CanRequestDevicePermission(
|
||||
content::RenderFrameHost* render_frame_host) override;
|
||||
bool HasDevicePermission(content::RenderFrameHost* render_frame_host,
|
||||
const device::mojom::HidDeviceInfo& device) override;
|
||||
device::mojom::HidManager* GetHidManager(
|
||||
content::RenderFrameHost* render_frame_host) override;
|
||||
void AddObserver(content::RenderFrameHost* render_frame_host,
|
||||
content::HidDelegate::Observer* observer) override;
|
||||
void RemoveObserver(content::RenderFrameHost* render_frame_host,
|
||||
content::HidDelegate::Observer* observer) override;
|
||||
const device::mojom::HidDeviceInfo* GetDeviceInfo(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const std::string& guid) override;
|
||||
bool IsFidoAllowedForOrigin(const url::Origin& origin) override;
|
||||
|
||||
// HidChooserContext::DeviceObserver:
|
||||
void OnDeviceAdded(const device::mojom::HidDeviceInfo&) override;
|
||||
void OnDeviceRemoved(const device::mojom::HidDeviceInfo&) override;
|
||||
void OnDeviceChanged(const device::mojom::HidDeviceInfo&) override;
|
||||
void OnHidManagerConnectionError() override;
|
||||
void OnHidChooserContextShutdown() override;
|
||||
|
||||
void DeleteControllerForFrame(content::RenderFrameHost* render_frame_host);
|
||||
|
||||
private:
|
||||
HidChooserController* ControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host);
|
||||
|
||||
HidChooserController* AddControllerForFrame(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
||||
content::HidChooser::Callback callback);
|
||||
|
||||
base::ScopedObservation<HidChooserContext,
|
||||
HidChooserContext::DeviceObserver,
|
||||
&HidChooserContext::AddDeviceObserver,
|
||||
&HidChooserContext::RemoveDeviceObserver>
|
||||
device_observation_{this};
|
||||
base::ObserverList<content::HidDelegate::Observer> observer_list_;
|
||||
|
||||
std::unordered_map<content::RenderFrameHost*,
|
||||
std::unique_ptr<HidChooserController>>
|
||||
controller_map_;
|
||||
|
||||
base::WeakPtrFactory<ElectronHidDelegate> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_HID_ELECTRON_HID_DELEGATE_H_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user