mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
77 Commits
v15.0.0-be
...
v15.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b51f82c73f | ||
|
|
e19f7fbaf7 | ||
|
|
955d6c82ff | ||
|
|
5fbb4fd8c9 | ||
|
|
9407a3ee09 | ||
|
|
86bb866ffb | ||
|
|
2b22f02354 | ||
|
|
c3ee7b4bd1 | ||
|
|
d788d817ee | ||
|
|
6fbd50ab37 | ||
|
|
097fd4c206 | ||
|
|
844d104d06 | ||
|
|
b62cef5a01 | ||
|
|
4cdb2c4bd4 | ||
|
|
bc655b8eaf | ||
|
|
4891e92f32 | ||
|
|
62b88b2a0b | ||
|
|
2cbfd19d94 | ||
|
|
da132e0289 | ||
|
|
622b79cd9d | ||
|
|
2e91d6e10c | ||
|
|
4a495542cb | ||
|
|
45813a0342 | ||
|
|
b55362b588 | ||
|
|
b39b6cde8c | ||
|
|
6919520c88 | ||
|
|
71fcb8d8f8 | ||
|
|
ee23788acf | ||
|
|
52196791b9 | ||
|
|
6dbf0c52ec | ||
|
|
5d95688753 | ||
|
|
6e60fa6d59 | ||
|
|
d072d408c0 | ||
|
|
cde7f04409 | ||
|
|
e143f654ca | ||
|
|
cc62c4a33a | ||
|
|
c3e6746fa9 | ||
|
|
436c3ba644 | ||
|
|
599babae00 | ||
|
|
5f7da14447 | ||
|
|
dc6f951f43 | ||
|
|
f4fa6c0cf4 | ||
|
|
98de50451a | ||
|
|
c78ab7a1f2 | ||
|
|
0928f322fa | ||
|
|
c6c59bf0b3 | ||
|
|
9d3bcfc559 | ||
|
|
fb2473bb5e | ||
|
|
4664b5da57 | ||
|
|
18c5401d08 | ||
|
|
3f81697e48 | ||
|
|
a00a43ba25 | ||
|
|
ce1435be30 | ||
|
|
c625b77bde | ||
|
|
4969c4ab19 | ||
|
|
9e1736f5bc | ||
|
|
200e26c602 | ||
|
|
bbc4545742 | ||
|
|
9874e940ab | ||
|
|
304453fa5c | ||
|
|
16a32a30d9 | ||
|
|
a227474809 | ||
|
|
3a2055ebba | ||
|
|
87042e1493 | ||
|
|
86f3aa0376 | ||
|
|
33eb6263c0 | ||
|
|
05d5ee4486 | ||
|
|
98845392d8 | ||
|
|
946baab086 | ||
|
|
e3aeba3581 | ||
|
|
e03c11598e | ||
|
|
3b1c9dfc54 | ||
|
|
2724456dc7 | ||
|
|
9333b091f5 | ||
|
|
cb12c4e392 | ||
|
|
1d38e14e92 | ||
|
|
9f39865999 |
@@ -1209,6 +1209,9 @@ steps-tests: &steps-tests
|
||||
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
|
||||
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging)
|
||||
else
|
||||
if [ "$TARGET_ARCH" == "ia32" ]; then
|
||||
npm_config_arch=x64 node electron/node_modules/dugite/script/download-git.js
|
||||
fi
|
||||
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split --split-by=timings))
|
||||
(cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split --split-by=timings))
|
||||
fi
|
||||
|
||||
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
.gitignore
vendored
1
.gitignore
vendored
@@ -26,6 +26,7 @@ compile_commands.json
|
||||
# npm package
|
||||
/npm/dist
|
||||
/npm/path.txt
|
||||
/npm/checksums.json
|
||||
|
||||
.npmrc
|
||||
|
||||
|
||||
10
BUILD.gn
10
BUILD.gn
@@ -361,6 +361,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",
|
||||
@@ -1006,6 +1007,12 @@ if (is_mac) {
|
||||
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
asar_hashed_info_plist("electron_app_plist") {
|
||||
keys = [ "DEFAULT_APP_ASAR_HEADER_SHA" ]
|
||||
hash_targets = [ ":default_app_asar_header_hash" ]
|
||||
plist_file = "shell/browser/resources/mac/Info.plist"
|
||||
}
|
||||
|
||||
mac_app_bundle("electron_app") {
|
||||
output_name = electron_product_name
|
||||
sources = filenames.app_sources
|
||||
@@ -1013,6 +1020,7 @@ if (is_mac) {
|
||||
include_dirs = [ "." ]
|
||||
deps = [
|
||||
":electron_app_framework_bundle_data",
|
||||
":electron_app_plist",
|
||||
":electron_app_resources",
|
||||
":electron_fuses",
|
||||
"//base",
|
||||
@@ -1021,7 +1029,7 @@ if (is_mac) {
|
||||
if (is_mas_build) {
|
||||
deps += [ ":electron_login_helper_app" ]
|
||||
}
|
||||
info_plist = "shell/browser/resources/mac/Info.plist"
|
||||
info_plist_target = ":electron_app_plist"
|
||||
extra_substitutions = [
|
||||
"ELECTRON_BUNDLE_ID=$electron_mac_bundle_id",
|
||||
"ELECTRON_VERSION=$electron_version",
|
||||
|
||||
@@ -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
@@ -15,7 +15,7 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'94.0.4606.31',
|
||||
'94.0.4606.61',
|
||||
'node_version':
|
||||
'v16.5.0',
|
||||
'nan_version':
|
||||
|
||||
@@ -1 +1 @@
|
||||
15.0.0-beta.3
|
||||
15.1.1
|
||||
@@ -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).
|
||||
|
||||
@@ -98,6 +98,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
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ is_electron_build = true
|
||||
root_extra_deps = [ "//electron" ]
|
||||
|
||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
|
||||
node_module_version = 89
|
||||
node_module_version = 98
|
||||
|
||||
v8_promise_internal_field_count = 1
|
||||
v8_typed_array_max_size_in_heap = 0
|
||||
@@ -33,7 +33,3 @@ is_cfi = false
|
||||
allow_runtime_configurable_key_storage = true
|
||||
|
||||
enable_cet_shadow_stack = false
|
||||
|
||||
# TODO(deepak1556): remove once https://bugs.chromium.org/p/chromium/issues/detail?id=1241610
|
||||
# is fixed.
|
||||
enable_blink_heap_use_v8_oilpan = false
|
||||
|
||||
@@ -57,4 +57,42 @@ template("asar") {
|
||||
rebase_path(outputs[0]),
|
||||
]
|
||||
}
|
||||
|
||||
node_action(target_name + "_header_hash") {
|
||||
invoker_out = invoker.outputs
|
||||
|
||||
deps = [ ":" + invoker.target_name ]
|
||||
sources = invoker.outputs
|
||||
|
||||
script = "//electron/script/gn-asar-hash.js"
|
||||
outputs = [ "$target_gen_dir/asar_hashes/$target_name.hash" ]
|
||||
|
||||
args = [
|
||||
rebase_path(invoker_out[0]),
|
||||
rebase_path(outputs[0]),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template("asar_hashed_info_plist") {
|
||||
node_action(target_name) {
|
||||
assert(defined(invoker.plist_file),
|
||||
"Need plist_file to add hashed assets to")
|
||||
assert(defined(invoker.keys), "Need keys to replace with asset hash")
|
||||
assert(defined(invoker.hash_targets), "Need hash_targets to read hash from")
|
||||
|
||||
deps = invoker.hash_targets
|
||||
|
||||
script = "//electron/script/gn-plist-but-with-hashes.js"
|
||||
inputs = [ invoker.plist_file ]
|
||||
outputs = [ "$target_gen_dir/hashed_plists/$target_name.plist" ]
|
||||
hash_files = []
|
||||
foreach(hash_target, invoker.hash_targets) {
|
||||
hash_files += get_target_outputs(hash_target)
|
||||
}
|
||||
args = [
|
||||
rebase_path(invoker.plist_file),
|
||||
rebase_path(outputs[0]),
|
||||
] + invoker.keys + rebase_path(hash_files)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,7 @@
|
||||
"run_as_node": "1",
|
||||
"cookie_encryption": "0",
|
||||
"node_options": "1",
|
||||
"node_cli_inspect": "1"
|
||||
"node_cli_inspect": "1",
|
||||
"embedded_asar_integrity_validation": "0",
|
||||
"only_load_app_from_asar": "0"
|
||||
}
|
||||
|
||||
@@ -314,17 +314,13 @@ source_set("plugins") {
|
||||
sources += [
|
||||
"//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc",
|
||||
"//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.cc",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.h",
|
||||
"//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc",
|
||||
"//chrome/renderer/pepper/pepper_shared_memory_message_filter.h",
|
||||
]
|
||||
if (enable_pdf_viewer) {
|
||||
sources += [
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.cc",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.h",
|
||||
]
|
||||
if (enable_pdf_viewer) {
|
||||
deps += [ "//components/pdf/renderer" ]
|
||||
}
|
||||
deps += [ "//components/pdf/renderer" ]
|
||||
}
|
||||
deps += [
|
||||
"//components/strings",
|
||||
|
||||
@@ -277,6 +277,7 @@ Returns:
|
||||
* `certificate` [Certificate](structures/certificate.md)
|
||||
* `callback` Function
|
||||
* `isTrusted` Boolean - Whether to consider the certificate as trusted
|
||||
* `isMainFrame` Boolean
|
||||
|
||||
Emitted when failed to verify the `certificate` for `url`, to trust the
|
||||
certificate you should prevent the default behavior with
|
||||
@@ -1071,7 +1072,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
|
||||
|
||||
@@ -43,7 +43,7 @@ The installer generated with Squirrel will create a shortcut icon with an
|
||||
same ID for your app with `app.setAppUserModelId` API, otherwise Windows will
|
||||
not be able to pin your app properly in task bar.
|
||||
|
||||
Unlike Squirrel.Mac, Windows can host updates on S3 or any other static file host.
|
||||
Like Squirrel.Mac, Windows can host updates on S3 or any other static file host.
|
||||
You can read the documents of [Squirrel.Windows][squirrel-windows] to get more details
|
||||
about how Squirrel.Windows works.
|
||||
|
||||
|
||||
@@ -22,12 +22,13 @@ win.loadFile('index.html')
|
||||
To create a window without chrome, or a transparent window in arbitrary shape,
|
||||
you can use the [Frameless Window](frameless-window.md) API.
|
||||
|
||||
## Showing window gracefully
|
||||
## Showing the window gracefully
|
||||
|
||||
When loading a page in the window directly, users may see the page load incrementally, which is not a good experience for a native app. To make the window display
|
||||
without visual flash, there are two solutions for different situations.
|
||||
When loading a page in the window directly, users may see the page load incrementally,
|
||||
which is not a good experience for a native app. To make the window display
|
||||
without a visual flash, there are two solutions for different situations.
|
||||
|
||||
## Using `ready-to-show` event
|
||||
### Using the `ready-to-show` event
|
||||
|
||||
While loading the page, the `ready-to-show` event will be emitted when the renderer
|
||||
process has rendered the page for the first time if the window has not been shown yet. Showing
|
||||
@@ -48,7 +49,7 @@ event.
|
||||
Please note that using this event implies that the renderer will be considered "visible" and
|
||||
paint even though `show` is false. This event will never fire if you use `paintWhenInitiallyHidden: false`
|
||||
|
||||
## Setting `backgroundColor`
|
||||
### Setting the `backgroundColor` property
|
||||
|
||||
For a complex app, the `ready-to-show` event could be emitted too late, making
|
||||
the app feel slow. In this case, it is recommended to show the window
|
||||
@@ -987,7 +988,7 @@ the player itself we would call this function with arguments of 16/9 and
|
||||
are within the content view--only that they exist. Sum any extra width and
|
||||
height areas you have within the overall content view.
|
||||
|
||||
The aspect ratio is not respected when window is resized programmingly with
|
||||
The aspect ratio is not respected when window is resized programmatically with
|
||||
APIs like `win.setSize`.
|
||||
|
||||
#### `win.setBackgroundColor(backgroundColor)`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -86,8 +86,8 @@ available from next tick of the process.
|
||||
const { session } = require('electron')
|
||||
session.defaultSession.on('will-download', (event, item, webContents) => {
|
||||
event.preventDefault()
|
||||
require('request')(item.getURL(), (data) => {
|
||||
require('fs').writeFileSync('/somewhere', data)
|
||||
require('got')(item.getURL()).then((response) => {
|
||||
require('fs').writeFileSync('/somewhere', response.body)
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -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:
|
||||
@@ -524,7 +614,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.
|
||||
@@ -552,6 +642,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.
|
||||
@@ -530,6 +530,7 @@ Returns:
|
||||
* `certificate` [Certificate](structures/certificate.md)
|
||||
* `callback` Function
|
||||
* `isTrusted` Boolean - Indicates whether the certificate can be considered trusted.
|
||||
* `isMainFrame` Boolean
|
||||
|
||||
Emitted when failed to verify the `certificate` for `url`.
|
||||
|
||||
@@ -650,6 +651,7 @@ Returns:
|
||||
* `params` Object
|
||||
* `x` Integer - x coordinate.
|
||||
* `y` Integer - y coordinate.
|
||||
* `frame` WebFrameMain - Frame from which the context menu was invoked.
|
||||
* `linkURL` String - URL of the link that encloses the node the context menu
|
||||
was invoked on.
|
||||
* `linkText` String - Text associated with the link. May be an empty
|
||||
@@ -1825,7 +1827,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.
|
||||
|
||||
|
||||
@@ -575,7 +575,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;
|
||||
|
||||
118
docs/glossary.md
118
docs/glossary.md
@@ -4,15 +4,39 @@ This page defines some terminology that is commonly used in Electron development
|
||||
|
||||
### ASAR
|
||||
|
||||
ASAR stands for Atom Shell Archive Format. An [asar][asar] archive is a simple
|
||||
ASAR stands for Atom Shell Archive Format. An [asar] archive is a simple
|
||||
`tar`-like format that concatenates files into a single file. Electron can read
|
||||
arbitrary files from it without unpacking the whole file.
|
||||
|
||||
The ASAR format was created primarily to improve performance on Windows... TODO
|
||||
The ASAR format was created primarily to improve performance on Windows when
|
||||
reading large quantities of small files (e.g. when loading your app's JavaScript
|
||||
dependency tree from `node_modules`).
|
||||
|
||||
### code signing
|
||||
|
||||
Code signing is a process where an app developer digitally signs their code to
|
||||
ensure that it hasn't been tampered with after packaging. Both Windows and
|
||||
macOS implement their own version of code signing. As a desktop app developer,
|
||||
it's important that you sign your code if you plan on distributing it to the
|
||||
general public.
|
||||
|
||||
For more information, read the [Code Signing] tutorial.
|
||||
|
||||
### context isolation
|
||||
|
||||
Context isolation is a security measure in Electron that ensures that your
|
||||
preload script cannot leak privileged Electron or Node.js APIs to the web
|
||||
contents in your renderer process. With context isolation enabled, the
|
||||
only way to expose APIs from your preload script is through the
|
||||
`contextBridge` API.
|
||||
|
||||
For more information, read the [Context Isolation] tutorial.
|
||||
|
||||
See also: [preload script](#preload-script), [renderer process](#renderer-process)
|
||||
|
||||
### CRT
|
||||
|
||||
The C Run-time Library (CRT) is the part of the C++ Standard Library that
|
||||
The C Runtime Library (CRT) is the part of the C++ Standard Library that
|
||||
incorporates the ISO C99 standard library. The Visual C++ libraries that
|
||||
implement the CRT support native code development, and both mixed native and
|
||||
managed code, and pure managed code for .NET development.
|
||||
@@ -20,8 +44,7 @@ managed code, and pure managed code for .NET development.
|
||||
### DMG
|
||||
|
||||
An Apple Disk Image is a packaging format used by macOS. DMG files are
|
||||
commonly used for distributing application "installers". [electron-builder]
|
||||
supports `dmg` as a build target.
|
||||
commonly used for distributing application "installers".
|
||||
|
||||
### IME
|
||||
|
||||
@@ -31,19 +54,15 @@ keyboards to input Chinese, Japanese, Korean and Indic characters.
|
||||
|
||||
### IDL
|
||||
|
||||
Interface description language. Write function signatures and data types in a format that can be used to generate interfaces in Java, C++, JavaScript, etc.
|
||||
Interface description language. Write function signatures and data types in a
|
||||
format that can be used to generate interfaces in Java, C++, JavaScript, etc.
|
||||
|
||||
### IPC
|
||||
|
||||
IPC stands for Inter-Process Communication. Electron uses IPC to send
|
||||
serialized JSON messages between the [main] and [renderer] processes.
|
||||
IPC stands for inter-process communication. Electron uses IPC to send
|
||||
serialized JSON messages between the main and renderer processes.
|
||||
|
||||
### libchromiumcontent
|
||||
|
||||
A shared library that includes the [Chromium Content module] and all its
|
||||
dependencies (e.g., Blink, [V8], etc.). Also referred to as "libcc".
|
||||
|
||||
- [github.com/electron/libchromiumcontent](https://github.com/electron/libchromiumcontent)
|
||||
see also: [main process](#main-process), [renderer process](#renderer-process)
|
||||
|
||||
### main process
|
||||
|
||||
@@ -68,10 +87,22 @@ MAS, see the [Mac App Store Submission Guide].
|
||||
|
||||
### Mojo
|
||||
|
||||
An IPC system for communicating intra- or inter-process, and that's important because Chrome is keen on being able to split its work into separate processes or not, depending on memory pressures etc.
|
||||
An IPC system for communicating intra- or inter-process, and that's important
|
||||
because Chrome is keen on being able to split its work into separate processes
|
||||
or not, depending on memory pressures etc.
|
||||
|
||||
See https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md
|
||||
|
||||
See also: [IPC](#ipc)
|
||||
|
||||
### MSI
|
||||
|
||||
On Windows, MSI packages are used by the Windows Installer
|
||||
(also known as Microsoft Installer) service to install and configure
|
||||
applications.
|
||||
|
||||
More information can be found in [Microsoft's documentation][msi].
|
||||
|
||||
### native modules
|
||||
|
||||
Native modules (also called [addons] in
|
||||
@@ -85,22 +116,33 @@ likely to use a different V8 version from the Node binary installed in your
|
||||
system, you have to manually specify the location of Electron’s headers when
|
||||
building native modules.
|
||||
|
||||
See also [Using Native Node Modules].
|
||||
For more information, read the [Native Node Modules] tutorial.
|
||||
|
||||
### NSIS
|
||||
### notarization
|
||||
|
||||
Nullsoft Scriptable Install System is a script-driven Installer
|
||||
authoring tool for Microsoft Windows. It is released under a combination of
|
||||
free software licenses, and is a widely-used alternative to commercial
|
||||
proprietary products like InstallShield. [electron-builder] supports NSIS
|
||||
as a build target.
|
||||
Notarization is a macOS-specific process where a developer can send a
|
||||
code-signed app to Apple servers to get verified for malicious
|
||||
components through an automated service.
|
||||
|
||||
See also: [code signing](#code-signing)
|
||||
|
||||
### OSR
|
||||
|
||||
OSR (Off-screen rendering) can be used for loading heavy page in
|
||||
OSR (offscreen rendering) can be used for loading heavy page in
|
||||
background and then displaying it after (it will be much faster).
|
||||
It allows you to render page without showing it on screen.
|
||||
|
||||
For more information, read the [Offscreen Rendering][osr] tutorial.
|
||||
|
||||
### preload script
|
||||
|
||||
Preload scripts contain code that executes in a renderer process
|
||||
before its web contents begin loading. These scripts run within
|
||||
the renderer context, but are granted more privileges by having
|
||||
access to Node.js APIs.
|
||||
|
||||
See also: [renderer process](#renderer-process), [context isolation](#context-isolation)
|
||||
|
||||
### process
|
||||
|
||||
A process is an instance of a computer program that is being executed. Electron
|
||||
@@ -120,13 +162,17 @@ The renderer process is a browser window in your app. Unlike the main process,
|
||||
there can be multiple of these and each is run in a separate process.
|
||||
They can also be hidden.
|
||||
|
||||
In normal browsers, web pages usually run in a sandboxed environment and are not
|
||||
allowed access to native resources. Electron users, however, have the power to
|
||||
use Node.js APIs in web pages allowing lower level operating system
|
||||
interactions.
|
||||
|
||||
See also: [process](#process), [main process](#main-process)
|
||||
|
||||
### sandbox
|
||||
|
||||
The sandbox is a security feature inherited from Chromium that restricts
|
||||
your renderer processes to a limited set of permissions.
|
||||
|
||||
For more information, read the [Process Sandboxing] tutorial.
|
||||
|
||||
See also: [process](#process)
|
||||
|
||||
### Squirrel
|
||||
|
||||
Squirrel is an open-source framework that enables Electron apps to update
|
||||
@@ -174,13 +220,15 @@ embedded content.
|
||||
|
||||
[addons]: https://nodejs.org/api/addons.html
|
||||
[asar]: https://github.com/electron/asar
|
||||
[autoUpdater]: api/auto-updater.md
|
||||
[Chromium Content module]: https://www.chromium.org/developers/content-module
|
||||
[electron-builder]: https://github.com/electron-userland/electron-builder
|
||||
[libchromiumcontent]: #libchromiumcontent
|
||||
[Mac App Store Submission Guide]: tutorial/mac-app-store-submission-guide.md
|
||||
[autoupdater]: api/auto-updater.md
|
||||
[code signing]: tutorial/code-signing.md
|
||||
[context isolation]: tutorial/context-isolation.md
|
||||
[mac app store submission guide]: tutorial/mac-app-store-submission-guide.md
|
||||
[main]: #main-process
|
||||
[msi]: https://docs.microsoft.com/en-us/windows/win32/msi/windows-installer-portal
|
||||
[offscreen rendering]: tutorial/offscreen-rendering.md
|
||||
[process sandboxing]: tutorial/sandbox.md
|
||||
[renderer]: #renderer-process
|
||||
[userland]: #userland
|
||||
[Using Native Node Modules]: tutorial/using-native-node-modules.md
|
||||
[V8]: #v8
|
||||
[using native node modules]: tutorial/using-native-node-modules.md
|
||||
[v8]: #v8
|
||||
|
||||
@@ -4,39 +4,38 @@
|
||||
|
||||
Context Isolation is a feature that ensures that both your `preload` scripts and Electron's internal logic run in a separate context to the website you load in a [`webContents`](../api/web-contents.md). This is important for security purposes as it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to.
|
||||
|
||||
This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled `window.hello` will be undefined if the website tries to access it.
|
||||
This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled, `window.hello` will be undefined if the website tries to access it.
|
||||
|
||||
Every single application should have context isolation enabled and from Electron 12 it will be enabled by default.
|
||||
|
||||
## How do I enable it?
|
||||
|
||||
From Electron 12, it will be enabled by default. For lower versions it is an option in the `webPreferences` option when constructing `new BrowserWindow`'s.
|
||||
|
||||
```javascript
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
contextIsolation: true
|
||||
}
|
||||
})
|
||||
```
|
||||
Context isolation has been enabled by default since Electron 12, and it is a recommended security setting for _all applications_.
|
||||
|
||||
## Migration
|
||||
|
||||
> I used to provide APIs from my preload script using `window.X = apiObject` now what?
|
||||
> Without context isolation, I used to provide APIs from my preload script using `window.X = apiObject`. Now what?
|
||||
|
||||
Exposing APIs from your preload script to the loaded website is a common usecase and there is a dedicated module in Electron to help you do this in a painless way.
|
||||
### Before: context isolation disabled
|
||||
|
||||
**Before: With context isolation disabled**
|
||||
Exposing APIs from your preload script to a loaded website in the renderer process is a common use-case. With context isolation disabled, your preload script would share a common global `window` object with the renderer. You could then attach arbitrary properties to a preload script:
|
||||
|
||||
```javascript
|
||||
```javascript title='preload.js'
|
||||
// preload with contextIsolation disabled
|
||||
window.myAPI = {
|
||||
doAThing: () => {}
|
||||
}
|
||||
```
|
||||
|
||||
**After: With context isolation enabled**
|
||||
The `doAThing()` function could then be used directly in the renderer process:
|
||||
|
||||
```javascript
|
||||
```javascript title='renderer.js'
|
||||
// use the exposed API in the renderer
|
||||
window.myAPI.doAThing()
|
||||
```
|
||||
|
||||
### After: context isolation enabled
|
||||
|
||||
There is a dedicated module in Electron to help you do this in a painless way. The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from your preload script's isolated context to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before.
|
||||
|
||||
```javascript title='preload.js'
|
||||
// preload with contextIsolation enabled
|
||||
const { contextBridge } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld('myAPI', {
|
||||
@@ -44,26 +43,63 @@ contextBridge.exposeInMainWorld('myAPI', {
|
||||
})
|
||||
```
|
||||
|
||||
The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from the isolated context your preload script runs in to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before.
|
||||
```javascript title='renderer.js'
|
||||
// use the exposed API in the renderer
|
||||
window.myAPI.doAThing()
|
||||
```
|
||||
|
||||
You should read the `contextBridge` documentation linked above to fully understand its limitations. For instance you can't send custom prototypes or symbols over the bridge.
|
||||
Please read the `contextBridge` documentation linked above to fully understand its limitations. For instance, you can't send custom prototypes or symbols over the bridge.
|
||||
|
||||
## Security Considerations
|
||||
## Security considerations
|
||||
|
||||
Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance this code is **unsafe**.
|
||||
Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance, this code is **unsafe**.
|
||||
|
||||
```javascript
|
||||
```javascript title='preload.js'
|
||||
// ❌ Bad code
|
||||
contextBridge.exposeInMainWorld('myAPI', {
|
||||
send: ipcRenderer.send
|
||||
})
|
||||
```
|
||||
|
||||
It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message.
|
||||
It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages, which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message.
|
||||
|
||||
```javascript
|
||||
```javascript title='preload.js'
|
||||
// ✅ Good code
|
||||
contextBridge.exposeInMainWorld('myAPI', {
|
||||
loadPreferences: () => ipcRenderer.invoke('load-prefs')
|
||||
})
|
||||
```
|
||||
|
||||
## Usage with TypeScript
|
||||
|
||||
If you're building your Electron app with TypeScript, you'll want to add types to your APIs exposed over the context bridge. The renderer's `window` object won't have the correct typings unless you extend the types with a [declaration file].
|
||||
|
||||
For example, given this `preload.ts` script:
|
||||
|
||||
```typescript title='preload.ts'
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
loadPreferences: () => ipcRenderer.invoke('load-prefs')
|
||||
})
|
||||
```
|
||||
|
||||
You can create a `renderer.d.ts` declaration file and globally augment the `Window` interface:
|
||||
|
||||
```typescript title='renderer.d.ts'
|
||||
export interface IElectronAPI {
|
||||
loadPreferences: () => Promise<void>,
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electronAPI: IElectronAPI
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Doing so will ensure that the TypeScript compiler will know about the `electronAPI` property on your global `window` object when writing scripts in your renderer process:
|
||||
|
||||
```typescript title='renderer.ts'
|
||||
window.electronAPI.loadPreferences()
|
||||
```
|
||||
|
||||
[declaration file]: https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html
|
||||
|
||||
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'
|
||||
|
||||
```
|
||||
@@ -23,5 +23,6 @@ Special notes:
|
||||
| 11.0.0 | -- | 2020-Aug-27 | 2020-Nov-17 | M87 | v12.18 |
|
||||
| 12.0.0 | -- | 2020-Nov-19 | 2021-Mar-02 | M89 | v14.16 |
|
||||
| 13.0.0 | -- | 2021-Mar-04 | 2021-May-25 | M91 | v14.16 |
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | TBD |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | TBD |
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | v14.17 |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | v16.5 |
|
||||
| 16.0.0 | -- | 2021-Sep-23 | 2021-Nov-16 | M96 | TBD |
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -90,6 +90,11 @@ ELECTRON_CUSTOM_DIR="{{ version }}"
|
||||
The above configuration will download from URLs such as
|
||||
`https://npm.taobao.org/mirrors/electron/8.0.0/electron-v8.0.0-linux-x64.zip`.
|
||||
|
||||
If your mirror serves artifacts with different checksums to the official
|
||||
Electron release you may have to set `ELECTRON_USE_REMOTE_CHECKSUMS=1` to
|
||||
force Electron to use the remote `SHASUMS256.txt` file to verify the checksum
|
||||
instead of the embedded checksums.
|
||||
|
||||
#### Cache
|
||||
|
||||
Alternatively, you can override the local cache. `@electron/get` will cache
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Launching Your Electron App From A URL In Another App
|
||||
title: Launching Your Electron App From a URL In Another App
|
||||
description: This guide will take you through the process of setting your electron app as the default handler for a specific protocol.
|
||||
slug: launch-app-from-url-in-another-app
|
||||
hide_title: true
|
||||
@@ -11,7 +11,7 @@ hide_title: true
|
||||
|
||||
<!-- ✍ Update this section if you want to provide more details -->
|
||||
|
||||
This guide will take you through the process of setting your electron app as the default
|
||||
This guide will take you through the process of setting your Electron app as the default
|
||||
handler for a specific [protocol](https://www.electronjs.org/docs/api/protocol).
|
||||
|
||||
By the end of this tutorial, we will have set our app to intercept and handle
|
||||
@@ -22,16 +22,17 @@ we will use will be "`electron-fiddle://`".
|
||||
|
||||
### Main Process (main.js)
|
||||
|
||||
First we will import the required modules from `electron`. These modules help control our application life and create a native browser window.
|
||||
First, we will import the required modules from `electron`. These modules help
|
||||
control our application lifecycle and create a native browser window.
|
||||
|
||||
```js
|
||||
```javascript
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
```
|
||||
|
||||
Next, we will proceed to register our application to handle all "`electron-fiddle://`" protocols.
|
||||
|
||||
```js
|
||||
```javascript
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
|
||||
@@ -43,8 +44,8 @@ if (process.defaultApp) {
|
||||
|
||||
We will now define the function in charge of creating our browser window and load our application's `index.html` file.
|
||||
|
||||
```js
|
||||
function createWindow () {
|
||||
```javascript
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
@@ -60,11 +61,11 @@ function createWindow () {
|
||||
|
||||
In this next step, we will create our `BrowserWindow` and tell our application how to handle an event in which an external protocol is clicked.
|
||||
|
||||
This code will be different in WindowsOS compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same electron instance. Read more about this [here](https://www.electronjs.org/docs/api/app#apprequestsingleinstancelock).
|
||||
This code will be different in Windows compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same Electron instance. Read more about this [here](https://www.electronjs.org/docs/api/app#apprequestsingleinstancelock).
|
||||
|
||||
### Windows code:
|
||||
#### Windows code:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
@@ -83,16 +84,16 @@ if (!gotTheLock) {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
// Handle the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### MacOS and Linux code:
|
||||
#### MacOS and Linux code:
|
||||
|
||||
```js
|
||||
```javascript
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
@@ -100,57 +101,101 @@ app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
// Handle the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
```
|
||||
|
||||
Finally, we will add some additional code to handle when someone closes our application
|
||||
Finally, we will add some additional code to handle when someone closes our application.
|
||||
|
||||
```js
|
||||
```javascript
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
```
|
||||
|
||||
## Important Note:
|
||||
## Important notes
|
||||
|
||||
### Packaging
|
||||
|
||||
This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS `plist` for the app is updated to include the new protocol handler. If you're using [`electron-packager`](https://github.com/electron/electron-packager) then you
|
||||
can add the flag `--extend-info` with a path to the `plist` you've created. The one for this app is below:
|
||||
On macOS and Linux, this feature will only work when your app is packaged. It will not work when
|
||||
you're launching it in development from the command-line. When you package your app you'll need to
|
||||
make sure the macOS `Info.plist` and the Linux `.desktop` files for the app are updated to include
|
||||
the new protocol handler. Some of the Electron tools for bundling and distributing apps handle
|
||||
this for you.
|
||||
|
||||
### Plist
|
||||
#### [Electron Forge](https://electronforge.io)
|
||||
|
||||
```XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
If you're using Electron Forge, adjust `packagerConfig` for macOS support, and the configuration for
|
||||
the appropriate Linux makers for Linux support, in your [Forge
|
||||
configuration](https://www.electronforge.io/configuration) _(please note the following example only
|
||||
shows the bare minimum needed to add the configuration changes)_:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {
|
||||
"protocols": [
|
||||
{
|
||||
"name": "Electron Fiddle",
|
||||
"schemes": ["electron-fiddle"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"makers": [
|
||||
{
|
||||
"name": "@electron-forge/maker-deb",
|
||||
"config": {
|
||||
"mimeType": ["x-scheme-handler/electron-fiddle"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [Electron Packager](https://github.com/electron/electron-packager)
|
||||
|
||||
For macOS support:
|
||||
|
||||
If you're using Electron Packager's API, adding support for protocol handlers is similar to how
|
||||
Electron Forge is handled, except
|
||||
`protocols` is part of the Packager options passed to the `packager` function.
|
||||
|
||||
```javascript
|
||||
const packager = require('electron-packager')
|
||||
|
||||
packager({
|
||||
// ...other options...
|
||||
protocols: [
|
||||
{
|
||||
name: 'Electron Fiddle',
|
||||
schemes: ['electron-fiddle']
|
||||
}
|
||||
]
|
||||
|
||||
}).then(paths => console.log(`SUCCESS: Created ${paths.join(', ')}`))
|
||||
.catch(err => console.error(`ERROR: ${err.message}`))
|
||||
```
|
||||
|
||||
If you're using Electron Packager's CLI, use the `--protocol` and `--protocol-name` flags. For
|
||||
example:
|
||||
|
||||
```shell
|
||||
npx electron-packager . --protocol=electron-fiddle --protocol-name="Electron Fiddle"
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
After you start your electron app, you can now enter in a URL in your browser that contains the custom protocol, for example `"electron-fiddle://open"` and observe that the application will respond and show an error dialog box.
|
||||
After you start your Electron app, you can enter in a URL in your browser that contains the custom
|
||||
protocol, for example `"electron-fiddle://open"` and observe that the application will respond and
|
||||
show an error dialog box.
|
||||
|
||||
<!--
|
||||
Because Electron examples usually require multiple files (HTML, CSS, JS
|
||||
|
||||
@@ -120,9 +120,9 @@ file in the directory you executed it in. Both files can be analyzed using
|
||||
the Chrome Developer Tools, using the `Performance` and `Memory` tabs
|
||||
respectively.
|
||||
|
||||
![Performance CPU Profile][performance-cpu-prof]
|
||||

|
||||
|
||||
![Performance Heap Memory Profile][performance-heap-prof]
|
||||

|
||||
|
||||
In this example, on the author's machine, we saw that loading `request` took
|
||||
almost half a second, whereas `node-fetch` took dramatically less memory
|
||||
@@ -412,8 +412,6 @@ As of writing this article, the popular choices include [Webpack][webpack],
|
||||
[Parcel][parcel], and [rollup.js][rollup].
|
||||
|
||||
[security]: ./security.md
|
||||
[performance-cpu-prof]: ../images/performance-cpu-prof.png
|
||||
[performance-heap-prof]: ../images/performance-heap-prof.png
|
||||
[chrome-devtools-tutorial]: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/
|
||||
[worker-threads]: https://nodejs.org/api/worker_threads.html
|
||||
[web-workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
|
||||
|
||||
@@ -7,16 +7,16 @@ without the need of switching to the window itself.
|
||||
|
||||
On Windows, you can use a taskbar button to display a progress bar.
|
||||
|
||||
![Windows Progress Bar][windows-progress-bar]
|
||||
![Windows Progress Bar][https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png]
|
||||
|
||||
On macOS, the progress bar will be displayed as a part of the dock icon.
|
||||
|
||||
![macOS Progress Bar][macos-progress-bar]
|
||||

|
||||
|
||||
On Linux, the Unity graphical interface also has a similar feature that allows
|
||||
you to specify the progress bar in the launcher.
|
||||
|
||||
![Linux Progress Bar][linux-progress-bar]
|
||||

|
||||
|
||||
> NOTE: on Windows, each window can have its own progress bar, whereas on macOS
|
||||
and Linux (Unity) there can be only one progress bar for the application.
|
||||
@@ -102,8 +102,4 @@ For macOS, the progress bar will also be indicated for your application
|
||||
when using [Mission Control](https://support.apple.com/en-us/HT204100):
|
||||
|
||||

|
||||
|
||||
[windows-progress-bar]: https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png
|
||||
[macos-progress-bar]: ../images/macos-progress-bar.png
|
||||
[linux-progress-bar]: ../images/linux-progress-bar.png
|
||||
[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress-options
|
||||
|
||||
@@ -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,10 +70,10 @@ until the maintainers feel the maintenance burden is too high to continue doing
|
||||
|
||||
### Currently supported versions
|
||||
|
||||
* 15.x.y
|
||||
* 14.x.y
|
||||
* 13.x.y
|
||||
* 12.x.y
|
||||
* 11.x.y
|
||||
* 12
|
||||
|
||||
### 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",
|
||||
|
||||
@@ -195,6 +195,7 @@ filenames = {
|
||||
"shell/browser/ui/tray_icon_cocoa.mm",
|
||||
"shell/common/api/electron_api_clipboard_mac.mm",
|
||||
"shell/common/api/electron_api_native_image_mac.mm",
|
||||
"shell/common/asar/archive_mac.mm",
|
||||
"shell/common/application_info_mac.mm",
|
||||
"shell/common/language_util_mac.mm",
|
||||
"shell/common/mac/main_application_bundle.h",
|
||||
@@ -387,8 +388,18 @@ filenames = {
|
||||
"shell/browser/file_select_helper.cc",
|
||||
"shell/browser/file_select_helper.h",
|
||||
"shell/browser/file_select_helper_mac.mm",
|
||||
"shell/browser/font/electron_font_access_delegate.cc",
|
||||
"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",
|
||||
@@ -408,6 +419,8 @@ filenames = {
|
||||
"shell/browser/native_window.cc",
|
||||
"shell/browser/native_window.h",
|
||||
"shell/browser/native_window_observer.h",
|
||||
"shell/browser/net/asar/asar_file_validator.cc",
|
||||
"shell/browser/net/asar/asar_file_validator.h",
|
||||
"shell/browser/net/asar/asar_url_loader.cc",
|
||||
"shell/browser/net/asar/asar_url_loader.h",
|
||||
"shell/browser/net/asar/asar_url_loader_factory.cc",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
import type * as Crypto from 'crypto';
|
||||
|
||||
const asar = process._linkedBinding('electron_common_asar');
|
||||
|
||||
@@ -194,6 +195,20 @@ const overrideAPI = function (module: Record<string, any>, name: string, pathArg
|
||||
}
|
||||
};
|
||||
|
||||
let crypto: typeof Crypto;
|
||||
function validateBufferIntegrity (buffer: Buffer, integrity: NodeJS.AsarFileInfo['integrity']) {
|
||||
if (!integrity) return;
|
||||
|
||||
// Delay load crypto to improve app boot performance
|
||||
// when integrity protection is not enabled
|
||||
crypto = crypto || require('crypto');
|
||||
const actual = crypto.createHash(integrity.algorithm).update(buffer).digest('hex');
|
||||
if (actual !== integrity.hash) {
|
||||
console.error(`ASAR Integrity Violation: got a hash mismatch (${actual} vs ${integrity.hash})`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const makePromiseFunction = function (orig: Function, pathArgumentIndex: number) {
|
||||
return function (this: any, ...args: any[]) {
|
||||
const pathArgument = args[pathArgumentIndex];
|
||||
@@ -531,7 +546,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
const fd = archive.getFdAndValidateIntegrityLater();
|
||||
if (!(fd >= 0)) {
|
||||
const error = createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
nextTick(callback, [error]);
|
||||
@@ -540,6 +555,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
fs.read(fd, buffer, 0, info.size, info.offset, (error: Error) => {
|
||||
validateBufferIntegrity(buffer, info.integrity);
|
||||
callback(error, encoding ? buffer.toString(encoding) : buffer);
|
||||
});
|
||||
}
|
||||
@@ -595,11 +611,12 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
|
||||
const { encoding } = options;
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
const fd = archive.getFdAndValidateIntegrityLater();
|
||||
if (!(fd >= 0)) throw createError(AsarError.NOT_FOUND, { asarPath, filePath });
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
fs.readSync(fd, buffer, 0, info.size, info.offset);
|
||||
validateBufferIntegrity(buffer, info.integrity);
|
||||
return (encoding) ? buffer.toString(encoding) : buffer;
|
||||
};
|
||||
|
||||
@@ -713,11 +730,12 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(info.size);
|
||||
const fd = archive.getFd();
|
||||
const fd = archive.getFdAndValidateIntegrityLater();
|
||||
if (!(fd >= 0)) return [];
|
||||
|
||||
logASARAccess(asarPath, filePath, info.offset);
|
||||
fs.readSync(fd, buffer, 0, info.size, info.offset);
|
||||
validateBufferIntegrity(buffer, info.integrity);
|
||||
const str = buffer.toString('utf8');
|
||||
return [str, str.length > 0];
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { BrowserWindowConstructorOptions, LoadURLOptions } from 'electron/m
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
import { openGuestWindow, makeWebPreferences, parseContentTypeFormat } from '@electron/internal/browser/guest-window-manager';
|
||||
import { parseFeatures } from '@electron/internal/common/parse-features-string';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
|
||||
@@ -665,6 +666,16 @@ WebContents.prototype._init = function () {
|
||||
postBody
|
||||
};
|
||||
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
|
||||
// if attempting to use this API with the deprecated new-window event,
|
||||
// windowOpenOverriddenOptions will always return null. This ensures
|
||||
// short-term backwards compatibility until new-window is removed.
|
||||
const parsedFeatures = parseFeatures(rawFeatures);
|
||||
const overriddenFeatures: BrowserWindowConstructorOptions = {
|
||||
...parsedFeatures.options,
|
||||
webPreferences: parsedFeatures.webPreferences
|
||||
};
|
||||
windowOpenOverriddenOptions = windowOpenOverriddenOptions || overriddenFeatures;
|
||||
|
||||
if (!event.defaultPrevented) {
|
||||
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
|
||||
// Allow setting of backgroundColor as a webPreference even though
|
||||
|
||||
@@ -81,9 +81,10 @@ require('@electron/internal/browser/guest-view-manager');
|
||||
require('@electron/internal/browser/guest-window-proxy');
|
||||
|
||||
// Now we try to load app's package.json.
|
||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
let packagePath = null;
|
||||
let packageJson = null;
|
||||
const searchPaths = ['app', 'app.asar', 'default_app.asar'];
|
||||
const searchPaths: string[] = v8Util.getHiddenValue(global, 'appSearchPaths');
|
||||
|
||||
if (process.resourcesPath) {
|
||||
for (packagePath of searchPaths) {
|
||||
|
||||
@@ -103,10 +103,14 @@ const warnAboutInsecureResources = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
const isLocal = (url: URL): boolean =>
|
||||
['localhost', '127.0.0.1', '[::1]', ''].includes(url.hostname);
|
||||
const isInsecure = (url: URL): boolean =>
|
||||
['http:', 'ftp:'].includes(url.protocol) && !isLocal(url);
|
||||
|
||||
const resources = window.performance
|
||||
.getEntriesByType('resource')
|
||||
.filter(({ name }) => /^(http|ftp):/gi.test(name || ''))
|
||||
.filter(({ name }) => new URL(name).hostname !== 'localhost')
|
||||
.filter(({ name }) => isInsecure(new URL(name)))
|
||||
.map(({ name }) => `- ${name}`)
|
||||
.join('\n');
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ downloadArtifact({
|
||||
artifactName: 'electron',
|
||||
force: process.env.force_no_cache === 'true',
|
||||
cacheRoot: process.env.electron_config_cache,
|
||||
checksums: process.env.electron_use_remote_checksums ? undefined : require('./checksums.json'),
|
||||
platform,
|
||||
arch
|
||||
}).then(extractFile).catch(err => {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"postinstall": "node install.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/get": "^1.0.1",
|
||||
"@electron/get": "^1.13.0",
|
||||
"@types/node": "^14.6.2",
|
||||
"extract-zip": "^1.0.3"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "15.0.0-beta.3",
|
||||
"version": "15.1.1",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
@@ -30,12 +30,12 @@
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.4.1",
|
||||
"@typescript-eslint/parser": "^4.4.1",
|
||||
"asar": "^3.0.3",
|
||||
"asar": "^3.1.0",
|
||||
"aws-sdk": "^2.727.1",
|
||||
"check-for-leaks": "^1.2.1",
|
||||
"colors": "^1.4.0",
|
||||
"dotenv-safe": "^4.0.4",
|
||||
"dugite": "^1.45.0",
|
||||
"dugite": "^1.103.0",
|
||||
"eslint": "^7.4.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
@@ -54,12 +54,10 @@
|
||||
"markdownlint": "^0.21.1",
|
||||
"markdownlint-cli": "^0.25.0",
|
||||
"minimist": "^1.2.5",
|
||||
"nugget": "^2.0.1",
|
||||
"null-loader": "^4.0.0",
|
||||
"pre-flight": "^1.1.0",
|
||||
"remark-cli": "^4.0.0",
|
||||
"remark-preset-lint-markdown-style-guide": "^2.1.1",
|
||||
"request": "^2.88.2",
|
||||
"semver": "^5.6.0",
|
||||
"shx": "^0.3.2",
|
||||
"standard-markdown": "^6.0.0",
|
||||
|
||||
@@ -101,7 +101,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
|
||||
feat_expose_raw_response_headers_from_urlloader.patch
|
||||
fix_media_key_usage_with_globalshortcuts.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;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ index 8bf6b4bc077cc41da5e0e6b13302bc343537c68f..01bddc0bcb7476408023c4cfc042a088
|
||||
// its owning reference back to our owning LocalFrame.
|
||||
client_->Detached(type);
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
index a9c4d4efe4d66a152c02c7d6029d8c7e3740ebfb..cce1fc3bc9d7779215cd3536553e09078c8d9680 100644
|
||||
index 1dd636810e0c153f66269132ff09433eaf6d90b2..6f730919d3831bb8287f4a819f8bd9ef7e7e6503 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
@@ -553,10 +553,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
|
||||
|
||||
@@ -46,10 +46,10 @@ index 135ad9b24745f6d016806f3c95993efe65b370f3..c5e694cd56b9db940e8564c82e2773aa
|
||||
}
|
||||
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index 3ddf1368f8ac78f32f523b2abde0addb79dcd9df..d878826b9782e65f92bf9316400f59cb55d2a4df 100644
|
||||
index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de5288ebaa 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -5324,7 +5324,6 @@ test("unit_tests") {
|
||||
@@ -5325,7 +5325,6 @@ test("unit_tests") {
|
||||
assert(toolkit_views)
|
||||
sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
|
||||
deps += [
|
||||
@@ -57,7 +57,7 @@ index 3ddf1368f8ac78f32f523b2abde0addb79dcd9df..d878826b9782e65f92bf9316400f59cb
|
||||
"//chrome/browser:chrome_process_finder",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner:public",
|
||||
@@ -5337,6 +5336,12 @@ test("unit_tests") {
|
||||
@@ -5338,6 +5337,12 @@ test("unit_tests") {
|
||||
"//components/chrome_cleaner/public/proto",
|
||||
"//ui/events/devices:test_support",
|
||||
]
|
||||
@@ -70,7 +70,7 @@ index 3ddf1368f8ac78f32f523b2abde0addb79dcd9df..d878826b9782e65f92bf9316400f59cb
|
||||
}
|
||||
|
||||
# TODO(crbug.com/931218): Ninja cannot handle certain characters appearing
|
||||
@@ -5929,7 +5934,6 @@ test("unit_tests") {
|
||||
@@ -5930,7 +5935,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
@@ -78,7 +78,7 @@ index 3ddf1368f8ac78f32f523b2abde0addb79dcd9df..d878826b9782e65f92bf9316400f59cb
|
||||
"//chrome/browser:cart_db_content_proto",
|
||||
"//chrome/browser/media/router:test_support",
|
||||
"//chrome/browser/promo_browser_command:mojo_bindings",
|
||||
@@ -5965,6 +5969,9 @@ test("unit_tests") {
|
||||
@@ -5966,6 +5970,9 @@ test("unit_tests") {
|
||||
"//ui/color:test_support",
|
||||
"//ui/native_theme:test_support",
|
||||
]
|
||||
|
||||
@@ -9,10 +9,10 @@ potentially prevent a window from being created.
|
||||
TODO(loc): this patch is currently broken.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 9bf31d2cb714f5def7db8ef4966d2ebff6223b92..621e5109e75db6e39ad488df0924b7bb98cc2aed 100644
|
||||
index 3e7b18a7f9ba48b010c329a3f857122977a7e205..ec3a51fcd891841f945b4f3629968330f25dd1c0 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -6367,6 +6367,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
@@ -6421,6 +6421,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
last_committed_origin_, params->window_container_type,
|
||||
params->target_url, params->referrer.To<Referrer>(),
|
||||
params->frame_name, params->disposition, *params->features,
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: frame_host_manager.patch
|
||||
Allows embedder to intercept site instances created by chromium.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
index fd21a0ae3c653e262dd049674a4f943feb23ddf6..f5857235687e0b923e9d73e17c19c36495d10680 100644
|
||||
index d44fe1f7dbef9d5bc1ffbc508fad5d5642e850e7..f6dfd1d7cd9b4f9b8f59613ee2960dc4cc27e1a3 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
|
||||
@@ -3077,6 +3077,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||
@@ -3095,6 +3095,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||
request->ResetStateForSiteInstanceChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ Note that we also need to manually update embedder's
|
||||
`api::WebContents::IsFullscreenForTabOrPending` value.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 621e5109e75db6e39ad488df0924b7bb98cc2aed..7c7c1ad7d31a547e13411548468f777e76fff0fd 100644
|
||||
index ec3a51fcd891841f945b4f3629968330f25dd1c0..a0c056f47b9582536f9c8ee93517c872bfadf2e3 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -5790,6 +5790,15 @@ void RenderFrameHostImpl::EnterFullscreen(
|
||||
@@ -5844,6 +5844,15 @@ void RenderFrameHostImpl::EnterFullscreen(
|
||||
notified_instances.insert(parent_site_instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,3 +27,5 @@ fix_account_for_debugger_agent_race_condition.patch
|
||||
fix_use_new_v8_error_message_property_access_format.patch
|
||||
add_should_read_node_options_from_env_option_to_disable_node_options.patch
|
||||
repl_fix_crash_when_sharedarraybuffer_disabled.patch
|
||||
fix_crash_creating_private_key_with_unsupported_algorithm.patch
|
||||
fix_remove_expired_dst_root_ca_x3.patch
|
||||
|
||||
@@ -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 c24b2d14eb50019d442a32ba92560c8c0c58d2d5..2b120d3c264f44eff452a8f4f8e8da4443bdb6f3 100644
|
||||
--- a/lib/internal/crypto/keys.js
|
||||
+++ b/lib/internal/crypto/keys.js
|
||||
@@ -459,15 +459,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;
|
||||
42
patches/node/fix_remove_expired_dst_root_ca_x3.patch
Normal file
42
patches/node/fix_remove_expired_dst_root_ca_x3.patch
Normal file
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Fri, 1 Oct 2021 07:21:11 +0900
|
||||
Subject: fix: remove expired DST Root CA X3
|
||||
|
||||
The alternative ISRG Root X1 trusted certificate is
|
||||
already available in this bundle.
|
||||
|
||||
https://letsencrypt.org/docs/certificate-compatibility/
|
||||
https://www.openssl.org/blog/blog/2021/09/13/LetsEncryptRootCertExpire/
|
||||
|
||||
diff --git a/src/node_root_certs.h b/src/node_root_certs.h
|
||||
index 47beb730f4b853f1bf248a7fd1b1cd7d726bdf7e..94ac882ec7e4e2eb61d1f0094f79fb6f603d978c 100644
|
||||
--- a/src/node_root_certs.h
|
||||
+++ b/src/node_root_certs.h
|
||||
@@ -525,26 +525,6 @@
|
||||
"yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K\n"
|
||||
"-----END CERTIFICATE-----",
|
||||
|
||||
-/* DST Root CA X3 */
|
||||
-"-----BEGIN CERTIFICATE-----\n"
|
||||
-"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYD\n"
|
||||
-"VQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENB\n"
|
||||
-"IFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRh\n"
|
||||
-"bCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJ\n"
|
||||
-"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdA\n"
|
||||
-"wRgUi+DoM3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwG\n"
|
||||
-"MoOifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4X\n"
|
||||
-"Lh7dIN9bxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n"
|
||||
-"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkq\n"
|
||||
-"tilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\n"
|
||||
-"HQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEBBQUAA4IBAQCjGiyb\n"
|
||||
-"FwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikugdB/OEIKcdBodfpga3csTS7MgROSR\n"
|
||||
-"6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaL\n"
|
||||
-"bumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir\n"
|
||||
-"/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06Xyx\n"
|
||||
-"V3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n"
|
||||
-"-----END CERTIFICATE-----",
|
||||
-
|
||||
/* SwissSign Gold CA - G2 */
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNI\n"
|
||||
@@ -6,3 +6,7 @@ workaround_an_undefined_symbol_error.patch
|
||||
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,208 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Lippautz <mlippautz@chromium.org>
|
||||
Date: Fri, 3 Sep 2021 14:17:59 +0200
|
||||
Subject: cppgc-js: Support eager traced value in ephemeron pairs
|
||||
|
||||
Before this patch, both key and value of an ephemeron pair was always
|
||||
considered to be GarbageCollected objects.
|
||||
|
||||
This patch adjusts the snapshotting mechanism to accomodate that
|
||||
values may not be GarbageCollected objects and must thus be eagerly
|
||||
traced for visibility and edge creation.
|
||||
|
||||
In practice this only shows up in Blink when associating an existing
|
||||
wrappable with a wrapper in a non-main world, e.g., through an
|
||||
extension. In this case, DOMWrapperMap keeps the wrapper value through
|
||||
a TracedReference in the ephemeron map with the existing wrappable as
|
||||
key. The semantics are intended to be general ephemeron semantics,
|
||||
i.e., value needs to be kept alive when the key is alive. This is
|
||||
visualized in DevTools as the main wrapper/wrappable pair (which is
|
||||
merged into a single node for the snapshot) retaining the non-main
|
||||
world wrapper.
|
||||
|
||||
Bug: chromium:1245894
|
||||
Change-Id: Ibfa6722f20c76f94c310f9a040f0d3d4b9083bbb
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3140601
|
||||
Reviewed-by: Omer Katz <omerkatz@chromium.org>
|
||||
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#76658}
|
||||
|
||||
diff --git a/src/heap/cppgc-js/cpp-snapshot.cc b/src/heap/cppgc-js/cpp-snapshot.cc
|
||||
index dc55753ff625a135b6e494344ee49105eb59121e..9b20b5c0a7831ea026819f90ea80c10eb2324282 100644
|
||||
--- a/src/heap/cppgc-js/cpp-snapshot.cc
|
||||
+++ b/src/heap/cppgc-js/cpp-snapshot.cc
|
||||
@@ -264,6 +264,10 @@ class State final : public StateBase {
|
||||
ephemeron_edges_.insert(&value);
|
||||
}
|
||||
|
||||
+ void AddEagerEphemeronEdge(const void* value, cppgc::TraceCallback callback) {
|
||||
+ eager_ephemeron_edges_.insert({value, callback});
|
||||
+ }
|
||||
+
|
||||
template <typename Callback>
|
||||
void ForAllEphemeronEdges(Callback callback) {
|
||||
for (const HeapObjectHeader* value : ephemeron_edges_) {
|
||||
@@ -271,10 +275,20 @@ class State final : public StateBase {
|
||||
}
|
||||
}
|
||||
|
||||
+ template <typename Callback>
|
||||
+ void ForAllEagerEphemeronEdges(Callback callback) {
|
||||
+ for (const auto& pair : eager_ephemeron_edges_) {
|
||||
+ callback(pair.first, pair.second);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
bool is_weak_container_ = false;
|
||||
// Values that are held alive through ephemerons by this particular key.
|
||||
std::unordered_set<const HeapObjectHeader*> ephemeron_edges_;
|
||||
+ // Values that are eagerly traced and held alive through ephemerons by this
|
||||
+ // particular key.
|
||||
+ std::unordered_map<const void*, cppgc::TraceCallback> eager_ephemeron_edges_;
|
||||
};
|
||||
|
||||
// Root states are similar to regular states with the difference that they are
|
||||
@@ -404,6 +418,9 @@ class CppGraphBuilderImpl final {
|
||||
void VisitForVisibility(State& parent, const TracedReferenceBase&);
|
||||
void VisitEphemeronForVisibility(const HeapObjectHeader& key,
|
||||
const HeapObjectHeader& value);
|
||||
+ void VisitEphemeronWithNonGarbageCollectedValueForVisibility(
|
||||
+ const HeapObjectHeader& key, const void* value,
|
||||
+ cppgc::TraceDescriptor value_desc);
|
||||
void VisitWeakContainerForVisibility(const HeapObjectHeader&);
|
||||
void VisitRootForGraphBuilding(RootState&, const HeapObjectHeader&,
|
||||
const cppgc::SourceLocation&);
|
||||
@@ -421,7 +438,7 @@ class CppGraphBuilderImpl final {
|
||||
}
|
||||
|
||||
void AddEdge(State& parent, const HeapObjectHeader& header,
|
||||
- const std::string& edge_name = {}) {
|
||||
+ const std::string& edge_name) {
|
||||
DCHECK(parent.IsVisibleNotDependent());
|
||||
auto& current = states_.GetExistingState(header);
|
||||
if (!current.IsVisibleNotDependent()) return;
|
||||
@@ -443,7 +460,8 @@ class CppGraphBuilderImpl final {
|
||||
}
|
||||
}
|
||||
|
||||
- void AddEdge(State& parent, const TracedReferenceBase& ref) {
|
||||
+ void AddEdge(State& parent, const TracedReferenceBase& ref,
|
||||
+ const std::string& edge_name) {
|
||||
DCHECK(parent.IsVisibleNotDependent());
|
||||
v8::Local<v8::Value> v8_value = ref.Get(cpp_heap_.isolate());
|
||||
if (!v8_value.IsEmpty()) {
|
||||
@@ -451,12 +469,19 @@ class CppGraphBuilderImpl final {
|
||||
parent.set_node(AddNode(*parent.header()));
|
||||
}
|
||||
auto* v8_node = graph_.V8Node(v8_value);
|
||||
- graph_.AddEdge(parent.get_node(), v8_node);
|
||||
+ if (!edge_name.empty()) {
|
||||
+ graph_.AddEdge(parent.get_node(), v8_node,
|
||||
+ parent.get_node()->InternalizeEdgeName(edge_name));
|
||||
+ } else {
|
||||
+ graph_.AddEdge(parent.get_node(), v8_node);
|
||||
+ }
|
||||
|
||||
// References that have a class id set may have their internal fields
|
||||
// pointing back to the object. Set up a wrapper node for the graph so
|
||||
// that the snapshot generator can merge the nodes appropriately.
|
||||
- if (!ref.WrapperClassId()) return;
|
||||
+ // Even with a set class id, do not set up a wrapper node when the edge
|
||||
+ // has a specific name.
|
||||
+ if (!ref.WrapperClassId() || !edge_name.empty()) return;
|
||||
|
||||
void* back_reference_object = ExtractEmbedderDataBackref(
|
||||
reinterpret_cast<v8::internal::Isolate*>(cpp_heap_.isolate()),
|
||||
@@ -598,8 +623,18 @@ class WeakVisitor : public JSVisitor {
|
||||
void VisitEphemeron(const void* key, const void* value,
|
||||
cppgc::TraceDescriptor value_desc) final {
|
||||
// For ephemerons, the key retains the value.
|
||||
+ // Key always must be a GarbageCollected object.
|
||||
+ auto& key_header = HeapObjectHeader::FromObject(key);
|
||||
+ if (!value_desc.base_object_payload) {
|
||||
+ // Value does not represent an actual GarbageCollected object but rather
|
||||
+ // should be traced eagerly.
|
||||
+ graph_builder_.VisitEphemeronWithNonGarbageCollectedValueForVisibility(
|
||||
+ key_header, value, value_desc);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Regular path where both key and value are GarbageCollected objects.
|
||||
graph_builder_.VisitEphemeronForVisibility(
|
||||
- HeapObjectHeader::FromObject(key), HeapObjectHeader::FromObject(value));
|
||||
+ key_header, HeapObjectHeader::FromObject(value));
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -645,7 +680,7 @@ class GraphBuildingVisitor final : public JSVisitor {
|
||||
void Visit(const void*, cppgc::TraceDescriptor desc) final {
|
||||
graph_builder_.AddEdge(
|
||||
parent_scope_.ParentAsRegularState(),
|
||||
- HeapObjectHeader::FromObject(desc.base_object_payload));
|
||||
+ HeapObjectHeader::FromObject(desc.base_object_payload), edge_name_);
|
||||
}
|
||||
void VisitWeakContainer(const void* object,
|
||||
cppgc::TraceDescriptor strong_desc,
|
||||
@@ -655,7 +690,8 @@ class GraphBuildingVisitor final : public JSVisitor {
|
||||
// container itself.
|
||||
graph_builder_.AddEdge(
|
||||
parent_scope_.ParentAsRegularState(),
|
||||
- HeapObjectHeader::FromObject(strong_desc.base_object_payload));
|
||||
+ HeapObjectHeader::FromObject(strong_desc.base_object_payload),
|
||||
+ edge_name_);
|
||||
}
|
||||
void VisitRoot(const void*, cppgc::TraceDescriptor desc,
|
||||
const cppgc::SourceLocation& loc) final {
|
||||
@@ -667,12 +703,18 @@ class GraphBuildingVisitor final : public JSVisitor {
|
||||
const void*, const cppgc::SourceLocation&) final {}
|
||||
// JS handling.
|
||||
void Visit(const TracedReferenceBase& ref) final {
|
||||
- graph_builder_.AddEdge(parent_scope_.ParentAsRegularState(), ref);
|
||||
+ graph_builder_.AddEdge(parent_scope_.ParentAsRegularState(), ref,
|
||||
+ edge_name_);
|
||||
+ }
|
||||
+
|
||||
+ void set_edge_name(std::string edge_name) {
|
||||
+ edge_name_ = std::move(edge_name);
|
||||
}
|
||||
|
||||
private:
|
||||
CppGraphBuilderImpl& graph_builder_;
|
||||
const ParentScope& parent_scope_;
|
||||
+ std::string edge_name_;
|
||||
};
|
||||
|
||||
// Base class for transforming recursion into iteration. Items are processed
|
||||
@@ -765,6 +807,19 @@ void CppGraphBuilderImpl::VisitForVisibility(State* parent,
|
||||
}
|
||||
}
|
||||
|
||||
+void CppGraphBuilderImpl::
|
||||
+ VisitEphemeronWithNonGarbageCollectedValueForVisibility(
|
||||
+ const HeapObjectHeader& key, const void* value,
|
||||
+ cppgc::TraceDescriptor value_desc) {
|
||||
+ auto& key_state = states_.GetOrCreateState(key);
|
||||
+ // Eagerly trace the value here, effectively marking key as visible and
|
||||
+ // queuing processing for all reachable values.
|
||||
+ ParentScope parent_scope(key_state);
|
||||
+ VisiblityVisitor visitor(*this, parent_scope);
|
||||
+ value_desc.callback(&visitor, value);
|
||||
+ key_state.AddEagerEphemeronEdge(value, value_desc.callback);
|
||||
+}
|
||||
+
|
||||
void CppGraphBuilderImpl::VisitEphemeronForVisibility(
|
||||
const HeapObjectHeader& key, const HeapObjectHeader& value) {
|
||||
auto& key_state = states_.GetOrCreateState(key);
|
||||
@@ -820,6 +875,12 @@ void CppGraphBuilderImpl::Run() {
|
||||
state.ForAllEphemeronEdges([this, &state](const HeapObjectHeader& value) {
|
||||
AddEdge(state, value, "part of key -> value pair in ephemeron table");
|
||||
});
|
||||
+ object_visitor.set_edge_name(
|
||||
+ "part of key -> value pair in ephemeron table");
|
||||
+ state.ForAllEagerEphemeronEdges(
|
||||
+ [&object_visitor](const void* value, cppgc::TraceCallback callback) {
|
||||
+ callback(&object_visitor, value);
|
||||
+ });
|
||||
});
|
||||
// Add roots.
|
||||
{
|
||||
@@ -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 9b369044754443ccf5ce07c3612f0a928e565ad6..21afa5310647eb67f3fe3fc4f2e0721b4bb4e0f6 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
|
||||
|
||||
##############################################################################
|
||||
@@ -666,6 +669,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 25fba193bbcc41d127d36949e103cb59688bfed7..b21222f14c533cb630946b6066bfe24d1be49f93 100644
|
||||
--- a/test/cctest/test-api.cc
|
||||
+++ b/test/cctest/test-api.cc
|
||||
@@ -21658,10 +21658,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 aa24fe3dd230ecc06d9eea2920826dc123979c58..2fb5b3d056f78d3eef3a0a1032ee99df1b2f35c5 100644
|
||||
--- a/test/cctest/test-regexp.cc
|
||||
+++ b/test/cctest/test-regexp.cc
|
||||
@@ -2348,6 +2348,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 535188c567ee3eafee2333a45e9d41c4cf3b4a0b..bb7512fbfa26678110a2a26a717975beddd369b8 100644
|
||||
--- a/src/builtins/builtins-regexp-gen.cc
|
||||
+++ b/src/builtins/builtins-regexp-gen.cc
|
||||
@@ -435,8 +435,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()));
|
||||
|
||||
@@ -605,26 +603,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);
|
||||
@@ -639,8 +629,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 911744b8b1c6d8a49100d88b53f8d9aedb943e2a..ca21530f99b618e5c46511d06ef93121a7e3c23e 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);
|
||||
@@ -751,11 +748,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 bff2d7da6645d6023fc218daf370a51a9d404495..def43dc2c167fd463947cbbbc507da664d38aead 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 1b44100cc88bed7825c0a30fb05e8477c47860ec..671792e5ef82919af652f431c5f6b325fea08d77 100644
|
||||
--- a/src/regexp/experimental/experimental.h
|
||||
+++ b/src/regexp/experimental/experimental.h
|
||||
@@ -33,7 +33,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 02fc3349208b7127d967a8b25763b3951f2c9dde..c9dd403e751502750cbb8bc4b4e820eb1136c9ea 100644
|
||||
--- a/src/regexp/regexp-interpreter.cc
|
||||
+++ b/src/regexp/regexp-interpreter.cc
|
||||
@@ -1110,7 +1110,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 9b4a8c6c307266a78a35f52ef4ef0afe5b6af6fe..19f9513acc2c7d309179ca5e18ca7ef2165e74f4 100644
|
||||
--- a/src/regexp/regexp-interpreter.h
|
||||
+++ b/src/regexp/regexp-interpreter.h
|
||||
@@ -34,9 +34,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
|
||||
@@ -45,7 +44,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 27590fac36cea92f557dc0c149d9cbed6efef8b5..73313f95ec1d6e5bd7e5479e45c6b1980c638aa9 100644
|
||||
--- a/src/regexp/regexp-macro-assembler.cc
|
||||
+++ b/src/regexp/regexp-macro-assembler.cc
|
||||
@@ -300,23 +300,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
|
||||
|
||||
@@ -1,52 +1,23 @@
|
||||
const args = require('minimist')(process.argv.slice(2));
|
||||
const nugget = require('nugget');
|
||||
const request = require('request');
|
||||
const fs = require('fs');
|
||||
const got = require('got');
|
||||
const stream = require('stream');
|
||||
const { promisify } = require('util');
|
||||
|
||||
async function makeRequest (requestOptions, parseResponse) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(requestOptions, (err, res, body) => {
|
||||
if (!err && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
if (parseResponse) {
|
||||
const build = JSON.parse(body);
|
||||
resolve(build);
|
||||
} else {
|
||||
resolve(body);
|
||||
}
|
||||
} else {
|
||||
if (args.verbose) {
|
||||
console.error('Error occurred while requesting:', requestOptions.url);
|
||||
if (parseResponse) {
|
||||
try {
|
||||
console.log('Error: ', `(status ${res.statusCode})`, err || JSON.parse(res.body), requestOptions);
|
||||
} catch (err) {
|
||||
console.log('Error: ', `(status ${res.statusCode})`, err || res.body, requestOptions);
|
||||
}
|
||||
} else {
|
||||
console.log('Error: ', `(status ${res.statusCode})`, err || res.body, requestOptions);
|
||||
}
|
||||
}
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
const pipeline = promisify(stream.pipeline);
|
||||
|
||||
async function downloadArtifact (name, buildNum, dest) {
|
||||
const circleArtifactUrl = `https://circleci.com/api/v1.1/project/github/electron/electron/${args.buildNum}/artifacts?circle-token=${process.env.CIRCLE_TOKEN}`;
|
||||
const artifacts = await makeRequest({
|
||||
method: 'GET',
|
||||
url: circleArtifactUrl,
|
||||
const responsePromise = got(circleArtifactUrl, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
}, true).catch(err => {
|
||||
if (args.verbose) {
|
||||
console.log('Error calling CircleCI:', err);
|
||||
} else {
|
||||
console.error('Error calling CircleCI to get artifact details');
|
||||
}
|
||||
});
|
||||
const [response, artifacts] = await Promise.all([responsePromise, responsePromise.json()]);
|
||||
if (response.statusCode !== 200) {
|
||||
console.error('Could not fetch circleci artifact list, got status code:', response.statusCode);
|
||||
}
|
||||
const artifactToDownload = artifacts.find(artifact => {
|
||||
return (artifact.path === name);
|
||||
});
|
||||
@@ -86,19 +57,10 @@ async function downloadWithRetry (url, directory) {
|
||||
}
|
||||
|
||||
function downloadFile (url, directory) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const nuggetOpts = {
|
||||
dir: directory,
|
||||
quiet: args.verbose
|
||||
};
|
||||
nugget(url, nuggetOpts, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
return pipeline(
|
||||
got.stream(url),
|
||||
fs.createWriteStream(directory)
|
||||
);
|
||||
}
|
||||
|
||||
if (!args.name || !args.buildNum || !args.dest) {
|
||||
|
||||
9
script/gn-asar-hash.js
Normal file
9
script/gn-asar-hash.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const asar = require('asar');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
|
||||
const archive = process.argv[2];
|
||||
const hashFile = process.argv[3];
|
||||
|
||||
const { headerString } = asar.getRawHeader(archive);
|
||||
fs.writeFileSync(hashFile, crypto.createHash('SHA256').update(headerString).digest('hex'));
|
||||
16
script/gn-plist-but-with-hashes.js
Normal file
16
script/gn-plist-but-with-hashes.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const fs = require('fs');
|
||||
|
||||
const [,, plistPath, outputPath, ...keySet] = process.argv;
|
||||
|
||||
const keyPairs = {};
|
||||
for (let i = 0; i * 2 < keySet.length; i++) {
|
||||
keyPairs[keySet[i]] = fs.readFileSync(keySet[(keySet.length / 2) + i], 'utf8');
|
||||
}
|
||||
|
||||
let plistContents = fs.readFileSync(plistPath, 'utf8');
|
||||
|
||||
for (const key of Object.keys(keyPairs)) {
|
||||
plistContents = plistContents.replace(`$\{${key}}`, keyPairs[key]);
|
||||
}
|
||||
|
||||
fs.writeFileSync(outputPath, plistContents);
|
||||
@@ -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,8 +29,21 @@ 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) {
|
||||
@@ -91,7 +104,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',
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
if (!process.env.CI) require('dotenv-safe').load();
|
||||
|
||||
const assert = require('assert');
|
||||
const request = require('request');
|
||||
const got = require('got');
|
||||
|
||||
const BUILD_APPVEYOR_URL = 'https://ci.appveyor.com/api/builds';
|
||||
const CIRCLECI_PIPELINE_URL = 'https://circleci.com/api/v2/project/gh/electron/electron/pipeline';
|
||||
@@ -35,31 +35,24 @@ const vstsArmJobs = [
|
||||
|
||||
let jobRequestedCount = 0;
|
||||
|
||||
async function makeRequest (requestOptions, parseResponse) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(requestOptions, (err, res, body) => {
|
||||
if (!err && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
if (parseResponse) {
|
||||
const build = JSON.parse(body);
|
||||
resolve(build);
|
||||
} else {
|
||||
resolve(body);
|
||||
}
|
||||
} else {
|
||||
console.error('Error occurred while requesting:', requestOptions.url);
|
||||
if (parseResponse) {
|
||||
try {
|
||||
console.log('Error: ', `(status ${res.statusCode})`, err || JSON.parse(res.body));
|
||||
} catch (err) {
|
||||
console.log('Error: ', `(status ${res.statusCode})`, res.body);
|
||||
}
|
||||
} else {
|
||||
console.log('Error: ', `(status ${res.statusCode})`, err || res.body);
|
||||
}
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
async function makeRequest ({ auth, url, headers, body, method }) {
|
||||
const clonedHeaders = {
|
||||
...(headers || {})
|
||||
};
|
||||
if (auth && auth.bearer) {
|
||||
clonedHeaders.Authorization = `Bearer ${auth.bearer}`;
|
||||
}
|
||||
const response = await got(url, {
|
||||
headers: clonedHeaders,
|
||||
body,
|
||||
method,
|
||||
auth: auth && (auth.username || auth.password) ? `${auth.username}:${auth.password}` : undefined
|
||||
});
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
console.error('Error: ', `(status ${response.statusCode})`, response.body);
|
||||
throw new Error(`Unexpected status code ${response.statusCode} from ${url}`);
|
||||
}
|
||||
return JSON.parse(response.body);
|
||||
}
|
||||
|
||||
async function circleCIcall (targetBranch, workflowName, options) {
|
||||
|
||||
43
script/release/get-asset.js
Normal file
43
script/release/get-asset.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const { Octokit } = require('@octokit/rest');
|
||||
const got = require('got');
|
||||
|
||||
const octokit = new Octokit({
|
||||
userAgent: 'electron-asset-fetcher',
|
||||
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||
});
|
||||
|
||||
async function getAssetContents (repo, assetId) {
|
||||
const requestOptions = octokit.repos.getReleaseAsset.endpoint({
|
||||
owner: 'electron',
|
||||
repo,
|
||||
asset_id: assetId,
|
||||
headers: {
|
||||
Accept: 'application/octet-stream'
|
||||
}
|
||||
});
|
||||
|
||||
const { url, headers } = requestOptions;
|
||||
headers.authorization = `token ${process.env.ELECTRON_GITHUB_TOKEN}`;
|
||||
|
||||
const response = await got(url, {
|
||||
followRedirect: false,
|
||||
method: 'HEAD',
|
||||
headers
|
||||
});
|
||||
if (!response.headers.location) {
|
||||
console.error(response.headers, `${response.body}`.slice(0, 300));
|
||||
throw new Error(`cannot find asset[${assetId}], asset download did not redirect`);
|
||||
}
|
||||
|
||||
const fileResponse = await got(response.headers.location);
|
||||
if (fileResponse.statusCode !== 200) {
|
||||
console.error(fileResponse.headers, `${fileResponse.body}`.slice(0, 300));
|
||||
throw new Error(`cannot download asset[${assetId}] from ${response.headers.location}, got status: ${fileResponse.status}`);
|
||||
}
|
||||
|
||||
return fileResponse.body;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAssetContents
|
||||
};
|
||||
@@ -2,12 +2,14 @@ const temp = require('temp');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const childProcess = require('child_process');
|
||||
const { getCurrentBranch, ELECTRON_DIR } = require('../lib/utils');
|
||||
const request = require('request');
|
||||
const got = require('got');
|
||||
const semver = require('semver');
|
||||
|
||||
const { getCurrentBranch, ELECTRON_DIR } = require('../lib/utils');
|
||||
const rootPackageJson = require('../../package.json');
|
||||
|
||||
const { Octokit } = require('@octokit/rest');
|
||||
const { getAssetContents } = require('./get-asset');
|
||||
const octokit = new Octokit({
|
||||
userAgent: 'electron-npm-publisher',
|
||||
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||
@@ -86,27 +88,41 @@ new Promise((resolve, reject) => {
|
||||
}
|
||||
return release;
|
||||
})
|
||||
.then((release) => {
|
||||
.then(async (release) => {
|
||||
const tsdAsset = release.assets.find((asset) => asset.name === 'electron.d.ts');
|
||||
if (!tsdAsset) {
|
||||
throw new Error(`cannot find electron.d.ts from v${rootPackageJson.version} release assets`);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get({
|
||||
url: tsdAsset.url,
|
||||
headers: {
|
||||
accept: 'application/octet-stream',
|
||||
'user-agent': 'electron-npm-publisher'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
if (err || response.statusCode !== 200) {
|
||||
reject(err || new Error('Cannot download electron.d.ts'));
|
||||
} else {
|
||||
fs.writeFileSync(path.join(tempDir, 'electron.d.ts'), body);
|
||||
resolve(release);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const typingsContent = await getAssetContents(
|
||||
rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron',
|
||||
tsdAsset.id
|
||||
);
|
||||
|
||||
fs.writeFileSync(path.join(tempDir, 'electron.d.ts'), typingsContent);
|
||||
|
||||
return release;
|
||||
})
|
||||
.then(async (release) => {
|
||||
const checksumsAsset = release.assets.find((asset) => asset.name === 'SHASUMS256.txt');
|
||||
if (!checksumsAsset) {
|
||||
throw new Error(`cannot find SHASUMS256.txt from v${rootPackageJson.version} release assets`);
|
||||
}
|
||||
|
||||
const checksumsContent = await getAssetContents(
|
||||
rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron',
|
||||
checksumsAsset.id
|
||||
);
|
||||
|
||||
const checksumsObject = {};
|
||||
for (const line of checksumsContent.trim().split('\n')) {
|
||||
const [checksum, file] = line.split(' *');
|
||||
checksumsObject[file] = checksum;
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(tempDir, 'checksums.json'), JSON.stringify(checksumsObject, null, 2));
|
||||
|
||||
return release;
|
||||
})
|
||||
.then(async (release) => {
|
||||
const currentBranch = await getCurrentBranch();
|
||||
@@ -150,10 +166,26 @@ new Promise((resolve, reject) => {
|
||||
// test that the package can install electron prebuilt from github release
|
||||
const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`);
|
||||
return new Promise((resolve, reject) => {
|
||||
childProcess.execSync(`npm install ${tarballPath} --force --silent`, {
|
||||
const result = childProcess.spawnSync('npm', ['install', tarballPath, '--force', '--silent'], {
|
||||
env: Object.assign({}, process.env, { electron_config_cache: tempDir }),
|
||||
cwd: tempDir
|
||||
cwd: tempDir,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
return reject(new Error(`npm install failed with status ${result.status}`));
|
||||
}
|
||||
try {
|
||||
const electronPath = require(path.resolve(tempDir, 'node_modules', rootPackageJson.name));
|
||||
if (typeof electronPath !== 'string') {
|
||||
return reject(new Error(`path to electron binary (${electronPath}) returned by the ${rootPackageJson.name} module is not a string`));
|
||||
}
|
||||
if (!fs.existsSync(electronPath)) {
|
||||
return reject(new Error(`path to electron binary (${electronPath}) returned by the ${rootPackageJson.name} module does not exist on disk`));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return reject(new Error(`loading the generated ${rootPackageJson.name} module failed with an error`));
|
||||
}
|
||||
resolve(tarballPath);
|
||||
});
|
||||
})
|
||||
@@ -186,6 +218,6 @@ new Promise((resolve, reject) => {
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`Error: ${err}`);
|
||||
console.error('Error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -384,7 +384,7 @@ async function verifyDraftGitHubReleaseAssets (release) {
|
||||
console.log('Fetching authenticated GitHub artifact URLs to verify shasums');
|
||||
|
||||
const remoteFilesToHash = await Promise.all(release.assets.map(async asset => {
|
||||
const requestOptions = await octokit.repos.getReleaseAsset.endpoint({
|
||||
const requestOptions = octokit.repos.getReleaseAsset.endpoint({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
asset_id: asset.id,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -815,10 +815,10 @@ void App::AllowCertificateError(
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
bool prevent_default =
|
||||
Emit("certificate-error",
|
||||
WebContents::FromOrCreate(isolate, web_contents), request_url,
|
||||
net::ErrorToString(cert_error), ssl_info.cert, adapted_callback);
|
||||
bool prevent_default = Emit(
|
||||
"certificate-error", WebContents::FromOrCreate(isolate, web_contents),
|
||||
request_url, net::ErrorToString(cert_error), ssl_info.cert,
|
||||
adapted_callback, is_main_frame_request);
|
||||
|
||||
// Deny the certificate by default.
|
||||
if (!prevent_default)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,7 @@ void BrowserWindow::UpdateDraggableRegions(
|
||||
if (window_->has_frame())
|
||||
return;
|
||||
|
||||
if (&draggable_regions_ != ®ions) {
|
||||
if (&draggable_regions_ != ®ions && web_contents()) {
|
||||
auto* view =
|
||||
static_cast<content::WebContentsImpl*>(web_contents())->GetView();
|
||||
if (view) {
|
||||
|
||||
@@ -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);
|
||||
@@ -1147,6 +1159,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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user