fix: register webview in main world when using contextIsolation (#16067)
This commit is contained in:
parent
dbda1a1b05
commit
8584c2f14b
11 changed files with 56 additions and 20 deletions
3
BUILD.gn
3
BUILD.gn
|
@ -75,6 +75,9 @@ npm_action("atom_browserify_sandbox") {
|
|||
]
|
||||
|
||||
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/api/exports/electron.js",
|
||||
"lib/sandboxed_renderer/api/exports/fs.js",
|
||||
|
|
|
@ -189,8 +189,10 @@ void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) {
|
|||
}
|
||||
|
||||
v8::Local<v8::Value> WebFrame::RegisterEmbedderCustomElement(
|
||||
v8::Local<v8::Object> context,
|
||||
const base::string16& name,
|
||||
v8::Local<v8::Object> options) {
|
||||
v8::Context::Scope context_scope(context->CreationContext());
|
||||
return web_frame_->GetDocument().RegisterEmbedderCustomElement(
|
||||
blink::WebString::FromUTF16(name), options);
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ class WebFrame : public mate::Wrappable<WebFrame> {
|
|||
void SetLayoutZoomLevelLimits(double min_level, double max_level);
|
||||
|
||||
v8::Local<v8::Value> RegisterEmbedderCustomElement(
|
||||
v8::Local<v8::Object> context,
|
||||
const base::string16& name,
|
||||
v8::Local<v8::Object> options);
|
||||
int GetWebFrameId(v8::Local<v8::Value> content_window);
|
||||
|
|
|
@ -2,9 +2,16 @@
|
|||
|
||||
/* global nodeProcess, isolatedWorld */
|
||||
|
||||
window.isolatedWorld = isolatedWorld
|
||||
|
||||
// Note: Don't use "process", as it will be replaced by browserify's one.
|
||||
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 { ipcRenderer, guestInstanceId, hiddenPage, openerId, usesNativeWindowOpen } = isolatedWorldArgs
|
||||
|
||||
|
|
|
@ -98,8 +98,12 @@ if (window.location.protocol === 'chrome-devtools:') {
|
|||
|
||||
// Load webview tag implementation.
|
||||
if (webviewTag && guestInstanceId == null) {
|
||||
require('@electron/internal/renderer/web-view/web-view')
|
||||
require('@electron/internal/renderer/web-view/web-view-attributes')
|
||||
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view')
|
||||
if (contextIsolation) {
|
||||
v8Util.setHiddenValue(window, 'setup-webview', setupWebView)
|
||||
} else {
|
||||
setupWebView(window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
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 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.
|
||||
if (!this.webViewImpl.beforeFirstNavigation) {
|
||||
window.console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED)
|
||||
console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED)
|
||||
this.setValueIgnoreMutation(oldValue)
|
||||
return
|
||||
}
|
||||
if (newValue === 'persist:') {
|
||||
this.validPartitionId = false
|
||||
window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE)
|
||||
console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,8 +198,8 @@ class WebViewImpl {
|
|||
}
|
||||
|
||||
// Registers <webview> custom element.
|
||||
const registerWebViewElement = function () {
|
||||
const proto = Object.create(HTMLObjectElement.prototype)
|
||||
const registerWebViewElement = (window) => {
|
||||
const proto = Object.create(window.HTMLObjectElement.prototype)
|
||||
proto.createdCallback = function () {
|
||||
return new WebViewImpl(this)
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ const registerWebViewElement = function () {
|
|||
this.contentWindow.focus()
|
||||
}
|
||||
|
||||
window.WebView = webFrame.registerEmbedderCustomElement('webview', {
|
||||
window.WebView = webFrame.registerEmbedderCustomElement(window, 'webview', {
|
||||
prototype: proto
|
||||
})
|
||||
|
||||
|
@ -300,16 +300,17 @@ const registerWebViewElement = function () {
|
|||
delete proto.attributeChangedCallback
|
||||
}
|
||||
|
||||
const useCapture = true
|
||||
const setupWebView = (window) => {
|
||||
require('@electron/internal/renderer/web-view/web-view-attributes')
|
||||
|
||||
const listener = function (event) {
|
||||
if (document.readyState === 'loading') {
|
||||
return
|
||||
}
|
||||
registerWebViewElement()
|
||||
window.removeEventListener(event.type, listener, useCapture)
|
||||
const useCapture = true
|
||||
window.addEventListener('readystatechange', function listener (event) {
|
||||
if (document.readyState === 'loading') {
|
||||
return
|
||||
}
|
||||
registerWebViewElement(window)
|
||||
window.removeEventListener(event.type, listener, useCapture)
|
||||
}, useCapture)
|
||||
}
|
||||
|
||||
window.addEventListener('readystatechange', listener, true)
|
||||
|
||||
module.exports = WebViewImpl
|
||||
module.exports = { setupWebView, WebViewImpl }
|
||||
|
|
|
@ -122,8 +122,7 @@ if (binding.guestInstanceId) {
|
|||
|
||||
if (!process.guestInstanceId && preloadProcess.argv.includes('--webview-tag=true')) {
|
||||
// don't allow recursive `<webview>`
|
||||
require('@electron/internal/renderer/web-view/web-view')
|
||||
require('@electron/internal/renderer/web-view/web-view-attributes')
|
||||
require('@electron/internal/renderer/web-view/web-view').setupWebView(window)
|
||||
}
|
||||
|
||||
// Wrap the script into a function executed in global scope. It won't have
|
||||
|
|
2
spec/fixtures/module/isolated-ping.js
vendored
Normal file
2
spec/fixtures/module/isolated-ping.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
const { ipcRenderer } = require('electron')
|
||||
ipcRenderer.send('pong')
|
5
spec/fixtures/pages/webview-isolated.html
vendored
Normal file
5
spec/fixtures/pages/webview-isolated.html
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<webview preload="../module/isolated-ping.js" src="about:blank"/>
|
||||
</body>
|
||||
</html>
|
|
@ -70,6 +70,18 @@ describe('<webview> tag', function () {
|
|||
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 () => {
|
||||
const w = await openTheWindow({
|
||||
show: false,
|
||||
|
|
Loading…
Reference in a new issue