diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 64c24722080ba..f12d1ba01a671 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -490,20 +490,27 @@ ipcMain.on('ELECTRON_BROWSER_CLIPBOARD_WRITE_FIND_TEXT', function (event, text) setReturnValue(event, () => electron.clipboard.writeFindText(text)) }) -ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) { - const preloadPath = event.sender._getPreloadPath() +const getPreloadScript = function (preloadPath) { let preloadSrc = null let preloadError = null if (preloadPath) { try { preloadSrc = fs.readFileSync(preloadPath).toString() } catch (err) { - preloadError = { stack: err ? err.stack : (new Error(`Failed to load "${preloadPath}"`)).stack } + preloadError = errorUtils.serialize(err) } } + return { preloadPath, preloadSrc, preloadError } +} + +ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) { + const preloadPaths = [ + ...(event.sender.session ? event.sender.session.getPreloads() : []), + event.sender._getPreloadPath() + ] + event.returnValue = { - preloadSrc, - preloadError, + preloadScripts: preloadPaths.map(path => getPreloadScript(path)), isRemoteModuleEnabled: event.sender._isRemoteModuleEnabled(), process: { arch: process.arch, diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index c6fb38cb94b78..caa0ccbf2ba80 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -67,7 +67,7 @@ ipcNative.onExit = function () { } const { - preloadSrc, preloadError, isRemoteModuleEnabled, process: processProps + preloadScripts, isRemoteModuleEnabled, process: processProps } = ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD') const makePropertyNonConfigurable = function (object, name) { @@ -131,6 +131,8 @@ if (!process.guestInstanceId && preloadProcess.argv.includes('--webview-tag=true require('@electron/internal/renderer/web-view/web-view').setupWebView(window) } +const errorUtils = require('@electron/internal/common/error-utils') + // Wrap the script into a function executed in global scope. It won't have // access to the current scope, so we'll expose a few objects as arguments: // @@ -150,7 +152,7 @@ if (!process.guestInstanceId && preloadProcess.argv.includes('--webview-tag=true // and any `require('electron')` calls in `preload.js` will work as expected // since browserify won't try to include `electron` in the bundle, falling back // to the `preloadRequire` function above. -if (preloadSrc) { +function runPreloadScript (preloadSrc) { const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate, clearImmediate) { ${preloadSrc} })` @@ -158,9 +160,21 @@ if (preloadSrc) { // eval in window scope const preloadFn = binding.createPreloadScript(preloadWrapperSrc) const { setImmediate, clearImmediate } = require('timers') + preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate) -} else if (preloadError) { - console.error(preloadError.stack) +} + +for (const { preloadPath, preloadSrc, preloadError } of preloadScripts) { + try { + if (preloadSrc) { + runPreloadScript(preloadSrc) + } else if (preloadError) { + throw errorUtils.deserialize(preloadError) + } + } catch (error) { + console.error(`Unable to load preload script: ${preloadPath}`) + console.error(`${error}`) + } } // Warn about security issues diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 0c82370cf45bf..540a197b4eb6e 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -1343,22 +1343,29 @@ describe('BrowserWindow module', () => { assert.deepStrictEqual(defaultSession.getPreloads(), preloads) }) - it('loads the script before other scripts in window including normal preloads', function (done) { - ipcMain.once('vars', function (event, preload1, preload2, preload3) { - assert.strictEqual(preload1, 'preload-1') - assert.strictEqual(preload2, 'preload-1-2') - assert.strictEqual(preload3, 'preload-1-2-3') - done() - }) - w.destroy() - w = new BrowserWindow({ - show: false, - webPreferences: { - preload: path.join(fixtures, 'module', 'set-global-preload-3.js') - } + const generateSpecs = (description, sandbox) => { + describe(description, () => { + it('loads the script before other scripts in window including normal preloads', function (done) { + ipcMain.once('vars', function (event, preload1, preload2) { + assert.strictEqual(preload1, 'preload-1') + assert.strictEqual(preload2, 'preload-1-2') + done() + }) + w.destroy() + w = new BrowserWindow({ + show: false, + webPreferences: { + sandbox, + preload: path.join(fixtures, 'module', 'get-global-preload.js') + } + }) + w.loadURL('about:blank') + }) }) - w.loadFile(path.join(fixtures, 'api', 'preloads.html')) - }) + } + + generateSpecs('without sandbox', false) + generateSpecs('with sandbox', true) }) describe('"additionalArguments" option', () => { diff --git a/spec/fixtures/module/get-global-preload.js b/spec/fixtures/module/get-global-preload.js new file mode 100644 index 0000000000000..438397f37073d --- /dev/null +++ b/spec/fixtures/module/get-global-preload.js @@ -0,0 +1 @@ +require('electron').ipcRenderer.send('vars', window.preload1, window.preload2) diff --git a/spec/fixtures/module/set-global-preload-3.js b/spec/fixtures/module/set-global-preload-3.js deleted file mode 100644 index 9cfef949277ed..0000000000000 --- a/spec/fixtures/module/set-global-preload-3.js +++ /dev/null @@ -1 +0,0 @@ -window.preload3 = window.preload2 + '-3'