mirror of
https://github.com/electron/electron.git
synced 2026-03-19 03:02:02 -04:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc489c43b | ||
|
|
af4f835276 | ||
|
|
9d0c858be0 | ||
|
|
e6e8269352 | ||
|
|
e17eef4d62 | ||
|
|
9ffc255d13 | ||
|
|
07a1e9c775 | ||
|
|
567435b94d | ||
|
|
5ee5aceaad | ||
|
|
2d9288632f | ||
|
|
18ee76cc47 | ||
|
|
38b309043a | ||
|
|
ab7f97e887 | ||
|
|
4d0e13b87c | ||
|
|
50c0081e05 | ||
|
|
1079f3bbfa |
4
.github/workflows/pipeline-electron-lint.yml
vendored
4
.github/workflows/pipeline-electron-lint.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
gn_version="$(curl -sL -b ~/.gitcookies "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
|
||||
cipd ensure -ensure-file - -root . <<-CIPD
|
||||
\$ServiceURL https://chrome-infra-packages.appspot.com/
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
|
||||
mkdir -p src/buildtools
|
||||
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS
|
||||
curl -sL -b ~/.gitcookies "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS
|
||||
|
||||
gclient sync --spec="solutions=[{'name':'src/buildtools','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':True},'managed':False}]"
|
||||
- name: Add ESLint problem matcher
|
||||
|
||||
@@ -113,6 +113,8 @@ filenames = {
|
||||
"shell/browser/win/scoped_hstring.h",
|
||||
"shell/common/api/electron_api_native_image_win.cc",
|
||||
"shell/common/application_info_win.cc",
|
||||
"shell/common/command_line_util_win.cc",
|
||||
"shell/common/command_line_util_win.h",
|
||||
"shell/common/language_util_win.cc",
|
||||
"shell/common/node_bindings_win.cc",
|
||||
"shell/common/node_bindings_win.h",
|
||||
|
||||
@@ -8,13 +8,19 @@ const {
|
||||
isOnBatteryPower
|
||||
} = process._linkedBinding('electron_browser_power_monitor');
|
||||
|
||||
// Hold the native PowerMonitor at module level so it is never garbage-collected
|
||||
// while this module is alive. The C++ side registers OS-level callbacks (HWND
|
||||
// user-data on Windows, shutdown handler on macOS, notification observers) that
|
||||
// prevent safe collection of the C++ wrapper while those registrations exist.
|
||||
let pm: any;
|
||||
|
||||
class PowerMonitor extends EventEmitter implements Electron.PowerMonitor {
|
||||
constructor () {
|
||||
super();
|
||||
// Don't start the event source until both a) the app is ready and b)
|
||||
// there's a listener registered for a powerMonitor event.
|
||||
this.once('newListener', () => {
|
||||
const pm = createPowerMonitor();
|
||||
pm = createPowerMonitor();
|
||||
pm.emit = this.emit.bind(this);
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
|
||||
@@ -19,8 +19,8 @@ export function invokeInWebContents<T> (sender: Electron.WebContents, command: s
|
||||
const requestId = ++nextId;
|
||||
const channel = `${command}_RESPONSE_${requestId}`;
|
||||
ipcMainInternal.on(channel, function handler (event, error: Error, result: any) {
|
||||
if (event.type === 'frame' && event.sender !== sender) {
|
||||
console.error(`Reply to ${command} sent by unexpected WebContents (${event.sender.id})`);
|
||||
if (event.type !== 'frame' || event.sender !== sender) {
|
||||
console.error(`Reply to ${command} sent by unexpected sender`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,3 +141,4 @@ inspectorpageagent_provisional_frame_speculative_fix.patch
|
||||
expose_referrerscriptinfo_hostdefinedoptionsindex.patch
|
||||
fix_release_mouse_buttons_on_focus_loss_on_wayland.patch
|
||||
cherry-pick-e045399a1ecb.patch
|
||||
feat_plumb_node_integration_in_worker_through_workersettings.patch
|
||||
|
||||
@@ -65,7 +65,7 @@ index 2748dd196fe1f56357348a204e24f0b8a28b97dd..5800dd00b47c657d9e6766f3fc5a3065
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
bool EscapeVirtualization(const base::FilePath& user_data_dir);
|
||||
diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
|
||||
index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435a50990d2 100644
|
||||
index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..c683575aab2154b46b1fa9cc9e5e30aa8ed4f0ee 100644
|
||||
--- a/chrome/browser/process_singleton_posix.cc
|
||||
+++ b/chrome/browser/process_singleton_posix.cc
|
||||
@@ -614,6 +614,7 @@ class ProcessSingleton::LinuxWatcher
|
||||
@@ -106,21 +106,39 @@ index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435
|
||||
const size_t kMinMessageLength = std::size(kStartToken) + 4;
|
||||
if (bytes_read_ < kMinMessageLength) {
|
||||
buf_[bytes_read_] = 0;
|
||||
@@ -757,10 +763,28 @@ void ProcessSingleton::LinuxWatcher::SocketReader::
|
||||
@@ -757,10 +763,46 @@ void ProcessSingleton::LinuxWatcher::SocketReader::
|
||||
tokens.erase(tokens.begin());
|
||||
tokens.erase(tokens.begin());
|
||||
|
||||
+ size_t num_args;
|
||||
+ base::StringToSizeT(tokens[0], &num_args);
|
||||
+ std::vector<std::string> command_line(tokens.begin() + 1, tokens.begin() + 1 + num_args);
|
||||
+ if (!base::StringToSizeT(tokens[0], &num_args) ||
|
||||
+ num_args > tokens.size() - 1) {
|
||||
+ LOG(ERROR) << "Invalid num_args in socket message";
|
||||
+ CleanupAndDeleteSelf();
|
||||
+ return;
|
||||
+ }
|
||||
+ std::vector<std::string> command_line(tokens.begin() + 1,
|
||||
+ tokens.begin() + 1 + num_args);
|
||||
+
|
||||
+ std::vector<uint8_t> additional_data;
|
||||
+ if (tokens.size() >= 3 + num_args) {
|
||||
+ // After consuming [num_args, argv...], two more tokens are needed for
|
||||
+ // additional data: [size, payload]. Subtract to avoid overflow when
|
||||
+ // num_args is large.
|
||||
+ if (tokens.size() - 1 - num_args >= 2) {
|
||||
+ size_t additional_data_size;
|
||||
+ base::StringToSizeT(tokens[1 + num_args], &additional_data_size);
|
||||
+ if (!base::StringToSizeT(tokens[1 + num_args], &additional_data_size)) {
|
||||
+ LOG(ERROR) << "Invalid additional_data_size in socket message";
|
||||
+ CleanupAndDeleteSelf();
|
||||
+ return;
|
||||
+ }
|
||||
+ std::string remaining_args = base::JoinString(
|
||||
+ base::span(tokens.begin() + 2 + num_args, tokens.end()),
|
||||
+ std::string(1, kTokenDelimiter));
|
||||
+ if (additional_data_size > remaining_args.size()) {
|
||||
+ LOG(ERROR) << "additional_data_size exceeds payload length";
|
||||
+ CleanupAndDeleteSelf();
|
||||
+ return;
|
||||
+ }
|
||||
+ const uint8_t* additional_data_bits =
|
||||
+ reinterpret_cast<const uint8_t*>(remaining_args.c_str());
|
||||
+ additional_data = std::vector<uint8_t>(
|
||||
@@ -136,7 +154,7 @@ index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435
|
||||
fd_watch_controller_.reset();
|
||||
|
||||
// LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader
|
||||
@@ -789,8 +813,10 @@ void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK(
|
||||
@@ -789,8 +831,10 @@ void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK(
|
||||
//
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const base::FilePath& user_data_dir,
|
||||
@@ -147,7 +165,7 @@ index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435
|
||||
current_pid_(base::GetCurrentProcId()) {
|
||||
socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
|
||||
lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
|
||||
@@ -911,7 +937,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
@@ -911,7 +955,8 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
sizeof(socket_timeout));
|
||||
|
||||
// Found another process, prepare our command line
|
||||
@@ -157,7 +175,7 @@ index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435
|
||||
std::string to_send(kStartToken);
|
||||
to_send.push_back(kTokenDelimiter);
|
||||
|
||||
@@ -921,11 +948,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
@@ -921,11 +966,21 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
to_send.append(current_dir.value());
|
||||
|
||||
const std::vector<std::string>& argv = cmd_line.argv();
|
||||
@@ -180,10 +198,18 @@ index 08cbe32a258bf478f1da0a07064d3e9ef14c44a5..b9f2a43cb90fac4b031a4b4da38d6435
|
||||
if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) {
|
||||
// Try to kill the other process, because it might have been dead.
|
||||
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
|
||||
index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a02ccbac0 100644
|
||||
index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..3458909dd20e2b7fdf624a0e0eaeed6e8271475b 100644
|
||||
--- a/chrome/browser/process_singleton_win.cc
|
||||
+++ b/chrome/browser/process_singleton_win.cc
|
||||
@@ -81,10 +81,12 @@ BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <shellapi.h>
|
||||
#include <stddef.h>
|
||||
|
||||
+#include "base/base64.h"
|
||||
#include "base/base_paths.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -81,10 +82,12 @@ BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
|
||||
|
||||
bool ParseCommandLine(const COPYDATASTRUCT* cds,
|
||||
base::CommandLine* parsed_command_line,
|
||||
@@ -198,7 +224,7 @@ index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a
|
||||
static const int min_message_size = 7;
|
||||
if (cds->cbData < min_message_size * sizeof(wchar_t) ||
|
||||
cds->cbData % sizeof(wchar_t) != 0) {
|
||||
@@ -134,6 +136,23 @@ bool ParseCommandLine(const COPYDATASTRUCT* cds,
|
||||
@@ -134,6 +137,25 @@ bool ParseCommandLine(const COPYDATASTRUCT* cds,
|
||||
const std::wstring cmd_line =
|
||||
msg.substr(second_null + 1, third_null - second_null);
|
||||
*parsed_command_line = base::CommandLine::FromString(cmd_line);
|
||||
@@ -211,18 +237,20 @@ index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ // Get the actual additional data.
|
||||
+ const std::wstring additional_data =
|
||||
+ msg.substr(third_null + 1, fourth_null - third_null);
|
||||
+ base::span<const uint8_t> additional_data_bytes =
|
||||
+ base::as_byte_span(additional_data);
|
||||
+ *parsed_additional_data = std::vector<uint8_t>(
|
||||
+ additional_data_bytes.begin(), additional_data_bytes.end());
|
||||
+ // Get the actual additional data. It is base64-encoded so it can
|
||||
+ // safely traverse the null-delimited wchar_t buffer.
|
||||
+ const std::wstring encoded_w =
|
||||
+ msg.substr(third_null + 1, fourth_null - third_null - 1);
|
||||
+ std::string encoded = base::WideToASCII(encoded_w);
|
||||
+ std::optional<std::vector<uint8_t>> decoded = base::Base64Decode(encoded);
|
||||
+ if (decoded) {
|
||||
+ *parsed_additional_data = std::move(*decoded);
|
||||
+ }
|
||||
+
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -155,13 +174,14 @@ bool ProcessLaunchNotification(
|
||||
@@ -155,13 +177,14 @@ bool ProcessLaunchNotification(
|
||||
|
||||
base::CommandLine parsed_command_line(base::CommandLine::NO_PROGRAM);
|
||||
base::FilePath current_directory;
|
||||
@@ -240,7 +268,7 @@ index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -265,9 +285,11 @@ bool ProcessSingleton::EscapeVirtualization(
|
||||
@@ -265,9 +288,11 @@ bool ProcessSingleton::EscapeVirtualization(
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const std::string& program_name,
|
||||
const base::FilePath& user_data_dir,
|
||||
@@ -252,7 +280,7 @@ index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a
|
||||
program_name_(program_name),
|
||||
is_app_sandboxed_(is_app_sandboxed),
|
||||
is_virtualized_(false),
|
||||
@@ -294,7 +316,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
|
||||
@@ -294,7 +319,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
@@ -262,10 +290,18 @@ index 64ebf49c0d1b6396d1cfbe3bf91480f61b47688d..bec94d4039379400ae8b00f1adbbb16a
|
||||
return PROCESS_NOTIFIED;
|
||||
case NotifyChromeResult::NOTIFY_FAILED:
|
||||
diff --git a/chrome/browser/win/chrome_process_finder.cc b/chrome/browser/win/chrome_process_finder.cc
|
||||
index 58a4c5adfda49fb4bd1b5351bd02d358946043bd..adaa070eb0f3cf8f771b57743a7436fd48a1e576 100644
|
||||
index 58a4c5adfda49fb4bd1b5351bd02d358946043bd..6f21585faca6e98d2ed08be6a91df88947da6b3a 100644
|
||||
--- a/chrome/browser/win/chrome_process_finder.cc
|
||||
+++ b/chrome/browser/win/chrome_process_finder.cc
|
||||
@@ -39,7 +39,9 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) {
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
+#include "base/base64.h"
|
||||
#include "base/check.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
@@ -39,7 +40,9 @@ HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) {
|
||||
return base::win::MessageWindow::FindWindow(user_data_dir.value());
|
||||
}
|
||||
|
||||
@@ -276,7 +312,7 @@ index 58a4c5adfda49fb4bd1b5351bd02d358946043bd..adaa070eb0f3cf8f771b57743a7436fd
|
||||
TRACE_EVENT0("startup", "AttemptToNotifyRunningChrome");
|
||||
|
||||
DCHECK(remote_window);
|
||||
@@ -70,12 +72,24 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) {
|
||||
@@ -70,12 +73,22 @@ NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window) {
|
||||
new_command_line.AppendSwitch(switches::kSourceAppId);
|
||||
}
|
||||
// Send the command line to the remote chrome window.
|
||||
@@ -288,14 +324,12 @@ index 58a4c5adfda49fb4bd1b5351bd02d358946043bd..adaa070eb0f3cf8f771b57743a7436fd
|
||||
std::wstring_view{L"\0", 1}, new_command_line.GetCommandLineString(),
|
||||
std::wstring_view{L"\0", 1}});
|
||||
|
||||
+ size_t additional_data_size = additional_data.size_bytes();
|
||||
+ if (additional_data_size) {
|
||||
+ size_t padded_size = additional_data_size / sizeof(wchar_t);
|
||||
+ if (additional_data_size % sizeof(wchar_t) != 0) {
|
||||
+ padded_size++;
|
||||
+ }
|
||||
+ to_send.append(reinterpret_cast<const wchar_t*>(additional_data.data()),
|
||||
+ padded_size);
|
||||
+ if (!additional_data.empty()) {
|
||||
+ // Base64-encode so the payload survives the null-delimited wchar_t
|
||||
+ // framing; raw serialized bytes can contain 0x0000 sequences which
|
||||
+ // would otherwise terminate the field early.
|
||||
+ std::string encoded = base::Base64Encode(additional_data);
|
||||
+ to_send.append(base::ASCIIToWide(encoded));
|
||||
+ to_send.append(L"\0", 1); // Null separator.
|
||||
+ }
|
||||
+
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <sattard@anthropic.com>
|
||||
Date: Sat, 7 Mar 2026 23:07:30 -0800
|
||||
Subject: feat: plumb node_integration_in_worker through WorkerSettings
|
||||
|
||||
Copy the node_integration_in_worker flag from the initiating frame's
|
||||
WebPreferences into WorkerSettings at dedicated worker creation time,
|
||||
so the value is readable per-worker on the worker thread rather than
|
||||
relying on a process-wide command line switch. The value is also
|
||||
propagated to nested workers via WorkerSettings::Copy.
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc
|
||||
index fffe252477c521216086db3a15c6c26d8ccc25dc..defc359ccf7097ad7783b31b8260be6d8b1b3e03 100644
|
||||
--- a/third_party/blink/renderer/core/workers/dedicated_worker.cc
|
||||
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
|
||||
#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
|
||||
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
|
||||
+#include "third_party/blink/renderer/core/exported/web_view_impl.h"
|
||||
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
|
||||
#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
|
||||
#include "third_party/blink/renderer/core/loader/document_loader.h"
|
||||
@@ -558,6 +559,12 @@ DedicatedWorker::CreateGlobalScopeCreationParams(
|
||||
auto* frame = window->GetFrame();
|
||||
parent_devtools_token = frame->GetDevToolsFrameToken();
|
||||
settings = std::make_unique<WorkerSettings>(frame->GetSettings());
|
||||
+ if (auto* web_local_frame = WebLocalFrameImpl::FromFrame(frame)) {
|
||||
+ if (auto* web_view = web_local_frame->ViewImpl()) {
|
||||
+ settings->SetNodeIntegrationInWorker(
|
||||
+ web_view->GetWebPreferences().node_integration_in_worker);
|
||||
+ }
|
||||
+ }
|
||||
agent_group_scheduler_compositor_task_runner =
|
||||
execution_context->GetScheduler()
|
||||
->ToFrameScheduler()
|
||||
diff --git a/third_party/blink/renderer/core/workers/worker_settings.cc b/third_party/blink/renderer/core/workers/worker_settings.cc
|
||||
index 45680c5f6ea0c7e89ccf43eb88f8a11e3318c02e..3fa3af62f4e7ba8186441c5e3184b1c04fe32d12 100644
|
||||
--- a/third_party/blink/renderer/core/workers/worker_settings.cc
|
||||
+++ b/third_party/blink/renderer/core/workers/worker_settings.cc
|
||||
@@ -40,6 +40,8 @@ std::unique_ptr<WorkerSettings> WorkerSettings::Copy(
|
||||
old_settings->strictly_block_blockable_mixed_content_;
|
||||
new_settings->generic_font_family_settings_ =
|
||||
old_settings->generic_font_family_settings_;
|
||||
+ new_settings->node_integration_in_worker_ =
|
||||
+ old_settings->node_integration_in_worker_;
|
||||
return new_settings;
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/workers/worker_settings.h b/third_party/blink/renderer/core/workers/worker_settings.h
|
||||
index 45c60dd2c44b05fdd279f759069383479823c7f2..33a2a0337efb9a46293e11d0d09b3fc182ab9618 100644
|
||||
--- a/third_party/blink/renderer/core/workers/worker_settings.h
|
||||
+++ b/third_party/blink/renderer/core/workers/worker_settings.h
|
||||
@@ -43,6 +43,11 @@ class CORE_EXPORT WorkerSettings {
|
||||
return generic_font_family_settings_;
|
||||
}
|
||||
|
||||
+ bool NodeIntegrationInWorker() const { return node_integration_in_worker_; }
|
||||
+ void SetNodeIntegrationInWorker(bool value) {
|
||||
+ node_integration_in_worker_ = value;
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
void CopyFlagValuesFromSettings(Settings*);
|
||||
|
||||
@@ -54,6 +59,7 @@ class CORE_EXPORT WorkerSettings {
|
||||
bool strict_mixed_content_checking_ = false;
|
||||
bool allow_running_of_insecure_content_ = false;
|
||||
bool strictly_block_blockable_mixed_content_ = false;
|
||||
+ bool node_integration_in_worker_ = false;
|
||||
|
||||
GenericFontFamilySettings generic_font_family_settings_;
|
||||
};
|
||||
@@ -367,6 +367,9 @@ def upload_io_to_github(release, filename, filepath, version):
|
||||
for c in iter(lambda: upload_process.stdout.read(1), b""):
|
||||
sys.stdout.buffer.write(c)
|
||||
sys.stdout.flush()
|
||||
upload_process.wait()
|
||||
if upload_process.returncode != 0:
|
||||
sys.exit(upload_process.returncode)
|
||||
|
||||
if "GITHUB_OUTPUT" in os.environ:
|
||||
output_path = os.environ["GITHUB_OUTPUT"]
|
||||
|
||||
@@ -80,6 +80,14 @@ PowerMonitor::PowerMonitor(v8::Isolate* isolate) {
|
||||
}
|
||||
|
||||
PowerMonitor::~PowerMonitor() {
|
||||
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
|
||||
DestroyPlatformSpecificMonitors();
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
Browser::Get()->SetShutdownHandler(base::RepeatingCallback<bool()>());
|
||||
#endif
|
||||
|
||||
auto* power_monitor = base::PowerMonitor::GetInstance();
|
||||
power_monitor->RemovePowerStateObserver(this);
|
||||
power_monitor->RemovePowerSuspendObserver(this);
|
||||
|
||||
@@ -49,6 +49,7 @@ class PowerMonitor final : public gin_helper::DeprecatedWrappable<PowerMonitor>,
|
||||
|
||||
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
|
||||
void InitPlatformSpecificMonitors();
|
||||
void DestroyPlatformSpecificMonitors();
|
||||
#endif
|
||||
|
||||
// base::PowerStateObserver implementations:
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
}
|
||||
|
||||
- (void)addEmitter:(electron::api::PowerMonitor*)monitor_;
|
||||
- (void)removeEmitter:(electron::api::PowerMonitor*)monitor_;
|
||||
|
||||
@end
|
||||
|
||||
@@ -62,6 +63,10 @@
|
||||
self->emitters.push_back(monitor_);
|
||||
}
|
||||
|
||||
- (void)removeEmitter:(electron::api::PowerMonitor*)monitor_ {
|
||||
std::erase(self->emitters, monitor_);
|
||||
}
|
||||
|
||||
- (void)onScreenLocked:(NSNotification*)notification {
|
||||
for (auto* emitter : self->emitters) {
|
||||
emitter->Emit("lock-screen");
|
||||
@@ -98,4 +103,9 @@ void PowerMonitor::InitPlatformSpecificMonitors() {
|
||||
[g_lock_monitor addEmitter:this];
|
||||
}
|
||||
|
||||
void PowerMonitor::DestroyPlatformSpecificMonitors() {
|
||||
if (g_lock_monitor)
|
||||
[g_lock_monitor removeEmitter:this];
|
||||
}
|
||||
|
||||
} // namespace electron::api
|
||||
|
||||
@@ -49,6 +49,20 @@ void PowerMonitor::InitPlatformSpecificMonitors() {
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
}
|
||||
|
||||
void PowerMonitor::DestroyPlatformSpecificMonitors() {
|
||||
if (window_) {
|
||||
WTSUnRegisterSessionNotification(window_);
|
||||
UnregisterSuspendResumeNotification(static_cast<HANDLE>(window_));
|
||||
gfx::SetWindowUserData(window_, nullptr);
|
||||
DestroyWindow(window_);
|
||||
window_ = nullptr;
|
||||
}
|
||||
if (atom_) {
|
||||
UnregisterClass(MAKEINTATOM(atom_), instance_);
|
||||
atom_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK PowerMonitor::WndProcStatic(HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
@@ -76,7 +90,7 @@ LRESULT CALLBACK PowerMonitor::WndProc(HWND hwnd,
|
||||
}
|
||||
if (should_treat_as_current_session) {
|
||||
if (wparam == WTS_SESSION_LOCK) {
|
||||
// Unretained is OK because this object is eternally pinned.
|
||||
// SelfKeepAlive prevents GC of this object, so Unretained is safe.
|
||||
content::GetUIThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce([](PowerMonitor* pm) { pm->Emit("lock-screen"); },
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
#include "shell/browser/electron_browser_context.h"
|
||||
#include "shell/browser/electron_browser_main_parts.h"
|
||||
#include "shell/browser/electron_navigation_throttle.h"
|
||||
#include "shell/browser/electron_permission_manager.h"
|
||||
#include "shell/browser/file_select_helper.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/browser/osr/osr_render_widget_host_view.h"
|
||||
@@ -1034,6 +1035,16 @@ void WebContents::InitWithWebContents(
|
||||
}
|
||||
|
||||
WebContents::~WebContents() {
|
||||
if (web_contents()) {
|
||||
auto* permission_manager = static_cast<ElectronPermissionManager*>(
|
||||
web_contents()->GetBrowserContext()->GetPermissionControllerDelegate());
|
||||
if (permission_manager)
|
||||
permission_manager->CancelPendingRequests(web_contents());
|
||||
}
|
||||
|
||||
if (inspectable_web_contents_)
|
||||
inspectable_web_contents_->GetView()->SetDelegate(nullptr);
|
||||
|
||||
if (owner_window_) {
|
||||
owner_window_->RemoveBackgroundThrottlingSource(this);
|
||||
}
|
||||
@@ -1459,18 +1470,24 @@ void WebContents::EnterFullscreenModeForTab(
|
||||
auto* permission_helper =
|
||||
WebContentsPermissionHelper::FromWebContents(source);
|
||||
auto callback =
|
||||
base::BindRepeating(&WebContents::OnEnterFullscreenModeForTab,
|
||||
base::Unretained(this), requesting_frame, options);
|
||||
permission_helper->RequestFullscreenPermission(requesting_frame, callback);
|
||||
base::BindOnce(&WebContents::OnEnterFullscreenModeForTab, GetWeakPtr(),
|
||||
requesting_frame->GetGlobalFrameToken(), options);
|
||||
permission_helper->RequestFullscreenPermission(requesting_frame,
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
void WebContents::OnEnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const content::GlobalRenderFrameHostToken& frame_token,
|
||||
const blink::mojom::FullscreenOptions& options,
|
||||
bool allowed) {
|
||||
if (!allowed || !owner_window())
|
||||
return;
|
||||
|
||||
auto* requesting_frame =
|
||||
content::RenderFrameHost::FromFrameToken(frame_token);
|
||||
if (!requesting_frame)
|
||||
return;
|
||||
|
||||
auto* source = content::WebContents::FromRenderFrameHost(requesting_frame);
|
||||
if (IsFullscreenForTabOrPending(source)) {
|
||||
DCHECK_EQ(fullscreen_frame_, source->GetFocusedFrame());
|
||||
@@ -1588,8 +1605,7 @@ void WebContents::RequestPointerLock(content::WebContents* web_contents,
|
||||
WebContentsPermissionHelper::FromWebContents(web_contents);
|
||||
permission_helper->RequestPointerLockPermission(
|
||||
user_gesture, last_unlocked_by_target,
|
||||
base::BindOnce(&WebContents::OnRequestPointerLock,
|
||||
base::Unretained(this)));
|
||||
base::BindOnce(&WebContents::OnRequestPointerLock, GetWeakPtr()));
|
||||
}
|
||||
|
||||
void WebContents::LostPointerLock() {
|
||||
@@ -1619,8 +1635,8 @@ void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
|
||||
auto* permission_helper =
|
||||
WebContentsPermissionHelper::FromWebContents(web_contents);
|
||||
permission_helper->RequestKeyboardLockPermission(
|
||||
esc_key_locked, base::BindOnce(&WebContents::OnRequestKeyboardLock,
|
||||
base::Unretained(this)));
|
||||
esc_key_locked,
|
||||
base::BindOnce(&WebContents::OnRequestKeyboardLock, GetWeakPtr()));
|
||||
}
|
||||
|
||||
void WebContents::CancelKeyboardLockRequest(
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/frame_tree_node_id.h"
|
||||
#include "content/public/browser/global_routing_id.h"
|
||||
#include "content/public/browser/javascript_dialog_manager.h"
|
||||
#include "content/public/browser/render_widget_host.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
@@ -333,7 +334,7 @@ class WebContents final : public ExclusiveAccessContext,
|
||||
|
||||
// Callback triggered on permission response.
|
||||
void OnEnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const content::GlobalRenderFrameHostToken& frame_token,
|
||||
const blink::mojom::FullscreenOptions& options,
|
||||
bool allowed);
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
@@ -71,6 +73,29 @@ Browser* Browser::Get() {
|
||||
return ElectronBrowserMainParts::Get()->browser();
|
||||
}
|
||||
|
||||
// static
|
||||
bool Browser::IsValidProtocolScheme(const std::string& scheme) {
|
||||
// RFC 3986 Section 3.1:
|
||||
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
if (scheme.empty()) {
|
||||
LOG(ERROR) << "Protocol scheme must not be empty";
|
||||
return false;
|
||||
}
|
||||
if (!base::IsAsciiAlpha(scheme[0])) {
|
||||
LOG(ERROR) << "Protocol scheme must start with an ASCII letter";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 1; i < scheme.size(); ++i) {
|
||||
const char c = scheme[i];
|
||||
if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c) && c != '+' &&
|
||||
c != '-' && c != '.') {
|
||||
LOG(ERROR) << "Protocol scheme contains invalid character: '" << c << "'";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
|
||||
void Browser::Focus(gin::Arguments* args) {
|
||||
// Focus on the first visible window.
|
||||
|
||||
@@ -133,6 +133,10 @@ class Browser : private WindowListObserver {
|
||||
void SetAppUserModelID(const std::wstring& name);
|
||||
#endif
|
||||
|
||||
// Validate that a protocol scheme conforms to RFC 3986:
|
||||
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
static bool IsValidProtocolScheme(const std::string& scheme);
|
||||
|
||||
// Remove the default protocol handler registry key
|
||||
bool RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args);
|
||||
|
||||
@@ -103,16 +103,19 @@ void Browser::ClearRecentDocuments() {}
|
||||
|
||||
bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args) {
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
return SetDefaultWebClient(protocol);
|
||||
}
|
||||
|
||||
bool Browser::IsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args) {
|
||||
auto env = base::Environment::Create();
|
||||
|
||||
if (protocol.empty())
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
auto env = base::Environment::Create();
|
||||
|
||||
std::vector<std::string> argv = {kXdgSettings, "check",
|
||||
kXdgSettingsDefaultSchemeHandler, protocol};
|
||||
if (std::optional<std::string> desktop_name = env->GetVar("CHROME_DESKTOP")) {
|
||||
|
||||
@@ -228,7 +228,7 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
|
||||
bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args) {
|
||||
if (protocol.empty())
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
NSString* identifier = [base::apple::MainBundle() bundleIdentifier];
|
||||
@@ -244,7 +244,7 @@ bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
|
||||
|
||||
bool Browser::IsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args) {
|
||||
if (protocol.empty())
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
NSString* identifier = [base::apple::MainBundle() bundleIdentifier];
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "shell/browser/ui/win/jump_list.h"
|
||||
#include "shell/browser/window_list.h"
|
||||
#include "shell/common/application_info.h"
|
||||
#include "shell/common/command_line_util_win.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/gin_converters/image_converter.h"
|
||||
#include "shell/common/gin_converters/login_item_settings_converter.h"
|
||||
@@ -78,13 +79,22 @@ bool GetProtocolLaunchPath(gin::Arguments* args, std::wstring* exe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip surrounding double quotes before re-quoting with AddQuoteForArg.
|
||||
if (exe->size() >= 2 && exe->front() == L'"' && exe->back() == L'"') {
|
||||
*exe = exe->substr(1, exe->size() - 2);
|
||||
}
|
||||
|
||||
// Read in optional args arg
|
||||
std::vector<std::wstring> launch_args;
|
||||
if (args->GetNext(&launch_args) && !launch_args.empty()) {
|
||||
std::wstring joined_args = base::JoinString(launch_args, L"\" \"");
|
||||
*exe = base::StrCat({L"\"", *exe, L"\" \"", joined_args, L"\" \"%1\""});
|
||||
std::wstring result = electron::AddQuoteForArg(*exe);
|
||||
for (const auto& arg : launch_args) {
|
||||
result += L' ';
|
||||
result += electron::AddQuoteForArg(arg);
|
||||
}
|
||||
*exe = base::StrCat({result, L" \"%1\""});
|
||||
} else {
|
||||
*exe = base::StrCat({L"\"", *exe, L"\" \"%1\""});
|
||||
*exe = base::StrCat({electron::AddQuoteForArg(*exe), L" \"%1\""});
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -152,9 +162,18 @@ bool FormatCommandLineString(std::wstring* exe,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip surrounding double quotes before re-quoting with AddQuoteForArg.
|
||||
if (exe->size() >= 2 && exe->front() == L'"' && exe->back() == L'"') {
|
||||
*exe = exe->substr(1, exe->size() - 2);
|
||||
}
|
||||
|
||||
*exe = electron::AddQuoteForArg(*exe);
|
||||
|
||||
if (!launch_args.empty()) {
|
||||
std::u16string joined_launch_args = base::JoinString(launch_args, u" ");
|
||||
*exe = base::StrCat({*exe, L" ", base::AsWStringView(joined_launch_args)});
|
||||
for (const auto& arg : launch_args) {
|
||||
*exe += L' ';
|
||||
*exe += electron::AddQuoteForArg(std::wstring(base::AsWStringView(arg)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -409,7 +428,7 @@ bool Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
|
||||
|
||||
bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args) {
|
||||
if (protocol.empty())
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
// Main Registry Key
|
||||
@@ -488,7 +507,7 @@ bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
|
||||
// Software\Classes", which is inherited by "HKEY_CLASSES_ROOT"
|
||||
// anyway, and can be written by unprivileged users.
|
||||
|
||||
if (protocol.empty())
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
std::wstring exe;
|
||||
@@ -518,7 +537,7 @@ bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
|
||||
|
||||
bool Browser::IsDefaultProtocolClient(const std::string& protocol,
|
||||
gin::Arguments* args) {
|
||||
if (protocol.empty())
|
||||
if (!IsValidProtocolScheme(protocol))
|
||||
return false;
|
||||
|
||||
std::wstring exe;
|
||||
|
||||
@@ -268,7 +268,7 @@ void ElectronDownloadManagerDelegate::OnDownloadPathGenerated(
|
||||
gin_helper::Promise<gin_helper::Dictionary> dialog_promise(isolate);
|
||||
auto dialog_callback = base::BindOnce(
|
||||
&ElectronDownloadManagerDelegate::OnDownloadSaveDialogDone,
|
||||
base::Unretained(this), download_guid, std::move(callback));
|
||||
weak_ptr_factory_.GetWeakPtr(), download_guid, std::move(callback));
|
||||
|
||||
std::ignore = dialog_promise.Then(std::move(dialog_callback));
|
||||
file_dialog::ShowSaveDialog(settings, std::move(dialog_promise));
|
||||
|
||||
@@ -150,6 +150,23 @@ bool ElectronPermissionManager::HasPermissionCheckHandler() const {
|
||||
return !check_handler_.is_null();
|
||||
}
|
||||
|
||||
void ElectronPermissionManager::CancelPendingRequests(
|
||||
content::WebContents* web_contents) {
|
||||
std::vector<int> ids_to_remove;
|
||||
for (PendingRequestsMap::iterator iter(&pending_requests_); !iter.IsAtEnd();
|
||||
iter.Advance()) {
|
||||
auto* pending_request = iter.GetCurrentValue();
|
||||
content::RenderFrameHost* rfh = pending_request->GetRenderFrameHost();
|
||||
if (!rfh ||
|
||||
content::WebContents::FromRenderFrameHost(rfh) == web_contents) {
|
||||
ids_to_remove.push_back(iter.GetCurrentKey());
|
||||
}
|
||||
}
|
||||
for (int id : ids_to_remove) {
|
||||
pending_requests_.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronPermissionManager::RequestPermissionWithDetails(
|
||||
blink::mojom::PermissionDescriptorPtr permission,
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
|
||||
@@ -85,6 +85,8 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
|
||||
bool HasPermissionRequestHandler() const;
|
||||
bool HasPermissionCheckHandler() const;
|
||||
|
||||
void CancelPendingRequests(content::WebContents* web_contents);
|
||||
|
||||
void CheckBluetoothDevicePair(gin_helper::Dictionary details,
|
||||
PairCallback pair_callback) const;
|
||||
|
||||
|
||||
@@ -88,13 +88,9 @@ HidChooserController::HidChooserController(
|
||||
exclusion_filters_(std::move(exclusion_filters)),
|
||||
callback_(std::move(callback)),
|
||||
initiator_document_(render_frame_host->GetWeakDocumentPtr()),
|
||||
origin_(content::WebContents::FromRenderFrameHost(render_frame_host)
|
||||
->GetPrimaryMainFrame()
|
||||
->GetLastCommittedOrigin()),
|
||||
origin_(render_frame_host->GetLastCommittedOrigin()),
|
||||
hid_delegate_(hid_delegate),
|
||||
render_frame_host_id_(render_frame_host->GetGlobalId()) {
|
||||
// The use above of GetMainFrame is safe as content::HidService instances are
|
||||
// not created for fenced frames.
|
||||
DCHECK(!render_frame_host->IsNestedWithinFencedFrame());
|
||||
|
||||
chooser_context_ = HidChooserContextFactory::GetForBrowserContext(
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "net/base/filename_util.h"
|
||||
#include "net/http/http_request_headers.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
#include "net/http/http_util.h"
|
||||
#include "net/url_request/redirect_util.h"
|
||||
#include "services/network/public/cpp/resource_request.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
@@ -138,13 +139,17 @@ network::mojom::URLResponseHeadPtr ToResponseHead(
|
||||
base::Value::Dict headers;
|
||||
if (dict.Get("headers", &headers)) {
|
||||
for (const auto iter : headers) {
|
||||
if (!net::HttpUtil::IsValidHeaderName(iter.first))
|
||||
continue;
|
||||
if (iter.second.is_string()) {
|
||||
// key, value
|
||||
head->headers->AddHeader(iter.first, iter.second.GetString());
|
||||
if (net::HttpUtil::IsValidHeaderValue(iter.second.GetString()))
|
||||
head->headers->AddHeader(iter.first, iter.second.GetString());
|
||||
} else if (iter.second.is_list()) {
|
||||
// key: [values...]
|
||||
for (const auto& item : iter.second.GetList()) {
|
||||
if (item.is_string())
|
||||
if (item.is_string() &&
|
||||
net::HttpUtil::IsValidHeaderValue(item.GetString()))
|
||||
head->headers->AddHeader(iter.first, item.GetString());
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "sandbox/win/src/nt_internals.h"
|
||||
#include "sandbox/win/src/win_utils.h"
|
||||
#include "shell/common/command_line_util_win.h"
|
||||
|
||||
namespace relauncher::internal {
|
||||
|
||||
@@ -50,49 +51,6 @@ HANDLE GetParentProcessHandle(base::ProcessHandle handle) {
|
||||
return ::OpenProcess(PROCESS_ALL_ACCESS, TRUE, ppid);
|
||||
}
|
||||
|
||||
StringType AddQuoteForArg(const StringType& arg) {
|
||||
// We follow the quoting rules of CommandLineToArgvW.
|
||||
// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
std::wstring quotable_chars(L" \\\"");
|
||||
if (arg.find_first_of(quotable_chars) == std::wstring::npos) {
|
||||
// No quoting necessary.
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::wstring out;
|
||||
out.push_back(L'"');
|
||||
for (size_t i = 0; i < arg.size(); ++i) {
|
||||
if (arg[i] == '\\') {
|
||||
// Find the extent of this run of backslashes.
|
||||
size_t start = i, end = start + 1;
|
||||
for (; end < arg.size() && arg[end] == '\\'; ++end) {
|
||||
}
|
||||
size_t backslash_count = end - start;
|
||||
|
||||
// Backslashes are escapes only if the run is followed by a double quote.
|
||||
// Since we also will end the string with a double quote, we escape for
|
||||
// either a double quote or the end of the string.
|
||||
if (end == arg.size() || arg[end] == '"') {
|
||||
// To quote, we need to output 2x as many backslashes.
|
||||
backslash_count *= 2;
|
||||
}
|
||||
for (size_t j = 0; j < backslash_count; ++j)
|
||||
out.push_back('\\');
|
||||
|
||||
// Advance i to one before the end to balance i++ in loop.
|
||||
i = end - 1;
|
||||
} else if (arg[i] == '"') {
|
||||
out.push_back('\\');
|
||||
out.push_back('"');
|
||||
} else {
|
||||
out.push_back(arg[i]);
|
||||
}
|
||||
}
|
||||
out.push_back('"');
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
StringType GetWaitEventName(base::ProcessId pid) {
|
||||
@@ -105,7 +63,7 @@ StringType ArgvToCommandLineString(const StringVector& argv) {
|
||||
for (const StringType& arg : argv) {
|
||||
if (!command_line.empty())
|
||||
command_line += L' ';
|
||||
command_line += AddQuoteForArg(arg);
|
||||
command_line += electron::AddQuoteForArg(arg);
|
||||
}
|
||||
return command_line;
|
||||
}
|
||||
|
||||
@@ -52,25 +52,21 @@ bool ElectronSerialDelegate::CanRequestPortPermission(
|
||||
auto* permission_helper =
|
||||
WebContentsPermissionHelper::FromWebContents(web_contents);
|
||||
return permission_helper->CheckSerialAccessPermission(
|
||||
web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin());
|
||||
frame->GetLastCommittedOrigin());
|
||||
}
|
||||
|
||||
bool ElectronSerialDelegate::HasPortPermission(
|
||||
content::RenderFrameHost* frame,
|
||||
const device::mojom::SerialPortInfo& port) {
|
||||
auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
|
||||
return GetChooserContext(frame)->HasPortPermission(
|
||||
web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin(), port,
|
||||
frame);
|
||||
frame->GetLastCommittedOrigin(), port, frame);
|
||||
}
|
||||
|
||||
void ElectronSerialDelegate::RevokePortPermissionWebInitiated(
|
||||
content::RenderFrameHost* frame,
|
||||
const base::UnguessableToken& token) {
|
||||
auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
|
||||
return GetChooserContext(frame)->RevokePortPermissionWebInitiated(
|
||||
web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin(), token,
|
||||
frame);
|
||||
frame->GetLastCommittedOrigin(), token, frame);
|
||||
}
|
||||
|
||||
const device::mojom::SerialPortInfo* ElectronSerialDelegate::GetPortInfo(
|
||||
|
||||
@@ -125,7 +125,7 @@ SerialChooserController::SerialChooserController(
|
||||
std::move(allowed_bluetooth_service_class_ids)),
|
||||
callback_(std::move(callback)),
|
||||
initiator_document_(render_frame_host->GetWeakDocumentPtr()) {
|
||||
origin_ = web_contents_->GetPrimaryMainFrame()->GetLastCommittedOrigin();
|
||||
origin_ = render_frame_host->GetLastCommittedOrigin();
|
||||
|
||||
chooser_context_ = SerialChooserContextFactory::GetForBrowserContext(
|
||||
web_contents_->GetBrowserContext())
|
||||
|
||||
@@ -270,34 +270,10 @@ void Relaunch(NSString* destinationPath) {
|
||||
}
|
||||
|
||||
bool Trash(NSString* path) {
|
||||
bool result = false;
|
||||
|
||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_8) {
|
||||
result = [[NSFileManager defaultManager]
|
||||
trashItemAtURL:[NSURL fileURLWithPath:path]
|
||||
resultingItemURL:nil
|
||||
error:nil];
|
||||
}
|
||||
|
||||
// As a last resort try trashing with AppleScript.
|
||||
// This allows us to trash the app in macOS Sierra even when the app is
|
||||
// running inside an app translocation image.
|
||||
if (!result) {
|
||||
auto* code = R"str(
|
||||
set theFile to POSIX file "%@"
|
||||
tell application "Finder"
|
||||
move theFile to trash
|
||||
end tell
|
||||
)str";
|
||||
NSAppleScript* appleScript = [[NSAppleScript alloc]
|
||||
initWithSource:[NSString stringWithFormat:@(code), path]];
|
||||
NSDictionary* errorDict = nil;
|
||||
NSAppleEventDescriptor* scriptResult =
|
||||
[appleScript executeAndReturnError:&errorDict];
|
||||
result = (scriptResult != nil);
|
||||
}
|
||||
|
||||
return result;
|
||||
return [[NSFileManager defaultManager]
|
||||
trashItemAtURL:[NSURL fileURLWithPath:path]
|
||||
resultingItemURL:nil
|
||||
error:nil];
|
||||
}
|
||||
|
||||
bool DeleteOrTrash(NSString* path) {
|
||||
|
||||
@@ -82,11 +82,13 @@ GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
|
||||
constexpr GdkColorspace kColorspace = GDK_COLORSPACE_RGB;
|
||||
constexpr gboolean kHasAlpha = true;
|
||||
constexpr int kBitsPerSample = 8;
|
||||
return gdk_pixbuf_new_from_bytes(
|
||||
g_bytes_new(std::data(bytes), std::size(bytes)), kColorspace, kHasAlpha,
|
||||
kBitsPerSample, width, height,
|
||||
GBytes* gbytes = g_bytes_new(std::data(bytes), std::size(bytes));
|
||||
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_bytes(
|
||||
gbytes, kColorspace, kHasAlpha, kBitsPerSample, width, height,
|
||||
gdk_pixbuf_calculate_rowstride(kColorspace, kHasAlpha, kBitsPerSample,
|
||||
width, height));
|
||||
g_bytes_unref(gbytes);
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
} // namespace gtk_util
|
||||
|
||||
@@ -43,7 +43,7 @@ UsbChooserController::UsbChooserController(
|
||||
: WebContentsObserver(web_contents),
|
||||
options_(std::move(options)),
|
||||
callback_(std::move(callback)),
|
||||
origin_(render_frame_host->GetMainFrame()->GetLastCommittedOrigin()),
|
||||
origin_(render_frame_host->GetLastCommittedOrigin()),
|
||||
usb_delegate_(usb_delegate),
|
||||
render_frame_host_id_(render_frame_host->GetGlobalId()) {
|
||||
chooser_context_ = UsbChooserContextFactory::GetForBrowserContext(
|
||||
@@ -68,6 +68,7 @@ api::Session* UsbChooserController::GetSession() {
|
||||
void UsbChooserController::OnDeviceAdded(
|
||||
const device::mojom::UsbDeviceInfo& device_info) {
|
||||
if (DisplayDevice(device_info)) {
|
||||
devices_.push_back(device_info.Clone());
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
session->Emit("usb-device-added", device_info.Clone(), web_contents());
|
||||
@@ -77,6 +78,9 @@ void UsbChooserController::OnDeviceAdded(
|
||||
|
||||
void UsbChooserController::OnDeviceRemoved(
|
||||
const device::mojom::UsbDeviceInfo& device_info) {
|
||||
std::erase_if(devices_, [&device_info](const auto& device) {
|
||||
return device->guid == device_info.guid;
|
||||
});
|
||||
api::Session* session = GetSession();
|
||||
if (session) {
|
||||
session->Emit("usb-device-removed", device_info.Clone(), web_contents());
|
||||
@@ -88,9 +92,11 @@ void UsbChooserController::OnDeviceChosen(gin::Arguments* args) {
|
||||
if (!args->GetNext(&device_id) || device_id.empty()) {
|
||||
RunCallback(/*device_info=*/nullptr);
|
||||
} else {
|
||||
auto* device_info = chooser_context_->GetDeviceInfo(device_id);
|
||||
if (device_info) {
|
||||
RunCallback(device_info->Clone());
|
||||
const auto it = std::ranges::find_if(
|
||||
devices_,
|
||||
[&device_id](const auto& device) { return device->guid == device_id; });
|
||||
if (it != devices_.end()) {
|
||||
RunCallback((*it)->Clone());
|
||||
} else {
|
||||
util::EmitWarning(
|
||||
base::StrCat({"The device id ", device_id, " was not found."}),
|
||||
@@ -125,6 +131,11 @@ void UsbChooserController::GotUsbDeviceList(
|
||||
return !DisplayDevice(*device_info);
|
||||
});
|
||||
|
||||
devices_.clear();
|
||||
for (const auto& device : devices) {
|
||||
devices_.push_back(device->Clone());
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> details = gin::DataObjectBuilder(isolate)
|
||||
.Set("deviceList", devices)
|
||||
.Set("frame", rfh)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef ELECTRON_SHELL_BROWSER_USB_USB_CHOOSER_CONTROLLER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_USB_USB_CHOOSER_CONTROLLER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
@@ -73,6 +74,9 @@ class UsbChooserController final : private UsbChooserContext::DeviceObserver,
|
||||
|
||||
base::WeakPtr<ElectronUsbDelegate> usb_delegate_;
|
||||
|
||||
// Filtered list of devices that passed DisplayDevice()
|
||||
std::vector<device::mojom::UsbDeviceInfoPtr> devices_;
|
||||
|
||||
content::GlobalRenderFrameHostId render_frame_host_id_;
|
||||
|
||||
base::WeakPtrFactory<UsbChooserController> weak_factory_{this};
|
||||
|
||||
@@ -219,7 +219,7 @@ void WebContentsPermissionHelper::RequestPermission(
|
||||
base::Value::Dict details) {
|
||||
auto* permission_manager = static_cast<ElectronPermissionManager*>(
|
||||
web_contents_->GetBrowserContext()->GetPermissionControllerDelegate());
|
||||
auto origin = web_contents_->GetLastCommittedURL();
|
||||
auto origin = requesting_frame->GetLastCommittedOrigin().GetURL();
|
||||
permission_manager->RequestPermissionWithDetails(
|
||||
content::PermissionDescriptorUtil::
|
||||
CreatePermissionDescriptorForPermissionType(permission),
|
||||
|
||||
@@ -135,7 +135,6 @@ void WebContentsPreferences::Clear() {
|
||||
default_encoding_ = std::nullopt;
|
||||
is_webview_ = false;
|
||||
custom_args_.clear();
|
||||
custom_switches_.clear();
|
||||
enable_blink_features_ = std::nullopt;
|
||||
disable_blink_features_ = std::nullopt;
|
||||
disable_popups_ = false;
|
||||
@@ -203,7 +202,6 @@ void WebContentsPreferences::SetFromDictionary(
|
||||
if (web_preferences.Get("defaultEncoding", &encoding))
|
||||
default_encoding_ = encoding;
|
||||
web_preferences.Get(options::kCustomArgs, &custom_args_);
|
||||
web_preferences.Get("commandLineSwitches", &custom_switches_);
|
||||
web_preferences.Get("disablePopups", &disable_popups_);
|
||||
web_preferences.Get("disableDialogs", &disable_dialogs_);
|
||||
web_preferences.Get("safeDialogs", &safe_dialogs_);
|
||||
@@ -335,11 +333,6 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
||||
if (!arg.empty())
|
||||
command_line->AppendArg(arg);
|
||||
|
||||
// Custom command line switches.
|
||||
for (const auto& arg : custom_switches_)
|
||||
if (!arg.empty())
|
||||
command_line->AppendSwitch(arg);
|
||||
|
||||
if (enable_blink_features_)
|
||||
command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures,
|
||||
*enable_blink_features_);
|
||||
@@ -347,9 +340,6 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
||||
command_line->AppendSwitchASCII(::switches::kDisableBlinkFeatures,
|
||||
*disable_blink_features_);
|
||||
|
||||
if (node_integration_in_worker_)
|
||||
command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
|
||||
|
||||
// We are appending args to a webContents so let's save the current state
|
||||
// of our preferences object so that during the lifetime of the WebContents
|
||||
// we can fetch the options used to initially configure the WebContents
|
||||
|
||||
@@ -121,7 +121,6 @@ class WebContentsPreferences
|
||||
std::optional<std::string> default_encoding_;
|
||||
bool is_webview_;
|
||||
std::vector<std::string> custom_args_;
|
||||
std::vector<std::string> custom_switches_;
|
||||
std::optional<std::string> enable_blink_features_;
|
||||
std::optional<std::string> disable_blink_features_;
|
||||
bool disable_popups_;
|
||||
|
||||
54
shell/common/command_line_util_win.cc
Normal file
54
shell/common/command_line_util_win.cc
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2026 Microsoft GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/common/command_line_util_win.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace electron {
|
||||
|
||||
std::wstring AddQuoteForArg(const std::wstring& arg) {
|
||||
// We follow the quoting rules of CommandLineToArgvW.
|
||||
// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
constexpr wchar_t kQuotableChars[] = L" \\\"";
|
||||
if (arg.find_first_of(kQuotableChars) == std::wstring::npos) {
|
||||
// No quoting necessary.
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::wstring out;
|
||||
out.push_back(L'"');
|
||||
for (size_t i = 0; i < arg.size(); ++i) {
|
||||
if (arg[i] == '\\') {
|
||||
// Find the extent of this run of backslashes.
|
||||
size_t start = i, end = start + 1;
|
||||
for (; end < arg.size() && arg[end] == '\\'; ++end) {
|
||||
}
|
||||
size_t backslash_count = end - start;
|
||||
|
||||
// Backslashes are escapes only if the run is followed by a double quote.
|
||||
// Since we also will end the string with a double quote, we escape for
|
||||
// either a double quote or the end of the string.
|
||||
if (end == arg.size() || arg[end] == '"') {
|
||||
// To quote, we need to output 2x as many backslashes.
|
||||
backslash_count *= 2;
|
||||
}
|
||||
for (size_t j = 0; j < backslash_count; ++j)
|
||||
out.push_back('\\');
|
||||
|
||||
// Advance i to one before the end to balance i++ in loop.
|
||||
i = end - 1;
|
||||
} else if (arg[i] == '"') {
|
||||
out.push_back('\\');
|
||||
out.push_back('"');
|
||||
} else {
|
||||
out.push_back(arg[i]);
|
||||
}
|
||||
}
|
||||
out.push_back('"');
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
20
shell/common/command_line_util_win.h
Normal file
20
shell/common/command_line_util_win.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2026 Microsoft GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_COMMON_COMMAND_LINE_UTIL_WIN_H_
|
||||
#define ELECTRON_SHELL_COMMON_COMMAND_LINE_UTIL_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Quotes |arg| using CommandLineToArgvW-compatible quoting rules so that
|
||||
// the argument round-trips correctly through CreateProcess →
|
||||
// CommandLineToArgvW. If no quoting is necessary the string is returned
|
||||
// unchanged. See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
std::wstring AddQuoteForArg(const std::wstring& arg);
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_COMMON_COMMAND_LINE_UTIL_WIN_H_
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "net/cert/x509_certificate.h"
|
||||
#include "net/cert/x509_util.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/http/http_util.h"
|
||||
#include "net/http/http_version.h"
|
||||
#include "net/url_request/redirect_info.h"
|
||||
#include "services/network/public/cpp/data_element.h"
|
||||
@@ -197,6 +198,10 @@ bool Converter<net::HttpResponseHeaders*>::FromV8(
|
||||
}
|
||||
std::string value;
|
||||
gin::ConvertFromV8(isolate, localStrVal, &value);
|
||||
if (!net::HttpUtil::IsValidHeaderName(key) ||
|
||||
!net::HttpUtil::IsValidHeaderValue(value)) {
|
||||
return false;
|
||||
}
|
||||
out->AddHeader(key, value);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -271,10 +271,6 @@ inline constexpr base::cstring_view kAppPath = "app-path";
|
||||
// The command line switch versions of the options.
|
||||
inline constexpr base::cstring_view kScrollBounce = "scroll-bounce";
|
||||
|
||||
// Command switch passed to renderer process to control nodeIntegration.
|
||||
inline constexpr base::cstring_view kNodeIntegrationInWorker =
|
||||
"node-integration-in-worker";
|
||||
|
||||
// Widevine options
|
||||
// Path to Widevine CDM binaries.
|
||||
inline constexpr base::cstring_view kWidevineCdmPath = "widevine-cdm-path";
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
#include "third_party/blink/renderer/core/execution_context/execution_context.h" // nogncheck
|
||||
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" // nogncheck
|
||||
#include "third_party/blink/renderer/core/workers/worker_global_scope.h" // nogncheck
|
||||
#include "third_party/blink/renderer/core/workers/worker_settings.h" // nogncheck
|
||||
|
||||
#if BUILDFLAG(IS_LINUX) && (defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM64))
|
||||
#define ENABLE_WEB_ASSEMBLY_TRAP_HANDLER_LINUX
|
||||
@@ -207,44 +209,54 @@ void ElectronRendererClient::WillReleaseScriptContext(
|
||||
electron_bindings_->EnvironmentDestroyed(env);
|
||||
}
|
||||
|
||||
void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
|
||||
v8::Local<v8::Context> context) {
|
||||
namespace {
|
||||
|
||||
bool WorkerHasNodeIntegration(blink::ExecutionContext* ec) {
|
||||
// We do not create a Node.js environment in service or shared workers
|
||||
// owing to an inability to customize sandbox policies in these workers
|
||||
// given that they're run out-of-process.
|
||||
// Also avoid creating a Node.js environment for worklet global scope
|
||||
// created on the main thread.
|
||||
auto* ec = blink::ExecutionContext::From(context);
|
||||
if (ec->IsServiceWorkerGlobalScope() || ec->IsSharedWorkerGlobalScope() ||
|
||||
ec->IsMainThreadWorkletGlobalScope())
|
||||
return false;
|
||||
|
||||
auto* wgs = blink::DynamicTo<blink::WorkerGlobalScope>(ec);
|
||||
if (!wgs)
|
||||
return false;
|
||||
|
||||
// Read the nodeIntegrationInWorker preference from the worker's settings,
|
||||
// which were copied from the initiating frame's WebPreferences at worker
|
||||
// creation time. This ensures that in-process child windows with different
|
||||
// webPreferences get the correct per-frame value rather than a process-wide
|
||||
// value.
|
||||
auto* worker_settings = wgs->GetWorkerSettings();
|
||||
return worker_settings && worker_settings->NodeIntegrationInWorker();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
|
||||
v8::Local<v8::Context> context) {
|
||||
auto* ec = blink::ExecutionContext::From(context);
|
||||
if (!WorkerHasNodeIntegration(ec))
|
||||
return;
|
||||
|
||||
// This won't be correct for in-process child windows with webPreferences
|
||||
// that have a different value for nodeIntegrationInWorker
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kNodeIntegrationInWorker)) {
|
||||
auto* current = WebWorkerObserver::GetCurrent();
|
||||
if (current)
|
||||
return;
|
||||
WebWorkerObserver::Create()->WorkerScriptReadyForEvaluation(context);
|
||||
}
|
||||
auto* current = WebWorkerObserver::GetCurrent();
|
||||
if (current)
|
||||
return;
|
||||
WebWorkerObserver::Create()->WorkerScriptReadyForEvaluation(context);
|
||||
}
|
||||
|
||||
void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
|
||||
v8::Local<v8::Context> context) {
|
||||
auto* ec = blink::ExecutionContext::From(context);
|
||||
if (ec->IsServiceWorkerGlobalScope() || ec->IsSharedWorkerGlobalScope() ||
|
||||
ec->IsMainThreadWorkletGlobalScope())
|
||||
if (!WorkerHasNodeIntegration(ec))
|
||||
return;
|
||||
|
||||
// TODO(loc): Note that this will not be correct for in-process child windows
|
||||
// with webPreferences that have a different value for nodeIntegrationInWorker
|
||||
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kNodeIntegrationInWorker)) {
|
||||
auto* current = WebWorkerObserver::GetCurrent();
|
||||
if (current)
|
||||
current->ContextWillDestroy(context);
|
||||
}
|
||||
auto* current = WebWorkerObserver::GetCurrent();
|
||||
if (current)
|
||||
current->ContextWillDestroy(context);
|
||||
}
|
||||
|
||||
void ElectronRendererClient::SetUpWebAssemblyTrapHandler() {
|
||||
|
||||
@@ -1470,6 +1470,29 @@ describe('app module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('protocol scheme validation', () => {
|
||||
it('rejects empty protocol names', () => {
|
||||
expect(app.setAsDefaultProtocolClient('')).to.equal(false);
|
||||
expect(app.isDefaultProtocolClient('')).to.equal(false);
|
||||
expect(app.removeAsDefaultProtocolClient('')).to.equal(false);
|
||||
});
|
||||
|
||||
it('rejects non-conformant protocol names ', () => {
|
||||
// Starting with a digit.
|
||||
expect(app.setAsDefaultProtocolClient('0badscheme')).to.equal(false);
|
||||
// Starting with a hyphen.
|
||||
expect(app.setAsDefaultProtocolClient('-badscheme')).to.equal(false);
|
||||
// Containing backslashes.
|
||||
expect(app.setAsDefaultProtocolClient('http\\shell\\open\\command')).to.equal(false);
|
||||
// Containing forward slashes.
|
||||
expect(app.setAsDefaultProtocolClient('bad/protocol')).to.equal(false);
|
||||
// Containing spaces.
|
||||
expect(app.setAsDefaultProtocolClient('bad protocol')).to.equal(false);
|
||||
// Containing colons.
|
||||
expect(app.setAsDefaultProtocolClient('bad:protocol')).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'win32')('app launch through uri', () => {
|
||||
it('does not launch for argument following a URL', async () => {
|
||||
const appPath = path.join(fixturesPath, 'api', 'quit-app');
|
||||
|
||||
@@ -1372,6 +1372,89 @@ describe('chromium features', () => {
|
||||
expect(data).to.equal('object function object function');
|
||||
});
|
||||
|
||||
it('Worker does not have node integration when nodeIntegrationInWorker is disabled via setWindowOpenHandler', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: true,
|
||||
contextIsolation: false
|
||||
}
|
||||
});
|
||||
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
nodeIntegrationInWorker: false,
|
||||
contextIsolation: true
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
await w.loadURL(`file://${fixturesPath}/pages/blank.html`);
|
||||
const childCreated = once(app, 'browser-window-created') as Promise<[any, BrowserWindow]>;
|
||||
w.webContents.executeJavaScript(`window.open(${JSON.stringify(`file://${fixturesPath}/pages/blank.html`)}); void 0;`);
|
||||
const [, child] = await childCreated;
|
||||
await once(child.webContents, 'did-finish-load');
|
||||
|
||||
const data = await child.webContents.executeJavaScript(`
|
||||
const worker = new Worker('../workers/worker_node.js');
|
||||
new Promise((resolve) => { worker.onmessage = e => resolve(e.data); })
|
||||
`);
|
||||
expect(data).to.equal('undefined undefined undefined undefined');
|
||||
});
|
||||
|
||||
it('Worker has node integration when nodeIntegrationInWorker is enabled via setWindowOpenHandler', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: false,
|
||||
contextIsolation: false
|
||||
}
|
||||
});
|
||||
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: true,
|
||||
contextIsolation: false
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
await w.loadURL(`file://${fixturesPath}/pages/blank.html`);
|
||||
|
||||
// Parent's workers should NOT have node integration.
|
||||
const parentData = await w.webContents.executeJavaScript(`
|
||||
new Promise((resolve) => {
|
||||
const worker = new Worker('../workers/worker_node.js');
|
||||
worker.onmessage = e => resolve(e.data);
|
||||
})
|
||||
`);
|
||||
expect(parentData).to.equal('undefined undefined undefined undefined');
|
||||
|
||||
const childCreated = once(app, 'browser-window-created') as Promise<[any, BrowserWindow]>;
|
||||
w.webContents.executeJavaScript(`window.open(${JSON.stringify(`file://${fixturesPath}/pages/blank.html`)}); void 0;`);
|
||||
const [, child] = await childCreated;
|
||||
await once(child.webContents, 'did-finish-load');
|
||||
|
||||
// Child's workers should have node integration.
|
||||
const childData = await child.webContents.executeJavaScript(`
|
||||
new Promise((resolve) => {
|
||||
const worker = new Worker('../workers/worker_node.js');
|
||||
worker.onmessage = e => resolve(e.data);
|
||||
})
|
||||
`);
|
||||
expect(childData).to.equal('object function object function');
|
||||
});
|
||||
|
||||
it('Worker has access to fetch-dependent interfaces with nodeIntegrationInWorker', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
|
||||
Reference in New Issue
Block a user