diff --git a/docs/README.md b/docs/README.md index 555e5f3637b0d..261c67c5941ce 100644 --- a/docs/README.md +++ b/docs/README.md @@ -106,7 +106,6 @@ These individual tutorials expand on topics discussed in the guide above. * [`File` Object](api/file-object.md) * [`` Tag](api/webview-tag.md) * [`window.open` Function](api/window-open.md) -* [`BrowserWindowProxy` Object](api/browser-window-proxy.md) ### Modules for the Main Process: diff --git a/docs/api/browser-window-proxy.md b/docs/api/browser-window-proxy.md deleted file mode 100644 index 23126d857f86d..0000000000000 --- a/docs/api/browser-window-proxy.md +++ /dev/null @@ -1,54 +0,0 @@ -## Class: BrowserWindowProxy - -> Manipulate the child browser window - -Process: [Renderer](../glossary.md#renderer-process)
-_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ - -The `BrowserWindowProxy` object is returned from `window.open` and provides -limited functionality with the child window. - -### Instance Methods - -The `BrowserWindowProxy` object has the following instance methods: - -#### `win.blur()` - -Removes focus from the child window. - -#### `win.close()` - -Forcefully closes the child window without calling its unload event. - -#### `win.eval(code)` - -* `code` string - -Evaluates the code in the child window. - -#### `win.focus()` - -Focuses the child window (brings the window to front). - -#### `win.print()` - -Invokes the print dialog on the child window. - -#### `win.postMessage(message, targetOrigin)` - -* `message` any -* `targetOrigin` string - -Sends a message to the child window with the specified origin or `*` for no -origin preference. - -In addition to these methods, the child window implements `window.opener` object -with no properties and a single method. - -### Instance Properties - -The `BrowserWindowProxy` object has the following instance properties: - -#### `win.closed` - -A `boolean` that is set to true after the child window gets closed. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index c3c79ea39bf66..20b41db94700e 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -341,9 +341,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. [Chrome Content Scripts][chrome-content-scripts]. You can access this context in the dev tools by selecting the 'Electron Isolated Context' entry in the combo box at the top of the Console tab. - * `nativeWindowOpen` boolean (optional) - Whether to use native - `window.open()`. Defaults to `true`. Child windows will always have node - integration disabled unless `nodeIntegrationInSubFrames` is true. * `webviewTag` boolean (optional) - Whether to enable the [`` tag](webview-tag.md). Defaults to `false`. **Note:** The `preload` script configured for the `` will have node integration diff --git a/docs/api/structures/post-body.md b/docs/api/structures/post-body.md index 1affb74b1095c..0488988ce456e 100644 --- a/docs/api/structures/post-body.md +++ b/docs/api/structures/post-body.md @@ -7,17 +7,3 @@ the `enctype` attribute of the submitted HTML form. * `boundary` string (optional) - The boundary used to separate multiple parts of the message. Only valid when `contentType` is `multipart/form-data`. - -Note that keys starting with `--` are not currently supported. For example, this will errantly submit as `multipart/form-data` when `nativeWindowOpen` is set to `false` in webPreferences: - -```html -
- - -
-``` diff --git a/docs/api/window-open.md b/docs/api/window-open.md index de931c078c962..a2cb76a2a569e 100644 --- a/docs/api/window-open.md +++ b/docs/api/window-open.md @@ -12,10 +12,6 @@ useful for app sub-windows that act as preference panels, or similar, as the parent can render to the sub-window directly, as if it were a `div` in the parent. This is the same behavior as in the browser. -When `nativeWindowOpen` is set to false, `window.open` instead results in the -creation of a [`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper -around `BrowserWindow`. - Electron pairs this native Chrome `Window` with a BrowserWindow under the hood. You can take advantage of all the customization available when creating a BrowserWindow in the main process by using `webContents.setWindowOpenHandler()` @@ -34,7 +30,7 @@ because it is invoked in the main process. * `frameName` string (optional) * `features` string (optional) -Returns [`BrowserWindowProxy`](browser-window-proxy.md) | [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) +Returns [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) | null `features` is a comma-separated key-value list, following the standard format of the browser. Electron will parse `BrowserWindowConstructorOptions` out of this @@ -108,33 +104,3 @@ mainWindow.webContents.setWindowOpenHandler(({ url }) => { const childWindow = window.open('', 'modal') childWindow.document.write('

Hello

') ``` - -### `BrowserWindowProxy` example - -```javascript - -// main.js -const mainWindow = new BrowserWindow({ - webPreferences: { nativeWindowOpen: false } -}) - -mainWindow.webContents.setWindowOpenHandler(({ url }) => { - if (url.startsWith('https://github.com/')) { - return { action: 'allow' } - } - return { action: 'deny' } -}) - -mainWindow.webContents.on('did-create-window', (childWindow) => { - // For example... - childWindow.webContents.on('will-navigate', (e) => { - e.preventDefault() - }) -}) -``` - -```javascript -// renderer.js -const windowProxy = window.open('https://github.com/', null, 'minimizable=false') -windowProxy.postMessage('hi', '*') -``` diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index a5e841c928abe..1a5c9477d6d9a 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -12,6 +12,18 @@ This document uses the following convention to categorize breaking changes: * **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release. * **Removed:** An API or feature was removed, and is no longer supported by Electron. +## Planned Breaking API Changes (18.0) + +### Removed: `nativeWindowOpen` + +Prior to Electron 15, `window.open` was by default shimmed to use +`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work +to open synchronously scriptable child windows, among other incompatibilities. +Since Electron 15, `nativeWindowOpen` has been enabled by default. + +See the documentation for [window.open in Electron](api/window-open.md) +for more details. + ## Planned Breaking API Changes (17.0) ### Removed: `desktopCapturer.getSources` in the renderer diff --git a/filenames.auto.gni b/filenames.auto.gni index 8738398d97037..b52d77f96ad89 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -5,7 +5,6 @@ auto_filenames = { "docs/api/app.md", "docs/api/auto-updater.md", "docs/api/browser-view.md", - "docs/api/browser-window-proxy.md", "docs/api/browser-window.md", "docs/api/client-request.md", "docs/api/clipboard.md", @@ -226,7 +225,6 @@ auto_filenames = { "lib/browser/devtools.ts", "lib/browser/guest-view-manager.ts", "lib/browser/guest-window-manager.ts", - "lib/browser/guest-window-proxy.ts", "lib/browser/init.ts", "lib/browser/ipc-main-impl.ts", "lib/browser/ipc-main-internal-utils.ts", diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index 6c82d9c431efd..5705cec695a07 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -692,8 +692,8 @@ WebContents.prototype._init = function () { // TODO(zcbenz): The features string is parsed twice: here where it is // passed to C++, and in |makeBrowserWindowOptions| later where it is // not actually used since the WebContents is created here. - // We should be able to remove the latter once the |nativeWindowOpen| - // option is removed. + // We should be able to remove the latter once the |new-window| event + // is removed. const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures); // Parameters should keep same with |makeBrowserWindowOptions|. const webPreferences = makeWebPreferences({ @@ -705,8 +705,7 @@ WebContents.prototype._init = function () { } }); - // Create a new browser window for the native implementation of - // "window.open", used in sandbox and nativeWindowOpen mode. + // Create a new browser window for "window.open" this.on('-add-new-contents' as any, (event: ElectronInternal.Event, webContents: Electron.WebContents, disposition: string, _userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string, referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => { diff --git a/lib/browser/guest-view-manager.ts b/lib/browser/guest-view-manager.ts index ca4f7aba0d5f8..fd6a0ac0d3704 100644 --- a/lib/browser/guest-view-manager.ts +++ b/lib/browser/guest-view-manager.ts @@ -56,7 +56,6 @@ function makeWebPreferences (embedder: Electron.WebContents, params: Record frameNamesToWindow.delete(name); const getGuestWindowByFrameName = (name: string) => frameNamesToWindow.get(name); /** - * `openGuestWindow` is called for both implementations of window.open - * (BrowserWindowProxy and nativeWindowOpen) to create and setup event handling - * for the new window. + * `openGuestWindow` is called to create and setup event handling for the new + * window. * * Until its removal in 12.0.0, the `new-window` event is fired, allowing the * user to preventDefault() on the passed event (which ends up calling - * DestroyWebContents in the nativeWindowOpen code path). + * DestroyWebContents). */ export function openGuestWindow ({ event, embedder, guest, referrer, disposition, postData, overrideBrowserWindowOptions, windowOpenArgs }: { event: { sender: WebContents, defaultPrevented: boolean }, @@ -78,22 +76,6 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition webContents: guest, ...browserWindowOptions }); - if (!guest) { - // We should only call `loadURL` if the webContents was constructed by us in - // the case of BrowserWindowProxy (non-sandboxed, nativeWindowOpen: false), - // as navigating to the url when creating the window from an existing - // webContents is not necessary (it will navigate there anyway). - // This can also happen if we enter this function from OpenURLFromTab, in - // which case the browser process is responsible for initiating navigation - // in the new window. - window.loadURL(url, { - httpReferrer: referrer, - ...(postData && { - postData, - extraHeaders: formatPostDataHeaders(postData as Electron.UploadRawData[]) - }) - }); - } handleWindowLifecycleEvents({ embedder, frameName, guest: window }); @@ -118,9 +100,7 @@ const handleWindowLifecycleEvents = function ({ embedder, guest, frameName }: { guest.destroy(); }; - const cachedGuestId = guest.webContents.id; const closedByUser = function () { - embedder._sendInternal(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_CLOSED}_${cachedGuestId}`); embedder.removeListener('current-render-view-deleted' as any, closedByEmbedder); }; embedder.once('current-render-view-deleted' as any, closedByEmbedder); @@ -195,7 +175,6 @@ function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, const securityWebPreferences: { [key: string]: boolean } = { contextIsolation: true, javascript: false, - nativeWindowOpen: true, nodeIntegration: false, sandbox: true, webviewTag: false, @@ -217,10 +196,10 @@ function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: { height: 600, ...parsedOptions, ...overrideOptions, - // Note that for |nativeWindowOpen: true| the WebContents is created in - // |api::WebContents::WebContentsCreatedWithFullParams|, with prefs - // parsed in the |-will-add-new-contents| event. - // The |webPreferences| here is only used by |nativeWindowOpen: false|. + // Note that for normal code path an existing WebContents created by + // Chromium will be used, with web preferences parsed in the + // |-will-add-new-contents| event. + // The |webPreferences| here is only used by the |new-window| event. webPreferences: makeWebPreferences({ embedder, insecureParsedWebPreferences: parsedWebPreferences, @@ -245,7 +224,6 @@ export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = { } return map; }, {} as Electron.WebPreferences)); - const openerId = parentWebPreferences.nativeWindowOpen ? null : embedder.id; return { ...parsedWebPreferences, @@ -253,22 +231,10 @@ export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = { // ability to change important security options but allow main (via // setWindowOpenHandler) to change them. ...securityWebPreferencesFromParent, - ...secureOverrideWebPreferences, - // Sets correct openerId here to give correct options to 'new-window' event handler - // TODO: Figure out another way to pass this? - openerId + ...secureOverrideWebPreferences }; } -function formatPostDataHeaders (postData: PostData) { - if (!postData) return; - - const { contentType, boundary } = parseContentTypeFormat(postData); - if (boundary != null) { return `content-type: ${contentType}; boundary=${boundary}`; } - - return `content-type: ${contentType}`; -} - const MULTIPART_CONTENT_TYPE = 'multipart/form-data'; const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded'; diff --git a/lib/browser/guest-window-proxy.ts b/lib/browser/guest-window-proxy.ts deleted file mode 100644 index f2eacad53b477..0000000000000 --- a/lib/browser/guest-window-proxy.ts +++ /dev/null @@ -1,213 +0,0 @@ -/** - * Manage guest windows when using the default BrowserWindowProxy version of the - * renderer's window.open (i.e. nativeWindowOpen off). This module mostly - * consists of marshaling IPC requests from the BrowserWindowProxy to the - * WebContents. - */ -import { webContents, BrowserWindow } from 'electron/main'; -import type { WebContents } from 'electron/main'; -import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal'; -import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils'; -import { openGuestWindow } from '@electron/internal/browser/guest-window-manager'; -import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; - -const { isSameOrigin } = process._linkedBinding('electron_common_v8_util'); - -const getGuestWindow = function (guestContents: WebContents) { - let guestWindow = BrowserWindow.fromWebContents(guestContents); - if (guestWindow == null) { - const hostContents = guestContents.hostWebContents; - if (hostContents != null) { - guestWindow = BrowserWindow.fromWebContents(hostContents); - } - } - if (!guestWindow) { - throw new Error('getGuestWindow failed'); - } - return guestWindow; -}; - -const isChildWindow = function (sender: WebContents, target: WebContents) { - return target.getLastWebPreferences()!.openerId === sender.id; -}; - -const isRelatedWindow = function (sender: WebContents, target: WebContents) { - return isChildWindow(sender, target) || isChildWindow(target, sender); -}; - -const isScriptableWindow = function (sender: WebContents, target: WebContents) { - return ( - isRelatedWindow(sender, target) && - isSameOrigin(sender.getURL(), target.getURL()) - ); -}; - -const isNodeIntegrationEnabled = function (sender: WebContents) { - return sender.getLastWebPreferences()!.nodeIntegration === true; -}; - -// Checks whether |sender| can access the |target|: -const canAccessWindow = function (sender: WebContents, target: WebContents) { - return ( - isChildWindow(sender, target) || - isScriptableWindow(sender, target) || - isNodeIntegrationEnabled(sender) - ); -}; - -// Routed window.open messages with raw options -ipcMainInternal.on( - IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN, - ( - event, - url: string, - frameName: string, - features: string - ) => { - // This should only be allowed for senders that have nativeWindowOpen: false - const lastWebPreferences = event.sender.getLastWebPreferences()!; - if (lastWebPreferences.nativeWindowOpen || lastWebPreferences.sandbox) { - event.returnValue = null; - throw new Error( - 'GUEST_WINDOW_MANAGER_WINDOW_OPEN denied: expected native window.open' - ); - } - - const referrer: Electron.Referrer = { url: '', policy: 'strict-origin-when-cross-origin' }; - const browserWindowOptions = event.sender._callWindowOpenHandler(event, { url, frameName, features, disposition: 'new-window', referrer }); - if (event.defaultPrevented) { - event.returnValue = null; - return; - } - const guest = openGuestWindow({ - event, - embedder: event.sender, - referrer, - disposition: 'new-window', - overrideBrowserWindowOptions: browserWindowOptions!, - windowOpenArgs: { - url: url || 'about:blank', - frameName: frameName || '', - features: features || '' - } - }); - - event.returnValue = guest ? guest.webContents.id : null; - } -); - -type IpcHandler = (event: Event, guestContents: Electron.WebContents, ...args: any[]) => T; -const makeSafeHandler = function (handler: IpcHandler) { - return (event: Event, guestId: number, ...args: any[]) => { - // Access webContents via electron to prevent circular require. - const guestContents = webContents.fromId(guestId); - if (!guestContents) { - throw new Error(`Invalid guestId: ${guestId}`); - } - - return handler(event, guestContents as Electron.WebContents, ...args); - }; -}; - -const handleMessage = function (channel: string, handler: IpcHandler) { - ipcMainInternal.handle(channel, makeSafeHandler(handler)); -}; - -const handleMessageSync = function (channel: string, handler: IpcHandler) { - ipcMainUtils.handleSync(channel, makeSafeHandler(handler)); -}; - -type ContentsCheck = (contents: WebContents, guestContents: WebContents) => boolean; -const securityCheck = function (contents: WebContents, guestContents: WebContents, check: ContentsCheck) { - if (!check(contents, guestContents)) { - console.error( - `Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}` - ); - throw new Error(`Access denied to guestId: ${guestContents.id}`); - } -}; - -const windowMethods = new Set(['destroy', 'focus', 'blur']); - -handleMessage( - IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_METHOD, - (event, guestContents, method, ...args) => { - securityCheck(event.sender, guestContents, canAccessWindow); - - if (!windowMethods.has(method)) { - console.error( - `Blocked ${event.senderFrame.url} from calling method: ${method}` - ); - throw new Error(`Invalid method: ${method}`); - } - - return (getGuestWindow(guestContents) as any)[method](...args); - } -); - -handleMessage( - IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE, - (event, guestContents, message, targetOrigin, sourceOrigin) => { - if (targetOrigin == null) { - targetOrigin = '*'; - } - - // The W3C does not seem to have word on how postMessage should work when the - // origins do not match, so we do not do |canAccessWindow| check here since - // postMessage across origins is useful and not harmful. - securityCheck(event.sender, guestContents, isRelatedWindow); - - if ( - targetOrigin === '*' || - isSameOrigin(guestContents.getURL(), targetOrigin) - ) { - const sourceId = event.sender.id; - guestContents._sendInternal( - IPC_MESSAGES.GUEST_WINDOW_POSTMESSAGE, - sourceId, - message, - sourceOrigin - ); - } - } -); - -const webContentsMethodsAsync = new Set([ - 'loadURL', - 'executeJavaScript', - 'print' -]); - -handleMessage( - IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, - (event, guestContents, method, ...args) => { - securityCheck(event.sender, guestContents, canAccessWindow); - - if (!webContentsMethodsAsync.has(method)) { - console.error( - `Blocked ${event.sender.getURL()} from calling method: ${method}` - ); - throw new Error(`Invalid method: ${method}`); - } - - return (guestContents as any)[method](...args); - } -); - -const webContentsMethodsSync = new Set(['getURL']); - -handleMessageSync( - IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, - (event, guestContents, method, ...args) => { - securityCheck(event.sender, guestContents, canAccessWindow); - - if (!webContentsMethodsSync.has(method)) { - console.error( - `Blocked ${event.sender.getURL()} from calling method: ${method}` - ); - throw new Error(`Invalid method: ${method}`); - } - - return (guestContents as any)[method](...args); - } -); diff --git a/lib/browser/init.ts b/lib/browser/init.ts index 5740af1a84037..db29322a5e6dd 100644 --- a/lib/browser/init.ts +++ b/lib/browser/init.ts @@ -78,7 +78,6 @@ require('@electron/internal/browser/rpc-server'); // Load the guest view manager. require('@electron/internal/browser/guest-view-manager'); -require('@electron/internal/browser/guest-window-proxy'); // Now we try to load app's package.json. const v8Util = process._linkedBinding('electron_common_v8_util'); diff --git a/lib/common/ipc-messages.ts b/lib/common/ipc-messages.ts index 11bf7fdd832d0..b920c79c48c59 100644 --- a/lib/common/ipc-messages.ts +++ b/lib/common/ipc-messages.ts @@ -18,13 +18,6 @@ export const enum IPC_MESSAGES { GUEST_VIEW_MANAGER_PROPERTY_GET = 'GUEST_VIEW_MANAGER_PROPERTY_GET', GUEST_VIEW_MANAGER_PROPERTY_SET = 'GUEST_VIEW_MANAGER_PROPERTY_SET', - GUEST_WINDOW_MANAGER_WINDOW_OPEN = 'GUEST_WINDOW_MANAGER_WINDOW_OPEN', - GUEST_WINDOW_MANAGER_WINDOW_CLOSED = 'GUEST_WINDOW_MANAGER_WINDOW_CLOSED', - GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE = 'GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', - GUEST_WINDOW_MANAGER_WINDOW_METHOD = 'GUEST_WINDOW_MANAGER_WINDOW_METHOD', - GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD = 'GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', - GUEST_WINDOW_POSTMESSAGE = 'GUEST_WINDOW_POSTMESSAGE', - RENDERER_WEB_FRAME_METHOD = 'RENDERER_WEB_FRAME_METHOD', INSPECTOR_CONFIRM = 'INSPECTOR_CONFIRM', diff --git a/lib/renderer/common-init.ts b/lib/renderer/common-init.ts index 30ff1eb3425fd..4ceff37416d59 100644 --- a/lib/renderer/common-init.ts +++ b/lib/renderer/common-init.ts @@ -12,9 +12,7 @@ const v8Util = process._linkedBinding('electron_common_v8_util'); const nodeIntegration = mainFrame.getWebPreference('nodeIntegration'); const webviewTag = mainFrame.getWebPreference('webviewTag'); const isHiddenPage = mainFrame.getWebPreference('hiddenPage'); -const nativeWindowOpen = mainFrame.getWebPreference('nativeWindowOpen') || process.sandboxed; const isWebView = mainFrame.getWebPreference('isWebView'); -const openerId = mainFrame.getWebPreference('openerId'); // ElectronApiServiceImpl will look for the "ipcNative" hidden object when // invoking the 'onMessage' callback. @@ -44,7 +42,7 @@ switch (window.location.protocol) { default: { // Override default web functions. const { windowSetup } = require('@electron/internal/renderer/window-setup') as typeof windowSetupModule; - windowSetup(isWebView, openerId, isHiddenPage, nativeWindowOpen); + windowSetup(isWebView, isHiddenPage); } } diff --git a/lib/renderer/window-setup.ts b/lib/renderer/window-setup.ts index de7bf37da5ef8..6c9f15a2d418b 100644 --- a/lib/renderer/window-setup.ts +++ b/lib/renderer/window-setup.ts @@ -1,249 +1,10 @@ import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; -import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; import { internalContextBridge } from '@electron/internal/renderer/api/context-bridge'; import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; const { contextIsolationEnabled } = internalContextBridge; -// This file implements the following APIs over the ctx bridge: -// - window.open() -// - window.opener.blur() -// - window.opener.close() -// - window.opener.eval() -// - window.opener.focus() -// - window.opener.location -// - window.opener.print() -// - window.opener.closed -// - window.opener.postMessage() -// - window.history.back() -// - window.history.forward() -// - window.history.go() -// - window.history.length -// - window.prompt() -// - document.hidden -// - document.visibilityState - -// Helper function to resolve relative url. -const resolveURL = (url: string, base: string) => new URL(url, base).href; - -// Use this method to ensure values expected as strings in the main process -// are convertible to strings in the renderer process. This ensures exceptions -// converting values to strings are thrown in this process. -const toString = (value: any) => { - return value != null ? `${value}` : value; -}; - -const windowProxies = new Map(); - -const getOrCreateProxy = (guestId: number): SafelyBoundBrowserWindowProxy => { - let proxy = windowProxies.get(guestId); - if (proxy == null) { - proxy = new BrowserWindowProxy(guestId); - windowProxies.set(guestId, proxy); - } - return proxy.getSafe(); -}; - -const removeProxy = (guestId: number) => { - windowProxies.delete(guestId); -}; - -type LocationProperties = 'hash' | 'href' | 'host' | 'hostname' | 'origin' | 'pathname' | 'port' | 'protocol' | 'search' - -class LocationProxy { - @LocationProxy.ProxyProperty public hash!: string; - @LocationProxy.ProxyProperty public href!: string; - @LocationProxy.ProxyProperty public host!: string; - @LocationProxy.ProxyProperty public hostname!: string; - @LocationProxy.ProxyProperty public origin!: string; - @LocationProxy.ProxyProperty public pathname!: string; - @LocationProxy.ProxyProperty public port!: string; - @LocationProxy.ProxyProperty public protocol!: string; - @LocationProxy.ProxyProperty public search!: URLSearchParams; - - private guestId: number; - - /** - * Beware: This decorator will have the _prototype_ as the `target`. It defines properties - * commonly found in URL on the LocationProxy. - */ - private static ProxyProperty (target: LocationProxy, propertyKey: LocationProperties) { - Object.defineProperty(target, propertyKey, { - enumerable: true, - configurable: true, - get: function (this: LocationProxy): T | string { - const guestURL = this.getGuestURL(); - const value = guestURL ? guestURL[propertyKey] : ''; - return value === undefined ? '' : value; - }, - set: function (this: LocationProxy, newVal: T) { - const guestURL = this.getGuestURL(); - if (guestURL) { - // TypeScript doesn't want us to assign to read-only variables. - // It's right, that's bad, but we're doing it anyway. - (guestURL as any)[propertyKey] = newVal; - - return this._invokeWebContentsMethod('loadURL', guestURL.toString()); - } - } - }); - } - - public getSafe = () => { - const that = this; - return { - get href () { return that.href; }, - set href (newValue) { that.href = newValue; }, - get hash () { return that.hash; }, - set hash (newValue) { that.hash = newValue; }, - get host () { return that.host; }, - set host (newValue) { that.host = newValue; }, - get hostname () { return that.hostname; }, - set hostname (newValue) { that.hostname = newValue; }, - get origin () { return that.origin; }, - set origin (newValue) { that.origin = newValue; }, - get pathname () { return that.pathname; }, - set pathname (newValue) { that.pathname = newValue; }, - get port () { return that.port; }, - set port (newValue) { that.port = newValue; }, - get protocol () { return that.protocol; }, - set protocol (newValue) { that.protocol = newValue; }, - get search () { return that.search; }, - set search (newValue) { that.search = newValue; } - }; - } - - constructor (guestId: number) { - // eslint will consider the constructor "useless" - // unless we assign them in the body. It's fine, that's what - // TS would do anyway. - this.guestId = guestId; - this.getGuestURL = this.getGuestURL.bind(this); - } - - public toString (): string { - return this.href; - } - - private getGuestURL (): URL | null { - const maybeURL = this._invokeWebContentsMethodSync('getURL') as string; - - // When there's no previous frame the url will be blank, so account for that here - // to prevent url parsing errors on an empty string. - const urlString = maybeURL !== '' ? maybeURL : 'about:blank'; - try { - return new URL(urlString); - } catch (e) { - console.error('LocationProxy: failed to parse string', urlString, e); - } - - return null; - } - - private _invokeWebContentsMethod (method: string, ...args: any[]) { - return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, this.guestId, method, ...args); - } - - private _invokeWebContentsMethodSync (method: string, ...args: any[]) { - return ipcRendererUtils.invokeSync(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, this.guestId, method, ...args); - } -} - -interface SafelyBoundBrowserWindowProxy { - location: WindowProxy['location']; - blur: WindowProxy['blur']; - close: WindowProxy['close']; - eval: typeof eval; // eslint-disable-line no-eval - focus: WindowProxy['focus']; - print: WindowProxy['print']; - postMessage: WindowProxy['postMessage']; - closed: boolean; -} - -class BrowserWindowProxy { - public closed: boolean = false - - private _location: LocationProxy - private guestId: number - - // TypeScript doesn't allow getters/accessors with different types, - // so for now, we'll have to make do with an "any" in the mix. - // https://github.com/Microsoft/TypeScript/issues/2521 - public get location (): LocationProxy | any { - return this._location.getSafe(); - } - - public set location (url: string | any) { - url = resolveURL(url, this.location.href); - this._invokeWebContentsMethod('loadURL', url); - } - - constructor (guestId: number) { - this.guestId = guestId; - this._location = new LocationProxy(guestId); - - ipcRendererInternal.once(`${IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_CLOSED}_${guestId}`, () => { - removeProxy(guestId); - this.closed = true; - }); - } - - public getSafe = (): SafelyBoundBrowserWindowProxy => { - const that = this; - return { - postMessage: this.postMessage, - blur: this.blur, - close: this.close, - focus: this.focus, - print: this.print, - eval: this.eval, - get location () { - return that.location; - }, - set location (url: string | any) { - that.location = url; - }, - get closed () { - return that.closed; - } - }; - } - - public close = () => { - this._invokeWindowMethod('destroy'); - } - - public focus = () => { - this._invokeWindowMethod('focus'); - } - - public blur = () => { - this._invokeWindowMethod('blur'); - } - - public print = () => { - this._invokeWebContentsMethod('print'); - } - - public postMessage = (message: any, targetOrigin: string) => { - ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE, this.guestId, message, toString(targetOrigin), window.location.origin); - } - - public eval = (code: string) => { - this._invokeWebContentsMethod('executeJavaScript', code); - } - - private _invokeWindowMethod (method: string, ...args: any[]) { - return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_METHOD, this.guestId, method, ...args); - } - - private _invokeWebContentsMethod (method: string, ...args: any[]) { - return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD, this.guestId, method, ...args); - } -} - -export const windowSetup = ( - isWebView: boolean, openerId: number, isHiddenPage: boolean, usesNativeWindowOpen: boolean) => { +export const windowSetup = (isWebView: boolean, isHiddenPage: boolean) => { if (!process.sandboxed && !isWebView) { // Override default window.close. window.close = function () { @@ -252,72 +13,12 @@ export const windowSetup = ( if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['close'], window.close); } - if (!usesNativeWindowOpen) { - // TODO(MarshallOfSound): Make compatible with ctx isolation without hole-punch - // Make the browser window or guest view emit "new-window" event. - window.open = function (url?: string, frameName?: string, features?: string) { - if (url != null && url !== '') { - url = resolveURL(url, location.href); - } - const guestId = ipcRendererInternal.sendSync(IPC_MESSAGES.GUEST_WINDOW_MANAGER_WINDOW_OPEN, url, toString(frameName), toString(features)); - if (guestId != null) { - return getOrCreateProxy(guestId) as any as WindowProxy; - } else { - return null; - } - }; - if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueWithDynamicPropsFromIsolatedWorld(['open'], window.open); - } - - // If this window uses nativeWindowOpen, but its opener window does not, we - // need to proxy window.opener in order to let the page communicate with its - // opener. - // Additionally, windows opened from a nativeWindowOpen child of a - // non-nativeWindowOpen parent will initially have their WebPreferences - // copied from their opener before having them updated, meaning openerId is - // initially incorrect. We detect this situation by checking for - // window.opener, which will be non-null for a natively-opened child, so we - // can ignore the openerId in that case, since it's incorrectly copied from - // the parent. This is, uh, confusing, so here's a diagram that will maybe - // help? - // - // [ grandparent window ] --> [ parent window ] --> [ child window ] - // n.W.O = false n.W.O = true n.W.O = true - // id = 1 id = 2 id = 3 - // openerId = 0 openerId = 1 openerId = 1 <- !!wrong!! - // opener = null opener = null opener = [parent window] - if (openerId && !window.opener) { - window.opener = getOrCreateProxy(openerId); - if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueWithDynamicPropsFromIsolatedWorld(['opener'], window.opener); - } - // But we do not support prompt(). window.prompt = function () { throw new Error('prompt() is and will not be supported.'); }; if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['prompt'], window.prompt); - if (!usesNativeWindowOpen || openerId) { - ipcRendererInternal.on(IPC_MESSAGES.GUEST_WINDOW_POSTMESSAGE, function ( - _event, sourceId: number, message: any, sourceOrigin: string - ) { - // Manually dispatch event instead of using postMessage because we also need to - // set event.source. - // - // Why any? We can't construct a MessageEvent and we can't - // use `as MessageEvent` because you're not supposed to override - // data, origin, and source - const event: any = document.createEvent('Event'); - event.initEvent('message', false, false); - - event.data = message; - event.origin = sourceOrigin; - event.source = getOrCreateProxy(sourceId); - - window.dispatchEvent(event as MessageEvent); - }); - } - if (isWebView) { // Webview `document.visibilityState` tracks window visibility (and ignores // the actual element visibility) for backwards compatibility. diff --git a/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch b/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch index 3963d32c0b057..9267c2378f59b 100644 --- a/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch +++ b/patches/chromium/allow_in-process_windows_to_have_different_web_prefs.patch @@ -8,21 +8,19 @@ WebPreferences of in-process child windows, rather than relying on process-level command line switches, as before. diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc -index db2d0536ed7a8143a60cebf1c5d7fee1acf4d10d..6cea8d7ce6ff75ae80a4db03c25f913915624342 100644 +index db2d0536ed7a8143a60cebf1c5d7fee1acf4d10d..0cad8646e8b733a3a2d4b1076fdb0276bcd5b7bf 100644 --- a/third_party/blink/common/web_preferences/web_preferences.cc +++ b/third_party/blink/common/web_preferences/web_preferences.cc -@@ -145,6 +145,22 @@ WebPreferences::WebPreferences() +@@ -145,6 +145,20 @@ WebPreferences::WebPreferences() fake_no_alloc_direct_call_for_testing_enabled(false), v8_cache_options(blink::mojom::V8CacheOptions::kDefault), record_whole_document(false), + // Begin Electron-specific WebPreferences. -+ opener_id(0), + context_isolation(false), + is_webview(false), + hidden_page(false), + offscreen(false), + preload(base::FilePath::StringType()), -+ native_window_open(false), + node_integration(false), + node_integration_in_worker(false), + node_integration_in_sub_frames(false), @@ -35,7 +33,7 @@ index db2d0536ed7a8143a60cebf1c5d7fee1acf4d10d..6cea8d7ce6ff75ae80a4db03c25f9139 accelerated_video_decode_enabled(false), animation_policy( diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc -index e9f2e215ee1220c66549112982df04201c68fe1a..a8e08adfdeaf3acde4d190766b65ad3fbacfdf58 100644 +index e9f2e215ee1220c66549112982df04201c68fe1a..e9118530b395dbb13180365521dcf03d9ca211e5 100644 --- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc +++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc @@ -23,6 +23,10 @@ bool StructTraitslazy_frame_loading_distance_thresholds_px) || !data.ReadLazyImageLoadingDistanceThresholdsPx( -@@ -158,6 +162,21 @@ bool StructTraitsv8_cache_options = data.v8_cache_options(); out->record_whole_document = data.record_whole_document(); + // Begin Electron-specific WebPreferences. -+ out->opener_id = data.opener_id(); + out->context_isolation = data.context_isolation(); + out->is_webview = data.is_webview(); + out->hidden_page = data.hidden_page(); + out->offscreen = data.offscreen(); -+ out->native_window_open = data.native_window_open(); + out->node_integration = data.node_integration(); + out->node_integration_in_worker = data.node_integration_in_worker(); + out->node_integration_in_sub_frames = data.node_integration_in_sub_frames(); @@ -72,7 +68,7 @@ index e9f2e215ee1220c66549112982df04201c68fe1a..a8e08adfdeaf3acde4d190766b65ad3f out->accelerated_video_decode_enabled = data.accelerated_video_decode_enabled(); diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h -index 0d74719b2f8fb91f094772fab96a880cc8787c77..bc447e53a87852aac03fd2487b77aa1009472d36 100644 +index 0d74719b2f8fb91f094772fab96a880cc8787c77..23126786a738c3fe83f7064bf8b597794d871ac5 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences.h +++ b/third_party/blink/public/common/web_preferences/web_preferences.h @@ -10,6 +10,7 @@ @@ -83,19 +79,17 @@ index 0d74719b2f8fb91f094772fab96a880cc8787c77..bc447e53a87852aac03fd2487b77aa10 #include "net/nqe/effective_connection_type.h" #include "third_party/blink/public/common/common_export.h" #include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-shared.h" -@@ -163,6 +164,24 @@ struct BLINK_COMMON_EXPORT WebPreferences { +@@ -163,6 +164,22 @@ struct BLINK_COMMON_EXPORT WebPreferences { blink::mojom::V8CacheOptions v8_cache_options; bool record_whole_document; + // Begin Electron-specific WebPreferences. + std::vector preloads; -+ int opener_id; + bool context_isolation; + bool is_webview; + bool hidden_page; + bool offscreen; + base::FilePath preload; -+ bool native_window_open; + bool node_integration; + bool node_integration_in_worker; + bool node_integration_in_sub_frames; @@ -109,7 +103,7 @@ index 0d74719b2f8fb91f094772fab96a880cc8787c77..bc447e53a87852aac03fd2487b77aa10 // only controls whether or not the "document.cookie" field is properly // connected to the backing store, for instance if you wanted to be able to diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h -index e0084598921ddcb0cf2aeb33875f05da0b5457e9..90bf73d7a1f2daf921f5a0ae9e4b3c292efaaaa0 100644 +index e0084598921ddcb0cf2aeb33875f05da0b5457e9..bcda6f35ad74b2b8aa9d439155048aab7bd02b21 100644 --- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h +++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h @@ -6,6 +6,7 @@ @@ -120,7 +114,7 @@ index e0084598921ddcb0cf2aeb33875f05da0b5457e9..90bf73d7a1f2daf921f5a0ae9e4b3c29 #include "mojo/public/cpp/bindings/struct_traits.h" #include "net/nqe/effective_connection_type.h" #include "third_party/blink/public/common/common_export.h" -@@ -456,6 +457,68 @@ struct BLINK_COMMON_EXPORT StructTraits preloads; -+ int32 opener_id; + bool context_isolation; + bool is_webview; + bool hidden_page; + bool offscreen; + mojo_base.mojom.FilePath preload; -+ bool native_window_open; + bool node_integration; + bool node_integration_in_worker; + bool node_integration_in_sub_frames; diff --git a/shell/browser/api/electron_api_browser_view.cc b/shell/browser/api/electron_api_browser_view.cc index 7193c00fa1c5e..6feadb81074a3 100644 --- a/shell/browser/api/electron_api_browser_view.cc +++ b/shell/browser/api/electron_api_browser_view.cc @@ -81,8 +81,7 @@ BrowserView::BrowserView(gin::Arguments* args, v8::Local value; - // Copy the webContents option to webPreferences. This is only used internally - // to implement nativeWindowOpen option. + // Copy the webContents option to webPreferences. if (options.Get("webContents", &value)) { web_preferences.SetHidden("webContents", value); } diff --git a/shell/browser/api/electron_api_browser_window.cc b/shell/browser/api/electron_api_browser_window.cc index 644df16d75bdb..1d9d9630bed1a 100644 --- a/shell/browser/api/electron_api_browser_window.cc +++ b/shell/browser/api/electron_api_browser_window.cc @@ -78,8 +78,7 @@ BrowserWindow::BrowserWindow(gin::Arguments* args, web_preferences.Set(options::kEnableBlinkFeatures, enabled_features); } - // Copy the webContents option to webPreferences. This is only used internally - // to implement nativeWindowOpen option. + // Copy the webContents option to webPreferences. if (options.Get("webContents", &value)) { web_preferences.SetHidden("webContents", value); } diff --git a/shell/browser/electron_browser_client.cc b/shell/browser/electron_browser_client.cc index d6065678a401d..7e9184a3f18de 100644 --- a/shell/browser/electron_browser_client.cc +++ b/shell/browser/electron_browser_client.cc @@ -721,7 +721,7 @@ bool ElectronBrowserClient::CanCreateWindow( content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(opener); WebContentsPreferences* prefs = WebContentsPreferences::From(web_contents); - if (prefs && prefs->ShouldUseNativeWindowOpen()) { + if (prefs) { if (prefs->ShouldDisablePopups()) { // without allowpopups attribute should return // null from window.open calls diff --git a/shell/browser/web_contents_preferences.cc b/shell/browser/web_contents_preferences.cc index 80e3844b5b414..47cc77f596009 100644 --- a/shell/browser/web_contents_preferences.cc +++ b/shell/browser/web_contents_preferences.cc @@ -130,7 +130,6 @@ void WebContentsPreferences::Clear() { disable_html_fullscreen_window_resize_ = false; webview_tag_ = false; sandbox_ = absl::nullopt; - native_window_open_ = true; context_isolation_ = true; javascript_ = true; images_ = true; @@ -148,7 +147,6 @@ void WebContentsPreferences::Clear() { default_monospace_font_size_ = absl::nullopt; minimum_font_size_ = absl::nullopt; default_encoding_ = absl::nullopt; - opener_id_ = 0; is_webview_ = false; custom_args_.clear(); custom_switches_.clear(); @@ -194,7 +192,6 @@ void WebContentsPreferences::Merge( bool sandbox; if (web_preferences.Get(options::kSandbox, &sandbox)) sandbox_ = sandbox; - web_preferences.Get(options::kNativeWindowOpen, &native_window_open_); web_preferences.Get(options::kContextIsolation, &context_isolation_); web_preferences.Get(options::kJavaScript, &javascript_); web_preferences.Get(options::kImages, &images_); @@ -223,7 +220,6 @@ void WebContentsPreferences::Merge( std::string encoding; if (web_preferences.Get("defaultEncoding", &encoding)) default_encoding_ = encoding; - web_preferences.Get(options::kOpenerID, &opener_id_); web_preferences.Get(options::kCustomArgs, &custom_args_); web_preferences.Get("commandLineSwitches", &custom_switches_); web_preferences.Get("disablePopups", &disable_popups_); @@ -406,13 +402,10 @@ void WebContentsPreferences::AppendCommandLineSwitches( void WebContentsPreferences::SaveLastPreferences() { last_web_preferences_ = base::Value(base::Value::Type::DICTIONARY); - last_web_preferences_.SetKey(options::kOpenerID, base::Value(opener_id_)); last_web_preferences_.SetKey(options::kNodeIntegration, base::Value(node_integration_)); last_web_preferences_.SetKey(options::kNodeIntegrationInSubFrames, base::Value(node_integration_in_sub_frames_)); - last_web_preferences_.SetKey(options::kNativeWindowOpen, - base::Value(native_window_open_)); last_web_preferences_.SetKey(options::kSandbox, base::Value(IsSandboxed())); last_web_preferences_.SetKey(options::kContextIsolation, base::Value(context_isolation_)); @@ -477,9 +470,6 @@ void WebContentsPreferences::OverrideWebkitPrefs( if (default_encoding_) prefs->default_encoding = *default_encoding_; - // Pass the opener's window id. - prefs->opener_id = opener_id_; - // Run Electron APIs and preload script in isolated world prefs->context_isolation = context_isolation_; prefs->is_webview = is_webview_; @@ -507,7 +497,6 @@ void WebContentsPreferences::OverrideWebkitPrefs( if (preload_path_) prefs->preload = *preload_path_; - prefs->native_window_open = native_window_open_; prefs->node_integration = node_integration_; prefs->node_integration_in_worker = node_integration_in_worker_; prefs->node_integration_in_sub_frames = node_integration_in_sub_frames_; diff --git a/shell/browser/web_contents_preferences.h b/shell/browser/web_contents_preferences.h index 0f2e465ec7aa5..c80c8108fec07 100644 --- a/shell/browser/web_contents_preferences.h +++ b/shell/browser/web_contents_preferences.h @@ -75,7 +75,6 @@ class WebContentsPreferences bool ShouldUseSafeDialogs() const { return safe_dialogs_; } bool GetSafeDialogsMessage(std::string* message) const; bool ShouldDisablePopups() const { return disable_popups_; } - bool ShouldUseNativeWindowOpen() const { return native_window_open_; } bool IsWebSecurityEnabled() const { return web_security_; } bool GetPreloadPath(base::FilePath* path) const; bool IsSandboxed() const; @@ -100,7 +99,6 @@ class WebContentsPreferences bool disable_html_fullscreen_window_resize_; bool webview_tag_; absl::optional sandbox_; - bool native_window_open_; bool context_isolation_; bool javascript_; bool images_; @@ -118,7 +116,6 @@ class WebContentsPreferences absl::optional default_monospace_font_size_; absl::optional minimum_font_size_; absl::optional default_encoding_; - int opener_id_; bool is_webview_; std::vector custom_args_; std::vector custom_switches_; diff --git a/shell/common/api/electron_api_v8_util.cc b/shell/common/api/electron_api_v8_util.cc index 4109ba1de9871..b4a95d228cf35 100644 --- a/shell/common/api/electron_api_v8_util.cc +++ b/shell/common/api/electron_api_v8_util.cc @@ -102,10 +102,6 @@ void RequestGarbageCollectionForTesting(v8::Isolate* isolate) { v8::Isolate::GarbageCollectionType::kFullGarbageCollection); } -bool IsSameOrigin(const GURL& l, const GURL& r) { - return url::Origin::Create(l).IsSameOriginWith(url::Origin::Create(r)); -} - // This causes a fatal error by creating a circular extension dependency. void TriggerFatalErrorForTesting(v8::Isolate* isolate) { static const char* aDeps[] = {"B"}; @@ -132,7 +128,6 @@ void Initialize(v8::Local exports, dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot); dict.SetMethod("requestGarbageCollectionForTesting", &RequestGarbageCollectionForTesting); - dict.SetMethod("isSameOrigin", &IsSameOrigin); dict.SetMethod("triggerFatalErrorForTesting", &TriggerFatalErrorForTesting); dict.SetMethod("runUntilIdle", &RunUntilIdle); } diff --git a/shell/common/options_switches.cc b/shell/common/options_switches.cc index 15d854d199120..7e68bedb66038 100644 --- a/shell/common/options_switches.cc +++ b/shell/common/options_switches.cc @@ -129,9 +129,6 @@ const char kContextIsolation[] = "contextIsolation"; // Web runtime features. const char kExperimentalFeatures[] = "experimentalFeatures"; -// Opener window's ID. -const char kOpenerID[] = "openerId"; - // Enable the rubber banding effect. const char kScrollBounce[] = "scrollBounce"; @@ -147,8 +144,6 @@ const char kNodeIntegrationInWorker[] = "nodeIntegrationInWorker"; // Enable the web view tag. const char kWebviewTag[] = "webviewTag"; -const char kNativeWindowOpen[] = "nativeWindowOpen"; - const char kCustomArgs[] = "additionalArguments"; const char kPlugins[] = "plugins"; diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h index a082c76afa4fe..61976c17dff1d 100644 --- a/shell/common/options_switches.h +++ b/shell/common/options_switches.h @@ -69,13 +69,11 @@ extern const char kPreloadURL[]; extern const char kNodeIntegration[]; extern const char kContextIsolation[]; extern const char kExperimentalFeatures[]; -extern const char kOpenerID[]; extern const char kScrollBounce[]; extern const char kEnableBlinkFeatures[]; extern const char kDisableBlinkFeatures[]; extern const char kNodeIntegrationInWorker[]; extern const char kWebviewTag[]; -extern const char kNativeWindowOpen[]; extern const char kCustomArgs[]; extern const char kPlugins[]; extern const char kSandbox[]; diff --git a/shell/renderer/api/electron_api_web_frame.cc b/shell/renderer/api/electron_api_web_frame.cc index a114d3a8470a6..7f069eea02d3a 100644 --- a/shell/renderer/api/electron_api_web_frame.cc +++ b/shell/renderer/api/electron_api_web_frame.cc @@ -496,9 +496,6 @@ class WebFrameRenderer : public gin::Wrappable, if (pref_name == options::kPreloadScripts) { return gin::ConvertToV8(isolate, prefs.preloads); - } else if (pref_name == options::kOpenerID) { - // NOTE: openerId is internal-only. - return gin::ConvertToV8(isolate, prefs.opener_id); } else if (pref_name == "isWebView") { // FIXME(zcbenz): For child windows opened with window.open('') from // webview, the WebPreferences is inherited from webview and the value @@ -516,8 +513,6 @@ class WebFrameRenderer : public gin::Wrappable, return gin::ConvertToV8(isolate, prefs.offscreen); } else if (pref_name == options::kPreloadScript) { return gin::ConvertToV8(isolate, prefs.preload.value()); - } else if (pref_name == options::kNativeWindowOpen) { - return gin::ConvertToV8(isolate, prefs.native_window_open); } else if (pref_name == options::kNodeIntegration) { return gin::ConvertToV8(isolate, prefs.node_integration); } else if (pref_name == options::kNodeIntegrationInWorker) { diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts index ee40a3099b181..fddfaa6f3bd07 100644 --- a/spec-main/api-browser-window-spec.ts +++ b/spec-main/api-browser-window-spec.ts @@ -15,6 +15,7 @@ import { closeWindow, closeAllWindows } from './window-helpers'; const features = process._linkedBinding('electron_common_features'); const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures'); +const mainFixtures = path.resolve(__dirname, 'fixtures'); // Is the display's scale factor possibly causing rounding of pixel coordinate // values? @@ -2450,7 +2451,7 @@ describe('BrowserWindow module', () => { } }); - const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js'); + const preloadPath = path.join(mainFixtures, 'api', 'new-window-preload.js'); w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload: preloadPath } } })); w.loadFile(path.join(fixtures, 'api', 'new-window.html')); const [, { argv }] = await emittedOnce(ipcMain, 'answer'); @@ -2465,7 +2466,7 @@ describe('BrowserWindow module', () => { } }); - const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js'); + const preloadPath = path.join(mainFixtures, 'api', 'new-window-preload.js'); w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload: preloadPath, contextIsolation: false } } })); w.loadFile(path.join(fixtures, 'api', 'new-window.html')); const [[, childWebContents]] = await Promise.all([ @@ -2636,7 +2637,7 @@ describe('BrowserWindow module', () => { }); }); - describe('nativeWindowOpen option', () => { + describe('child windows', () => { let w: BrowserWindow = null as unknown as BrowserWindow; beforeEach(() => { @@ -2644,7 +2645,6 @@ describe('BrowserWindow module', () => { show: false, webPreferences: { nodeIntegration: true, - nativeWindowOpen: true, // tests relies on preloads in opened windows nodeIntegrationInSubFrames: true, contextIsolation: false @@ -2676,6 +2676,17 @@ describe('BrowserWindow module', () => { const [, content] = await answer; expect(content).to.equal('Hello'); }); + it('opens window with cross-scripting enabled from isolated context', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + preload: path.join(fixtures, 'api', 'native-window-open-isolated-preload.js') + } + }); + w.loadFile(path.join(fixtures, 'api', 'native-window-open-isolated.html')); + const [, content] = await emittedOnce(ipcMain, 'answer'); + expect(content).to.equal('Hello'); + }); ifit(!process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS)('loads native addons correctly after reload', async () => { w.loadFile(path.join(__dirname, 'fixtures', 'api', 'native-window-open-native-addon.html')); { @@ -2695,7 +2706,6 @@ describe('BrowserWindow module', () => { show: false, webPreferences: { nodeIntegrationInSubFrames: true, - nativeWindowOpen: true, webviewTag: true, contextIsolation: false, preload @@ -2703,7 +2713,7 @@ describe('BrowserWindow module', () => { }); w.webContents.setWindowOpenHandler(() => ({ action: 'allow', - overrideBrowserWindowOptions: { show: false, webPreferences: { contextIsolation: false, webviewTag: true, nativeWindowOpen: true, nodeIntegrationInSubFrames: true } } + overrideBrowserWindowOptions: { show: false, webPreferences: { contextIsolation: false, webviewTag: true, nodeIntegrationInSubFrames: true } } })); w.webContents.once('new-window', (event, url, frameName, disposition, options) => { options.show = false; @@ -2713,23 +2723,8 @@ describe('BrowserWindow module', () => { w.loadFile(path.join(fixtures, 'api', 'new-window-webview.html')); await webviewLoaded; }); - it('should inherit the nativeWindowOpen setting in opened windows', async () => { - const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js'); - - w.webContents.setWindowOpenHandler(() => ({ - action: 'allow', - overrideBrowserWindowOptions: { - webPreferences: { - preload: preloadPath - } - } - })); - w.loadFile(path.join(fixtures, 'api', 'new-window.html')); - const [, { nativeWindowOpen }] = await emittedOnce(ipcMain, 'answer'); - expect(nativeWindowOpen).to.be.true(); - }); it('should open windows with the options configured via new-window event listeners', async () => { - const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js'); + const preloadPath = path.join(mainFixtures, 'api', 'new-window-preload.js'); w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { @@ -2772,7 +2767,6 @@ describe('BrowserWindow module', () => { const w = new BrowserWindow({ show: false, webPreferences: { - nativeWindowOpen: true, // test relies on preloads in opened window nodeIntegrationInSubFrames: true, contextIsolation: false @@ -2783,7 +2777,7 @@ describe('BrowserWindow module', () => { action: 'allow', overrideBrowserWindowOptions: { webPreferences: { - preload: path.join(fixtures, 'api', 'window-open-preload.js'), + preload: path.join(mainFixtures, 'api', 'window-open-preload.js'), contextIsolation: false, nodeIntegrationInSubFrames: true } @@ -2791,9 +2785,8 @@ describe('BrowserWindow module', () => { })); w.loadFile(path.join(fixtures, 'api', 'window-open-location-open.html')); - const [, { nodeIntegration, nativeWindowOpen, typeofProcess }] = await emittedOnce(ipcMain, 'answer'); + const [, { nodeIntegration, typeofProcess }] = await emittedOnce(ipcMain, 'answer'); expect(nodeIntegration).to.be.false(); - expect(nativeWindowOpen).to.be.true(); expect(typeofProcess).to.eql('undefined'); }); @@ -2801,7 +2794,6 @@ describe('BrowserWindow module', () => { const w = new BrowserWindow({ show: false, webPreferences: { - nativeWindowOpen: true, // test relies on preloads in opened window nodeIntegrationInSubFrames: true } @@ -2811,7 +2803,7 @@ describe('BrowserWindow module', () => { action: 'allow', overrideBrowserWindowOptions: { webPreferences: { - preload: path.join(fixtures, 'api', 'window-open-preload.js') + preload: path.join(mainFixtures, 'api', 'window-open-preload.js') } } })); @@ -2840,23 +2832,6 @@ describe('BrowserWindow module', () => { }); }); - describe('nativeWindowOpen + contextIsolation options', () => { - afterEach(closeAllWindows); - it('opens window with cross-scripting enabled from isolated context', async () => { - const w = new BrowserWindow({ - show: false, - webPreferences: { - nativeWindowOpen: true, - contextIsolation: true, - preload: path.join(fixtures, 'api', 'native-window-open-isolated-preload.js') - } - }); - w.loadFile(path.join(fixtures, 'api', 'native-window-open-isolated.html')); - const [, content] = await emittedOnce(ipcMain, 'answer'); - expect(content).to.equal('Hello'); - }); - }); - describe('beforeunload handler', function () { let w: BrowserWindow = null as unknown as BrowserWindow; beforeEach(() => { diff --git a/spec-main/api-ipc-renderer-spec.ts b/spec-main/api-ipc-renderer-spec.ts index 6e09796a3ce16..81d62bf47b22e 100644 --- a/spec-main/api-ipc-renderer-spec.ts +++ b/spec-main/api-ipc-renderer-spec.ts @@ -9,7 +9,7 @@ describe('ipcRenderer module', () => { let w: BrowserWindow; before(async () => { - w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen: true, contextIsolation: false } }); + w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); await w.loadURL('about:blank'); }); after(async () => { diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index 09d6a445f8b01..c8e325dab76ae 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -1245,8 +1245,8 @@ describe('webContents module', () => { expect(currentRenderViewDeletedEmitted).to.be.false('current-render-view-deleted was emitted'); }); - it('does not emit current-render-view-deleted when speculative RVHs are deleted and nativeWindowOpen is set to true', async () => { - const parentWindow = new BrowserWindow({ show: false, webPreferences: { nativeWindowOpen: true } }); + it('does not emit current-render-view-deleted when speculative RVHs are deleted', async () => { + const parentWindow = new BrowserWindow({ show: false }); let currentRenderViewDeletedEmitted = false; let childWindow: BrowserWindow | null = null; const destroyed = emittedOnce(parentWindow.webContents, 'destroyed'); @@ -2054,7 +2054,7 @@ describe('webContents module', () => { describe('page-title-updated event', () => { afterEach(closeAllWindows); it('is emitted with a full title for pages with no navigation', async () => { - const bw = new BrowserWindow({ show: false, webPreferences: { nativeWindowOpen: true } }); + const bw = new BrowserWindow({ show: false }); await bw.loadURL('about:blank'); bw.webContents.executeJavaScript('child = window.open("", "", "show=no"); null'); const [, child] = await emittedOnce(app, 'web-contents-created'); diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index 951c158fb969b..d1c9e365bc02f 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -84,19 +84,15 @@ describe('window.postMessage', () => { await closeAllWindows(); }); - for (const nativeWindowOpen of [true, false]) { - describe(`when nativeWindowOpen: ${nativeWindowOpen}`, () => { - it('sets the source and origin correctly', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen, contextIsolation: false } }); - w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`); - const [, message] = await emittedOnce(ipcMain, 'complete'); - expect(message.data).to.equal('testing'); - expect(message.origin).to.equal('file://'); - expect(message.sourceEqualsOpener).to.equal(true); - expect(message.eventOrigin).to.equal('file://'); - }); - }); - } + it('sets the source and origin correctly', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } }); + w.loadURL(`file://${fixturesPath}/pages/window-open-postMessage-driver.html`); + const [, message] = await emittedOnce(ipcMain, 'complete'); + expect(message.data).to.equal('testing'); + expect(message.origin).to.equal('file://'); + expect(message.sourceEqualsOpener).to.equal(true); + expect(message.eventOrigin).to.equal('file://'); + }); }); describe('focus handling', () => { @@ -814,8 +810,8 @@ describe('chromium features', () => { expect(typeofProcessGlobal).to.equal('undefined'); }); - it('can disable node integration when it is enabled on the parent window with nativeWindowOpen: true', async () => { - const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen: true } }); + it('can disable node integration when it is enabled on the parent window', async () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } }); w.loadURL('about:blank'); w.webContents.executeJavaScript(` { b = window.open('about:blank', '', 'nodeIntegration=no,show=no'); null } @@ -909,34 +905,6 @@ describe('chromium features', () => { expect(frameName).to.equal('__proto__'); }); - - it('denies custom open when nativeWindowOpen: true', async () => { - const w = new BrowserWindow({ - show: false, - webPreferences: { - contextIsolation: false, - nodeIntegration: true, - nativeWindowOpen: true - } - }); - w.loadURL('about:blank'); - - const previousListeners = process.listeners('uncaughtException'); - process.removeAllListeners('uncaughtException'); - try { - const uncaughtException = new Promise(resolve => { - process.once('uncaughtException', resolve); - }); - expect(await w.webContents.executeJavaScript(`(${function () { - const { ipc } = process._linkedBinding('electron_renderer_ipc'); - return ipc.sendSync(true, 'GUEST_WINDOW_MANAGER_WINDOW_OPEN', ['', '', '']); - }})()`)).to.be.null(); - const exception = await uncaughtException; - expect(exception.message).to.match(/denied: expected native window\.open/); - } finally { - previousListeners.forEach(l => process.on('uncaughtException', l)); - } - }); }); describe('window.opener', () => { @@ -1047,31 +1015,21 @@ describe('chromium features', () => { const httpBlank = `${scheme}://origin1/blank`; const table = [ - { parent: fileBlank, child: httpUrl1, nodeIntegration: false, nativeWindowOpen: false, openerAccessible: false }, - { parent: fileBlank, child: httpUrl1, nodeIntegration: false, nativeWindowOpen: true, openerAccessible: false }, - { parent: fileBlank, child: httpUrl1, nodeIntegration: true, nativeWindowOpen: false, openerAccessible: true }, - { parent: fileBlank, child: httpUrl1, nodeIntegration: true, nativeWindowOpen: true, openerAccessible: false }, + { parent: fileBlank, child: httpUrl1, nodeIntegration: false, openerAccessible: false }, + { parent: fileBlank, child: httpUrl1, nodeIntegration: true, openerAccessible: false }, - { parent: httpBlank, child: fileUrl, nodeIntegration: false, nativeWindowOpen: false, openerAccessible: false }, - // {parent: httpBlank, child: fileUrl, nodeIntegration: false, nativeWindowOpen: true, openerAccessible: false}, // can't window.open() - { parent: httpBlank, child: fileUrl, nodeIntegration: true, nativeWindowOpen: false, openerAccessible: true }, - // {parent: httpBlank, child: fileUrl, nodeIntegration: true, nativeWindowOpen: true, openerAccessible: false}, // can't window.open() + // {parent: httpBlank, child: fileUrl, nodeIntegration: false, openerAccessible: false}, // can't window.open() + // {parent: httpBlank, child: fileUrl, nodeIntegration: true, openerAccessible: false}, // can't window.open() // NB. this is different from Chrome's behavior, which isolates file: urls from each other - { parent: fileBlank, child: fileUrl, nodeIntegration: false, nativeWindowOpen: false, openerAccessible: true }, - { parent: fileBlank, child: fileUrl, nodeIntegration: false, nativeWindowOpen: true, openerAccessible: true }, - { parent: fileBlank, child: fileUrl, nodeIntegration: true, nativeWindowOpen: false, openerAccessible: true }, - { parent: fileBlank, child: fileUrl, nodeIntegration: true, nativeWindowOpen: true, openerAccessible: true }, - - { parent: httpBlank, child: httpUrl1, nodeIntegration: false, nativeWindowOpen: false, openerAccessible: true }, - { parent: httpBlank, child: httpUrl1, nodeIntegration: false, nativeWindowOpen: true, openerAccessible: true }, - { parent: httpBlank, child: httpUrl1, nodeIntegration: true, nativeWindowOpen: false, openerAccessible: true }, - { parent: httpBlank, child: httpUrl1, nodeIntegration: true, nativeWindowOpen: true, openerAccessible: true }, - - { parent: httpBlank, child: httpUrl2, nodeIntegration: false, nativeWindowOpen: false, openerAccessible: false }, - { parent: httpBlank, child: httpUrl2, nodeIntegration: false, nativeWindowOpen: true, openerAccessible: false }, - { parent: httpBlank, child: httpUrl2, nodeIntegration: true, nativeWindowOpen: false, openerAccessible: true }, - { parent: httpBlank, child: httpUrl2, nodeIntegration: true, nativeWindowOpen: true, openerAccessible: false } + { parent: fileBlank, child: fileUrl, nodeIntegration: false, openerAccessible: true }, + { parent: fileBlank, child: fileUrl, nodeIntegration: true, openerAccessible: true }, + + { parent: httpBlank, child: httpUrl1, nodeIntegration: false, openerAccessible: true }, + { parent: httpBlank, child: httpUrl1, nodeIntegration: true, openerAccessible: true }, + + { parent: httpBlank, child: httpUrl2, nodeIntegration: false, openerAccessible: false }, + { parent: httpBlank, child: httpUrl2, nodeIntegration: true, openerAccessible: false } ]; const s = (url: string) => url.startsWith('file') ? 'file://...' : url; @@ -1090,11 +1048,11 @@ describe('chromium features', () => { afterEach(closeAllWindows); describe('when opened from main window', () => { - for (const { parent, child, nodeIntegration, nativeWindowOpen, openerAccessible } of table) { + for (const { parent, child, nodeIntegration, openerAccessible } of table) { for (const sandboxPopup of [false, true]) { - const description = `when parent=${s(parent)} opens child=${s(child)} with nodeIntegration=${nodeIntegration} nativeWindowOpen=${nativeWindowOpen} sandboxPopup=${sandboxPopup}, child should ${openerAccessible ? '' : 'not '}be able to access opener`; + const description = `when parent=${s(parent)} opens child=${s(child)} with nodeIntegration=${nodeIntegration} sandboxPopup=${sandboxPopup}, child should ${openerAccessible ? '' : 'not '}be able to access opener`; it(description, async () => { - const w = new BrowserWindow({ show: true, webPreferences: { nodeIntegration: true, nativeWindowOpen, contextIsolation: false } }); + const w = new BrowserWindow({ show: true, webPreferences: { nodeIntegration: true, contextIsolation: false } }); w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { @@ -1121,11 +1079,9 @@ describe('chromium features', () => { }); describe('when opened from ', () => { - for (const { parent, child, nodeIntegration, nativeWindowOpen, openerAccessible } of table) { - const description = `when parent=${s(parent)} opens child=${s(child)} with nodeIntegration=${nodeIntegration} nativeWindowOpen=${nativeWindowOpen}, child should ${openerAccessible ? '' : 'not '}be able to access opener`; - // WebView erroneously allows access to the parent window when nativeWindowOpen is false. - const skip = !nativeWindowOpen && !openerAccessible; - ifit(!skip)(description, async () => { + for (const { parent, child, nodeIntegration, openerAccessible } of table) { + const description = `when parent=${s(parent)} opens child=${s(child)} with nodeIntegration=${nodeIntegration}, child should ${openerAccessible ? '' : 'not '}be able to access opener`; + it(description, async () => { // This test involves three contexts: // 1. The root BrowserWindow in which the test is run, // 2. A belonging to the root window, @@ -1133,7 +1089,7 @@ describe('chromium features', () => { // We are testing whether context (3) can access context (2) under various conditions. // This is context (1), the base window for the test. - const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true, contextIsolation: false, nativeWindowOpen: false } }); + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true, contextIsolation: false } }); await w.loadURL('about:blank'); const parentCode = `new Promise((resolve) => { @@ -1147,7 +1103,7 @@ describe('chromium features', () => { // This is context (2), a WebView which will call window.open() const webview = new WebView() webview.setAttribute('nodeintegration', '${nodeIntegration ? 'on' : 'off'}') - webview.setAttribute('webpreferences', 'nativeWindowOpen=${nativeWindowOpen ? 'yes' : 'no'},contextIsolation=no') + webview.setAttribute('webpreferences', 'contextIsolation=no') webview.setAttribute('allowpopups', 'on') webview.src = ${JSON.stringify(parent + '?p=' + encodeURIComponent(child))} webview.addEventListener('dom-ready', async () => { diff --git a/spec/fixtures/api/new-window-preload.js b/spec-main/fixtures/api/new-window-preload.js similarity index 65% rename from spec/fixtures/api/new-window-preload.js rename to spec-main/fixtures/api/new-window-preload.js index b0f17aa20d622..090804a618b18 100644 --- a/spec/fixtures/api/new-window-preload.js +++ b/spec-main/fixtures/api/new-window-preload.js @@ -1,7 +1,6 @@ const { ipcRenderer, webFrame } = require('electron'); ipcRenderer.send('answer', { - nativeWindowOpen: webFrame.getWebPreference('nativeWindowOpen'), argv: process.argv }); window.close(); diff --git a/spec/fixtures/api/window-open-preload.js b/spec-main/fixtures/api/window-open-preload.js similarity index 84% rename from spec/fixtures/api/window-open-preload.js rename to spec-main/fixtures/api/window-open-preload.js index eb28b594af292..10c7c7085ed97 100644 --- a/spec/fixtures/api/window-open-preload.js +++ b/spec-main/fixtures/api/window-open-preload.js @@ -4,7 +4,6 @@ setImmediate(function () { if (window.location.toString() === 'bar://page/') { const windowOpenerIsNull = window.opener == null; ipcRenderer.send('answer', { - nativeWindowOpen: webFrame.getWebPreference('nativeWindowOpen'), nodeIntegration: webFrame.getWebPreference('nodeIntegration'), typeofProcess: typeof global.process, windowOpenerIsNull diff --git a/spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.js b/spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.js index 2032f096c11c0..b9cfe83aec46e 100644 --- a/spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.js +++ b/spec-main/fixtures/crash-cases/setimmediate-window-open-crash/index.js @@ -4,8 +4,7 @@ function createWindow () { const mainWindow = new BrowserWindow({ webPreferences: { nodeIntegration: true, - contextIsolation: false, - nativeWindowOpen: true + contextIsolation: false } }); diff --git a/spec-main/fixtures/snapshots/native-window-open.snapshot.txt b/spec-main/fixtures/snapshots/native-window-open.snapshot.txt index 83a7d9364ba95..fcc4a9885ef58 100644 --- a/spec-main/fixtures/snapshots/native-window-open.snapshot.txt +++ b/spec-main/fixtures/snapshots/native-window-open.snapshot.txt @@ -18,12 +18,10 @@ "y": 5, "webPreferences": { "contextIsolation": true, - "nativeWindowOpen": true, "nodeIntegration": false, "sandbox": true, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": null + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -52,12 +50,10 @@ "webPreferences": { "zoomFactor": "2", "contextIsolation": true, - "nativeWindowOpen": true, "nodeIntegration": false, "sandbox": true, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": null + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -83,12 +79,10 @@ "backgroundColor": "gray", "webPreferences": { "contextIsolation": true, - "nativeWindowOpen": true, "nodeIntegration": false, "sandbox": true, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": null + "nodeIntegrationInSubFrames": false }, "x": 100, "y": 100, @@ -118,12 +112,10 @@ "title": "sup", "webPreferences": { "contextIsolation": true, - "nativeWindowOpen": true, "nodeIntegration": false, "sandbox": true, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": null + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -152,12 +144,10 @@ "y": 1, "webPreferences": { "contextIsolation": true, - "nativeWindowOpen": true, "nodeIntegration": false, "sandbox": true, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": null + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -168,4 +158,4 @@ }, null ] -] \ No newline at end of file +] diff --git a/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt b/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt index 816d83ef0609c..b7ed882540099 100644 --- a/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt +++ b/spec-main/fixtures/snapshots/proxy-window-open.snapshot.txt @@ -22,8 +22,7 @@ "contextIsolation": true, "nodeIntegration": false, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": "placeholder-opener-id" + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -56,8 +55,7 @@ "contextIsolation": true, "nodeIntegration": false, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": "placeholder-opener-id" + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -87,8 +85,7 @@ "contextIsolation": true, "nodeIntegration": false, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": "placeholder-opener-id" + "nodeIntegrationInSubFrames": false }, "x": 100, "y": 100, @@ -122,8 +119,7 @@ "contextIsolation": true, "nodeIntegration": false, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": "placeholder-opener-id" + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -156,8 +152,7 @@ "contextIsolation": true, "nodeIntegration": false, "webviewTag": false, - "nodeIntegrationInSubFrames": false, - "openerId": "placeholder-opener-id" + "nodeIntegrationInSubFrames": false }, "webContents": "[WebContents]" }, @@ -168,4 +163,4 @@ }, null ] -] \ No newline at end of file +] diff --git a/spec-main/guest-window-manager-spec.ts b/spec-main/guest-window-manager-spec.ts index fe83906757004..7d802709c66f1 100644 --- a/spec-main/guest-window-manager-spec.ts +++ b/spec-main/guest-window-manager-spec.ts @@ -15,266 +15,220 @@ function genSnapshot (browserWindow: BrowserWindow, features: string) { } describe('new-window event', () => { - const testConfig = { - native: { - snapshotFileName: 'native-window-open.snapshot.txt', - browserWindowOptions: { - show: false, - width: 200, - title: 'cool', - backgroundColor: 'blue', - focusable: false, - webPreferences: { - nativeWindowOpen: true, - sandbox: true - } - } - }, - proxy: { - snapshotFileName: 'proxy-window-open.snapshot.txt', - browserWindowOptions: { - show: false, - webPreferences: { - nativeWindowOpen: false, - sandbox: false - } - } + const snapshotFileName = 'native-window-open.snapshot.txt'; + const browserWindowOptions = { + show: false, + width: 200, + title: 'cool', + backgroundColor: 'blue', + focusable: false, + webPreferences: { + sandbox: true } }; - for (const testName of Object.keys(testConfig) as (keyof typeof testConfig)[]) { - const { snapshotFileName, browserWindowOptions } = testConfig[testName]; + const snapshotFile = resolve(__dirname, 'fixtures', 'snapshots', snapshotFileName); + let browserWindow: BrowserWindow; + let existingSnapshots: any[]; - describe(`for ${testName} window opening`, () => { - const snapshotFile = resolve(__dirname, 'fixtures', 'snapshots', snapshotFileName); - let browserWindow: BrowserWindow; - let existingSnapshots: any[]; - - before(() => { - existingSnapshots = parseSnapshots(readFileSync(snapshotFile, { encoding: 'utf8' })); - }); - - beforeEach((done) => { - browserWindow = new BrowserWindow(browserWindowOptions); - browserWindow.loadURL('about:blank'); - browserWindow.on('ready-to-show', () => { done(); }); - }); + before(() => { + existingSnapshots = parseSnapshots(readFileSync(snapshotFile, { encoding: 'utf8' })); + }); - afterEach(closeAllWindows); - - const newSnapshots: any[] = []; - [ - 'top=5,left=10,resizable=no', - 'zoomFactor=2,resizable=0,x=0,y=10', - 'backgroundColor=gray,webPreferences=0,x=100,y=100', - 'x=50,y=20,title=sup', - 'show=false,top=1,left=1' - ].forEach((features, index) => { - /** - * ATTN: If this test is failing, you likely just need to change - * `shouldOverwriteSnapshot` to true and then evaluate the snapshot diff - * to see if the change is harmless. - */ - it(`matches snapshot for ${features}`, async () => { - const newSnapshot = await genSnapshot(browserWindow, features); - newSnapshots.push(newSnapshot); - // TODO: The output when these fail could be friendlier. - expect(stringifySnapshots(newSnapshot)).to.equal(stringifySnapshots(existingSnapshots[index])); - }); - }); + beforeEach((done) => { + browserWindow = new BrowserWindow(browserWindowOptions); + browserWindow.loadURL('about:blank'); + browserWindow.on('ready-to-show', () => { done(); }); + }); - after(() => { - const shouldOverwriteSnapshot = false; - if (shouldOverwriteSnapshot) writeFileSync(snapshotFile, stringifySnapshots(newSnapshots, true)); - }); + afterEach(closeAllWindows); + + const newSnapshots: any[] = []; + [ + 'top=5,left=10,resizable=no', + 'zoomFactor=2,resizable=0,x=0,y=10', + 'backgroundColor=gray,webPreferences=0,x=100,y=100', + 'x=50,y=20,title=sup', + 'show=false,top=1,left=1' + ].forEach((features, index) => { + /** + * ATTN: If this test is failing, you likely just need to change + * `shouldOverwriteSnapshot` to true and then evaluate the snapshot diff + * to see if the change is harmless. + */ + it(`matches snapshot for ${features}`, async () => { + const newSnapshot = await genSnapshot(browserWindow, features); + newSnapshots.push(newSnapshot); + // TODO: The output when these fail could be friendlier. + expect(stringifySnapshots(newSnapshot)).to.equal(stringifySnapshots(existingSnapshots[index])); }); - } + }); + + after(() => { + const shouldOverwriteSnapshot = false; + if (shouldOverwriteSnapshot) writeFileSync(snapshotFile, stringifySnapshots(newSnapshots, true)); + }); }); describe('webContents.setWindowOpenHandler', () => { - const testConfig = { - native: { - browserWindowOptions: { - show: false, - webPreferences: { - nativeWindowOpen: true - } - } - }, - proxy: { - browserWindowOptions: { - show: false, - webPreferences: { - nativeWindowOpen: false - } - } - } - }; + let browserWindow: BrowserWindow; + beforeEach(async () => { + browserWindow = new BrowserWindow({ show: false }); + await browserWindow.loadURL('about:blank'); + }); - for (const testName of Object.keys(testConfig) as (keyof typeof testConfig)[]) { - let browserWindow: BrowserWindow; - const { browserWindowOptions } = testConfig[testName]; + afterEach(closeAllWindows); - describe(testName, () => { - beforeEach(async () => { - browserWindow = new BrowserWindow(browserWindowOptions); - await browserWindow.loadURL('about:blank'); + it('does not fire window creation events if an override returns action: deny', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; }); + }); + browserWindow.webContents.on('new-window', () => { + assert.fail('new-window should not to be called with an overridden window.open'); + }); - afterEach(closeAllWindows); - - it('does not fire window creation events if an override returns action: deny', async () => { - const denied = new Promise((resolve) => { - browserWindow.webContents.setWindowOpenHandler(() => { - setTimeout(resolve); - return { action: 'deny' }; - }); - }); - browserWindow.webContents.on('new-window', () => { - assert.fail('new-window should not to be called with an overridden window.open'); - }); + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not to be called with an overridden window.open'); + }); - browserWindow.webContents.on('did-create-window', () => { - assert.fail('did-create-window should not to be called with an overridden window.open'); - }); + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); - browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + await denied; + }); - await denied; + it('is called when clicking on a target=_blank link', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; }); + }); + browserWindow.webContents.on('new-window', () => { + assert.fail('new-window should not to be called with an overridden window.open'); + }); - it('is called when clicking on a target=_blank link', async () => { - const denied = new Promise((resolve) => { - browserWindow.webContents.setWindowOpenHandler(() => { - setTimeout(resolve); - return { action: 'deny' }; - }); - }); - browserWindow.webContents.on('new-window', () => { - assert.fail('new-window should not to be called with an overridden window.open'); - }); - - browserWindow.webContents.on('did-create-window', () => { - assert.fail('did-create-window should not to be called with an overridden window.open'); - }); - - await browserWindow.webContents.loadURL('data:text/html,link'); - browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1 }); - browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1 }); - - await denied; - }); + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not to be called with an overridden window.open'); + }); - it('is called when shift-clicking on a link', async () => { - const denied = new Promise((resolve) => { - browserWindow.webContents.setWindowOpenHandler(() => { - setTimeout(resolve); - return { action: 'deny' }; - }); - }); - browserWindow.webContents.on('new-window', () => { - assert.fail('new-window should not to be called with an overridden window.open'); - }); - - browserWindow.webContents.on('did-create-window', () => { - assert.fail('did-create-window should not to be called with an overridden window.open'); - }); - - await browserWindow.webContents.loadURL('data:text/html,link'); - browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1, modifiers: ['shift'] }); - browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1, modifiers: ['shift'] }); - - await denied; - }); + await browserWindow.webContents.loadURL('data:text/html,link'); + browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1 }); + browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1 }); - it('fires handler with correct params', async () => { - const testFrameName = 'test-frame-name'; - const testFeatures = 'top=10&left=10&something-unknown&show=no'; - const testUrl = 'app://does-not-exist/'; - const details = await new Promise(resolve => { - browserWindow.webContents.setWindowOpenHandler((details) => { - setTimeout(() => resolve(details)); - return { action: 'deny' }; - }); - - browserWindow.webContents.executeJavaScript(`window.open('${testUrl}', '${testFrameName}', '${testFeatures}') && true`); - }); - const { url, frameName, features, disposition, referrer } = details; - expect(url).to.equal(testUrl); - expect(frameName).to.equal(testFrameName); - expect(features).to.equal(testFeatures); - expect(disposition).to.equal('new-window'); - expect(referrer).to.deep.equal({ - policy: 'strict-origin-when-cross-origin', - url: '' - }); - }); + await denied; + }); - it('includes post body', async () => { - const details = await new Promise(resolve => { - browserWindow.webContents.setWindowOpenHandler((details) => { - setTimeout(() => resolve(details)); - return { action: 'deny' }; - }); - - browserWindow.webContents.loadURL(`data:text/html,${encodeURIComponent(` -
- -
- - `)}`); - }); - const { url, frameName, features, disposition, referrer, postBody } = details; - expect(url).to.equal('http://example.com/'); - expect(frameName).to.equal(''); - expect(features).to.deep.equal(''); - expect(disposition).to.equal('foreground-tab'); - expect(referrer).to.deep.equal({ - policy: 'strict-origin-when-cross-origin', - url: '' - }); - expect(postBody).to.deep.equal({ - contentType: 'application/x-www-form-urlencoded', - data: [{ - type: 'rawData', - bytes: Buffer.from('key=value') - }] - }); + it('is called when shift-clicking on a link', async () => { + const denied = new Promise((resolve) => { + browserWindow.webContents.setWindowOpenHandler(() => { + setTimeout(resolve); + return { action: 'deny' }; }); + }); + browserWindow.webContents.on('new-window', () => { + assert.fail('new-window should not to be called with an overridden window.open'); + }); - it('does fire window creation events if an override returns action: allow', async () => { - browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + browserWindow.webContents.on('did-create-window', () => { + assert.fail('did-create-window should not to be called with an overridden window.open'); + }); - setImmediate(() => { - browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); - }); + await browserWindow.webContents.loadURL('data:text/html,link'); + browserWindow.webContents.sendInputEvent({ type: 'mouseDown', x: 10, y: 10, button: 'left', clickCount: 1, modifiers: ['shift'] }); + browserWindow.webContents.sendInputEvent({ type: 'mouseUp', x: 10, y: 10, button: 'left', clickCount: 1, modifiers: ['shift'] }); - await Promise.all([ - emittedOnce(browserWindow.webContents, 'did-create-window'), - emittedOnce(browserWindow.webContents, 'new-window') - ]); - }); + await denied; + }); - it('can change webPreferences of child windows', (done) => { - browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } })); + it('fires handler with correct params', async () => { + const testFrameName = 'test-frame-name'; + const testFeatures = 'top=10&left=10&something-unknown&show=no'; + const testUrl = 'app://does-not-exist/'; + const details = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler((details) => { + setTimeout(() => resolve(details)); + return { action: 'deny' }; + }); - browserWindow.webContents.on('did-create-window', async (childWindow) => { - await childWindow.webContents.executeJavaScript("document.write('hello')"); - const size = await childWindow.webContents.executeJavaScript("getComputedStyle(document.querySelector('body')).fontSize"); - expect(size).to.equal('30px'); - done(); - }); + browserWindow.webContents.executeJavaScript(`window.open('${testUrl}', '${testFrameName}', '${testFeatures}') && true`); + }); + const { url, frameName, features, disposition, referrer } = details; + expect(url).to.equal(testUrl); + expect(frameName).to.equal(testFrameName); + expect(features).to.equal(testFeatures); + expect(disposition).to.equal('new-window'); + expect(referrer).to.deep.equal({ + policy: 'strict-origin-when-cross-origin', + url: '' + }); + }); - browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + it('includes post body', async () => { + const details = await new Promise(resolve => { + browserWindow.webContents.setWindowOpenHandler((details) => { + setTimeout(() => resolve(details)); + return { action: 'deny' }; }); - it('does not hang parent window when denying window.open', async () => { - browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' })); - browserWindow.webContents.executeJavaScript("window.open('https://127.0.0.1')"); - expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42); - }); + browserWindow.webContents.loadURL(`data:text/html,${encodeURIComponent(` +
+ +
+ + `)}`); + }); + const { url, frameName, features, disposition, referrer, postBody } = details; + expect(url).to.equal('http://example.com/'); + expect(frameName).to.equal(''); + expect(features).to.deep.equal(''); + expect(disposition).to.equal('foreground-tab'); + expect(referrer).to.deep.equal({ + policy: 'strict-origin-when-cross-origin', + url: '' + }); + expect(postBody).to.deep.equal({ + contentType: 'application/x-www-form-urlencoded', + data: [{ + type: 'rawData', + bytes: Buffer.from('key=value') + }] }); - } + }); + + it('does fire window creation events if an override returns action: allow', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow' })); + + setImmediate(() => { + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + await Promise.all([ + emittedOnce(browserWindow.webContents, 'did-create-window'), + emittedOnce(browserWindow.webContents, 'new-window') + ]); + }); + + it('can change webPreferences of child windows', (done) => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { defaultFontSize: 30 } } })); + + browserWindow.webContents.on('did-create-window', async (childWindow) => { + await childWindow.webContents.executeJavaScript("document.write('hello')"); + const size = await childWindow.webContents.executeJavaScript("getComputedStyle(document.querySelector('body')).fontSize"); + expect(size).to.equal('30px'); + done(); + }); + + browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true"); + }); + + it('does not hang parent window when denying window.open', async () => { + browserWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' })); + browserWindow.webContents.executeJavaScript("window.open('https://127.0.0.1')"); + expect(await browserWindow.webContents.executeJavaScript('42')).to.equal(42); + }); }); function stringifySnapshots (snapshots: any, pretty = false) { @@ -282,9 +236,6 @@ function stringifySnapshots (snapshots: any, pretty = false) { if (['sender', 'webContents'].includes(key)) { return '[WebContents]'; } - if (key === 'openerId' && typeof value === 'number') { - return 'placeholder-opener-id'; - } if (key === 'processId' && typeof value === 'number') { return 'placeholder-process-id'; } @@ -296,8 +247,5 @@ function stringifySnapshots (snapshots: any, pretty = false) { } function parseSnapshots (snapshotsJson: string) { - return JSON.parse(snapshotsJson, (key, value) => { - if (key === 'openerId' && value === 'placeholder-opener-id') return 1; - return value; - }); + return JSON.parse(snapshotsJson); } diff --git a/spec-main/webview-spec.ts b/spec-main/webview-spec.ts index 99a8d4e8d1b0c..bcb05b7206904 100644 --- a/spec-main/webview-spec.ts +++ b/spec-main/webview-spec.ts @@ -503,7 +503,7 @@ describe(' tag', function () { }); }); - describe('nativeWindowOpen option', () => { + describe('child windows', () => { let w: BrowserWindow; beforeEach(async () => { w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true, contextIsolation: false } }); @@ -516,7 +516,7 @@ describe(' tag', function () { loadWebView(w.webContents, { allowpopups: 'on', nodeintegration: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}` }); @@ -529,7 +529,7 @@ describe(' tag', function () { loadWebView(w.webContents, { allowpopups: 'on', nodeintegration: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${path.join(fixtures, 'api', 'native-window-open-file.html')}` }); @@ -541,7 +541,7 @@ describe(' tag', function () { // Don't wait for loading to finish. loadWebView(w.webContents, { nodeintegration: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html')}` }); @@ -554,7 +554,7 @@ describe(' tag', function () { loadWebView(w.webContents, { allowpopups: 'on', nodeintegration: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}` }); @@ -570,7 +570,7 @@ describe(' tag', function () { const attributes = { allowpopups: 'on', nodeintegration: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${fixtures}/pages/window-open.html` }; const { url, frameName } = await w.webContents.executeJavaScript(` @@ -594,7 +594,7 @@ describe(' tag', function () { // Don't wait for loading to finish. loadWebView(w.webContents, { allowpopups: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${fixtures}/pages/window-open.html` }); @@ -607,7 +607,7 @@ describe(' tag', function () { loadWebView(w.webContents, { allowpopups: 'on', - webpreferences: 'nativeWindowOpen=1,contextIsolation=no', + webpreferences: 'contextIsolation=no', src: `file://${fixtures}/pages/window-open.html` }); @@ -617,7 +617,6 @@ describe(' tag', function () { it('does not crash when creating window with noopener', async () => { loadWebView(w.webContents, { allowpopups: 'on', - webpreferences: 'nativeWindowOpen=1', src: `file://${path.join(fixtures, 'api', 'native-window-open-noopener.html')}` }); await emittedOnce(app, 'browser-window-created'); diff --git a/spec/webview-spec.js b/spec/webview-spec.js index ebc5ecab387d4..3cff1700b72c1 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -490,7 +490,6 @@ describe(' tag', function () { generateSpecs('without sandbox'); generateSpecs('with sandbox', 'sandbox=yes'); - generateSpecs('with nativeWindowOpen', 'nativeWindowOpen=yes'); }); describe('webpreferences attribute', () => { diff --git a/typings/internal-ambient.d.ts b/typings/internal-ambient.d.ts index 2f1521a9df4d3..d0e6f8e0b2ba2 100644 --- a/typings/internal-ambient.d.ts +++ b/typings/internal-ambient.d.ts @@ -45,7 +45,6 @@ declare namespace NodeJS { deleteHiddenValue(obj: any, key: string): void; requestGarbageCollectionForTesting(): void; runUntilIdle(): void; - isSameOrigin(a: string, b: string): boolean; triggerFatalErrorForTesting(): void; } @@ -108,9 +107,7 @@ declare namespace NodeJS { interface InternalWebPreferences { isWebView: boolean; hiddenPage: boolean; - nativeWindowOpen: boolean; nodeIntegration: boolean; - openerId: number; preload: string preloadScripts: string[]; webviewTag: boolean; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 20135dd4ea11c..0a0ab49b8fbb2 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -96,7 +96,6 @@ declare namespace Electron { } interface WebPreferences { - openerId?: number | null; disablePopups?: boolean; preloadURL?: string; embedder?: Electron.WebContents;