diff --git a/BUILD.gn b/BUILD.gn index 619bf42dcbeae..2c54194e30dfb 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -67,6 +67,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", diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index 0e96bc135053a..393825e040c99 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -188,8 +188,10 @@ void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) { } v8::Local WebFrame::RegisterEmbedderCustomElement( + v8::Local context, const base::string16& name, v8::Local options) { + v8::Context::Scope context_scope(context->CreationContext()); return web_frame_->GetDocument().RegisterEmbedderCustomElement( blink::WebString::FromUTF16(name), options); } diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index 9fbdb165e6972..52ed3c45ebd00 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -51,6 +51,7 @@ class WebFrame : public mate::Wrappable { void SetLayoutZoomLevelLimits(double min_level, double max_level); v8::Local RegisterEmbedderCustomElement( + v8::Local context, const base::string16& name, v8::Local options); int GetWebFrameId(v8::Local content_window); diff --git a/lib/isolated_renderer/init.js b/lib/isolated_renderer/init.js index ed490b9dc63cc..c419c0230bb14 100644 --- a/lib/isolated_renderer/init.js +++ b/lib/isolated_renderer/init.js @@ -5,6 +5,11 @@ // 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 diff --git a/lib/renderer/init.js b/lib/renderer/init.js index c65c6066b7cdd..cf1af5bbf33ad 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -84,8 +84,12 @@ if (window.location.protocol === 'chrome-devtools:') { // Load webview tag implementation. if (webviewTag && process.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 (process.argv.includes('--context-isolation')) { + v8Util.setHiddenValue(window, 'setup-webview', setupWebView) + } else { + setupWebView(window) + } } } diff --git a/lib/renderer/web-view/web-view-attributes.js b/lib/renderer/web-view/web-view-attributes.js index e9a5d9b0952ed..39d986e40073e 100644 --- a/lib/renderer/web-view/web-view-attributes.js +++ b/lib/renderer/web-view/web-view-attributes.js @@ -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) } } } diff --git a/lib/renderer/web-view/web-view.js b/lib/renderer/web-view/web-view.js index cf07522fcfdb7..5cd3df52c924e 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -197,8 +197,8 @@ class WebViewImpl { } // Registers 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) } @@ -352,7 +352,7 @@ const registerWebViewElement = function () { this.contentWindow.focus() } - window.WebView = webFrame.registerEmbedderCustomElement('webview', { + window.WebView = webFrame.registerEmbedderCustomElement(window, 'webview', { prototype: proto }) @@ -364,16 +364,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 } diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index 0512cf5359bf2..1acd43b3796d7 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -123,8 +123,7 @@ if (binding.guestInstanceId) { if (!process.guestInstanceId && preloadProcess.argv.includes('--webview-tag=true')) { // don't allow recursive `` - 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 diff --git a/spec/fixtures/module/isolated-ping.js b/spec/fixtures/module/isolated-ping.js new file mode 100644 index 0000000000000..7088d346c8ef1 --- /dev/null +++ b/spec/fixtures/module/isolated-ping.js @@ -0,0 +1,2 @@ +const { ipcRenderer } = require('electron') +ipcRenderer.send('pong') diff --git a/spec/fixtures/pages/webview-isolated.html b/spec/fixtures/pages/webview-isolated.html new file mode 100644 index 0000000000000..824118b572cf4 --- /dev/null +++ b/spec/fixtures/pages/webview-isolated.html @@ -0,0 +1,5 @@ + + + + + diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 2271c2cc58475..6357d4f97fb7c 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -70,6 +70,18 @@ describe(' 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,