fix: register webview in main world when using contextIsolation (#16067)

This commit is contained in:
Cheng Zhao 2018-12-14 15:38:35 +09:00 committed by GitHub
parent dbda1a1b05
commit 8584c2f14b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 56 additions and 20 deletions

View file

@ -75,6 +75,9 @@ npm_action("atom_browserify_sandbox") {
] ]
inputs = [ inputs = [
# FIXME(zcbenz): The dependencies of these files are not listed here, so
# the generated file will be out-dated when dependencies are modified.
# Use a script to generate all dependencies and put them here.
"lib/sandboxed_renderer/init.js", "lib/sandboxed_renderer/init.js",
"lib/sandboxed_renderer/api/exports/electron.js", "lib/sandboxed_renderer/api/exports/electron.js",
"lib/sandboxed_renderer/api/exports/fs.js", "lib/sandboxed_renderer/api/exports/fs.js",

View file

@ -189,8 +189,10 @@ void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) {
} }
v8::Local<v8::Value> WebFrame::RegisterEmbedderCustomElement( v8::Local<v8::Value> WebFrame::RegisterEmbedderCustomElement(
v8::Local<v8::Object> context,
const base::string16& name, const base::string16& name,
v8::Local<v8::Object> options) { v8::Local<v8::Object> options) {
v8::Context::Scope context_scope(context->CreationContext());
return web_frame_->GetDocument().RegisterEmbedderCustomElement( return web_frame_->GetDocument().RegisterEmbedderCustomElement(
blink::WebString::FromUTF16(name), options); blink::WebString::FromUTF16(name), options);
} }

View file

@ -51,6 +51,7 @@ class WebFrame : public mate::Wrappable<WebFrame> {
void SetLayoutZoomLevelLimits(double min_level, double max_level); void SetLayoutZoomLevelLimits(double min_level, double max_level);
v8::Local<v8::Value> RegisterEmbedderCustomElement( v8::Local<v8::Value> RegisterEmbedderCustomElement(
v8::Local<v8::Object> context,
const base::string16& name, const base::string16& name,
v8::Local<v8::Object> options); v8::Local<v8::Object> options);
int GetWebFrameId(v8::Local<v8::Value> content_window); int GetWebFrameId(v8::Local<v8::Value> content_window);

View file

@ -2,9 +2,16 @@
/* global nodeProcess, isolatedWorld */ /* global nodeProcess, isolatedWorld */
window.isolatedWorld = isolatedWorld
// Note: Don't use "process", as it will be replaced by browserify's one. // Note: Don't use "process", as it will be replaced by browserify's one.
const v8Util = nodeProcess.atomBinding('v8_util') const v8Util = nodeProcess.atomBinding('v8_util')
const setupWebView = v8Util.getHiddenValue(isolatedWorld, 'setup-webview')
if (setupWebView) {
setupWebView(window)
}
const isolatedWorldArgs = v8Util.getHiddenValue(isolatedWorld, 'isolated-world-args') const isolatedWorldArgs = v8Util.getHiddenValue(isolatedWorld, 'isolated-world-args')
const { ipcRenderer, guestInstanceId, hiddenPage, openerId, usesNativeWindowOpen } = isolatedWorldArgs const { ipcRenderer, guestInstanceId, hiddenPage, openerId, usesNativeWindowOpen } = isolatedWorldArgs

View file

@ -98,8 +98,12 @@ if (window.location.protocol === 'chrome-devtools:') {
// Load webview tag implementation. // Load webview tag implementation.
if (webviewTag && guestInstanceId == null) { if (webviewTag && guestInstanceId == null) {
require('@electron/internal/renderer/web-view/web-view') const { setupWebView } = require('@electron/internal/renderer/web-view/web-view')
require('@electron/internal/renderer/web-view/web-view-attributes') if (contextIsolation) {
v8Util.setHiddenValue(window, 'setup-webview', setupWebView)
} else {
setupWebView(window)
}
} }
} }

View file

@ -1,7 +1,7 @@
'use strict' 'use strict'
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal') const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
const WebViewImpl = require('@electron/internal/renderer/web-view/web-view') const { WebViewImpl } = require('@electron/internal/renderer/web-view/web-view')
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants') const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
const errorUtils = require('@electron/internal/common/error-utils') const errorUtils = require('@electron/internal/common/error-utils')
@ -86,13 +86,13 @@ class PartitionAttribute extends WebViewAttribute {
// The partition cannot change if the webview has already navigated. // The partition cannot change if the webview has already navigated.
if (!this.webViewImpl.beforeFirstNavigation) { if (!this.webViewImpl.beforeFirstNavigation) {
window.console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED) console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED)
this.setValueIgnoreMutation(oldValue) this.setValueIgnoreMutation(oldValue)
return return
} }
if (newValue === 'persist:') { if (newValue === 'persist:') {
this.validPartitionId = false this.validPartitionId = false
window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE) console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE)
} }
} }
} }

View file

@ -198,8 +198,8 @@ class WebViewImpl {
} }
// Registers <webview> custom element. // Registers <webview> custom element.
const registerWebViewElement = function () { const registerWebViewElement = (window) => {
const proto = Object.create(HTMLObjectElement.prototype) const proto = Object.create(window.HTMLObjectElement.prototype)
proto.createdCallback = function () { proto.createdCallback = function () {
return new WebViewImpl(this) return new WebViewImpl(this)
} }
@ -288,7 +288,7 @@ const registerWebViewElement = function () {
this.contentWindow.focus() this.contentWindow.focus()
} }
window.WebView = webFrame.registerEmbedderCustomElement('webview', { window.WebView = webFrame.registerEmbedderCustomElement(window, 'webview', {
prototype: proto prototype: proto
}) })
@ -300,16 +300,17 @@ const registerWebViewElement = function () {
delete proto.attributeChangedCallback delete proto.attributeChangedCallback
} }
const useCapture = true const setupWebView = (window) => {
require('@electron/internal/renderer/web-view/web-view-attributes')
const listener = function (event) { const useCapture = true
if (document.readyState === 'loading') { window.addEventListener('readystatechange', function listener (event) {
return if (document.readyState === 'loading') {
} return
registerWebViewElement() }
window.removeEventListener(event.type, listener, useCapture) registerWebViewElement(window)
window.removeEventListener(event.type, listener, useCapture)
}, useCapture)
} }
window.addEventListener('readystatechange', listener, true) module.exports = { setupWebView, WebViewImpl }
module.exports = WebViewImpl

View file

@ -122,8 +122,7 @@ if (binding.guestInstanceId) {
if (!process.guestInstanceId && preloadProcess.argv.includes('--webview-tag=true')) { if (!process.guestInstanceId && preloadProcess.argv.includes('--webview-tag=true')) {
// don't allow recursive `<webview>` // don't allow recursive `<webview>`
require('@electron/internal/renderer/web-view/web-view') require('@electron/internal/renderer/web-view/web-view').setupWebView(window)
require('@electron/internal/renderer/web-view/web-view-attributes')
} }
// Wrap the script into a function executed in global scope. It won't have // Wrap the script into a function executed in global scope. It won't have

2
spec/fixtures/module/isolated-ping.js vendored Normal file
View file

@ -0,0 +1,2 @@
const { ipcRenderer } = require('electron')
ipcRenderer.send('pong')

View file

@ -0,0 +1,5 @@
<html>
<body>
<webview preload="../module/isolated-ping.js" src="about:blank"/>
</body>
</html>

View file

@ -70,6 +70,18 @@ describe('<webview> tag', function () {
await emittedOnce(ipcMain, 'pong') await emittedOnce(ipcMain, 'pong')
}) })
it('works with contextIsolation', async () => {
const w = await openTheWindow({
show: false,
webPreferences: {
webviewTag: true,
contextIsolation: true
}
})
w.loadFile(path.join(fixtures, 'pages', 'webview-isolated.html'))
await emittedOnce(ipcMain, 'pong')
})
it('is disabled when nodeIntegration is disabled', async () => { it('is disabled when nodeIntegration is disabled', async () => {
const w = await openTheWindow({ const w = await openTheWindow({
show: false, show: false,