refactor: use IPC helpers in window-setup (#17948)
This commit is contained in:
parent
c3ae476deb
commit
419ce494e9
7 changed files with 72 additions and 93 deletions
|
@ -35,7 +35,7 @@ Invokes the print dialog on the child window.
|
||||||
|
|
||||||
#### `win.postMessage(message, targetOrigin)`
|
#### `win.postMessage(message, targetOrigin)`
|
||||||
|
|
||||||
* `message` String
|
* `message` any
|
||||||
* `targetOrigin` String
|
* `targetOrigin` String
|
||||||
|
|
||||||
Sends a message to the child window with the specified origin or `*` for no
|
Sends a message to the child window with the specified origin or `*` for no
|
||||||
|
|
|
@ -166,7 +166,9 @@ auto_filenames = {
|
||||||
|
|
||||||
isolated_bundle_deps = [
|
isolated_bundle_deps = [
|
||||||
"lib/common/electron-binding-setup.ts",
|
"lib/common/electron-binding-setup.ts",
|
||||||
|
"lib/common/error-utils.js",
|
||||||
"lib/isolated_renderer/init.js",
|
"lib/isolated_renderer/init.js",
|
||||||
|
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||||
"lib/renderer/ipc-renderer-internal.ts",
|
"lib/renderer/ipc-renderer-internal.ts",
|
||||||
"lib/renderer/web-view/web-view-constants.ts",
|
"lib/renderer/web-view/web-view-constants.ts",
|
||||||
"lib/renderer/web-view/web-view-element.ts",
|
"lib/renderer/web-view/web-view-element.ts",
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
const { BrowserWindow, webContents } = require('electron')
|
const { BrowserWindow, webContents } = require('electron')
|
||||||
const { isSameOrigin } = process.electronBinding('v8_util')
|
const { isSameOrigin } = process.electronBinding('v8_util')
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
||||||
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
||||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
|
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
|
||||||
|
|
||||||
const hasProp = {}.hasOwnProperty
|
const hasProp = {}.hasOwnProperty
|
||||||
|
@ -153,6 +154,9 @@ const getGuestWindow = function (guestContents) {
|
||||||
guestWindow = BrowserWindow.fromWebContents(hostContents)
|
guestWindow = BrowserWindow.fromWebContents(hostContents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!guestWindow) {
|
||||||
|
throw new Error('getGuestWindow failed')
|
||||||
|
}
|
||||||
return guestWindow
|
return guestWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,53 +271,42 @@ ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN', functio
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestId) {
|
const handleMessage = function (channel, handler) {
|
||||||
const guestContents = webContents.fromId(guestId)
|
ipcMainUtils.handle(channel, (event, guestId, ...args) => {
|
||||||
if (guestContents == null) return
|
const guestContents = webContents.fromId(guestId)
|
||||||
|
if (!guestContents) {
|
||||||
|
throw new Error(`Invalid guestId: ${guestId}`)
|
||||||
|
}
|
||||||
|
|
||||||
if (!canAccessWindow(event.sender, guestContents)) {
|
return handler(event, guestContents, ...args)
|
||||||
console.error(`Blocked ${event.sender.getURL()} from closing its opener.`)
|
})
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const guestWindow = getGuestWindow(guestContents)
|
|
||||||
if (guestWindow != null) guestWindow.destroy()
|
|
||||||
})
|
|
||||||
|
|
||||||
const windowMethods = new Set([
|
const windowMethods = new Set([
|
||||||
|
'destroy',
|
||||||
'focus',
|
'focus',
|
||||||
'blur'
|
'blur'
|
||||||
])
|
])
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) {
|
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestContents, method, ...args) => {
|
||||||
const guestContents = webContents.fromId(guestId)
|
if (!canAccessWindow(event.sender, guestContents)) {
|
||||||
if (guestContents == null) {
|
console.error(`Blocked ${event.sender.getURL()} from accessing guestId: ${guestContents.id}`)
|
||||||
event.returnValue = null
|
throw new Error(`Access denied to guestId: ${guestContents.id}`)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canAccessWindow(event.sender, guestContents) || !windowMethods.has(method)) {
|
if (!windowMethods.has(method)) {
|
||||||
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
|
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`)
|
||||||
event.returnValue = null
|
throw new Error(`Invalid method: ${method}`)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const guestWindow = getGuestWindow(guestContents)
|
return getGuestWindow(guestContents)[method](...args)
|
||||||
if (guestWindow != null) {
|
|
||||||
event.returnValue = guestWindow[method](...args)
|
|
||||||
} else {
|
|
||||||
event.returnValue = null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, guestId, message, targetOrigin, sourceOrigin) {
|
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestContents, message, targetOrigin, sourceOrigin) => {
|
||||||
if (targetOrigin == null) {
|
if (targetOrigin == null) {
|
||||||
targetOrigin = '*'
|
targetOrigin = '*'
|
||||||
}
|
}
|
||||||
|
|
||||||
const guestContents = webContents.fromId(guestId)
|
|
||||||
if (guestContents == null) return
|
|
||||||
|
|
||||||
// The W3C does not seem to have word on how postMessage should work when the
|
// 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
|
// origins do not match, so we do not do |canAccessWindow| check here since
|
||||||
// postMessage across origins is useful and not harmful.
|
// postMessage across origins is useful and not harmful.
|
||||||
|
@ -324,37 +317,22 @@ ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function
|
||||||
})
|
})
|
||||||
|
|
||||||
const webContentsMethods = new Set([
|
const webContentsMethods = new Set([
|
||||||
'print',
|
|
||||||
'executeJavaScript'
|
|
||||||
])
|
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) {
|
|
||||||
const guestContents = webContents.fromId(guestId)
|
|
||||||
if (guestContents == null) return
|
|
||||||
|
|
||||||
if (canAccessWindow(event.sender, guestContents) && webContentsMethods.has(method)) {
|
|
||||||
guestContents[method](...args)
|
|
||||||
} else {
|
|
||||||
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const webContentsSyncMethods = new Set([
|
|
||||||
'getURL',
|
'getURL',
|
||||||
'loadURL'
|
'loadURL',
|
||||||
|
'executeJavaScript',
|
||||||
|
'print'
|
||||||
])
|
])
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (event, guestId, method, ...args) {
|
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestContents, method, ...args) => {
|
||||||
const guestContents = webContents.fromId(guestId)
|
if (!canAccessWindow(event.sender, guestContents)) {
|
||||||
if (guestContents == null) {
|
console.error(`Blocked ${event.sender.getURL()} from accessing guestId: ${guestContents.id}`)
|
||||||
event.returnValue = null
|
throw new Error(`Access denied to guestId: ${guestContents.id}`)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAccessWindow(event.sender, guestContents) && webContentsSyncMethods.has(method)) {
|
if (!webContentsMethods.has(method)) {
|
||||||
event.returnValue = guestContents[method](...args)
|
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`)
|
||||||
} else {
|
throw new Error(`Invalid method: ${method}`)
|
||||||
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
|
|
||||||
event.returnValue = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return guestContents[method](...args)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
||||||
|
|
||||||
// The history operation in renderer is redirected to browser.
|
// The history operation in renderer is redirected to browser.
|
||||||
ipcMainInternal.on('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK', function (event) {
|
ipcMainUtils.handle('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK', function (event) {
|
||||||
event.sender.goBack()
|
return event.sender.goBack()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD', function (event) {
|
ipcMainUtils.handle('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD', function (event) {
|
||||||
event.sender.goForward()
|
return event.sender.goForward()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', function (event, offset) {
|
ipcMainUtils.handle('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', function (event, offset) {
|
||||||
event.sender.goToOffset(offset)
|
return event.sender.goToOffset(offset)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMainInternal.on('ELECTRON_NAVIGATION_CONTROLLER_LENGTH', function (event) {
|
ipcMainUtils.handle('ELECTRON_NAVIGATION_CONTROLLER_LENGTH', function (event) {
|
||||||
event.returnValue = event.sender.length()
|
return event.sender.length()
|
||||||
})
|
})
|
||||||
|
|
||||||
// JavaScript implementation of Chromium's NavigationController.
|
// JavaScript implementation of Chromium's NavigationController.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'
|
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'
|
||||||
|
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'
|
||||||
|
|
||||||
// This file implements the following APIs:
|
// This file implements the following APIs:
|
||||||
// - window.history.back()
|
// - window.history.back()
|
||||||
|
@ -17,8 +18,6 @@ import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-in
|
||||||
// - document.hidden
|
// - document.hidden
|
||||||
// - document.visibilityState
|
// - document.visibilityState
|
||||||
|
|
||||||
const { defineProperty } = Object
|
|
||||||
|
|
||||||
// Helper function to resolve relative url.
|
// Helper function to resolve relative url.
|
||||||
const resolveURL = (url: string, base: string) => new URL(url, base).href
|
const resolveURL = (url: string, base: string) => new URL(url, base).href
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ class LocationProxy {
|
||||||
// It's right, that's bad, but we're doing it anway.
|
// It's right, that's bad, but we're doing it anway.
|
||||||
(guestURL as any)[propertyKey] = newVal
|
(guestURL as any)[propertyKey] = newVal
|
||||||
|
|
||||||
return this._invokeWebContentsMethodSync('loadURL', guestURL.toString())
|
return this._invokeWebContentsMethod('loadURL', guestURL.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -107,7 +106,7 @@ class LocationProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _invokeWebContentsMethodSync (method: string, ...args: any[]) {
|
private _invokeWebContentsMethodSync (method: string, ...args: any[]) {
|
||||||
return ipcRendererInternal.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, method, ...args)
|
return ipcRendererUtils.invokeSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, method, ...args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +124,7 @@ class BrowserWindowProxy {
|
||||||
}
|
}
|
||||||
public set location (url: string | any) {
|
public set location (url: string | any) {
|
||||||
url = resolveURL(url, this.location.href)
|
url = resolveURL(url, this.location.href)
|
||||||
this._invokeWebContentsMethodSync('loadURL', url)
|
this._invokeWebContentsMethod('loadURL', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (guestId: number) {
|
constructor (guestId: number) {
|
||||||
|
@ -139,7 +138,7 @@ class BrowserWindowProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
public close () {
|
public close () {
|
||||||
ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId)
|
this._invokeWindowMethod('destroy')
|
||||||
}
|
}
|
||||||
|
|
||||||
public focus () {
|
public focus () {
|
||||||
|
@ -154,8 +153,8 @@ class BrowserWindowProxy {
|
||||||
this._invokeWebContentsMethod('print')
|
this._invokeWebContentsMethod('print')
|
||||||
}
|
}
|
||||||
|
|
||||||
public postMessage (message: any, targetOrigin: any) {
|
public postMessage (message: any, targetOrigin: string) {
|
||||||
ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, toString(targetOrigin), window.location.origin)
|
ipcRendererUtils.invoke('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, toString(targetOrigin), window.location.origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
public eval (code: string) {
|
public eval (code: string) {
|
||||||
|
@ -163,15 +162,11 @@ class BrowserWindowProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _invokeWindowMethod (method: string, ...args: any[]) {
|
private _invokeWindowMethod (method: string, ...args: any[]) {
|
||||||
return ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, method, ...args)
|
return ipcRendererUtils.invoke('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, method, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
private _invokeWebContentsMethod (method: string, ...args: any[]) {
|
private _invokeWebContentsMethod (method: string, ...args: any[]) {
|
||||||
return ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, method, ...args)
|
return ipcRendererUtils.invoke('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, method, ...args)
|
||||||
}
|
|
||||||
|
|
||||||
private _invokeWebContentsMethodSync (method: string, ...args: any[]) {
|
|
||||||
return ipcRendererInternal.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, method, ...args)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,20 +224,20 @@ export const windowSetup = (
|
||||||
})
|
})
|
||||||
|
|
||||||
window.history.back = function () {
|
window.history.back = function () {
|
||||||
ipcRendererInternal.send('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK')
|
ipcRendererUtils.invoke('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK')
|
||||||
}
|
}
|
||||||
|
|
||||||
window.history.forward = function () {
|
window.history.forward = function () {
|
||||||
ipcRendererInternal.send('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD')
|
ipcRendererUtils.invoke('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD')
|
||||||
}
|
}
|
||||||
|
|
||||||
window.history.go = function (offset: number) {
|
window.history.go = function (offset: number) {
|
||||||
ipcRendererInternal.send('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', +offset)
|
ipcRendererUtils.invoke('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', +offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProperty(window.history, 'length', {
|
Object.defineProperty(window.history, 'length', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return ipcRendererInternal.sendSync('ELECTRON_NAVIGATION_CONTROLLER_LENGTH')
|
return ipcRendererUtils.invokeSync('ELECTRON_NAVIGATION_CONTROLLER_LENGTH')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -265,13 +260,13 @@ export const windowSetup = (
|
||||||
})
|
})
|
||||||
|
|
||||||
// Make document.hidden and document.visibilityState return the correct value.
|
// Make document.hidden and document.visibilityState return the correct value.
|
||||||
defineProperty(document, 'hidden', {
|
Object.defineProperty(document, 'hidden', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return cachedVisibilityState !== 'visible'
|
return cachedVisibilityState !== 'visible'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
defineProperty(document, 'visibilityState', {
|
Object.defineProperty(document, 'visibilityState', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return cachedVisibilityState
|
return cachedVisibilityState
|
||||||
}
|
}
|
||||||
|
|
|
@ -618,9 +618,9 @@ describe('chromium feature', () => {
|
||||||
w.close()
|
w.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does nothing when origin of current window does not match opener', (done) => {
|
it('fails when origin of current window does not match opener', (done) => {
|
||||||
listener = (event) => {
|
listener = (event) => {
|
||||||
expect(event.data).to.equal('')
|
expect(event.data).to.equal(null)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
window.addEventListener('message', listener)
|
window.addEventListener('message', listener)
|
||||||
|
@ -666,10 +666,10 @@ describe('chromium feature', () => {
|
||||||
if (webview != null) webview.remove()
|
if (webview != null) webview.remove()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does nothing when origin of webview src URL does not match opener', (done) => {
|
it('fails when origin of webview src URL does not match opener', (done) => {
|
||||||
webview = new WebView()
|
webview = new WebView()
|
||||||
webview.addEventListener('console-message', (e) => {
|
webview.addEventListener('console-message', (e) => {
|
||||||
expect(e.message).to.equal('')
|
expect(e.message).to.equal('null')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
webview.setAttribute('allowpopups', 'on')
|
webview.setAttribute('allowpopups', 'on')
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript" charset="utf-8">
|
<script type="text/javascript" charset="utf-8">
|
||||||
window.opener.postMessage(window.opener.location.href, '*')
|
try {
|
||||||
|
window.opener.postMessage(window.opener.location.href, '*')
|
||||||
|
} catch {
|
||||||
|
window.opener.postMessage(null, '*')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue