Compare commits

...

11 Commits

Author SHA1 Message Date
trop[bot]
0e84572a8f docs: fix typo in ASAR integrity docs (#42626)
Fix typo in ASAR integrity docs

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Corbin Crutchley <git@crutchcorn.dev>
2024-06-24 11:53:30 +02:00
trop[bot]
79751340c6 fix: fetch-dependent interfaces in Web Workers (#42595)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-20 16:32:58 -04:00
trop[bot]
50ea20168d feat: expose system preferences to utility process (#42599)
* chore: expose  system preferences to utility process

* chore: add tests, doc changes and module-list update

* relative link

* use @

* fix test

* chore: disable linux test

* kick

* noop on windows utility process

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: George Xu <33054982+georgexu99@users.noreply.github.com>
2024-06-20 16:12:16 -04:00
trop[bot]
38f7beb216 chore: improve error message on failed SMApp register/unregister (#42558)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-20 20:28:27 +02:00
trop[bot]
d7858f2f91 fix: MessagePort closing unexpectedly with non-cloneable objects (#42581)
* fix: MessagePort closing unexpectedly with non-cloneable objects

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* fix: handle serialization failure in parentPort

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-19 10:10:57 -04:00
trop[bot]
76204e184a docs: add backticks around example URL (#42544)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2024-06-18 21:47:39 -07:00
trop[bot]
23b61cf833 chore: cherry-pick f8010390 from chromium (#42568)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2024-06-18 18:51:16 -04:00
trop[bot]
ff16e0e858 test: use longer timeout on contentTracing tests on WOA (#42551)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-06-18 17:29:06 +02:00
trop[bot]
a9b0e73492 build: fix clang format location helper (#42530)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-17 16:21:50 -04:00
Keeley Hammond
9fc0bfece2 build: disable GitHub Actions in 32-x-y (#42532)
build: disable GHActions in 32-x-y
2024-06-17 11:32:12 -07:00
trop[bot]
efe98f76d1 docs(web-embeds): replace BrowserView ref with WebContentsView (#42469)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Mark Lee <malept@users.noreply.github.com>
2024-06-12 15:04:23 -05:00
25 changed files with 261 additions and 40 deletions

View File

@@ -279,7 +279,7 @@ Aliased to `--debug[=[host:]port`.
Specify ways of the inspector web socket url exposure.
By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list.
By default inspector websocket url is available in stderr and under /json/list endpoint on `http://host:port/json/list`.
### `--no-deprecation`

View File

@@ -2,7 +2,7 @@
> Get system preferences.
Process: [Main](../glossary.md#main-process)
Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)
```js
const { systemPreferences } = require('electron')

View File

@@ -125,7 +125,7 @@ in the form included below:
]
```
::: info
:::info
For an implementation example, see [`src/resedit.ts`](https://github.com/electron/packager/blob/main/src/resedit.ts)
in the Electron Packager code.

View File

@@ -23,8 +23,8 @@ and only allow the capabilities you want to support.
[we do not recommend you to use WebViews](../api/webview-tag.md#warning),
as this tag undergoes dramatic architectural changes that may affect stability
of your application. Consider switching to alternatives, like `iframe` and
Electron's `BrowserView`, or an architecture that avoids embedded content
by design.
Electron's [`WebContentsView`](../api/web-contents-view.md), or an architecture
that avoids embedded content by design.
[WebViews](../api/webview-tag.md) are based on Chromium's WebViews and are not
explicitly supported by Electron. We do not guarantee that the WebView API will

View File

@@ -350,6 +350,7 @@ auto_filenames = {
utility_bundle_deps = [
"lib/browser/api/net-fetch.ts",
"lib/browser/api/system-preferences.ts",
"lib/browser/message-port-main.ts",
"lib/common/api/net-client-request.ts",
"lib/common/define-properties.ts",

View File

@@ -1,4 +1,5 @@
// Utility side modules, please sort alphabetically.
export const utilityNodeModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'net', loader: () => require('./net') }
{ name: 'net', loader: () => require('./net') },
{ name: 'systemPreferences', loader: () => require('@electron/internal/browser/api/system-preferences') }
];

View File

@@ -17,6 +17,14 @@ const { makeRequireFunction } = __non_webpack_require__('internal/modules/helper
global.module = new Module('electron/js2c/worker_init');
global.require = makeRequireFunction(global.module);
// See WebWorkerObserver::WorkerScriptReadyForEvaluation.
if ((globalThis as any).blinkfetch) {
const keys = ['fetch', 'Response', 'FormData', 'Request', 'Headers'];
for (const key of keys) {
(globalThis as any)[key] = (globalThis as any)[`blink${key}`];
}
}
// Set the __filename to the path of html file if it is file: protocol.
// NB. 'self' isn't defined in an AudioWorklet.
if (typeof self !== 'undefined' && self.location.protocol === 'file:') {

View File

@@ -129,3 +129,4 @@ feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch
fix_font_face_resolution_when_renderer_is_blocked.patch
feat_enable_passing_exit_code_on_service_process_crash.patch
chore_remove_reference_to_chrome_browser_themes.patch
x11_use_localized_display_label_only_for_browser_process.patch

View File

@@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
Date: Mon, 17 Jun 2024 18:05:47 +0000
Subject: Use localized display label only for browser process
With https://crrev.com/c/5098130, GetPrimaryDisplayRefreshIntervalFromXrandr uses BuildDisplaysFromXRandRInfo
to calculate the primary display frequency. In software compositing mode --disable-gpu-compositing,
this code path will be called from the gpu process via SoftwareOutputSurface::SwapBuffers and
can trigger a crash when attempting to set localized string. This is because on linux,
gpu process does not have access to the resource bundle.
Bug: none
Change-Id: I9d66b98c07a1a8671369546d4fc685213904a84f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5631219
Auto-Submit: Deepak Mohan (Robo) <hop2deep@gmail.com>
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Commit-Queue: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1315980}
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index ffaea4fef9931050f1c1888674bf2f7498c578da..faf59929eb7e291502c449631e54f3841582bd9e 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -299,6 +299,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
const display::DisplayConfig& display_config,
size_t* primary_display_index_out) {
DCHECK(primary_display_index_out);
+ auto* command_line = base::CommandLine::ForCurrentProcess();
const float primary_scale = display_config.primary_scale;
auto* connection = x11::Connection::Get();
@@ -348,7 +349,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
connection->Flush();
std::vector<x11::Future<x11::GetPropertyReply>> icc_futures{n_iccs};
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) {
+ if (!command_line->HasSwitch(switches::kHeadless)) {
for (size_t monitor = 0; monitor < n_iccs; ++monitor) {
icc_futures[monitor] = GetIccProfileFuture(connection, monitor);
}
@@ -446,11 +447,18 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
}
const std::string name(output_info->name.begin(), output_info->name.end());
+ auto process_type =
+ command_line->GetSwitchValueASCII("type");
if (base::StartsWith(name, "eDP") || base::StartsWith(name, "LVDS")) {
display::SetInternalDisplayIds({display_id});
- // Use localized variant of "Built-in display" for internal displays.
+ // For browser process which has access to resource bundle,
+ // use localized variant of "Built-in display" for internal displays.
// This follows the ozone DRM behavior (i.e. ChromeOS).
- display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
+ if (process_type.empty()) {
+ display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
+ } else {
+ display.set_label("Built-in display");
+ }
} else {
display.set_label(edid_parser.display_name());
}

View File

@@ -4,6 +4,7 @@ import contextlib
import errno
import json
import os
import platform
import shutil
import subprocess
import sys
@@ -184,13 +185,16 @@ def get_electron_exec():
def get_buildtools_executable(name):
buildtools = os.path.realpath(os.path.join(ELECTRON_DIR, '..', 'buildtools'))
chromium_platform = {
'darwin': 'mac',
'linux': 'linux64',
'linux2': 'linux64',
'win32': 'win',
'cygwin': 'win',
}[sys.platform]
if sys.platform == 'darwin':
chromium_platform = 'mac_arm64' if platform.machine() == 'arm64' else 'mac'
elif sys.platform in ['win32', 'cygwin']:
chromium_platform = 'win'
elif sys.platform in ['linux', 'linux2']:
chromium_platform = 'linux64'
else:
raise Exception(f"Unsupported platform: {sys.platform}")
if name == 'clang-format':
path = os.path.join(buildtools, chromium_platform, 'format', name)
else:

View File

@@ -385,6 +385,7 @@ function buildCircleCI (targetBranch, options) {
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function buildGHActions (targetBranch, options) {
if (options.job) {
assert(ghActionsPublishWorkflows.includes(options.job), `Unknown GitHub Actions workflow name: ${options.job}. Valid values are: ${ghActionsPublishWorkflows}.`);
@@ -405,10 +406,10 @@ function runRelease (targetBranch, options) {
buildCircleCI(targetBranch, options);
break;
}
case 'GitHubActions': {
buildGHActions(targetBranch, options);
break;
}
// case 'GitHubActions': {
// buildGHActions(targetBranch, options);
// break;
// }
case 'AppVeyor': {
buildAppVeyor(targetBranch, options);
break;
@@ -421,7 +422,7 @@ function runRelease (targetBranch, options) {
} else {
buildCircleCI(targetBranch, options);
buildAppVeyor(targetBranch, options);
buildGHActions(targetBranch, options);
// buildGHActions(targetBranch, options);
}
console.log(`${jobRequestedCount} jobs were requested.`);
}

View File

@@ -159,6 +159,8 @@ std::string SystemPreferences::GetMediaAccessStatus(
}
void SystemPreferences::InitializeWindow() {
if (electron::IsUtilityProcess())
return;
// Wait until app is ready before creating sys color listener
// Creating this listener before the app is ready causes global shortcuts
// to not fire

View File

@@ -76,8 +76,11 @@ void MessagePort::PostMessage(gin::Arguments* args) {
return;
}
electron::SerializeV8Value(args->isolate(), message_value,
&transferable_message);
if (!electron::SerializeV8Value(args->isolate(), message_value,
&transferable_message)) {
// SerializeV8Value sets an exception.
return;
}
v8::Local<v8::Value> transferables;
std::vector<gin::Handle<MessagePort>> wrapped_ports;

View File

@@ -100,9 +100,10 @@
V(electron_renderer_ipc) \
V(electron_renderer_web_frame)
#define ELECTRON_UTILITY_BINDINGS(V) \
V(electron_browser_event_emitter) \
V(electron_common_net) \
#define ELECTRON_UTILITY_BINDINGS(V) \
V(electron_browser_event_emitter) \
V(electron_browser_system_preferences) \
V(electron_common_net) \
V(electron_utility_parent_port)
#define ELECTRON_TESTING_BINDINGS(V) V(electron_common_testing)

View File

@@ -111,7 +111,7 @@ std::string GetLaunchStringForError(NSError* error) {
return "The specified path doesn't exist or the helper tool at the "
"specified path isn't valid";
default:
return "Failed to register the login item";
return base::SysNSStringToUTF8([error localizedDescription]);
}
}

View File

@@ -66,9 +66,25 @@ void WebWorkerObserver::WorkerScriptReadyForEvaluation(
std::shared_ptr<node::Environment> env =
node_bindings_->CreateEnvironment(worker_context, nullptr);
// We need to use the Blink implementation of fetch in web workers
// Node.js deletes the global fetch function when their fetch implementation
// is disabled, so we need to save and re-add it after the Node.js environment
// is loaded. See corresponding change in node/init.ts.
v8::Local<v8::Object> global = worker_context->Global();
v8::Local<v8::String> fetch_string = gin::StringToV8(env->isolate(), "fetch");
v8::MaybeLocal<v8::Value> fetch = global->Get(worker_context, fetch_string);
std::vector<std::string> keys = {"fetch", "Response", "FormData", "Request",
"Headers"};
for (const auto& key : keys) {
v8::MaybeLocal<v8::Value> value =
global->Get(worker_context, gin::StringToV8(isolate, key.c_str()));
if (!value.IsEmpty()) {
std::string blink_key = "blink" + key;
global
->Set(worker_context, gin::StringToV8(isolate, blink_key.c_str()),
value.ToLocalChecked())
.Check();
}
}
// Add Electron extended APIs.
electron_bindings_->BindTo(env->isolate(), env->process_object());
@@ -76,16 +92,6 @@ void WebWorkerObserver::WorkerScriptReadyForEvaluation(
// Load everything.
node_bindings_->LoadEnvironment(env.get());
// We need to use the Blink implementation of fetch in WebWorker process
// Node.js deletes the global fetch function when their fetch implementation
// is disabled, so we need to save and re-add it after the Node.js environment
// is loaded.
if (!fetch.IsEmpty()) {
worker_context->Global()
->Set(worker_context, fetch_string, fetch.ToLocalChecked())
.Check();
}
// Make uv loop being wrapped by window context.
node_bindings_->set_uv_env(env.get());

View File

@@ -44,7 +44,13 @@ void ParentPort::PostMessage(v8::Local<v8::Value> message_value) {
if (!connector_closed_ && connector_ && connector_->is_valid()) {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
blink::TransferableMessage transferable_message;
electron::SerializeV8Value(isolate, message_value, &transferable_message);
if (!electron::SerializeV8Value(isolate, message_value,
&transferable_message)) {
// SerializeV8Value sets an exception.
return;
}
mojo::Message mojo_message =
blink::mojom::TransferableMessage::WrapAsMessage(
std::move(transferable_message));

View File

@@ -25,7 +25,12 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
});
describe('startRecording', function () {
this.timeout(5e3);
if (process.platform === 'win32' && process.arch === 'arm64') {
// WOA needs more time
this.timeout(10e3);
} else {
this.timeout(5e3);
}
const getFileSizeInKiloBytes = (filePath: string) => {
const stats = fs.statSync(filePath);
@@ -84,7 +89,12 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
});
describe('stopRecording', function () {
this.timeout(5e3);
if (process.platform === 'win32' && process.arch === 'arm64') {
// WOA needs more time
this.timeout(10e3);
} else {
this.timeout(5e3);
}
it('does not crash on empty string', async () => {
const options = {

View File

@@ -7,6 +7,7 @@ import { closeWindow } from './lib/window-helpers';
import { once } from 'node:events';
import { pathToFileURL } from 'node:url';
import { setImmediate } from 'node:timers/promises';
import { systemPreferences } from 'electron';
const fixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process');
const isWindowsOnArm = process.platform === 'win32' && process.arch === 'arm64';
@@ -297,6 +298,17 @@ describe('utilityProcess module', () => {
expect(child.kill()).to.be.true();
await exit;
});
it('handles the parent port trying to send an non-clonable object', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'non-cloneable.js'));
await once(child, 'spawn');
child.postMessage('non-cloneable');
const [data] = await once(child, 'message');
expect(data).to.equal('caught-non-cloneable');
const exit = once(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
});
});
describe('behavior', () => {
@@ -393,6 +405,18 @@ describe('utilityProcess module', () => {
expect(output).to.include(result);
});
ifit(process.platform !== 'linux')('can access exposed main process modules from the utility process', async () => {
const message = 'Message from utility process';
const child = utilityProcess.fork(path.join(fixturesPath, 'expose-main-process-module.js'));
await once(child, 'spawn');
child.postMessage(message);
const [data] = await once(child, 'message');
expect(data).to.equal(systemPreferences.getMediaAccessStatus('screen'));
const exit = once(child, 'exit');
expect(child.kill()).to.be.true();
await exit;
});
it('can establish communication channel with sandboxed renderer', async () => {
const result = 'Message from sandboxed renderer';
const w = new BrowserWindow({

View File

@@ -1019,12 +1019,35 @@ describe('chromium features', () => {
});
it('Worker has node integration with nodeIntegrationInWorker', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nodeIntegrationInWorker: true, contextIsolation: false } });
const w = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true,
contextIsolation: false
}
});
w.loadURL(`file://${fixturesPath}/pages/worker.html`);
const [, data] = await once(ipcMain, 'worker-result');
expect(data).to.equal('object function object function');
});
it('Worker has access to fetch-dependent interfaces with nodeIntegrationInWorker', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true,
contextIsolation: false
}
});
w.loadURL(`file://${fixturesPath}/pages/worker-fetch.html`);
const [, data] = await once(ipcMain, 'worker-fetch-result');
expect(data).to.equal('function function function function function');
});
describe('SharedWorker', () => {
it('can work', async () => {
const w = new BrowserWindow({ show: false });

View File

@@ -0,0 +1,6 @@
const { systemPreferences } = require('electron');
const status = systemPreferences.getMediaAccessStatus('screen');
process.parentPort.on('message', () => {
process.parentPort.postMessage(status);
});

View File

@@ -0,0 +1,11 @@
const nonClonableObject = () => {};
process.parentPort.on('message', () => {
try {
process.parentPort.postMessage(nonClonableObject);
} catch (error) {
if (/An object could not be cloned/.test(error.message)) {
process.parentPort.postMessage('caught-non-cloneable');
}
}
});

12
spec/fixtures/pages/worker-fetch.html vendored Normal file
View File

@@ -0,0 +1,12 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
const { ipcRenderer } = require('electron')
let worker = new Worker(`../workers/worker_node_fetch.js`)
worker.onmessage = function (event) {
ipcRenderer.send('worker-fetch-result', event.data)
worker.terminate()
}
</script>
</body>
</html>

View File

@@ -0,0 +1,7 @@
self.postMessage([
typeof fetch,
typeof Response,
typeof Request,
typeof Headers,
typeof FormData
].join(' '));

View File

@@ -159,6 +159,38 @@ describe('node feature', () => {
});
});
describe('fetch', () => {
itremote('works correctly when nodeIntegration is enabled in the renderer', async (fixtures: string) => {
const file = require('node:path').join(fixtures, 'hello.txt');
expect(() => {
fetch('file://' + file);
}).to.not.throw();
expect(() => {
const formData = new FormData();
formData.append('username', 'Groucho');
}).not.to.throw();
expect(() => {
const request = new Request('https://example.com', {
method: 'POST',
body: JSON.stringify({ foo: 'bar' })
});
expect(request.method).to.equal('POST');
}).not.to.throw();
expect(() => {
const response = new Response('Hello, world!');
expect(response.status).to.equal(200);
}).not.to.throw();
expect(() => {
const headers = new Headers();
headers.append('Content-Type', 'text/xml');
}).not.to.throw();
}, [fixtures]);
});
it('does not hang when using the fs module in the renderer process', async () => {
const appPath = path.join(mainFixturesPath, 'apps', 'libuv-hang', 'main.js');
const appProcess = childProcess.spawn(process.execPath, [appPath], {