if (window) {
bool visible = window->IsVisible() && !window->IsMinimized();
if (!visible) // Default state is visible.
- command_line->AppendSwitch("hidden-page");
+ command_line->AppendSwitch(switches::kHiddenPage);
}
// Use frame scheduling for offscreen renderers.
// Enable context isolation of Electron APIs and preload script
const char kContextIsolation[] = "contextIsolation";
-// Instancd ID of guest WebContents.
+// Instance ID of guest WebContents.
const char kGuestInstanceID[] = "guestInstanceId";
// Web runtime features.
const char kGuestInstanceID[] = "guest-instance-id";
const char kOpenerID[] = "opener-id";
const char kScrollBounce[] = "scroll-bounce";
+const char kHiddenPage[] = "hidden-page";
// Widevine options
// Path to Widevine CDM binaries.
extern const char kGuestInstanceID[];
extern const char kOpenerID[];
extern const char kScrollBounce[];
+extern const char kHiddenPage[];
extern const char kWidevineCdmPath[];
extern const char kWidevineCdmVersion[];
#include "atom/renderer/atom_renderer_client.h"
+#include "atom_natives.h" // NOLINT: This file is generated with js2c
+
#include <string>
#include <vector>
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_bindings.h"
#include "atom/common/options_switches.h"
+#include "atom/renderer/api/atom_api_renderer_ipc.h"
#include "atom/renderer/atom_render_view_observer.h"
#include "atom/renderer/content_settings_observer.h"
#include "atom/renderer/guest_view_container.h"
World::ISOLATED_WORLD, &source, 1, ExtensionGroup::MAIN_GROUP);
}
+ void SetupMainWorldOverrides(v8::Handle<v8::Context> context) {
+ // Setup window overrides in the main world context
+ v8::Isolate* isolate = context->GetIsolate();
+
+ // Wrap the bundle into a function that receives the binding object as
+ // an argument.
+ std::string bundle(node::isolated_bundle_native,
+ node::isolated_bundle_native + sizeof(node::isolated_bundle_native));
+ std::string wrapper = "(function (binding) {\n" + bundle + "\n})";
+ auto script = v8::Script::Compile(
+ mate::ConvertToV8(isolate, wrapper)->ToString());
+ auto func = v8::Handle<v8::Function>::Cast(
+ script->Run(context).ToLocalChecked());
+
+ auto binding = v8::Object::New(isolate);
+ api::Initialize(binding, v8::Null(isolate), context, nullptr);
+
+ // Pass in CLI flags needed to setup window
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ mate::Dictionary dict(isolate, binding);
+ if (command_line->HasSwitch(switches::kGuestInstanceID))
+ dict.Set("guestInstanceId",
+ command_line->GetSwitchValueASCII(switches::kGuestInstanceID));
+ if (command_line->HasSwitch(switches::kOpenerID))
+ dict.Set("openerId",
+ command_line->GetSwitchValueASCII(switches::kOpenerID));
+ dict.Set("hiddenPage", command_line->HasSwitch(switches::kHiddenPage));
+
+ v8::Local<v8::Value> args[] = { binding };
+
+ ignore_result(func->Call(context, v8::Null(isolate), 1, args));
+ }
+
bool IsMainWorld(int world_id) {
return world_id == World::MAIN_WORLD;
}
if (NotifyClient(world_id))
renderer_client_->DidCreateScriptContext(context, render_frame_);
- if (renderer_client_->isolated_world() && IsMainWorld(world_id))
+ if (renderer_client_->isolated_world() && IsMainWorld(world_id)) {
CreateIsolatedWorldContext();
+ SetupMainWorldOverrides(context);
+ }
}
void WillReleaseScriptContext(v8::Local<v8::Context> context,
],
'actions': [
{
- 'action_name': 'atom_browserify',
+ 'action_name': 'atom_browserify_sandbox',
'inputs': [
'<@(browserify_entries)',
],
'-o',
'<@(_outputs)',
],
- }
+ },
+ {
+ 'action_name': 'atom_browserify_isolated_context',
+ 'inputs': [
+ '<@(isolated_context_browserify_entries)',
+ ],
+ 'outputs': [
+ '<(js2c_input_dir)/isolated_bundle.js',
+ ],
+ 'action': [
+ 'npm',
+ 'run',
+ '--silent',
+ 'browserify',
+ '--',
+ 'lib/isolated_renderer/init.js',
+ '-o',
+ '<@(_outputs)',
+ ],
+ },
],
}, # target atom_browserify
{
# List all input files that should trigger a rebuild with js2c
'<@(js2c_sources)',
'<(js2c_input_dir)/preload_bundle.js',
+ '<(js2c_input_dir)/isolated_bundle.js',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
'lib/renderer/init.js',
'lib/renderer/inspector.js',
'lib/renderer/override.js',
+ 'lib/renderer/window-setup.js',
'lib/renderer/web-view/guest-view-internal.js',
'lib/renderer/web-view/web-view.js',
'lib/renderer/web-view/web-view-attributes.js',
'lib/renderer/api/ipc-renderer-setup.js',
'lib/sandboxed_renderer/init.js',
],
+ 'isolated_context_browserify_entries': [
+ 'lib/renderer/window-setup.js',
+ 'lib/isolated_renderer/init.js',
+ ],
'js2c_sources': [
'lib/common/asar.js',
'lib/common/asar_init.js',
const {BrowserWindow, ipcMain, webContents} = require('electron')
const {isSameOrigin} = process.atomBinding('v8_util')
+const parseFeaturesString = require('../common/parse-features-string')
const hasProp = {}.hasOwnProperty
const frameToGuest = {}
isSameOrigin(sender.getURL(), target.getURL())
}
-// Routed window.open messages.
-ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName,
+// Routed window.open messages with raw options
+ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName, features) => {
+ if (url == null || url === '') url = 'about:blank'
+ if (frameName == null) frameName = ''
+ if (features == null) features = ''
+
+ const options = {}
+
+ const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
+ const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload']
+ const disposition = 'new-window'
+
+ // Used to store additional features
+ const additionalFeatures = []
+
+ // Parse the features
+ parseFeaturesString(features, function (key, value) {
+ if (value === undefined) {
+ additionalFeatures.push(key)
+ } else {
+ if (webPreferences.includes(key)) {
+ if (options.webPreferences == null) {
+ options.webPreferences = {}
+ }
+ options.webPreferences[key] = value
+ } else {
+ options[key] = value
+ }
+ }
+ })
+ if (options.left) {
+ if (options.x == null) {
+ options.x = options.left
+ }
+ }
+ if (options.top) {
+ if (options.y == null) {
+ options.y = options.top
+ }
+ }
+ if (options.title == null) {
+ options.title = frameName
+ }
+ if (options.width == null) {
+ options.width = 800
+ }
+ if (options.height == null) {
+ options.height = 600
+ }
+
+ for (const name of ints) {
+ if (options[name] != null) {
+ options[name] = parseInt(options[name], 10)
+ }
+ }
+
+ ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN', event,
+ url, frameName, disposition, options, additionalFeatures)
+})
+
+// Routed window.open messages with fully parsed options
+ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN', function (event, url, frameName,
disposition, options,
additionalFeatures, postData) {
options = mergeBrowserWindowOptions(event.sender, options)
})
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, guestId, message, targetOrigin, sourceOrigin) {
+ if (targetOrigin == null) {
+ targetOrigin = '*'
+ }
+
const guestContents = webContents.fromId(guestId)
if (guestContents == null) return
--- /dev/null
+/* global binding */
+
+'use strict'
+
+const {guestInstanceId, hiddenPage, openerId, send, sendSync} = binding
+const {parse} = JSON
+
+const ipcRenderer = {
+ send (...args) {
+ return send('ipc-message', args)
+ },
+
+ sendSync (...args) {
+ return parse(sendSync('ipc-message-sync', args))
+ },
+
+ // No-ops since events aren't received
+ on () {},
+ once () {}
+}
+
+require('../renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, hiddenPage)
'use strict'
const {ipcRenderer} = require('electron')
-const parseFeaturesString = require('../common/parse-features-string')
-const {defineProperty} = Object
+const {guestInstanceId, openerId} = process
+const hiddenPage = process.argv.includes('--hidden-page')
-// Helper function to resolve relative url.
-const a = window.top.document.createElement('a')
-const resolveURL = function (url) {
- a.href = url
- return a.href
-}
-
-// Window object returned by "window.open".
-const BrowserWindowProxy = (function () {
- BrowserWindowProxy.proxies = {}
-
- BrowserWindowProxy.getOrCreate = function (guestId) {
- let proxy = this.proxies[guestId]
- if (proxy == null) {
- proxy = new BrowserWindowProxy(guestId)
- this.proxies[guestId] = proxy
- }
- return proxy
- }
-
- BrowserWindowProxy.remove = function (guestId) {
- delete this.proxies[guestId]
- }
-
- function BrowserWindowProxy (guestId1) {
- defineProperty(this, 'guestId', {
- configurable: false,
- enumerable: true,
- writeable: false,
- value: guestId1
- })
-
- this.closed = false
- ipcRenderer.once('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + this.guestId, () => {
- BrowserWindowProxy.remove(this.guestId)
- this.closed = true
- })
- }
-
- BrowserWindowProxy.prototype.close = function () {
- ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId)
- }
-
- BrowserWindowProxy.prototype.focus = function () {
- ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus')
- }
-
- BrowserWindowProxy.prototype.blur = function () {
- ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur')
- }
-
- BrowserWindowProxy.prototype.print = function () {
- ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print')
- }
-
- defineProperty(BrowserWindowProxy.prototype, 'location', {
- get: function () {
- return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL')
- },
- set: function (url) {
- url = resolveURL(url)
- return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'loadURL', url)
- }
- })
-
- BrowserWindowProxy.prototype.postMessage = function (message, targetOrigin) {
- if (targetOrigin == null) {
- targetOrigin = '*'
- }
- ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, targetOrigin, window.location.origin)
- }
-
- BrowserWindowProxy.prototype['eval'] = function (...args) {
- ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript', ...args)
- }
-
- return BrowserWindowProxy
-})()
-
-if (process.guestInstanceId == null) {
- // Override default window.close.
- window.close = function () {
- ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE')
- }
-}
-
-// Make the browser window or guest view emit "new-window" event.
-window.open = function (url, frameName, features) {
- let guestId, j, len1, name, options, additionalFeatures
- if (frameName == null) {
- frameName = ''
- }
- if (features == null) {
- features = ''
- }
- options = {}
-
- const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
- const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload']
- const disposition = 'new-window'
-
- // Used to store additional features
- additionalFeatures = []
-
- // Parse the features
- parseFeaturesString(features, function (key, value) {
- if (value === undefined) {
- additionalFeatures.push(key)
- } else {
- if (webPreferences.includes(key)) {
- if (options.webPreferences == null) {
- options.webPreferences = {}
- }
- options.webPreferences[key] = value
- } else {
- options[key] = value
- }
- }
- })
- if (options.left) {
- if (options.x == null) {
- options.x = options.left
- }
- }
- if (options.top) {
- if (options.y == null) {
- options.y = options.top
- }
- }
- if (options.title == null) {
- options.title = frameName
- }
- if (options.width == null) {
- options.width = 800
- }
- if (options.height == null) {
- options.height = 600
- }
-
- // Resolve relative urls.
- if (url == null || url === '') {
- url = 'about:blank'
- } else {
- url = resolveURL(url)
- }
- for (j = 0, len1 = ints.length; j < len1; j++) {
- name = ints[j]
- if (options[name] != null) {
- options[name] = parseInt(options[name], 10)
- }
- }
- guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, disposition, options, additionalFeatures)
- if (guestId) {
- return BrowserWindowProxy.getOrCreate(guestId)
- } else {
- return null
- }
-}
-
-window.alert = function (message, title) {
- ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
-}
-
-window.confirm = function (message, title) {
- return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
-}
-
-// But we do not support prompt().
-window.prompt = function () {
- throw new Error('prompt() is and will not be supported.')
-}
-
-if (process.openerId != null) {
- window.opener = BrowserWindowProxy.getOrCreate(process.openerId)
-}
-
-ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) {
- // Manually dispatch event instead of using postMessage because we also need to
- // set event.source.
- event = document.createEvent('Event')
- event.initEvent('message', false, false)
- event.data = message
- event.origin = sourceOrigin
- event.source = BrowserWindowProxy.getOrCreate(sourceId)
- window.dispatchEvent(event)
-})
-
-// Forward history operations to browser.
-const sendHistoryOperation = function (...args) {
- ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
-}
-
-const getHistoryOperation = function (...args) {
- return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
-}
-
-window.history.back = function () {
- sendHistoryOperation('goBack')
-}
-
-window.history.forward = function () {
- sendHistoryOperation('goForward')
-}
-
-window.history.go = function (offset) {
- sendHistoryOperation('goToOffset', offset)
-}
-
-defineProperty(window.history, 'length', {
- get: function () {
- return getHistoryOperation('length')
- }
-})
-
-// The initial visibilityState.
-let cachedVisibilityState = process.argv.includes('--hidden-page') ? 'hidden' : 'visible'
-
-// Subscribe to visibilityState changes.
-ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, visibilityState) {
- if (cachedVisibilityState !== visibilityState) {
- cachedVisibilityState = visibilityState
- document.dispatchEvent(new Event('visibilitychange'))
- }
-})
-
-// Make document.hidden and document.visibilityState return the correct value.
-defineProperty(document, 'hidden', {
- get: function () {
- return cachedVisibilityState !== 'visible'
- }
-})
-
-defineProperty(document, 'visibilityState', {
- get: function () {
- return cachedVisibilityState
- }
-})
+require('./window-setup')(ipcRenderer, guestInstanceId, openerId, hiddenPage)
--- /dev/null
+// This file should have no requires since it is used by the isolated context
+// preload bundle. Instead arguments should be passed in for everything it
+// needs.
+
+'use strict'
+
+const {defineProperty} = Object
+
+// Helper function to resolve relative url.
+const a = window.top.document.createElement('a')
+const resolveURL = function (url) {
+ a.href = url
+ return a.href
+}
+
+const windowProxies = {}
+
+module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage) => {
+ const getOrCreateProxy = (guestId) => {
+ let proxy = windowProxies[guestId]
+ if (proxy == null) {
+ proxy = new BrowserWindowProxy(guestId)
+ windowProxies[guestId] = proxy
+ }
+ return proxy
+ }
+
+ const removeProxy = (guestId) => {
+ delete windowProxies[guestId]
+ }
+
+ function BrowserWindowProxy (guestId) {
+ this.closed = false
+
+ ipcRenderer.once(`ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_${guestId}`, () => {
+ removeProxy(this.guestId)
+ this.closed = true
+ })
+
+ this.close = () => {
+ ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', guestId)
+ }
+
+ this.focus = () => {
+ ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', guestId, 'focus')
+ }
+
+ this.blur = () => {
+ ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', guestId, 'blur')
+ }
+
+ this.print = () => {
+ ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', guestId, 'print')
+ }
+
+ this.postMessage = (message, targetOrigin) => {
+ ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', guestId, message, targetOrigin, window.location.origin)
+ }
+
+ this.eval = (...args) => {
+ ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', guestId, 'executeJavaScript', ...args)
+ }
+ }
+
+ if (guestInstanceId == null) {
+ // Override default window.close.
+ window.close = function () {
+ ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE')
+ }
+ }
+
+ // Make the browser window or guest view emit "new-window" event.
+ window.open = function (url, frameName, features) {
+ if (url != null && url.length > 0) {
+ url = resolveURL(url)
+ }
+ const guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, features)
+ if (guestId != null) {
+ return getOrCreateProxy(guestId)
+ } else {
+ return null
+ }
+ }
+
+ window.alert = function (message, title) {
+ ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
+ }
+
+ window.confirm = function (message, title) {
+ return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
+ }
+
+ // But we do not support prompt().
+ window.prompt = function () {
+ throw new Error('prompt() is and will not be supported.')
+ }
+
+ if (openerId != null) {
+ window.opener = getOrCreateProxy(openerId)
+ }
+
+ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) {
+ // Manually dispatch event instead of using postMessage because we also need to
+ // set event.source.
+ event = document.createEvent('Event')
+ event.initEvent('message', false, false)
+ event.data = message
+ event.origin = sourceOrigin
+ event.source = BrowserWindowProxy.getOrCreate(sourceId)
+ window.dispatchEvent(event)
+ })
+
+ // Forward history operations to browser.
+ const sendHistoryOperation = function (...args) {
+ ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
+ }
+
+ const getHistoryOperation = function (...args) {
+ return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
+ }
+
+ window.history.back = function () {
+ sendHistoryOperation('goBack')
+ }
+
+ window.history.forward = function () {
+ sendHistoryOperation('goForward')
+ }
+
+ window.history.go = function (offset) {
+ sendHistoryOperation('goToOffset', offset)
+ }
+
+ defineProperty(window.history, 'length', {
+ get: function () {
+ return getHistoryOperation('length')
+ }
+ })
+
+ // The initial visibilityState.
+ let cachedVisibilityState = hiddenPage ? 'hidden' : 'visible'
+
+ // Subscribe to visibilityState changes.
+ ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, visibilityState) {
+ if (cachedVisibilityState !== visibilityState) {
+ cachedVisibilityState = visibilityState
+ document.dispatchEvent(new Event('visibilitychange'))
+ }
+ })
+
+ // Make document.hidden and document.visibilityState return the correct value.
+ defineProperty(document, 'hidden', {
+ get: function () {
+ return cachedVisibilityState !== 'visible'
+ }
+ })
+
+ defineProperty(document, 'visibilityState', {
+ get: function () {
+ return cachedVisibilityState
+ }
+ })
+}
})
describe('contextIsolation option', () => {
+ const expectedContextData = {
+ preloadContext: {
+ preloadProperty: 'number',
+ pageProperty: 'undefined',
+ typeofRequire: 'function',
+ typeofProcess: 'object',
+ typeofArrayPush: 'function',
+ typeofFunctionApply: 'function'
+ },
+ pageContext: {
+ preloadProperty: 'undefined',
+ pageProperty: 'string',
+ typeofRequire: 'undefined',
+ typeofProcess: 'undefined',
+ typeofArrayPush: 'number',
+ typeofFunctionApply: 'boolean',
+ typeofPreloadExecuteJavaScriptProperty: 'number',
+ typeofOpenedWindow: 'object'
+ }
+ }
+
beforeEach(() => {
if (w != null) w.destroy()
w = new BrowserWindow({
it('separates the page context from the Electron/preload context', (done) => {
ipcMain.once('isolated-world', (event, data) => {
- assert.deepEqual(data, {
- preloadContext: {
- preloadProperty: 'number',
- pageProperty: 'undefined',
- typeofRequire: 'function',
- typeofProcess: 'object',
- typeofArrayPush: 'function',
- typeofFunctionApply: 'function'
- },
- pageContext: {
- preloadProperty: 'undefined',
- pageProperty: 'string',
- typeofRequire: 'undefined',
- typeofProcess: 'undefined',
- typeofArrayPush: 'number',
- typeofFunctionApply: 'boolean',
- typeofPreloadExecuteJavaScriptProperty: 'number'
- }
- })
+ assert.deepEqual(data, expectedContextData)
done()
})
-
w.loadURL('file://' + fixtures + '/api/isolated.html')
})
it('recreates the contexts on reload', (done) => {
w.webContents.once('did-finish-load', () => {
ipcMain.once('isolated-world', (event, data) => {
- assert.deepEqual(data, {
- preloadContext: {
- preloadProperty: 'number',
- pageProperty: 'undefined',
- typeofRequire: 'function',
- typeofProcess: 'object',
- typeofArrayPush: 'function',
- typeofFunctionApply: 'function'
- },
- pageContext: {
- preloadProperty: 'undefined',
- pageProperty: 'string',
- typeofRequire: 'undefined',
- typeofProcess: 'undefined',
- typeofArrayPush: 'number',
- typeofFunctionApply: 'boolean',
- typeofPreloadExecuteJavaScriptProperty: 'number'
- }
- })
+ assert.deepEqual(data, expectedContextData)
done()
})
-
w.webContents.reload()
})
w.loadURL('file://' + fixtures + '/api/isolated.html')
assert.equal(window.webContents.getWebPreferences().contextIsolation, true)
done()
})
-
w.loadURL('file://' + fixtures + '/pages/window-open.html')
})
})
window.hello = 'world'
Array.prototype.push = 3
Function.prototype.apply = true
+
+ const opened = window.open()
+ opened.close()
+
window.postMessage({
preloadProperty: typeof window.foo,
pageProperty: typeof window.hello,
typeofProcess: typeof process,
typeofArrayPush: typeof Array.prototype.push,
typeofFunctionApply: typeof Function.prototype.apply,
- typeofPreloadExecuteJavaScriptProperty: typeof window.preloadExecuteJavaScriptProperty
+ typeofPreloadExecuteJavaScriptProperty: typeof window.preloadExecuteJavaScriptProperty,
+ typeofOpenedWindow: typeof opened
}, '*')
</script>
</head>
typeofProcess: 'undefined',
typeofArrayPush: 'number',
typeofFunctionApply: 'boolean',
- typeofPreloadExecuteJavaScriptProperty: 'number'
+ typeofPreloadExecuteJavaScriptProperty: 'number',
+ typeofOpenedWindow: 'object'
}
})
done()
})
webview.setAttribute('preload', path.join(fixtures, 'api', 'isolated-preload.js'))
+ webview.setAttribute('allowpopups', 'yes')
webview.setAttribute('webpreferences', 'contextIsolation=yes')
webview.src = 'file://' + fixtures + '/api/isolated.html'
document.body.appendChild(webview)