8000 feat: add webContents.setWindowOpenHandler API by loc · Pull Request #24517 · electron/electron · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: add webContents.setWindowOpenHandler API #24517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
1dad4d7
convert guest-window-manager to typescript
loc Apr 23, 2020
4cd6d0d
break out guest-window-proxy
loc Apr 23, 2020
a25ca69
docs: describe new methods for opening windows from the renderer
loc Jul 10, 2020
ac39d24
test: add test for setWindowOpenOverride
loc Jul 10, 2020
f7296ed
feat: add webContents.setWindowOpenOverride API
loc Jul 10, 2020
61db4d6
test: update tests to use setWindowOpenOverride
loc Jul 10, 2020
509926e
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Jul 10, 2020
ddf63cd
fixup! feat: add webContents.setWindowOpenOverride API
loc Jul 10, 2020
279db05
docs: describe new method
loc Jul 20, 2020
2d2e88b
add miscellaneous types and docs from initial review
loc Jul 20, 2020
28c0180
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Jul 21, 2020
ab954be
fix lint
loc Jul 21, 2020
c8e05fa
fixup! add miscellaneous types and docs from initial review
loc Jul 21, 2020
c74a539
test: update new-window snapshots
8000 loc Jul 22, 2020
34d5aee
test: adjust tests for new behavior
loc Jul 22, 2020
202a97b
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Jul 22, 2020
7e56af6
make sure webviews can read the new webPreferences in the renderer
loc Jul 28, 2020
a32c704
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Jul 28, 2020
1227ef5
fix file path string type for windows
loc Jul 28, 2020
ee974ba
include raw features string in the window.open override handler
loc Sep 10, 2020
72fee07
consolodate duplicate patching in can_create_window
loc Oct 1, 2020
eb7ecbd
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Oct 1, 2020
ae23fb5
incorporate master changes
loc Oct 6, 2020
04b3022
ensure child webcontents get inherited preferences when not overridden
loc Oct 6, 2020
c451940
use v8::Global rather than converting from v8 -> base::Value -> v8
loc Oct 7, 2020
7b8939b
setWindowOpenOverride -> setWindowOpenHandler
loc Oct 7, 2020
feef054
Merge commit 'e1a19d7^' into in-process-web-prefs
loc Oct 7, 2020
236eebf
Merge commit 'e1a19d7' into in-process-web-prefs
loc Oct 7, 2020
8a73ffa
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Oct 7, 2020
858a3e7
add missing file path header
loc Oct 7, 2020
c2ac175
specify content:: namespace
loc Oct 7, 2020
6779b64
fixup! setWindowOpenOverride -> setWindowOpenHandler
loc Oct 7, 2020
71b2ae1
update test and documentation
loc Oct 8, 2020
dddbd19
cleanup overwritten patches
loc Oct 8, 2020
2cbc9bd
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
loc Oct 8, 2020
7df53d4
fix types
loc Oct 8, 2020
ee0de13
Apply documentation suggestions
loc Oct 8, 2020
74e28ee
adding documentation to webcontents delegate handlers
loc Oct 8, 2020
25caa3a
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
nornagon Oct 14, 2020
52e217c
whoops, fix postmessage
nornagon Oct 15, 2020
a0b7221
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
nornagon Oct 19, 2020
56ba531
fix build on windows
nornagon Oct 20, 2020
8337737
review comment
nornagon Oct 20, 2020
bfc7ba4
move windowOpenOverriddenOptions reset sooner
nornagon Oct 21, 2020
c3ed64c
some comments
nornagon Oct 21, 2020
3323d98
check for null in window open handler response
nornagon Oct 21, 2020
c90193b
Merge branch 'master' into in-process-web-prefs
nornagon Oct 22, 2020
847af20
preloads is a vector, not a joined string
nornagon Oct 22, 2020
99dab99
change api to return action object
nornagon Oct 23, 2020
871b5c4
bump docs-parser to 0.10.1
nornagon Oct 26, 2020
83ed201
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
nornagon Oct 26, 2020
c6077f5
catch webcontents destroyed on loadURL promise
nornagon Oct 26, 2020
d3f7226
fix test timeout when window.open disallowed
nornagon Oct 27, 2020
a36d544
Merge remote-tracking branch 'origin/master' into in-process-web-prefs
nornagon Oct 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@typescript-eslint/no-unused-vars": ["error", {
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": false
"ignoreRestSiblings": true
}],
"prefer-const": ["error", {
"destructuring": "all"
Expand Down
53 changes: 52 additions & 1 deletion docs/api/web-contents.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Returns:

Emitted when page receives favicon urls.

F438 #### Event: 'new-window'
#### Event: 'new-window' _Deprecated_

Returns:

Expand All @@ -155,6 +155,8 @@ Returns:
be set. If no post data is to be sent, the value will be `null`. Only defined
when the window is being created by a form that set `target=_blank`.

Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).

Emitted when the page requests to open a new window for a `url`. It could be
requested by `window.open` or an external link like `<a target='_blank'>`.

Expand Down Expand Up @@ -189,6 +191,39 @@ myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition
})
```

#### Event: 'did-create-window'

Returns:
* `window` BrowserWindow
* `details` Object
* `url` String - URL for the created window.
* `frameName` String - Name given to the created window in the
`window.open()` call.
* `options` BrowserWindowConstructorOptions - The options used to create the
BrowserWindow. They are merged in increasing precedence: options inherited
from the parent, parsed options from the `features` string from
`window.open()`, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Unrecognized options are not filtered out.
* `additionalFeatures` String[] - The non-standard features (features not
handled Chromium or Electron) _Deprecated_
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
passed to the new window. May or may not result in the `Referer` header
being sent, depending on the referrer policy.
* `postBody` [PostBody](structures/post-body.md) (optional) - The post data
that will be sent to the new window, along with the appropriate headers
that will be set. If no post data is to be sent, the value will be `null`.
Only defined when the window is being created by a form that set
`target=_blank`.
* `disposition` String - Can be `default`, `foreground-tab`,
`background-tab`, `new-window`, `save-to-disk` and `other`.

Emitted _after_ successful creation of a window via `window.open` in the renderer.
Not emitted if the creation of the window is canceled from
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).

See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `webContents.setWindowOpenHandler`.

#### Event: 'will-navigate'

Returns:
Expand Down Expand Up @@ -1122,6 +1157,22 @@ Works like `executeJavaScript` but evaluates `scripts` in an isolated context.

Ignore application menu shortcuts while this web contents is focused.

#### `contents.setWindowOpenHandler(handler)`

* `handler` Function<{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
* `details` Object
* `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
* `frameName` String - Name of the window provided in `window.open()`
* `features` String - Comma separated list of window features provided to `window.open()`.
Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
Returning an unrecognized value such as a null, undefined, or an object
without a recognized 'action' value will result in a console error and have
the same effect as returning `{action: 'deny'}`.

Called before creating a window when `window.open()` is called from the
renderer. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`.

#### `contents.setAudioMuted(muted)`

* `muted` Boolean
Expand Down
144 changes: 90 additions & 54 deletions docs/api/window-open.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
# `window.open` Function

> Open a new window and load a URL.

When `window.open` is called to create a new window in a web page, a new instance
of [`BrowserWindow`](browser-window.md) will be created for the `url` and a proxy will be returned
to `window.open` to let the page have limited control over it.

The proxy has limited standard functionality implemented to be
compatible with traditional web pages. For full control of the new window
you should create a `BrowserWindow` directly.

The newly created `BrowserWindow` will inherit the parent window's options by
default. To override inherited options you can set them in the `features`
string.
# Opening windows from the renderer

There are several ways to control how windows are created from trusted or
untrusted content within a renderer. Windows can be created from the renderer in two ways:

- clicking on links or submitting forms adorned with `target=_blank`
- JavaScript calling `window.open()`

In non-sandboxed renderers, or when `nativeWindowOpen` is false (the default), this results in the creation of a
[`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper around
`BrowserWindow`.

However, when the `sandbox` (or directly, `nativeWindowOpen`) option is set, a
`Window` instance is created, as you'd expect in the browser. For same-origin
content, the new window is created within the same process, enabling the parent
to access the child window directly. This can be very 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.

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()`
for renderer-created windows.

BrowserWindow constructor options are set by, in increasing precedence
order: options inherited from the parent, parsed options
from the `features` string from `window.open()`, security-related webPreferences
inherited from the parent, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Note that `webContents.setWindowOpenHandler` has final say and full privilege
because it is invoked in the main process.

### `window.open(url[, frameName][, features])`

* `url` String
* `frameName` String (optional)
* `features` String (optional)

Returns [`BrowserWindowProxy`](browser-window-proxy.md) - Creates a new window
and returns an instance of `BrowserWindowProxy` class.
Returns [`BrowserWindowProxy`](browser-window-proxy.md) | [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window)

The `features` string follows the format of standard browser, but each feature
has to be a field of `BrowserWindow`'s options. These are the features you can set via `features` string: `zoomFactor`, `nodeIntegration`, `preload`, `javascript`, `contextIsolation`, `webviewTag`.
`features` is a comma-separated key-value list, following the standard format of
the browser. Electron will parse `BrowserWindowConstructorOptions` out of this
list where possible, for convenience. For full control and better ergonomics,
consider using `webContents.setWindowOpenHandler` to customize the
BrowserWindow creation.

A subset of `WebPreferences` can be set directly,
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`,
`javascript`, `contextIsolation`, and `webviewTag`.

For example:
```js
window.open('https://github.com', '_blank', 'nodeIntegration=no')
window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIntegration=no')
```

**Notes:**
Expand All @@ -40,60 +62,74 @@ window.open('https://github.com', '_blank', 'nodeIntegration=no')
* JavaScript will always be disabled in the opened `window` if it is disabled on
the parent window.
* Non-standard features (that are not handled by Chromium or Electron) given in
`features` will be passed to any registered `webContent`'s `new-window` event
handler in the `additionalFeatures` argument.

### `window.opener.postMessage(message, targetOrigin)`
`features` will be passed to any registered `webContents`'s
`did-create-window` event handler in the `additionalFeatures` argument.

* `message` String
* `targetOrigin` String
To customize or cancel the creation of the window, you can optionally set an
override handler with CEB7 `webContents.setWindowOpenHandler()` from the main
process. Returning `false` cancels the window, while returning an object sets
the `BrowserWindowConstructorOptions` used when creating the window. Note that
this is more powerful than passing options through the feature string, as the
renderer has more limited privileges in deciding security preferences than the
main process.

Sends a message to the parent window with the specified origin or `*` for no
origin preference.
### `BrowserWindowProxy` example

### Using Chrome's `window.open()` implementation
```javascript

If you want to use Chrome's built-in `window.open()` implementation, set
`nativeWindowOpen` to `true` in the `webPreferences` options object.
// main.js
const mainWindow = new BrowserWindow()

Native `window.open()` allows synchronous access to opened windows so it is
convenient choice if you need to open a dialog or a preferences window.
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https://github.com/')) {
return true
}
return false
})

This option can also be set on `<webview>` tags as well:
mainWindow.webContents.on('did-create-window', (childWindow) => {
// For example...
childWindow.webContents('will-navigate', (e) => {
e.preventDefault()
})
})
```

```html
<webview webpreferences="nativeWindowOpen=yes"></webview>
```javascript
// renderer.js
const windowProxy = window.open('https://github.com/', null, 'minimizable=false')
windowProxy.postMessage('hi', '*')
```

The creation of the `BrowserWindow` is customizable via `WebContents`'s
`new-window` event.
### Native `Window` example

```javascript
// main process
// main.js
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nativeWindowOpen: true
}
})
mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
if (frameName === 'modal') {
// open window as modal
event.preventDefault()
Object.assign(options, {
modal: true,
parent: mainWindow,
width: 100,
height: 100
})
event.newGuest = new BrowserWindow(options)

// In this example, only windows with the `about:blank` url will be created.
// All other urls will be blocked.
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url === 'about:blank') {
return {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
}
}
}
return false
})
```

```javascript
// renderer process (mainWindow)
const modal = window.open('', 'modal')
modal.document.write('<h1>Hello</h1>')
const childWindow = window.open('', 'modal')
childWindow.document.write('<h1>Hello</h1>')
```
25 changes: 16 additions & 9 deletions docs/tutorial/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -620,22 +620,29 @@ windows at runtime.

### How?

[`webContents`][web-contents] will emit the [`new-window`][new-window] event
before creating new windows. That event will be passed, amongst other
parameters, the `url` the window was requested to open and the options used to
create it. We recommend that you use the event to scrutinize the creation of
windows, limiting it to only what you need.
[`webContents`][web-contents] will delegate to its [window open
handler][window-open-handler] before creating new windows. The handler will
receive, amongst other parameters, the `url` the window was requested to open
and the options used to create it. We recommend that you register a handler to
monitor the creation of windows, and deny any unexpected window creation.

```js
const { shell } = require('electron')

app.on('web-contents-created', (event, contents) => {
contents.on('new-window', async (event, navigationUrl) => {
contents.setWindowOpenHandler(({ url }) => {
// In this example, we'll ask the operating system
// to open this event's url in the default browser.
event.preventDefault()
//
// See the following item for considerations regarding what
// URLs should be allowed through to shell.openExternal.
if (isSafeForExternalOpen(url)) {
setImmediate(() => {
shell.openExternal(url)
})
}

await shell.openExternal(navigationUrl)
return { action: 'deny' }
})
})
```
Expand Down Expand Up @@ -812,7 +819,7 @@ which potential security issues are not as widely known.
[browser-view]: ../api/browser-view.md
[webview-tag]: ../api/webview-tag.md
[web-contents]: ../api/web-contents.md
[new-window]: ../api/web-contents.md#event-new-window
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandler-handler
[will-navigate]: ../api/web-contents.md#event-will-navigate
[open-external]: ../api/shell.md#shellopenexternalurl-options
[sandbox]: ../api/sandbox-option.md
Expand Down
1 change: 1 addition & 0 deletions filenames.auto.gni
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ 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",
Expand Down
Loading
0