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 = [
|
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",
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
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')
|
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,
|
||||||
|
|
Loading…
Reference in a new issue