diff --git a/BUILD.gn b/BUILD.gn index a425992a5fa68..178f04f4b7401 100644 --- a/BUILD.gn +++ b/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", diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index faacdb0084d80..4ec14086be652 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -189,8 +189,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 9b368670dbf65..1c5b76ae569c3 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..26d10c8a6128c 100644 --- a/lib/isolated_renderer/init.js +++ b/lib/isolated_renderer/init.js @@ -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 diff --git a/lib/renderer/init.js b/lib/renderer/init.js index a9cd444f19c15..af114785d13b4 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -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) + } } } 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 4d1ca5455ae9d..eecf4a5c589cb 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -198,8 +198,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) } @@ -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 } diff --git a/lib/sandboxed_renderer/init.js b/lib/sandboxed_renderer/init.js index 1d21e335321f3..3910b28594112 100644 --- a/lib/sandboxed_renderer/init.js +++ b/lib/sandboxed_renderer/init.js @@ -122,8 +122,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,