Compare commits

..

27 Commits

Author SHA1 Message Date
Sudowoodo Release Bot
e02de74ff2 Bump v23.0.0-nightly.20221010 2022-10-10 14:35:21 -07:00
Shelley Vohr
ebb866e63d fix: override content::ContentMainDelegate::CreateContentClient() (#35932) 2022-10-10 16:48:44 +02:00
Sudowoodo Release Bot
ef00a2a1da Revert "Bump v23.0.0-nightly.20221010"
This reverts commit 6072c4c71b.
2022-10-10 07:35:18 -07:00
Sudowoodo Release Bot
6072c4c71b Bump v23.0.0-nightly.20221010 2022-10-10 06:01:40 -07:00
Samuel Attard
1fe21ff712 fix: expose the built-in electron module via the ESM loader (#35930) 2022-10-10 03:02:30 -07:00
David Sanders
a072f06168 docs: remove pywin32 mention in Windows build instructions (#35940) 2022-10-10 03:01:11 -07:00
Milan Burda
8bfbb251cc fix: add missing #include "base/cxx17_backports.h" (#35945) 2022-10-10 03:00:56 -07:00
Sudowoodo Release Bot
3f4c4a4470 Bump v23.0.0-nightly.20221007 2022-10-07 06:01:54 -07:00
Sudowoodo Release Bot
5c784c2b1b Bump v23.0.0-nightly.20221006 2022-10-06 06:01:26 -07:00
Samuel Attard
e1494ddc47 chore: cherry-pick c83640db21b5 from chromium (#35924)
* chore: cherry-pick c83640db21b5 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-10-06 04:27:28 -07:00
Samuel Attard
e31c96a564 fix: only override valid electron module names (#35915)
Fixes #33014
2022-10-06 19:14:03 +09:00
Shelley Vohr
faafcc7f87 refactor: eliminate DecrementCapturerCount patch (#35710) 2022-10-05 19:51:33 +02:00
Shelley Vohr
a6b6816bec build: clean up patch linting errors (#35917) 2022-10-05 10:34:53 -07:00
Sudowoodo Release Bot
f916ce2c49 Bump v23.0.0-nightly.20221005 2022-10-05 06:01:06 -07:00
Keeley Hammond
6196393c94 docs: update supported Mac versions (#35911) 2022-10-04 21:25:03 -07:00
Shmuel Leider
ff0517be3e docs: update bluetooth fiddle example event name to trigger correct event (#35894)
* Fix event type spelling for bluetooth fiddle example

* docs: Fix event type spelling for bluetooth documentation fiddle example
2022-10-04 15:31:02 -04:00
Sudowoodo Release Bot
d8e037e426 Bump v23.0.0-nightly.20221004 2022-10-04 12:30:32 -07:00
Keeley Hammond
3bd85c8dc2 chore: update libcxx filenames (#35904)
* chore: update libcxx filenames

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-10-04 15:29:24 -04:00
Sudowoodo Release Bot
e63d4a6321 Revert "Bump v23.0.0-nightly.20221004"
This reverts commit 256d4678bb.
2022-10-04 08:16:47 -07:00
Sudowoodo Release Bot
256d4678bb Bump v23.0.0-nightly.20221004 2022-10-04 06:00:58 -07:00
Samuel Attard
2cda1443fc fix: ensure mas builds of the same application can use safestorage (#35864)
feat: ensure mas builds of the same application can use safestorage

This change ensures that MAS builds of applications with an equivilant darwin build that share the same name do not fight over access to the same Safe Storage account.

Specifically this changes the account name for app "My App" from "My App" to "My App AppStore" if the app is using a MAS build of Electron.

We attempt to migrate the safe storage key from the old account, if that migration succeeds we delete the old key and move on.

Existing apps that aren't built for the app store should be unimpacted, there is one edge case where a user uses BOTH an AppStore and a darwin build of the same app only one will keep it's access to the safestorage key as during the migration we delete the old account.  This is an acceptable edge case as no one should be actively using two versions of the same app.
2022-10-03 23:36:17 -07:00
Samuel Attard
12eade752d build: move from stale GH app to stale action (#35845)
* build: move from stale GH app to stale action

* Update .github/workflows/stale.yml

Co-authored-by: Jeremy Rose <jeremya@chromium.org>

* Update stale.yml

* Update .github/workflows/stale.yml

Co-authored-by: Jeremy Rose <jeremya@chromium.org>

* Update stale.yml

* Update .github/workflows/stale.yml

Co-authored-by: Jeremy Rose <jeremya@chromium.org>

* Update stale.yml

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-10-03 23:36:01 -07:00
Shelley Vohr
c76a931e20 fix: TryCatch scope in node_bindings (#35850)
fix: TryCatch scope in node_bindings
2022-10-03 23:35:20 -07:00
electron-roller[bot]
16f459228b chore: bump chromium to 108.0.5329.0 (main) (#35628)
Co-authored-by: Samuel Attard <sattard@salesforce.com>
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-10-03 13:21:00 -07:00
Sudowoodo Release Bot
94955a7999 Bump v23.0.0-nightly.20221003 2022-10-03 06:01:17 -07:00
Sudowoodo Release Bot
29ca3d1467 Bump v23.0.0-nightly.20220930 2022-09-30 06:01:05 -07:00
Sudowoodo Release Bot
3f598ef1ed Bump v23.0.0-nightly.20220929 2022-09-29 06:00:48 -07:00
21 changed files with 431 additions and 44 deletions

14
.github/stale.yml vendored
View File

@@ -1,14 +0,0 @@
daysUntilStale: 90
daysUntilClose: 30
exemptLabels:
- discussion
- security 🔒
- "enhancement :sparkles:"
staleLabel: stale
markComment: >
This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment!
closeComment: >
This issue has been closed as it was considered stale, this issue will not be
monitored. If this is a bug and you can reproduce this issue on a [supported
version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and ensure a repro is provided.

25
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: 'Close stale issues'
on:
schedule:
# 1:30am every day
- cron: '30 1 * * *'
permissions:
issues: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@3de2653986ebd134983c79fe2be5d45cc3d9f4e1
with:
days-before-stale: 90
days-before-close: 30
stale-issue-label: stale
operations-per-run: 1750
stale-issue-message: >
This issue has been automatically marked as stale. **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the [latest version of Electron](https://www.electronjs.org/releases/stable) or in the [beta](https://www.electronjs.org/releases/beta)—please include it with your comment!
close-issue-message: >
This issue has been closed due to inactivity, and will not be monitored. If this is a bug and you can reproduce this issue on a [supported version of Electron](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#timeline) please open a new issue and include instructions for reproducing the issue.
exempt-issue-labels: "discussion,security \U0001F512,enhancement :sparkles:"
only-pr-labels: not-a-real-label

View File

@@ -1 +1 @@
22.0.0-alpha.3
23.0.0-nightly.20221010

View File

@@ -1437,13 +1437,16 @@ Returns `boolean` - Whether the window's document has been edited.
#### `win.blurWebView()`
#### `win.capturePage([rect])`
#### `win.capturePage([rect, opts])`
* `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture
* `opts` Object (optional)
* `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`.
* `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`.
Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty.
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. The page is considered visible when its browser window is hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true.
#### `win.loadURL(url[, options])`

View File

@@ -1338,20 +1338,25 @@ const requestId = webContents.findInPage('api')
console.log(requestId)
```
#### `contents.capturePage([rect])`
#### `contents.capturePage([rect, opts])`
* `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured.
* `opts` Object (optional)
* `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`.
* `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`.
Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
The page is considered visible when its browser window is hidden and the capturer count is non-zero.
If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true.
#### `contents.isBeingCaptured()`
Returns `boolean` - Whether this page is being captured. It returns true when the capturer count
is large then 0.
#### `contents.incrementCapturerCount([size, stayHidden, stayAwake])`
#### `contents.incrementCapturerCount([size, stayHidden, stayAwake])` _Deprecated_
* `size` [Size](structures/size.md) (optional) - The preferred size for the capturer.
* `stayHidden` boolean (optional) - Keep the page hidden instead of visible.
@@ -1362,7 +1367,9 @@ hidden and the capturer count is non-zero. If you would like the page to stay hi
This also affects the Page Visibility API.
#### `contents.decrementCapturerCount([stayHidden, stayAwake])`
**Deprecated:** This API's functionality is now handled automatically within `contents.capturePage()`. See [breaking changes](../breaking-changes.md).
#### `contents.decrementCapturerCount([stayHidden, stayAwake])` _Deprecated_
* `stayHidden` boolean (optional) - Keep the page in hidden state instead of visible.
* `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep.
@@ -1371,6 +1378,9 @@ Decrease the capturer count by one. The page will be set to hidden or occluded s
browser window is hidden or occluded and the capturer count reaches zero. If you want to
decrease the hidden capturer count instead you should set `stayHidden` to true.
**Deprecated:** This API's functionality is now handled automatically within `contents.capturePage()`.
See [breaking changes](../breaking-changes.md).
#### `contents.getPrinters()` _Deprecated_
Get the system printer list.

View File

@@ -38,14 +38,98 @@ win.webContents.on('input-event', (_, event) => {
})
```
### Removed: `webContents.incrementCapturerCount(stayHidden, stayAwake)`
The `webContents.incrementCapturerCount(stayHidden, stayAwake)` function has been removed.
It is now automatically handled by `webContents.capturePage` when a page capture completes.
```js
const w = new BrowserWindow({ show: false })
// Removed in Electron 23
w.webContents.incrementCapturerCount()
w.capturePage().then(image => {
console.log(image.toDataURL())
w.webContents.decrementCapturerCount()
})
// Replace with
w.capturePage().then(image => {
console.log(image.toDataURL())
})
```
### Removed: `webContents.decrementCapturerCount(stayHidden, stayAwake)`
The `webContents.decrementCapturerCount(stayHidden, stayAwake)` function has been removed.
It is now automatically handled by `webContents.capturePage` when a page capture completes.
```js
const w = new BrowserWindow({ show: false })
// Removed in Electron 23
w.webContents.incrementCapturerCount()
w.capturePage().then(image => {
console.log(image.toDataURL())
w.webContents.decrementCapturerCount()
})
// Replace with
w.capturePage().then(image => {
console.log(image.toDataURL())
})
```
## Planned Breaking API Changes (22.0)
### Deprecated: `webContents.incrementCapturerCount(stayHidden, stayAwake)`
`webContents.incrementCapturerCount(stayHidden, stayAwake)` has been deprecated.
It is now automatically handled by `webContents.capturePage` when a page capture completes.
```js
const w = new BrowserWindow({ show: false })
// Removed in Electron 23
w.webContents.incrementCapturerCount()
w.capturePage().then(image => {
console.log(image.toDataURL())
w.webContents.decrementCapturerCount()
})
// Replace with
w.capturePage().then(image => {
console.log(image.toDataURL())
})
```
### Removed: `webContents.decrementCapturerCount(stayHidden, stayAwake)`
`webContents.decrementCapturerCount(stayHidden, stayAwake)` has been deprecated.
It is now automatically handled by `webContents.capturePage` when a page capture completes.
```js
const w = new BrowserWindow({ show: false })
// Removed in Electron 23
w.webContents.incrementCapturerCount()
w.capturePage().then(image => {
console.log(image.toDataURL())
w.webContents.decrementCapturerCount()
})
// Replace with
w.capturePage().then(image => {
console.log(image.toDataURL())
})
```
### Removed: WebContents `new-window` event
The `new-window` event of WebContents has been removed. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler).
```js
// Removed in Electron 21
// Removed in Electron 22
webContents.on('new-window', (event) => {
event.preventDefault()
})

View File

@@ -116,10 +116,6 @@ $ git config --system core.longpaths true
This can happen during build, when Debugging Tools for Windows has been installed with Windows Driver Kit. Uninstall Windows Driver Kit and install Debugging Tools with steps described above.
### ImportError: No module named win32file
Make sure you have installed `pywin32` with `pip install pywin32`.
### Build Scripts Hang Until Keypress
This bug is a "feature" of Windows' command prompt. It happens when clicking inside the prompt window with

View File

@@ -52,8 +52,9 @@ if (process.type === 'renderer') {
}
const originalResolveFilename = Module._resolveFilename;
const electronModuleNames = new Set(['electron', 'electron/main', 'electron/renderer', 'electron/common']);
Module._resolveFilename = function (request: string, parent: NodeModule, isMain: boolean, options?: { paths: Array<string>}) {
if (request === 'electron' || request.startsWith('electron/')) {
if (electronModuleNames.has(request)) {
return 'electron';
} else {
return originalResolveFilename(request, parent, isMain, options);

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "22.0.0-alpha.3",
"version": "23.0.0-nightly.20221010",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {

View File

@@ -120,4 +120,5 @@ fix_crash_loading_non-standard_schemes_in_iframes.patch
disable_optimization_guide_for_preconnect_feature.patch
fix_return_v8_value_from_localframe_requestexecutescript.patch
create_browser_v8_snapshot_file_name_fuse.patch
feat_ensure_mas_builds_of_the_same_application_can_use_safestorage.patch
cherry-pick-c83640db21b5.patch

View File

@@ -0,0 +1,105 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@salesforce.com>
Date: Thu, 29 Sep 2022 16:58:47 -0700
Subject: feat: ensure mas builds of the same application can use safestorage
This change ensures that MAS builds of applications with an equivilant darwin build that share the same name do not fight over access to the same Safe Storage account.
Specifically this changes the account name for app "My App" from "My App" to "My App AppStore" if the app is using a MAS build of Electron.
We attempt to migrate the safe storage key from the old account, if that migration succeeds we delete the old key and move on.
Existing apps that aren't built for the app store should be unimpacted, there is one edge case where a user uses BOTH an AppStore and a darwin build of the same app only one will keep it's access to the safestorage key as during the migration we delete the old account. This is an acceptable edge case as no one should be actively using two versions of the same app.
diff --git a/components/os_crypt/keychain_password_mac.mm b/components/os_crypt/keychain_password_mac.mm
index 214ae79b9a6de27b99ccfa9cf03327449fd79198..1b740e8dd19eeb34e68db30ba66ebadd1a132a39 100644
--- a/components/os_crypt/keychain_password_mac.mm
+++ b/components/os_crypt/keychain_password_mac.mm
@@ -22,6 +22,12 @@
using KeychainNameContainerType = const base::NoDestructor<std::string>;
#endif
+#if defined(MAS_BUILD)
+const char kAccountNameSuffix[] = " App Store Key";
+#else
+const char kAccountNameSuffix[] = " Key";
+#endif
+
namespace {
// These two strings ARE indeed user facing. But they are used to access
@@ -82,11 +88,18 @@
std::string KeychainPassword::GetPassword() const {
UInt32 password_length = 0;
void* password_data = nullptr;
+ KeychainPassword::KeychainNameType service_name = GetServiceName();
+ KeychainPassword::KeychainNameType account_name = GetAccountName();
+ const std::string account_name_suffix = kAccountNameSuffix;
+ const std::string suffixed_account_name = account_name + account_name_suffix;
+
+ // We should check if the suffixed account exists first
OSStatus error = keychain_.FindGenericPassword(
- GetServiceName().size(), GetServiceName().c_str(),
- GetAccountName().size(), GetAccountName().c_str(), &password_length,
+ service_name.size(), service_name.c_str(),
+ suffixed_account_name.size(), suffixed_account_name.c_str(), &password_length,
&password_data, nullptr);
+ // If it exists we can return it immediately
if (error == noErr) {
std::string password =
std::string(static_cast<char*>(password_data), password_length);
@@ -94,9 +107,52 @@
return password;
}
+ // If the error was anything other than "it does not exist" we should error out here
+ // This normally means the account exists but we were deniged access to it
+ if (error != errSecItemNotFound) {
+ OSSTATUS_LOG(ERROR, error) << "Keychain lookup for suffixed key failed";
+ return std::string();
+ }
+
+ // If the suffixed account didn't exist, we should check if the legacy non-suffixed account
+ // exists. If it does we can use that key and migrate it to the new account
+ base::ScopedCFTypeRef<SecKeychainItemRef> item_ref;
+ error = keychain_.FindGenericPassword(
+ service_name.size(), service_name.c_str(),
+ account_name.size(), account_name.c_str(), &password_length,
+ &password_data, item_ref.InitializeInto());
+
+ if (error == noErr) {
+ std::string password =
+ std::string(static_cast<char*>(password_data), password_length);
+
+ // If we found the legacy account name we should copy it over to
+ // the new suffixed account
+ error = keychain_.AddGenericPassword(
+ service_name.size(), service_name.data(), suffixed_account_name.size(),
+ suffixed_account_name.data(), password.size(), password_data, NULL);
+
+ if (error == noErr) {
+ // If we successfully made the suffixed account we can delete the old
+ // account to ensure new apps don't try to use it and run into IAM
+ // issues
+ error = keychain_.ItemDelete(item_ref.get());
+ if (error != noErr) {
+ OSSTATUS_DLOG(ERROR, error) << "Keychain delete for legacy key failed";
+ }
+ } else {
+ OSSTATUS_DLOG(ERROR, error) << "Keychain add for suffixed key failed";
+ }
+
+ keychain_.ItemFreeContent(password_data);
+ return password;
+ }
+
+ // If the legacy account name was not found, make a new account in the
+ // with the suffixed name
if (error == errSecItemNotFound) {
std::string password = AddRandomPasswordToKeychain(
- keychain_, GetServiceName(), GetAccountName());
+ keychain_, service_name, suffixed_account_name);
return password;
}

View File

@@ -51,3 +51,4 @@ fixup_for_error_declaration_shadows_a_local_variable.patch
fixup_for_wc_98-compat-extra-semi.patch
drop_deserializerequest_move_constructor_for_c_20_compat.patch
fix_parallel_test-v8-stats.patch
fix_expose_the_built-in_electron_module_via_the_esm_loader.patch

View File

@@ -0,0 +1,87 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@salesforce.com>
Date: Thu, 6 Oct 2022 04:09:16 -0700
Subject: fix: expose the built-in electron module via the ESM loader
This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer
diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js
index 5ae0e17dcfb5e24a1a117c33c4d42891686e693f..619fe6cef3b02eb575410225f41d3e7d51f37b93 100644
--- a/lib/internal/modules/esm/get_format.js
+++ b/lib/internal/modules/esm/get_format.js
@@ -31,6 +31,7 @@ const protocolHandlers = ObjectAssign(ObjectCreate(null), {
'http:': getHttpProtocolModuleFormat,
'https:': getHttpProtocolModuleFormat,
'node:'() { return 'builtin'; },
+ 'electron:'() { return 'commonjs'; },
});
function getDataProtocolModuleFormat(parsed) {
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index fc5dcd6863dc358102a74bd2cc723d54436fae64..97eea17d815967671a2a0fc2a9c95a9bb85947ac 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -883,6 +883,8 @@ function parsePackageName(specifier, base) {
return { packageName, packageSubpath, isScoped };
}
+const electronSpecifiers = new SafeSet(['electron', 'electron/main', 'electron/common', 'electron/renderer']);
+
/**
* @param {string} specifier
* @param {string | URL | undefined} base
@@ -895,6 +897,10 @@ function packageResolve(specifier, base, conditions) {
return new URL('node:' + specifier);
}
+ if (electronSpecifiers.has(specifier)) {
+ return new URL('electron:electron');
+ }
+
const { packageName, packageSubpath, isScoped } =
parsePackageName(specifier, base);
@@ -1095,7 +1101,7 @@ function checkIfDisallowedImport(specifier, parsed, parsedParentURL) {
function throwIfUnsupportedURLProtocol(url) {
if (url.protocol !== 'file:' && url.protocol !== 'data:' &&
- url.protocol !== 'node:') {
+ url.protocol !== 'node:' && url.protocol !== 'electron:') {
throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(url);
}
}
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index 8fb3c96f8dc4c535c3898755f7846ae24d9867c4..bda3ca0797e8f1b1d69295c2276c0f841cae99f2 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -155,7 +155,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
if (!cjsParse) await initCJSParse();
const { module, exportNames } = cjsPreparseModuleExports(filename);
- const namesWithDefault = exportNames.has('default') ?
+ const namesWithDefault = filename === 'electron' ? ['default', ...Object.keys(module.exports)] : exportNames.has('default') ?
[...exportNames] : ['default', ...exportNames];
return new ModuleWrap(url, undefined, namesWithDefault, function() {
@@ -174,7 +174,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
}
}
- for (const exportName of exportNames) {
+ for (const exportName of namesWithDefault) {
if (!ObjectPrototypeHasOwnProperty(exports, exportName) ||
exportName === 'default')
continue;
diff --git a/lib/internal/url.js b/lib/internal/url.js
index 22bff28595f6f5b109ae47c79aa1f5ac463ec6c3..d4eb2e044cc1152f48c92d0503f9216e3aad5f4b 100644
--- a/lib/internal/url.js
+++ b/lib/internal/url.js
@@ -1432,6 +1432,8 @@ function fileURLToPath(path) {
path = new URL(path);
else if (!isURLInstance(path))
throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path);
+ if (path.protocol === 'electron:')
+ return 'electron';
if (path.protocol !== 'file:')
throw new ERR_INVALID_URL_SCHEME('file');
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);

View File

@@ -181,6 +181,7 @@ const LINTERS = [{
const patchesConfig = path.resolve(patchesDir, 'config.json');
// If the config does not exist, that's a problem
if (!fs.existsSync(patchesConfig)) {
console.error(`Patches config file: "${patchesConfig}" does not exist`);
process.exit(1);
}
@@ -188,34 +189,48 @@ const LINTERS = [{
for (const key of Object.keys(config)) {
// The directory the config points to should exist
const targetPatchesDir = path.resolve(__dirname, '../../..', key);
if (!fs.existsSync(targetPatchesDir)) throw new Error(`target patch directory: "${targetPatchesDir}" does not exist`);
if (!fs.existsSync(targetPatchesDir)) {
console.error(`target patch directory: "${targetPatchesDir}" does not exist`);
process.exit(1);
}
// We need a .patches file
const dotPatchesPath = path.resolve(targetPatchesDir, '.patches');
if (!fs.existsSync(dotPatchesPath)) throw new Error(`.patches file: "${dotPatchesPath}" does not exist`);
if (!fs.existsSync(dotPatchesPath)) {
console.error(`.patches file: "${dotPatchesPath}" does not exist`);
process.exit(1);
}
// Read the patch list
const patchFileList = fs.readFileSync(dotPatchesPath, 'utf8').trim().split('\n');
const patchFileSet = new Set(patchFileList);
patchFileList.reduce((seen, file) => {
if (seen.has(file)) {
throw new Error(`'${file}' is listed in ${dotPatchesPath} more than once`);
console.error(`'${file}' is listed in ${dotPatchesPath} more than once`);
process.exit(1);
}
return seen.add(file);
}, new Set());
if (patchFileList.length !== patchFileSet.size) throw new Error('each patch file should only be in the .patches file once');
if (patchFileList.length !== patchFileSet.size) {
console.error('Each patch file should only be in the .patches file once');
process.exit(1);
}
for (const file of fs.readdirSync(targetPatchesDir)) {
// Ignore the .patches file and READMEs
if (file === '.patches' || file === 'README.md') continue;
if (!patchFileSet.has(file)) {
throw new Error(`Expected the .patches file at "${dotPatchesPath}" to contain a patch file ("${file}") present in the directory but it did not`);
console.error(`Expected the .patches file at "${dotPatchesPath}" to contain a patch file ("${file}") present in the directory but it did not`);
process.exit(1);
}
patchFileSet.delete(file);
}
// If anything is left in this set, it means it did not exist on disk
if (patchFileSet.size > 0) {
throw new Error(`Expected all the patch files listed in the .patches file at "${dotPatchesPath}" to exist but some did not:\n${JSON.stringify([...patchFileSet.values()], null, 2)}`);
console.error(`Expected all the patch files listed in the .patches file at "${dotPatchesPath}" to exist but some did not:\n${JSON.stringify([...patchFileSet.values()], null, 2)}`);
process.exit(1);
}
}

View File

@@ -317,9 +317,6 @@ absl::optional<int> ElectronMainDelegate::BasicStartupComplete() {
::switches::kDisableGpuMemoryBufferCompositorResources);
#endif
content_client_ = std::make_unique<ElectronContentClient>();
SetContentClient(content_client_.get());
return absl::nullopt;
}
@@ -440,6 +437,11 @@ base::StringPiece ElectronMainDelegate::GetBrowserV8SnapshotFilename() {
return ContentMainDelegate::GetBrowserV8SnapshotFilename();
}
content::ContentClient* ElectronMainDelegate::CreateContentClient() {
content_client_ = std::make_unique<ElectronContentClient>();
return content_client_.get();
}
content::ContentBrowserClient*
ElectronMainDelegate::CreateContentBrowserClient() {
browser_client_ = std::make_unique<ElectronBrowserClient>();

View File

@@ -38,6 +38,7 @@ class ElectronMainDelegate : public content::ContentMainDelegate {
void PreSandboxStartup() override;
void SandboxInitialized(const std::string& process_type) override;
absl::optional<int> PreBrowserMain() override;
content::ContentClient* CreateContentClient() override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
content::ContentGpuClient* CreateContentGpuClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;

View File

@@ -386,11 +386,13 @@ base::IDMap<WebContents*>& GetAllWebContents() {
return *s_all_web_contents;
}
// Called when CapturePage is done.
void OnCapturePageDone(gin_helper::Promise<gfx::Image> promise,
base::ScopedClosureRunner capture_handle,
const SkBitmap& bitmap) {
// Hack to enable transparency in captured image
promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap));
capture_handle.RunAndReset();
}
absl::optional<base::TimeDelta> GetCursorBlinkInterval() {
@@ -3174,13 +3176,22 @@ void WebContents::StartDrag(const gin_helper::Dictionary& item,
}
v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
gfx::Rect rect;
gin_helper::Promise<gfx::Image> promise(args->isolate());
v8::Local<v8::Promise> handle = promise.GetHandle();
// get rect arguments if they exist
gfx::Rect rect;
args->GetNext(&rect);
bool stay_hidden = false;
bool stay_awake = false;
if (args && args->Length() == 2) {
gin_helper::Dictionary options;
if (args->GetNext(&options)) {
options.Get("stayHidden", &stay_hidden);
options.Get("stayAwake", &stay_awake);
}
}
auto* const view = web_contents()->GetRenderWidgetHostView();
if (!view) {
promise.Resolve(gfx::Image());
@@ -3199,6 +3210,9 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
}
#endif // BUILDFLAG(IS_MAC)
auto capture_handle = web_contents()->IncrementCapturerCount(
rect.size(), stay_hidden, stay_awake);
// Capture full page if user doesn't specify a |rect|.
const gfx::Size view_size =
rect.IsEmpty() ? view->GetViewBounds().size() : rect.size();
@@ -3215,11 +3229,18 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
view->CopyFromSurface(gfx::Rect(rect.origin(), view_size), bitmap_size,
base::BindOnce(&OnCapturePageDone, std::move(promise)));
base::BindOnce(&OnCapturePageDone, std::move(promise),
std::move(capture_handle)));
return handle;
}
// TODO(codebytere): remove in Electron v23.
void WebContents::IncrementCapturerCount(gin::Arguments* args) {
EmitWarning(node::Environment::GetCurrent(args->isolate()),
"webContents.incrementCapturerCount() is deprecated and will be "
"removed in v23",
"electron");
gfx::Size size;
bool stay_hidden = false;
bool stay_awake = false;
@@ -3236,7 +3257,13 @@ void WebContents::IncrementCapturerCount(gin::Arguments* args) {
.Release();
}
// TODO(codebytere): remove in Electron v23.
void WebContents::DecrementCapturerCount(gin::Arguments* args) {
EmitWarning(node::Environment::GetCurrent(args->isolate()),
"webContents.decrementCapturerCount() is deprecated and will be "
"removed in v23",
"electron");
bool stay_hidden = false;
bool stay_awake = false;

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 22,0,0,3
PRODUCTVERSION 22,0,0,3
FILEVERSION 23,0,0,20221010
PRODUCTVERSION 23,0,0,20221010
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "22.0.0"
VALUE "FileVersion", "23.0.0"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "22.0.0"
VALUE "ProductVersion", "23.0.0"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -6,6 +6,7 @@
#include <memory>
#include <vector>
#include "base/cxx17_backports.h"
#include "base/feature_list.h"
#include "base/i18n/rtl.h"
#include "components/autofill/core/common/autofill_features.h"

View File

@@ -1737,6 +1737,36 @@ describe('BrowserWindow module', () => {
expect(image.isEmpty()).to.equal(true);
});
ifit(process.platform === 'darwin')('honors the stayHidden argument', async () => {
const w = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
w.loadFile(path.join(fixtures, 'pages', 'visibilitychange.html'));
{
const [, visibilityState, hidden] = await emittedOnce(ipcMain, 'pong');
expect(visibilityState).to.equal('visible');
expect(hidden).to.be.false('hidden');
}
w.hide();
{
const [, visibilityState, hidden] = await emittedOnce(ipcMain, 'pong');
expect(visibilityState).to.equal('hidden');
expect(hidden).to.be.true('hidden');
}
await w.capturePage({ x: 0, y: 0, width: 0, height: 0 }, { stayHidden: true });
const visible = await w.webContents.executeJavaScript('document.visibilityState');
expect(visible).to.equal('hidden');
});
it('resolves after the window is hidden', async () => {
const w = new BrowserWindow({ show: false });
w.loadFile(path.join(fixtures, 'pages', 'a.html'));

View File

@@ -174,4 +174,16 @@ describe('modules support', () => {
});
});
});
describe('esm', () => {
it('can load the built-in "electron" module via ESM import', async () => {
await expect(import('electron')).to.eventually.be.ok();
});
it('the built-in "electron" module loaded via ESM import has the same exports as the CJS module', async () => {
const esmElectron = await import('electron');
const cjsElectron = require('electron');
expect(Object.keys(esmElectron)).to.deep.equal(Object.keys(cjsElectron));
});
});
});