Skip to content

Commit

Permalink
fix: <webview> not working with contextIsolation + sandbox
Browse files Browse the repository at this point in the history
  • Loading branch information
miniak committed Jan 20, 2019
1 parent 4038053 commit 67044a4
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 49 deletions.
24 changes: 24 additions & 0 deletions atom/renderer/atom_sandboxed_renderer_client.cc
Expand Up @@ -202,6 +202,30 @@ void AtomSandboxedRendererClient::DidCreateScriptContext(
&preload_bundle_params, &preload_bundle_args, nullptr);
}

void AtomSandboxedRendererClient::SetupMainWorldOverrides(
v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) {
// Setup window overrides in the main world context
// Wrap the bundle into a function that receives the isolatedWorld as
// an argument.
auto* isolate = context->GetIsolate();

mate::Dictionary process = mate::Dictionary::CreateEmpty(isolate);
process.SetMethod("binding", GetBinding);

std::vector<v8::Local<v8::String>> isolated_bundle_params = {
node::FIXED_ONE_BYTE_STRING(isolate, "nodeProcess"),
node::FIXED_ONE_BYTE_STRING(isolate, "isolatedWorld")};

std::vector<v8::Local<v8::Value>> isolated_bundle_args = {
process.GetHandle(),
GetContext(render_frame->GetWebFrame(), isolate)->Global()};

node::per_process::native_module_loader.CompileAndCall(
context, "electron/js2c/isolated_bundle", &isolated_bundle_params,
&isolated_bundle_args, nullptr);
}

void AtomSandboxedRendererClient::WillReleaseScriptContext(
v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) {
Expand Down
2 changes: 1 addition & 1 deletion atom/renderer/atom_sandboxed_renderer_client.h
Expand Up @@ -29,7 +29,7 @@ class AtomSandboxedRendererClient : public RendererClientBase {
void WillReleaseScriptContext(v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) override;
void SetupMainWorldOverrides(v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) override {}
content::RenderFrame* render_frame) override;
// content::ContentRendererClient:
void RenderFrameCreated(content::RenderFrame*) override;
void RenderViewCreated(content::RenderView*) override;
Expand Down
14 changes: 10 additions & 4 deletions lib/isolated_renderer/init.js
Expand Up @@ -3,15 +3,21 @@
/* global nodeProcess, isolatedWorld */

// Note: Don't use "process", as it will be replaced by browserify's one.
const v8Util = nodeProcess.atomBinding('v8_util')
process.atomBinding = require('@electron/internal/common/atom-binding-setup')(nodeProcess.binding, 'renderer')

const isolatedWorldArgs = v8Util.getHiddenValue(isolatedWorld, 'isolated-world-args')
const { webViewImpl, ipcRenderer, guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen } = isolatedWorldArgs
const v8Util = process.atomBinding('v8_util')

const webViewImpl = v8Util.getHiddenValue(isolatedWorld, 'web-view-impl')

if (webViewImpl) {
// Must setup the WebView element in main world.
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
setupWebView(v8Util, webViewImpl)
}

require('@electron/internal/renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen)
const isolatedWorldArgs = v8Util.getHiddenValue(isolatedWorld, 'isolated-world-args')

if (isolatedWorldArgs) {
const { ipcRenderer, guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen } = isolatedWorldArgs
require('@electron/internal/renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen)
}
48 changes: 19 additions & 29 deletions lib/renderer/init.js
Expand Up @@ -58,33 +58,29 @@ if (preloadScript) {
preloadScripts.push(preloadScript)
}

if (window.location.protocol === 'chrome-devtools:') {
// Override some inspector APIs.
require('@electron/internal/renderer/inspector')
} else if (window.location.protocol === 'chrome-extension:') {
// Add implementations of chrome API.
require('@electron/internal/renderer/chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
} else if (window.location.protocol === 'chrome:') {
// Disable node integration for chrome UI scheme.
} else {
// Override default web functions.
require('@electron/internal/renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen)

// Inject content scripts.
require('@electron/internal/renderer/content-scripts-injector')
switch (window.location.protocol) {
case 'chrome-devtools:': {
// Override some inspector APIs.
require('@electron/internal/renderer/inspector')
break
}
case 'chrome-extension:': {
// Inject the chrome.* APIs that chrome extensions require
require('@electron/internal/renderer/chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
break
}
default: {
// Override default web functions.
require('@electron/internal/renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen)

// Load webview tag implementation.
if (webviewTag && guestInstanceId == null) {
const webViewImpl = require('@electron/internal/renderer/web-view/web-view-impl')
if (contextIsolation) {
Object.assign(isolatedWorldArgs, { webViewImpl })
} else {
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
setupWebView(v8Util, webViewImpl)
}
// Inject content scripts.
require('@electron/internal/renderer/content-scripts-injector')
}
}

// Load webview tag implementation.
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, webviewTag, guestInstanceId)

// Pass the arguments to isolatedWorld.
if (contextIsolation) {
v8Util.setHiddenValue(global, 'isolated-world-args', isolatedWorldArgs)
Expand Down Expand Up @@ -163,9 +159,3 @@ for (const preloadScript of preloadScripts) {

// Warn about security issues
require('@electron/internal/renderer/security-warnings')(nodeIntegration)

if (guestInstanceId) {
// Report focus/blur events of webview to browser.
const { handleFocusBlur } = require('@electron/internal/renderer/web-view/web-view-init')
handleFocusBlur(guestInstanceId)
}
23 changes: 21 additions & 2 deletions lib/renderer/web-view/web-view-init.js
@@ -1,8 +1,9 @@
'use strict'

exports.handleFocusBlur = function (guestInstanceId) {
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
const v8Util = process.atomBinding('v8_util')

function handleFocusBlur (guestInstanceId) {
// Note that while Chromium content APIs have observer for focus/blur, they
// unfortunately do not work for webview.

Expand All @@ -14,3 +15,21 @@ exports.handleFocusBlur = function (guestInstanceId) {
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', false, guestInstanceId)
})
}

module.exports = function (contextIsolation, webviewTag, guestInstanceId) {
// Load webview tag implementation.
if (webviewTag && guestInstanceId == null) {
const webViewImpl = require('@electron/internal/renderer/web-view/web-view-impl')
if (contextIsolation) {
v8Util.setHiddenValue(window, 'web-view-impl', webViewImpl)
} else {
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
setupWebView(v8Util, webViewImpl)
}
}

if (guestInstanceId) {
// Report focus/blur events of webview to browser.
handleFocusBlur(guestInstanceId)
}
}
19 changes: 6 additions & 13 deletions lib/sandboxed_renderer/init.js
Expand Up @@ -105,8 +105,12 @@ function preloadRequire (module) {
throw new Error('module not found')
}

// Process command line arguments.
const { hasSwitch } = process.atomBinding('command_line')

const isBackgroundPage = hasSwitch('background-page')
const contextIsolation = hasSwitch('context-isolation')

switch (window.location.protocol) {
case 'chrome-devtools:': {
// Override some inspector APIs.
Expand All @@ -115,20 +119,15 @@ switch (window.location.protocol) {
}
case 'chrome-extension:': {
// Inject the chrome.* APIs that chrome extensions require
const isBackgroundPage = hasSwitch('background-page')
require('@electron/internal/renderer/chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
break
}
}

const guestInstanceId = binding.guestInstanceId && parseInt(binding.guestInstanceId)

// Don't allow recursive `<webview>`.
if (!guestInstanceId && isWebViewTagEnabled) {
const webViewImpl = require('@electron/internal/renderer/web-view/web-view-impl')
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
setupWebView(v8Util, webViewImpl)
}
// Load webview tag implementation.
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, isWebViewTagEnabled, guestInstanceId)

const errorUtils = require('@electron/internal/common/error-utils')

Expand Down Expand Up @@ -178,9 +177,3 @@ try {

// Warn about security issues
require('@electron/internal/renderer/security-warnings')()

if (guestInstanceId) {
// Report focus/blur events of webview to browser.
const { handleFocusBlur } = require('@electron/internal/renderer/web-view/web-view-init')
handleFocusBlur(guestInstanceId)
}
27 changes: 27 additions & 0 deletions spec/webview-spec.js
Expand Up @@ -76,6 +76,19 @@ describe('<webview> tag', function () {
await emittedOnce(ipcMain, 'pong')
})

it('works with sandbox', async () => {
const w = await openTheWindow({
show: false,
webPreferences: {
webviewTag: true,
nodeIntegration: true,
sandbox: true
}
})
w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html'))
await emittedOnce(ipcMain, 'pong')
})

it('works with contextIsolation', async () => {
const w = await openTheWindow({
show: false,
Expand All @@ -89,6 +102,20 @@ describe('<webview> tag', function () {
await emittedOnce(ipcMain, 'pong')
})

it('works with contextIsolation + sandbox', async () => {
const w = await openTheWindow({
show: false,
webPreferences: {
webviewTag: true,
nodeIntegration: true,
contextIsolation: true,
sandbox: true
}
})
w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html'))
await emittedOnce(ipcMain, 'pong')
})

it('is disabled by default', async () => {
const w = await openTheWindow({
show: false,
Expand Down

0 comments on commit 67044a4

Please sign in to comment.