diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index cb3005574220d..c5a012e582948 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -1578,20 +1578,23 @@ void WebContents::TabTraverse(bool reverse) { web_contents()->FocusThroughTabTraversal(reverse); } -bool WebContents::SendIPCMessage(bool all_frames, +bool WebContents::SendIPCMessage(bool internal, + bool send_to_all, const std::string& channel, const base::ListValue& args) { - return SendIPCMessageWithSender(all_frames, channel, args); + return SendIPCMessageWithSender(internal, send_to_all, channel, args); } -bool WebContents::SendIPCMessageWithSender(bool all_frames, +bool WebContents::SendIPCMessageWithSender(bool internal, + bool send_to_all, const std::string& channel, const base::ListValue& args, int32_t sender_id) { auto* frame_host = web_contents()->GetMainFrame(); if (frame_host) { - return frame_host->Send(new AtomFrameMsg_Message( - frame_host->GetRoutingID(), all_frames, channel, args, sender_id)); + return frame_host->Send(new AtomFrameMsg_Message(frame_host->GetRoutingID(), + internal, send_to_all, + channel, args, sender_id)); } return false; } @@ -2107,6 +2110,7 @@ void WebContents::OnRendererMessageSync(content::RenderFrameHost* frame_host, } void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host, + bool internal, bool send_to_all, int32_t web_contents_id, const std::string& channel, @@ -2115,7 +2119,8 @@ void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host, isolate(), web_contents_id); if (web_contents) { - web_contents->SendIPCMessageWithSender(send_to_all, channel, args, ID()); + web_contents->SendIPCMessageWithSender(internal, send_to_all, channel, args, + ID()); } } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 55ff352f7d030..6f908b48851dc 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -179,11 +179,13 @@ class WebContents : public mate::TrackableObject, void TabTraverse(bool reverse); // Send messages to browser. - bool SendIPCMessage(bool all_frames, + bool SendIPCMessage(bool internal, + bool send_to_all, const std::string& channel, const base::ListValue& args); - bool SendIPCMessageWithSender(bool all_frames, + bool SendIPCMessageWithSender(bool internal, + bool send_to_all, const std::string& channel, const base::ListValue& args, int32_t sender_id = 0); @@ -442,6 +444,7 @@ class WebContents : public mate::TrackableObject, // Called when received a message from renderer to be forwarded. void OnRendererMessageTo(content::RenderFrameHost* frame_host, + bool internal, bool send_to_all, int32_t web_contents_id, const std::string& channel, diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index 8062e1d7e9c37..6bf95afe423a6 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -34,13 +34,15 @@ IPC_SYNC_MESSAGE_ROUTED2_1(AtomFrameHostMsg_Message_Sync, base::ListValue /* arguments */, base::ListValue /* result */) -IPC_MESSAGE_ROUTED4(AtomFrameHostMsg_Message_To, +IPC_MESSAGE_ROUTED5(AtomFrameHostMsg_Message_To, + bool /* internal */, bool /* send_to_all */, int32_t /* web_contents_id */, std::string /* channel */, base::ListValue /* arguments */) -IPC_MESSAGE_ROUTED4(AtomFrameMsg_Message, +IPC_MESSAGE_ROUTED5(AtomFrameMsg_Message, + bool /* internal */, bool /* send_to_all */, std::string /* channel */, base::ListValue /* arguments */, diff --git a/atom/common/api/remote_callback_freer.cc b/atom/common/api/remote_callback_freer.cc index 43f77a797dad8..4c5603106cc7a 100644 --- a/atom/common/api/remote_callback_freer.cc +++ b/atom/common/api/remote_callback_freer.cc @@ -41,8 +41,8 @@ void RemoteCallbackFreer::RunDestructor() { args.AppendInteger(object_id_); auto* frame_host = web_contents()->GetMainFrame(); if (frame_host) { - frame_host->Send(new AtomFrameMsg_Message(frame_host->GetRoutingID(), false, - channel, args, sender_id)); + frame_host->Send(new AtomFrameMsg_Message(frame_host->GetRoutingID(), true, + false, channel, args, sender_id)); } Observe(nullptr); diff --git a/atom/common/api/remote_object_freer.cc b/atom/common/api/remote_object_freer.cc index 7429a93bad288..9712e19cbb4a3 100644 --- a/atom/common/api/remote_object_freer.cc +++ b/atom/common/api/remote_object_freer.cc @@ -56,7 +56,7 @@ void RemoteObjectFreer::RunDestructor() { if (!render_frame) return; - auto* channel = "ipc-message"; + auto* channel = "ipc-internal-message"; base::ListValue args; args.AppendString("ELECTRON_BROWSER_DEREFERENCE"); args.AppendString(context_id_); diff --git a/atom/renderer/api/atom_api_renderer_ipc.cc b/atom/renderer/api/atom_api_renderer_ipc.cc index 5f1947be20204..f2596f7e22205 100644 --- a/atom/renderer/api/atom_api_renderer_ipc.cc +++ b/atom/renderer/api/atom_api_renderer_ipc.cc @@ -61,6 +61,7 @@ base::ListValue SendSync(mate::Arguments* args, } void SendTo(mate::Arguments* args, + bool internal, bool send_to_all, int32_t web_contents_id, const std::string& channel, @@ -69,9 +70,9 @@ void SendTo(mate::Arguments* args, if (render_frame == nullptr) return; - bool success = render_frame->Send( - new AtomFrameHostMsg_Message_To(render_frame->GetRoutingID(), send_to_all, - web_contents_id, channel, arguments)); + bool success = render_frame->Send(new AtomFrameHostMsg_Message_To( + render_frame->GetRoutingID(), internal, send_to_all, web_contents_id, + channel, arguments)); if (!success) args->ThrowError("Unable to send AtomFrameHostMsg_Message_To"); diff --git a/atom/renderer/api/atom_api_renderer_ipc.h b/atom/renderer/api/atom_api_renderer_ipc.h index b517e78301e87..725aa3001f598 100644 --- a/atom/renderer/api/atom_api_renderer_ipc.h +++ b/atom/renderer/api/atom_api_renderer_ipc.h @@ -23,6 +23,7 @@ base::ListValue SendSync(mate::Arguments* args, const base::ListValue& arguments); void SendTo(mate::Arguments* args, + bool internal, bool send_to_all, int32_t web_contents_id, const std::string& channel, diff --git a/atom/renderer/atom_render_frame_observer.cc b/atom/renderer/atom_render_frame_observer.cc index bebe40633e8f6..09f2a2f32f6c9 100644 --- a/atom/renderer/atom_render_frame_observer.cc +++ b/atom/renderer/atom_render_frame_observer.cc @@ -35,8 +35,10 @@ namespace { bool GetIPCObject(v8::Isolate* isolate, v8::Local context, + bool internal, v8::Local* ipc) { - v8::Local key = mate::StringToV8(isolate, "ipc"); + v8::Local key = + mate::StringToV8(isolate, internal ? "ipc-internal" : "ipc"); v8::Local privateKey = v8::Private::ForApi(isolate, key); v8::Local global_object = context->Global(); v8::Local value; @@ -170,7 +172,8 @@ bool AtomRenderFrameObserver::OnMessageReceived(const IPC::Message& message) { return handled; } -void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all, +void AtomRenderFrameObserver::OnBrowserMessage(bool internal, + bool send_to_all, const std::string& channel, const base::ListValue& args, int32_t sender_id) { @@ -186,14 +189,15 @@ void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all, if (!frame || !render_frame_->IsMainFrame()) return; - EmitIPCEvent(frame, channel, args, sender_id); + EmitIPCEvent(frame, internal, channel, args, sender_id); // Also send the message to all sub-frames. if (send_to_all) { for (blink::WebFrame* child = frame->FirstChild(); child; child = child->NextSibling()) if (child->IsWebLocalFrame()) { - EmitIPCEvent(child->ToWebLocalFrame(), channel, args, sender_id); + EmitIPCEvent(child->ToWebLocalFrame(), internal, channel, args, + sender_id); } } } @@ -215,6 +219,7 @@ void AtomRenderFrameObserver::OnTakeHeapSnapshot( } void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame, + bool internal, const std::string& channel, const base::ListValue& args, int32_t sender_id) { @@ -233,7 +238,7 @@ void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame, return; v8::Local ipc; - if (GetIPCObject(isolate, context, &ipc)) { + if (GetIPCObject(isolate, context, internal, &ipc)) { TRACE_EVENT0("devtools.timeline", "FunctionCall"); auto args_vector = ListValueToVector(isolate, args); // Insert the Event object, event.sender is ipc. diff --git a/atom/renderer/atom_render_frame_observer.h b/atom/renderer/atom_render_frame_observer.h index 7a1a102617dfa..0390e8ddf9fbc 100644 --- a/atom/renderer/atom_render_frame_observer.h +++ b/atom/renderer/atom_render_frame_observer.h @@ -45,6 +45,7 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { protected: virtual void EmitIPCEvent(blink::WebLocalFrame* frame, + bool internal, const std::string& channel, const base::ListValue& args, int32_t sender_id); @@ -54,7 +55,8 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { void CreateIsolatedWorldContext(); bool IsMainWorld(int world_id); bool IsIsolatedWorld(int world_id); - void OnBrowserMessage(bool send_to_all, + void OnBrowserMessage(bool internal, + bool send_to_all, const std::string& channel, const base::ListValue& args, int32_t sender_id); diff --git a/atom/renderer/atom_sandboxed_renderer_client.cc b/atom/renderer/atom_sandboxed_renderer_client.cc index 58fb99f40a86d..29a5b84517aa5 100644 --- a/atom/renderer/atom_sandboxed_renderer_client.cc +++ b/atom/renderer/atom_sandboxed_renderer_client.cc @@ -103,6 +103,7 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver { protected: void EmitIPCEvent(blink::WebLocalFrame* frame, + bool internal, const std::string& channel, const base::ListValue& args, int32_t sender_id) override { @@ -117,7 +118,7 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver { mate::ConvertToV8(isolate, args), mate::ConvertToV8(isolate, sender_id)}; renderer_client_->InvokeIpcCallback( - context, "onMessage", + context, internal ? "onInternalMessage" : "onMessage", std::vector>(argv, argv + node::arraysize(argv))); } diff --git a/filenames.gni b/filenames.gni index 4728fca1ee811..e7f080e0715b2 100644 --- a/filenames.gni +++ b/filenames.gni @@ -13,6 +13,7 @@ filenames = { "lib/browser/api/browser-view.js", "lib/browser/api/browser-window.js", "lib/browser/api/content-tracing.js", + "lib/browser/api/crash-reporter.js", "lib/browser/api/dialog.js", "lib/browser/api/exports/electron.js", "lib/browser/api/global-shortcut.js", @@ -43,10 +44,10 @@ filenames = { "lib/browser/guest-view-manager.js", "lib/browser/guest-window-manager.js", "lib/browser/init.js", + "lib/browser/ipc-main-internal.js", "lib/browser/objects-registry.js", "lib/browser/rpc-server.js", "lib/common/api/clipboard.js", - "lib/common/api/crash-reporter.js", "lib/common/api/deprecate.js", "lib/common/api/deprecations.js", "lib/common/api/is-promise.js", @@ -56,6 +57,7 @@ filenames = { "lib/common/api/shell.js", "lib/common/atom-binding-setup.js", "lib/common/buffer-utils.js", + "lib/common/crash-reporter.js", "lib/common/error-utils.js", "lib/common/init.js", "lib/common/parse-features-string.js", @@ -65,6 +67,7 @@ filenames = { "lib/renderer/content-scripts-injector.js", "lib/renderer/init.js", "lib/renderer/inspector.js", + "lib/renderer/ipc-renderer-internal.js", "lib/renderer/override.js", "lib/renderer/security-warnings.js", "lib/renderer/web-frame-init.js", @@ -74,6 +77,7 @@ filenames = { "lib/renderer/web-view/web-view-attributes.js", "lib/renderer/web-view/web-view-constants.js", "lib/renderer/api/exports/electron.js", + "lib/renderer/api/crash-reporter.js", "lib/renderer/api/ipc-renderer.js", "lib/renderer/api/module-list.js", "lib/renderer/api/remote.js", diff --git a/lib/browser/api/browser-window.js b/lib/browser/api/browser-window.js index 9d377d4e3565a..d0e6d38c2f5cb 100644 --- a/lib/browser/api/browser-window.js +++ b/lib/browser/api/browser-window.js @@ -1,9 +1,10 @@ 'use strict' const electron = require('electron') -const { ipcMain, WebContentsView, TopLevelWindow } = electron +const { WebContentsView, TopLevelWindow } = electron const { BrowserWindow } = process.atomBinding('window') const v8Util = process.atomBinding('v8_util') +const ipcMain = require('@electron/internal/browser/ipc-main-internal') Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype) diff --git a/lib/browser/api/crash-reporter.js b/lib/browser/api/crash-reporter.js new file mode 100644 index 0000000000000..a963be8cab070 --- /dev/null +++ b/lib/browser/api/crash-reporter.js @@ -0,0 +1,14 @@ +'use strict' + +const CrashReporter = require('@electron/internal/common/crash-reporter') +const ipcMain = require('@electron/internal/browser/ipc-main-internal') + +class CrashReporterMain extends CrashReporter { + sendSync (channel, ...args) { + const event = {} + ipcMain.emit(channel, event, ...args) + return event.returnValue + } +} + +module.exports = new CrashReporterMain() diff --git a/lib/browser/api/ipc-main.js b/lib/browser/api/ipc-main.js index d610ac91f981f..9ab9569310801 100644 --- a/lib/browser/api/ipc-main.js +++ b/lib/browser/api/ipc-main.js @@ -1,17 +1,9 @@ 'use strict' -const EventEmitter = require('events').EventEmitter +const { EventEmitter } = require('events') const emitter = new EventEmitter() -const removeAllListeners = emitter.removeAllListeners.bind(emitter) -emitter.removeAllListeners = function (...args) { - if (args.length === 0) { - throw new Error('Removing all listeners from ipcMain will make Electron internals stop working. Please specify a event name') - } - removeAllListeners(...args) -} - // Do not throw exception when channel name is "error". emitter.on('error', () => {}) diff --git a/lib/browser/api/module-list.js b/lib/browser/api/module-list.js index 3fcebe89ba2c6..8ec7bda360ee5 100644 --- a/lib/browser/api/module-list.js +++ b/lib/browser/api/module-list.js @@ -9,6 +9,7 @@ module.exports = [ { name: 'BrowserView', file: 'browser-view' }, { name: 'BrowserWindow', file: 'browser-window' }, { name: 'contentTracing', file: 'content-tracing' }, + { name: 'crashReporter', file: 'crash-reporter' }, { name: 'dialog', file: 'dialog' }, { name: 'globalShortcut', file: 'global-shortcut' }, { name: 'ipcMain', file: 'ipc-main' }, diff --git a/lib/browser/api/navigation-controller.js b/lib/browser/api/navigation-controller.js index 846e487eae77b..1863961d06470 100644 --- a/lib/browser/api/navigation-controller.js +++ b/lib/browser/api/navigation-controller.js @@ -1,6 +1,6 @@ 'use strict' -const { ipcMain } = require('electron') +const ipcMain = require('@electron/internal/browser/ipc-main-internal') // The history operation in renderer is redirected to browser. ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER', function (event, method, ...args) { diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index e833e85e7b6a2..69668e3891ef7 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -6,6 +6,7 @@ const path = require('path') const url = require('url') const { app, ipcMain, session, NavigationController, deprecate } = electron +const ipcMainInternal = require('@electron/internal/browser/ipc-main-internal') const errorUtils = require('@electron/internal/common/error-utils') // session is not used here, the purpose is to make sure session is initalized @@ -98,12 +99,45 @@ Object.setPrototypeOf(WebContents.prototype, NavigationController.prototype) // WebContents::send(channel, args..) // WebContents::sendToAll(channel, args..) WebContents.prototype.send = function (channel, ...args) { - if (channel == null) throw new Error('Missing required channel argument') - return this._send(false, channel, args) + if (typeof channel !== 'string') { + throw new Error('Missing required channel argument') + } + + const internal = false + const sendToAll = false + + return this._send(internal, sendToAll, channel, args) } WebContents.prototype.sendToAll = function (channel, ...args) { - if (channel == null) throw new Error('Missing required channel argument') - return this._send(true, channel, args) + if (typeof channel !== 'string') { + throw new Error('Missing required channel argument') + } + + const internal = false + const sendToAll = true + + return this._send(internal, sendToAll, channel, args) +} + +WebContents.prototype._sendInternal = function (channel, ...args) { + if (typeof channel !== 'string') { + throw new Error('Missing required channel argument') + } + + const internal = true + const sendToAll = false + + return this._send(internal, sendToAll, channel, args) +} +WebContents.prototype._sendInternalToAll = function (channel, ...args) { + if (typeof channel !== 'string') { + throw new Error('Missing required channel argument') + } + + const internal = true + const sendToAll = true + + return this._send(internal, sendToAll, channel, args) } // Following methods are mapped to webFrame. @@ -116,8 +150,7 @@ const webFrameMethods = [ const asyncWebFrameMethods = function (requestId, method, callback, ...args) { return new Promise((resolve, reject) => { - this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args) - ipcMain.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, error, result) { + ipcMainInternal.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, error, result) { if (error == null) { if (typeof callback === 'function') callback(result) resolve(result) @@ -125,12 +158,13 @@ const asyncWebFrameMethods = function (requestId, method, callback, ...args) { reject(errorUtils.deserialize(error)) } }) + this._sendInternal('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args) }) } for (const method of webFrameMethods) { WebContents.prototype[method] = function (...args) { - this.send('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args) + this._sendInternal('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args) } } @@ -277,6 +311,19 @@ WebContents.prototype._init = function () { ipcMain.emit(channel, event, ...args) }) + this.on('ipc-internal-message', function (event, [channel, ...args]) { + ipcMainInternal.emit(channel, event, ...args) + }) + this.on('ipc-internal-message-sync', function (event, [channel, ...args]) { + Object.defineProperty(event, 'returnValue', { + set: function (value) { + return event.sendReply([value]) + }, + get: function () {} + }) + ipcMainInternal.emit(channel, event, ...args) + }) + // Handle context menu action request from pepper plugin. this.on('pepper-context-menu', function (event, params, callback) { // Access Menu via electron.Menu to prevent circular require. diff --git a/lib/browser/chrome-extension.js b/lib/browser/chrome-extension.js index 8f10658320ae0..1171a498648e9 100644 --- a/lib/browser/chrome-extension.js +++ b/lib/browser/chrome-extension.js @@ -1,8 +1,9 @@ 'use strict' -const { app, ipcMain, webContents, BrowserWindow } = require('electron') +const { app, webContents, BrowserWindow } = require('electron') const { getAllWebContents } = process.atomBinding('web_contents') const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllWebContents() +const ipcMain = require('@electron/internal/browser/ipc-main-internal') const { Buffer } = require('buffer') const fs = require('fs') @@ -108,7 +109,7 @@ const removeBackgroundPages = function (manifest) { const sendToBackgroundPages = function (...args) { for (const page of Object.values(backgroundPages)) { - page.webContents.sendToAll(...args) + page.webContents._sendInternalToAll(...args) } } @@ -160,9 +161,9 @@ ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) event.sender.once('render-view-deleted', () => { if (page.webContents.isDestroyed()) return - page.webContents.sendToAll(`CHROME_PORT_DISCONNECT_${portId}`) + page.webContents._sendInternalToAll(`CHROME_PORT_DISCONNECT_${portId}`) }) - page.webContents.sendToAll(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, event.sender.id, portId, connectInfo) + page.webContents._sendInternalToAll(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, event.sender.id, portId, connectInfo) }) ipcMain.on('CHROME_I18N_MANIFEST', function (event, extensionId) { @@ -177,9 +178,9 @@ ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message, return } - page.webContents.sendToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, event.sender.id, message, resultID) + page.webContents._sendInternalToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, event.sender.id, message, resultID) ipcMain.once(`CHROME_RUNTIME_ONMESSAGE_RESULT_${resultID}`, (event, result) => { - event.sender.send(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, result) + event.sender._sendInternal(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, result) }) resultID++ }) @@ -193,9 +194,9 @@ ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBa const senderTabId = isBackgroundPage ? null : event.sender.id - contents.sendToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, senderTabId, message, resultID) + contents._sendInternalToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, senderTabId, message, resultID) ipcMain.once(`CHROME_RUNTIME_ONMESSAGE_RESULT_${resultID}`, (event, result) => { - event.sender.send(`CHROME_TABS_SEND_MESSAGE_RESULT_${originResultID}`, result) + event.sender._sendInternal(`CHROME_TABS_SEND_MESSAGE_RESULT_${originResultID}`, result) }) resultID++ }) @@ -217,7 +218,7 @@ ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, exten url = `chrome-extension://${extensionId}/${String(Math.random()).substr(2, 8)}.js` } - contents.send('CHROME_TABS_EXECUTESCRIPT', event.sender.id, requestId, extensionId, url, code) + contents._sendInternal('CHROME_TABS_EXECUTESCRIPT', event.sender.id, requestId, extensionId, url, code) }) // Transfer the content scripts to renderer. diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index 8d31217c05532..62e68bb4240fb 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -1,6 +1,6 @@ 'use strict' -const { ipcMain } = require('electron') +const ipcMain = require('@electron/internal/browser/ipc-main-internal') const { desktopCapturer } = process.atomBinding('desktop_capturer') const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b) @@ -49,14 +49,16 @@ desktopCapturer.emit = (event, name, sources) => { }) if (handledWebContents) { - handledWebContents.send(capturerResult(handledRequest.id), result) + handledWebContents._sendInternal(capturerResult(handledRequest.id), result) } // Check the queue to see whether there is another identical request & handle requestsQueue.forEach(request => { const webContents = request.webContents if (deepEqual(handledRequest.options, request.options)) { - if (webContents) webContents.send(capturerResult(request.id), result) + if (webContents) { + webContents._sendInternal(capturerResult(request.id), result) + } } else { unhandledRequestsQueue.push(request) } diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index dd3cf7ff1ab70..05b02863d197d 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -1,6 +1,7 @@ 'use strict' -const { ipcMain, webContents } = require('electron') +const { webContents } = require('electron') +const ipcMain = require('@electron/internal/browser/ipc-main-internal') const parseFeaturesString = require('@electron/internal/common/parse-features-string') // Doesn't exist in early initialization. @@ -118,7 +119,7 @@ const createGuest = function (embedder, params) { const sendToEmbedder = (channel, ...args) => { if (!embedder.isDestroyed()) { - embedder.send(`${channel}-${guest.viewInstanceId}`, ...args) + embedder._sendInternal(`${channel}-${guest.viewInstanceId}`, ...args) } } @@ -142,7 +143,7 @@ const createGuest = function (embedder, params) { guest.on('dom-ready', function () { const guestInstance = guestInstances[guestInstanceId] if (guestInstance != null && guestInstance.visibilityState != null) { - guest.send('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', guestInstance.visibilityState) + guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', guestInstance.visibilityState) } }) @@ -201,7 +202,7 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn // Remove guest from embedder if moving across web views if (guest.viewInstanceId !== params.instanceId) { webViewManager.removeGuest(guestInstance.embedder, guestInstanceId) - guestInstance.embedder.send(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${guest.viewInstanceId}`) + guestInstance.embedder._sendInternal(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${guest.viewInstanceId}`) } } @@ -302,7 +303,7 @@ const watchEmbedder = function (embedder) { const guestInstance = guestInstances[guestInstanceId] guestInstance.visibilityState = visibilityState if (guestInstance.embedder === embedder) { - guestInstance.guest.send('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', visibilityState) + guestInstance.guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', visibilityState) } } } @@ -325,7 +326,7 @@ const watchEmbedder = function (embedder) { } ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) { - event.sender.send(`ELECTRON_RESPONSE_${requestId}`, createGuest(event.sender, params)) + event.sender._sendInternal(`ELECTRON_RESPONSE_${requestId}`, createGuest(event.sender, params)) }) ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', function (event, params) { diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index bd251559143d4..8663b2cb8fe1a 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -1,7 +1,8 @@ 'use strict' -const { BrowserWindow, ipcMain, webContents } = require('electron') +const { BrowserWindow, webContents } = require('electron') const { isSameOrigin } = process.atomBinding('v8_util') +const ipcMain = require('@electron/internal/browser/ipc-main-internal') const parseFeaturesString = require('@electron/internal/common/parse-features-string') const hasProp = {}.hasOwnProperty @@ -87,7 +88,7 @@ const setupGuest = function (embedder, frameName, guest, options) { guest.destroy() } const closedByUser = function () { - embedder.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId) + embedder._sendInternal('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId) embedder.removeListener('render-view-deleted', closedByEmbedder) } embedder.once('render-view-deleted', closedByEmbedder) @@ -320,7 +321,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, // postMessage across origins is useful and not harmful. if (targetOrigin === '*' || isSameOrigin(guestContents.getURL(), targetOrigin)) { const sourceId = event.sender.id - guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) + guestContents._sendInternal('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) } }) diff --git a/lib/browser/ipc-main-internal.js b/lib/browser/ipc-main-internal.js new file mode 100644 index 0000000000000..9ab9569310801 --- /dev/null +++ b/lib/browser/ipc-main-internal.js @@ -0,0 +1,10 @@ +'use strict' + +const { EventEmitter } = require('events') + +const emitter = new EventEmitter() + +// Do not throw exception when channel name is "error". +emitter.on('error', () => {}) + +module.exports = emitter diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 312328e853eb4..262d7e2ea9f45 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -8,8 +8,9 @@ const os = require('os') const path = require('path') const v8Util = process.atomBinding('v8_util') -const { ipcMain, isPromise } = electron +const { isPromise } = electron +const ipcMain = require('@electron/internal/browser/ipc-main-internal') const objectsRegistry = require('@electron/internal/browser/objects-registry') const bufferUtils = require('@electron/internal/common/buffer-utils') const errorUtils = require('@electron/internal/common/error-utils') @@ -215,7 +216,7 @@ const unwrapArgs = function (sender, contextId, args) { const processId = sender.getProcessId() const callIntoRenderer = function (...args) { if (!sender.isDestroyed() && processId === sender.getProcessId()) { - sender.send('ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args)) + sender._sendInternal('ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args)) } else { removeRemoteListenersAndLogWarning(this, meta, callIntoRenderer) } @@ -390,7 +391,7 @@ ipcMain.on('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function (event, request }, error => { return [errorUtils.serialize(error)] }).then(responseArgs => { - event.sender.send(`ELECTRON_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, ...responseArgs) + event.sender._sendInternal(`ELECTRON_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, ...responseArgs) }) }) @@ -424,7 +425,7 @@ const getTempDirectory = function () { } } -ipcMain.on('ELECTRON_CRASH_REPORTER_INIT', function (event, options) { +const crashReporterInit = function (options) { const productName = options.productName || electron.app.getName() const crashesDirectory = path.join(getTempDirectory(), `${productName} Crashes`) @@ -445,11 +446,19 @@ ipcMain.on('ELECTRON_CRASH_REPORTER_INIT', function (event, options) { }) } - event.returnValue = { + return { productName, crashesDirectory, appVersion: electron.app.getVersion() } +} + +ipcMain.on('ELECTRON_CRASH_REPORTER_INIT', function (event, options) { + try { + event.returnValue = [null, crashReporterInit(options)] + } catch (error) { + event.returnValue = [errorUtils.serialize(error)] + } }) ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) { diff --git a/lib/common/api/module-list.js b/lib/common/api/module-list.js index 38f3832caf7cc..3741f17fb6452 100644 --- a/lib/common/api/module-list.js +++ b/lib/common/api/module-list.js @@ -3,7 +3,6 @@ // Common modules, please sort alphabetically module.exports = [ { name: 'clipboard', file: 'clipboard' }, - { name: 'crashReporter', file: 'crash-reporter' }, { name: 'nativeImage', file: 'native-image' }, { name: 'shell', file: 'shell' }, // The internal modules, invisible unless you know their names. diff --git a/lib/common/api/crash-reporter.js b/lib/common/crash-reporter.js similarity index 85% rename from lib/common/api/crash-reporter.js rename to lib/common/crash-reporter.js index 25fb45aa82cb6..bc9d4c583ef4c 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/crash-reporter.js @@ -1,17 +1,8 @@ 'use strict' -const electron = require('electron') const binding = process.atomBinding('crash_reporter') -const sendSync = function (channel, ...args) { - if (process.type === 'browser') { - const event = {} - electron.ipcMain.emit(channel, event, ...args) - return event.returnValue - } else { - return electron.ipcRenderer.sendSync(channel, ...args) - } -} +const errorUtils = require('@electron/internal/common/error-utils') class CrashReporter { contructor () { @@ -19,6 +10,20 @@ class CrashReporter { this.crashesDirectory = null } + sendSync (channel, ...args) { + throw new Error('Not implemented') + } + + invoke (command, ...args) { + const [ error, result ] = this.sendSync(command, ...args) + + if (error) { + throw errorUtils.deserialize(error) + } + + return result + } + start (options) { if (options == null) options = {} @@ -46,7 +51,7 @@ class CrashReporter { throw new Error('submitURL is a required option to crashReporter.start') } - const ret = sendSync('ELECTRON_CRASH_REPORTER_INIT', { + const ret = this.invoke('ELECTRON_CRASH_REPORTER_INIT', { submitURL, productName }) @@ -114,4 +119,4 @@ class CrashReporter { } } -module.exports = new CrashReporter() +module.exports = CrashReporter diff --git a/lib/isolated_renderer/init.js b/lib/isolated_renderer/init.js index a13256527ffcb..c87bed4afbe19 100644 --- a/lib/isolated_renderer/init.js +++ b/lib/isolated_renderer/init.js @@ -6,11 +6,11 @@ const { send, sendSync } = binding const ipcRenderer = { send (...args) { - return send('ipc-message', args) + return send('ipc-internal-message', args) }, sendSync (...args) { - return sendSync('ipc-message-sync', args)[0] + return sendSync('ipc-internal-message-sync', args)[0] }, // No-ops since events aren't received diff --git a/lib/renderer/api/crash-reporter.js b/lib/renderer/api/crash-reporter.js new file mode 100644 index 0000000000000..5bbd90e10d8be --- /dev/null +++ b/lib/renderer/api/crash-reporter.js @@ -0,0 +1,12 @@ +'use strict' + +const CrashReporter = require('@electron/internal/common/crash-reporter') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') + +class CrashReporterRenderer extends CrashReporter { + sendSync (channel, ...args) { + return ipcRenderer.sendSync(channel, ...args) + } +} + +module.exports = new CrashReporterRenderer() diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index 0d2e7883ae328..e4ece821b9060 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -1,6 +1,7 @@ 'use strict' -const { ipcRenderer, nativeImage } = require('electron') +const { nativeImage } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const includes = [].includes let currentId = 0 diff --git a/lib/renderer/api/ipc-renderer.js b/lib/renderer/api/ipc-renderer.js index 3c083216c126f..7705f9f9ae77c 100644 --- a/lib/renderer/api/ipc-renderer.js +++ b/lib/renderer/api/ipc-renderer.js @@ -5,6 +5,7 @@ const v8Util = process.atomBinding('v8_util') // Created by init.js. const ipcRenderer = v8Util.getHiddenValue(global, 'ipc') +const internal = false ipcRenderer.send = function (...args) { return binding.send('ipc-message', args) @@ -19,19 +20,11 @@ ipcRenderer.sendToHost = function (...args) { } ipcRenderer.sendTo = function (webContentsId, channel, ...args) { - return binding.sendTo(false, webContentsId, channel, args) + return binding.sendTo(internal, false, webContentsId, channel, args) } ipcRenderer.sendToAll = function (webContentsId, channel, ...args) { - return binding.sendTo(true, webContentsId, channel, args) -} - -const removeAllListeners = ipcRenderer.removeAllListeners.bind(ipcRenderer) -ipcRenderer.removeAllListeners = function (...args) { - if (args.length === 0) { - throw new Error('Removing all listeners from ipcRenderer will make Electron internals stop working. Please specify a event name') - } - removeAllListeners(...args) + return binding.sendTo(internal, true, webContentsId, channel, args) } module.exports = ipcRenderer diff --git a/lib/renderer/api/module-list.js b/lib/renderer/api/module-list.js index cc9b12e2d2ad9..bc2c8b2d2b6cd 100644 --- a/lib/renderer/api/module-list.js +++ b/lib/renderer/api/module-list.js @@ -5,6 +5,7 @@ const features = process.atomBinding('features') // Renderer side modules, please sort alphabetically. // A module is `enabled` if there is no explicit condition defined. module.exports = [ + { name: 'crashReporter', file: 'crash-reporter', enabled: true }, { name: 'desktopCapturer', file: 'desktop-capturer', diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index e5ae256f4bc10..20562992dcdf4 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -1,12 +1,13 @@ 'use strict' const v8Util = process.atomBinding('v8_util') -const { ipcRenderer, isPromise } = require('electron') +const { isPromise } = require('electron') const resolvePromise = Promise.resolve.bind(Promise) const CallbacksRegistry = require('@electron/internal/renderer/callbacks-registry') const bufferUtils = require('@electron/internal/common/buffer-utils') const errorUtils = require('@electron/internal/common/error-utils') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const callbacksRegistry = new CallbacksRegistry() const remoteObjectCache = v8Util.createIDWeakMap() diff --git a/lib/renderer/chrome-api.js b/lib/renderer/chrome-api.js index 629370b95968c..b6b816afc0dc6 100644 --- a/lib/renderer/chrome-api.js +++ b/lib/renderer/chrome-api.js @@ -1,6 +1,6 @@ 'use strict' -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const Event = require('@electron/internal/renderer/extensions/event') const url = require('url') @@ -43,12 +43,12 @@ class Port { disconnect () { if (this.disconnected) return - ipcRenderer.sendToAll(this.tabId, `CHROME_PORT_DISCONNECT_${this.portId}`) + ipcRenderer._sendInternalToAll(this.tabId, `CHROME_PORT_DISCONNECT_${this.portId}`) this._onDisconnect() } postMessage (message) { - ipcRenderer.sendToAll(this.tabId, `CHROME_PORT_POSTMESSAGE_${this.portId}`, message) + ipcRenderer._sendInternalToAll(this.tabId, `CHROME_PORT_POSTMESSAGE_${this.portId}`, message) } _onDisconnect () { diff --git a/lib/renderer/content-scripts-injector.js b/lib/renderer/content-scripts-injector.js index 19727948401ed..5091d84f69685 100644 --- a/lib/renderer/content-scripts-injector.js +++ b/lib/renderer/content-scripts-injector.js @@ -1,6 +1,6 @@ 'use strict' -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const { runInThisContext } = require('vm') // Check whether pattern matches. diff --git a/lib/renderer/extensions/i18n.js b/lib/renderer/extensions/i18n.js index 027ec322b4aa9..661b264494602 100644 --- a/lib/renderer/extensions/i18n.js +++ b/lib/renderer/extensions/i18n.js @@ -6,7 +6,7 @@ // Does not implement predefined messages: // https://developer.chrome.com/extensions/i18n#overview-predefined -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const fs = require('fs') const path = require('path') diff --git a/lib/renderer/extensions/web-navigation.js b/lib/renderer/extensions/web-navigation.js index 5ced9d5b79edc..9c3f3f04e537b 100644 --- a/lib/renderer/extensions/web-navigation.js +++ b/lib/renderer/extensions/web-navigation.js @@ -1,7 +1,7 @@ 'use strict' const Event = require('@electron/internal/renderer/extensions/event') -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') class WebNavigation { constructor () { diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 539ab8edd5b19..b19ace73c81ce 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -1,6 +1,6 @@ 'use strict' -const events = require('events') +const { EventEmitter } = require('events') const path = require('path') const Module = require('module') @@ -22,10 +22,11 @@ globalPaths.push(path.join(__dirname, 'api', 'exports')) // The global variable will be used by ipc for event dispatching const v8Util = process.atomBinding('v8_util') -v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter()) +v8Util.setHiddenValue(global, 'ipc', new EventEmitter()) +v8Util.setHiddenValue(global, 'ipc-internal', new EventEmitter()) // Use electron module after everything is ready. -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') require('@electron/internal/renderer/web-frame-init')() diff --git a/lib/renderer/ipc-renderer-internal.js b/lib/renderer/ipc-renderer-internal.js new file mode 100644 index 0000000000000..a8dda32632b6c --- /dev/null +++ b/lib/renderer/ipc-renderer-internal.js @@ -0,0 +1,26 @@ +'use strict' + +const binding = process.atomBinding('ipc') +const v8Util = process.atomBinding('v8_util') + +// Created by init.js. +const ipcRenderer = v8Util.getHiddenValue(global, 'ipc-internal') +const internal = true + +ipcRenderer.send = function (...args) { + return binding.send('ipc-internal-message', args) +} + +ipcRenderer.sendSync = function (...args) { + return binding.sendSync('ipc-internal-message-sync', args)[0] +} + +ipcRenderer.sendTo = function (webContentsId, channel, ...args) { + return binding.sendTo(internal, false, webContentsId, channel, args) +} + +ipcRenderer.sendToAll = function (webContentsId, channel, ...args) { + return binding.sendTo(internal, true, webContentsId, channel, args) +} + +module.exports = ipcRenderer diff --git a/lib/renderer/override.js b/lib/renderer/override.js index 79fc76e5646de..413b8b820452f 100644 --- a/lib/renderer/override.js +++ b/lib/renderer/override.js @@ -1,6 +1,6 @@ 'use strict' -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const { guestInstanceId, openerId } = process const hiddenPage = process.argv.includes('--hidden-page') diff --git a/lib/renderer/security-warnings.js b/lib/renderer/security-warnings.js index 8235ce46bc7de..9d68ee0f2f656 100644 --- a/lib/renderer/security-warnings.js +++ b/lib/renderer/security-warnings.js @@ -264,7 +264,7 @@ const logSecurityWarnings = function (webPreferences, nodeIntegration) { } const getWebPreferences = function () { - const { ipcRenderer } = require('electron') + const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const errorUtils = require('@electron/internal/common/error-utils') const [ error, result ] = ipcRenderer.sendSync('ELECTRON_BROWSER_GET_LAST_WEB_PREFERENCES') diff --git a/lib/renderer/web-frame-init.js b/lib/renderer/web-frame-init.js index bffd761612be0..f7861dbb60b57 100644 --- a/lib/renderer/web-frame-init.js +++ b/lib/renderer/web-frame-init.js @@ -1,6 +1,7 @@ 'use strict' -const { ipcRenderer, webFrame } = require('electron') +const { webFrame } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const errorUtils = require('@electron/internal/common/error-utils') module.exports = () => { diff --git a/lib/renderer/web-view/guest-view-internal.js b/lib/renderer/web-view/guest-view-internal.js index ac17606a1c507..3d544aa626ae1 100644 --- a/lib/renderer/web-view/guest-view-internal.js +++ b/lib/renderer/web-view/guest-view-internal.js @@ -1,6 +1,7 @@ 'use strict' -const { ipcRenderer, webFrame } = require('electron') +const { webFrame } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') let requestId = 0 diff --git a/lib/renderer/web-view/web-view-attributes.js b/lib/renderer/web-view/web-view-attributes.js index 6c51e77bf0203..9ed48f406a53e 100644 --- a/lib/renderer/web-view/web-view-attributes.js +++ b/lib/renderer/web-view/web-view-attributes.js @@ -1,6 +1,6 @@ 'use strict' -const { ipcRenderer } = require('electron') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const WebViewImpl = require('@electron/internal/renderer/web-view/web-view') const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants') const errorUtils = require('@electron/internal/common/error-utils') diff --git a/lib/renderer/web-view/web-view.js b/lib/renderer/web-view/web-view.js index 56bdb21b5f63d..b8d25eb3f4905 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -1,8 +1,9 @@ 'use strict' -const { ipcRenderer, remote, webFrame } = require('electron') +const { remote, webFrame } = require('electron') const v8Util = process.atomBinding('v8_util') +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const guestViewInternal = require('@electron/internal/renderer/web-view/guest-view-internal') const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants') const errorUtils = require('@electron/internal/common/error-utils') diff --git a/lib/sandboxed_renderer/api/module-list.js b/lib/sandboxed_renderer/api/module-list.js index e510462a73814..b2fd9d8a4e848 100644 --- a/lib/sandboxed_renderer/api/module-list.js +++ b/lib/sandboxed_renderer/api/module-list.js @@ -5,7 +5,7 @@ const features = process.atomBinding('features') module.exports = [ { name: 'crashReporter', - load: () => require('@electron/internal/common/api/crash-reporter') + load: () => require('@electron/internal/renderer/api/crash-reporter') }, { name: 'desktopCapturer', @@ -14,7 +14,7 @@ module.exports = [ }, { name: 'ipcRenderer', - load: () => require('@electron/internal/sandboxed_renderer/api/ipc-renderer') + load: () => require('@electron/internal/renderer/api/ipc-renderer') }, { name: 'isPromise', diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index 35006bdf58d81..46271fadaf354 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -17,6 +17,9 @@ v8Util.setHiddenValue(global, 'Buffer', Buffer) // The `lib/renderer/api/ipc-renderer.js` module looks for the ipc object in the // "ipc" hidden value v8Util.setHiddenValue(global, 'ipc', new EventEmitter()) +// The `lib/renderer/ipc-renderer-internal.js` module looks for the ipc object in the +// "ipc-internal" hidden value +v8Util.setHiddenValue(global, 'ipc-internal', new EventEmitter()) // The process object created by browserify is not an event emitter, fix it so // the API is more compatible with non-sandboxed renderers. for (const prop of Object.keys(EventEmitter.prototype)) { @@ -40,9 +43,28 @@ const loadedModules = new Map([ ['url', require('url')] ]) +// AtomSandboxedRendererClient will look for the "ipcNative" hidden object when +// invoking the `onMessage`/`onExit` callbacks. +const ipcNative = process.atomBinding('ipc') +v8Util.setHiddenValue(global, 'ipcNative', ipcNative) + +const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') + +ipcNative.onInternalMessage = function (channel, args, senderId) { + ipcRenderer.emit(channel, { sender: ipcRenderer, senderId }, ...args) +} + +ipcNative.onMessage = function (channel, args, senderId) { + electron.ipcRenderer.emit(channel, { sender: electron.ipcRenderer, senderId }, ...args) +} + +ipcNative.onExit = function () { + process.emit('exit') +} + const { preloadSrc, preloadError, process: processProps -} = electron.ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD') +} = ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD') require('@electron/internal/renderer/web-frame-init')() diff --git a/spec/api-ipc-main-spec.js b/spec/api-ipc-main-spec.js index b7262593087d9..47a9ee6c6573e 100644 --- a/spec/api-ipc-main-spec.js +++ b/spec/api-ipc-main-spec.js @@ -3,7 +3,9 @@ const chai = require('chai') const dirtyChai = require('dirty-chai') const path = require('path') +const cp = require('child_process') const { closeWindow } = require('./window-helpers') +const { emittedOnce } = require('./events-helpers') const { expect } = chai chai.use(dirtyChai) @@ -55,18 +57,6 @@ describe('ipc main module', () => { }) }) - it('throws an error when removing all the listeners', () => { - ipcMain.on('test-event', () => {}) - expect(ipcMain.listenerCount('test-event')).to.equal(1) - - expect(() => { - ipcMain.removeAllListeners() - }).to.throw(/Removing all listeners from ipcMain will make Electron internals stop working/) - - ipcMain.removeAllListeners('test-event') - expect(ipcMain.listenerCount('test-event')).to.equal(0) - }) - describe('remote objects registry', () => { it('does not dereference until the render view is deleted (regression)', (done) => { w = new BrowserWindow({ show: false }) @@ -80,4 +70,20 @@ describe('ipc main module', () => { w.loadFile(path.join(fixtures, 'api', 'render-view-deleted.html')) }) }) + + describe('ipcMain.on', () => { + it('is not used for internals', async () => { + const appPath = path.join(__dirname, 'fixtures', 'api', 'ipc-main-listeners') + const electronPath = remote.getGlobal('process').execPath + const appProcess = cp.spawn(electronPath, [appPath]) + + let output = '' + appProcess.stdout.on('data', (data) => { output += data }) + + await emittedOnce(appProcess.stdout, 'end') + + output = JSON.parse(output) + expect(output).to.deep.equal(['error']) + }) + }) }) diff --git a/spec/api-ipc-renderer-spec.js b/spec/api-ipc-renderer-spec.js index 80f2ec2c5cc07..b3a3d349756ed 100644 --- a/spec/api-ipc-renderer-spec.js +++ b/spec/api-ipc-renderer-spec.js @@ -5,6 +5,7 @@ const dirtyChai = require('dirty-chai') const http = require('http') const path = require('path') const { closeWindow } = require('./window-helpers') +const { emittedOnce } = require('./events-helpers') const { expect } = chai chai.use(dirtyChai) @@ -225,15 +226,16 @@ describe('ipc renderer module', () => { }) }) - it('throws an error when removing all the listeners', () => { - ipcRenderer.on('test-event', () => {}) - expect(ipcRenderer.listenerCount('test-event')).to.equal(1) + describe('ipcRenderer.on', () => { + it('is not used for internals', async () => { + w = new BrowserWindow({ show: false }) + w.loadURL('about:blank') - expect(() => { - ipcRenderer.removeAllListeners() - }).to.throw(/Removing all listeners from ipcRenderer will make Electron internals stop working/) + await emittedOnce(w.webContents, 'did-finish-load') - ipcRenderer.removeAllListeners('test-event') - expect(ipcRenderer.listenerCount('test-event')).to.equal(0) + const script = `require('electron').ipcRenderer.eventNames()` + const result = await w.webContents.executeJavaScript(script) + expect(result).to.deep.equal([]) + }) }) }) diff --git a/spec/fixtures/api/ipc-main-listeners/main.js b/spec/fixtures/api/ipc-main-listeners/main.js new file mode 100644 index 0000000000000..d56348136bc1d --- /dev/null +++ b/spec/fixtures/api/ipc-main-listeners/main.js @@ -0,0 +1,10 @@ +const { app, ipcMain } = require('electron') + +app.on('ready', () => { + process.stdout.write(JSON.stringify(ipcMain.eventNames())) + process.stdout.end() + + setImmediate(() => { + app.quit() + }) +}) diff --git a/spec/fixtures/api/ipc-main-listeners/package.json b/spec/fixtures/api/ipc-main-listeners/package.json new file mode 100644 index 0000000000000..7acf9eb5274bc --- /dev/null +++ b/spec/fixtures/api/ipc-main-listeners/package.json @@ -0,0 +1,4 @@ +{ + "name": "ipc-main-listeners", + "main": "main.js" +}