Skip to content

Commit

Permalink
fix: execute session preload scripts in sandboxed renderers (#17875)
Browse files Browse the repository at this point in the history
  • Loading branch information
miniak authored and codebytere committed Apr 19, 2019
1 parent 2360f3e commit b3ed830
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 25 deletions.
17 changes: 12 additions & 5 deletions lib/browser/rpc-server.js
Expand Up @@ -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,
Expand Down
22 changes: 18 additions & 4 deletions lib/sandboxed_renderer/init.js
Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
//
Expand All @@ -150,17 +152,29 @@ 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}
})`

// 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
Expand Down
37 changes: 22 additions & 15 deletions spec/api-browser-window-spec.js
Expand Up @@ -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', () => {
Expand Down
1 change: 1 addition & 0 deletions spec/fixtures/module/get-global-preload.js
@@ -0,0 +1 @@
require('electron').ipcRenderer.send('vars', window.preload1, window.preload2)
1 change: 0 additions & 1 deletion spec/fixtures/module/set-global-preload-3.js

This file was deleted.

0 comments on commit b3ed830

Please sign in to comment.