mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
fix: lost window.opener after cross-origin navigation (#18173)
* Get a site instance related to current one instead of creation a new one Using `GetRelatedSiteInstance` will keep the relation (same browsing instance) between the current and the new site instance. * Some relies on preloads in opened window The fact that, now, we always have an opener for opened windows diables note integration in opened windows, except if `nodeIntegrationInSubFrames` is enabled. * Add a test on window.opener after cross-orgin navigation * Make sure to unregisterProtocol in tests * Introduc and use a NetworkSandbox for tests * Modify tests about zoom persistence to properly simulate cross-origin navigation * Revert "Modify tests about zoom persistence to properly simulate cross-origin navigation" This reverts commit 0a7537f2eb7f183ddec16637e8a2e92a0d600321.
This commit is contained in:
committed by
Samuel Attard
parent
cec61d010b
commit
b4276835d8
@@ -9,6 +9,7 @@ const qs = require('querystring')
|
||||
const http = require('http')
|
||||
const { closeWindow } = require('./window-helpers')
|
||||
const { emittedOnce } = require('./events-helpers')
|
||||
const { createNetworkSandbox } = require('./network-helper')
|
||||
const { ipcRenderer, remote } = require('electron')
|
||||
const { app, ipcMain, BrowserWindow, BrowserView, protocol, session, screen, webContents } = remote
|
||||
|
||||
@@ -1997,17 +1998,29 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
|
||||
describe('nativeWindowOpen option', () => {
|
||||
beforeEach(() => {
|
||||
const networkSandbox = createNetworkSandbox(protocol)
|
||||
|
||||
beforeEach(async () => {
|
||||
// used to create cross-origin navigation situations
|
||||
await networkSandbox.serveFileFromProtocol('foo', path.join(fixtures, 'api', 'window-open-location-change.html'))
|
||||
await networkSandbox.serveFileFromProtocol('bar', path.join(fixtures, 'api', 'window-open-location-final.html'))
|
||||
|
||||
w.destroy()
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nativeWindowOpen: true
|
||||
nativeWindowOpen: true,
|
||||
// tests relies on preloads in opened windows
|
||||
nodeIntegrationInSubFrames: true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await networkSandbox.reset()
|
||||
})
|
||||
|
||||
it('opens window of about:blank with cross-scripting enabled', (done) => {
|
||||
ipcMain.once('answer', (event, content) => {
|
||||
expect(content).to.equal('Hello')
|
||||
@@ -2052,7 +2065,9 @@ describe('BrowserWindow module', () => {
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true
|
||||
nativeWindowOpen: true,
|
||||
// test relies on preloads in opened window
|
||||
nodeIntegrationInSubFrames: true
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2069,7 +2084,9 @@ describe('BrowserWindow module', () => {
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true
|
||||
nativeWindowOpen: true,
|
||||
// test relies on preloads in opened window
|
||||
nodeIntegrationInSubFrames: true
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2083,14 +2100,13 @@ describe('BrowserWindow module', () => {
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'))
|
||||
})
|
||||
it('retains the original web preferences when window.location is changed to a new origin', async () => {
|
||||
await serveFileFromProtocol('foo', path.join(fixtures, 'api', 'window-open-location-change.html'))
|
||||
await serveFileFromProtocol('bar', path.join(fixtures, 'api', 'window-open-location-final.html'))
|
||||
|
||||
w.destroy()
|
||||
w = new BrowserWindow({
|
||||
show: true,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true
|
||||
nativeWindowOpen: true,
|
||||
// test relies on preloads in opened window
|
||||
nodeIntegrationInSubFrames: true
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2103,7 +2119,33 @@ describe('BrowserWindow module', () => {
|
||||
expect(typeofProcess).to.eql('undefined')
|
||||
})
|
||||
|
||||
it('window.opener is not null when window.location is changed to a new origin', async () => {
|
||||
w.destroy()
|
||||
w = new BrowserWindow({
|
||||
show: true,
|
||||
webPreferences: {
|
||||
nativeWindowOpen: true,
|
||||
// test relies on preloads in opened window
|
||||
nodeIntegrationInSubFrames: true
|
||||
}
|
||||
})
|
||||
|
||||
ipcRenderer.send('set-web-preferences-on-next-new-window', w.webContents.id, 'preload', path.join(fixtures, 'api', 'window-open-preload.js'))
|
||||
const p = emittedOnce(ipcMain, 'answer')
|
||||
w.loadFile(path.join(fixtures, 'api', 'window-open-location-open.html'))
|
||||
const [, , , windowOpenerIsNull] = await p
|
||||
expect(windowOpenerIsNull).to.be.false('window.opener is null')
|
||||
})
|
||||
|
||||
it('should have nodeIntegration disabled in child windows', async () => {
|
||||
w.destroy()
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nativeWindowOpen: true
|
||||
}
|
||||
})
|
||||
const p = emittedOnce(ipcMain, 'answer')
|
||||
w.loadFile(path.join(fixtures, 'api', 'native-window-open-argv.html'))
|
||||
const [, typeofProcess] = await p
|
||||
@@ -3777,22 +3819,3 @@ const isScaleFactorRounding = () => {
|
||||
// Return true if scale factor is odd number above 2
|
||||
return scaleFactor > 2 && scaleFactor % 2 === 1
|
||||
}
|
||||
|
||||
function serveFileFromProtocol (protocolName, filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
protocol.registerBufferProtocol(protocolName, (request, callback) => {
|
||||
// Disabled due to false positive in StandardJS
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
callback({
|
||||
mimeType: 'text/html',
|
||||
data: fs.readFileSync(filePath)
|
||||
})
|
||||
}, (error) => {
|
||||
if (error != null) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
3
spec/fixtures/api/window-open-preload.js
vendored
3
spec/fixtures/api/window-open-preload.js
vendored
@@ -2,7 +2,8 @@ const { ipcRenderer } = require('electron')
|
||||
|
||||
setImmediate(function () {
|
||||
if (window.location.toString() === 'bar://page') {
|
||||
ipcRenderer.send('answer', process.argv, typeof global.process)
|
||||
const windowOpenerIsNull = window.opener == null
|
||||
ipcRenderer.send('answer', process.argv, typeof global.process, windowOpenerIsNull)
|
||||
window.close()
|
||||
}
|
||||
})
|
||||
|
||||
75
spec/network-helper.js
Normal file
75
spec/network-helper.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const fs = require('fs')
|
||||
|
||||
/**
|
||||
* Test sandbox environment used to fake network responses.
|
||||
*/
|
||||
class NetworkSandbox {
|
||||
constructor (protocol) {
|
||||
this.protocol = protocol
|
||||
this._resetFns = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the sandbox.
|
||||
*/
|
||||
async reset () {
|
||||
for (const resetFn of this._resetFns) {
|
||||
await resetFn()
|
||||
}
|
||||
this._resetFns = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Will serve the content of file at `filePath` to network requests towards
|
||||
* `protocolName` scheme.
|
||||
*
|
||||
* Example: `sandbox.serveFileFromProtocol('foo', 'index.html')` will serve the content
|
||||
* of 'index.html' to `foo://page` requests.
|
||||
*
|
||||
* @param {string} protocolName
|
||||
* @param {string} filePath
|
||||
*/
|
||||
serveFileFromProtocol (protocolName, filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.protocol.registerBufferProtocol(protocolName, (request, callback) => {
|
||||
// Disabled due to false positive in StandardJS
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
callback({
|
||||
mimeType: 'text/html',
|
||||
data: fs.readFileSync(filePath)
|
||||
})
|
||||
}, (error) => {
|
||||
if (error != null) {
|
||||
reject(error)
|
||||
} else {
|
||||
this._resetFns.push(() => this.unregisterProtocol(protocolName))
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
unregisterProtocol (protocolName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.protocol.unregisterProtocol(protocolName, (error) => {
|
||||
if (error != null) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will create a NetworkSandbox that uses
|
||||
* `protocol` as `Electron.Protocol`.
|
||||
*
|
||||
* @param {Electron.Protocol} protocol
|
||||
*/
|
||||
function createNetworkSandbox (protocol) {
|
||||
return new NetworkSandbox(protocol)
|
||||
}
|
||||
|
||||
exports.createNetworkSandbox = createNetworkSandbox
|
||||
Reference in New Issue
Block a user