Skip to content

Commit

Permalink
fix: crash when setWindowOpenHandler callback throws (#34523)
Browse files Browse the repository at this point in the history
  • Loading branch information
codebytere authored and miniak committed Jun 19, 2022
1 parent 4f70332 commit e953380
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 8 deletions.
18 changes: 16 additions & 2 deletions lib/browser/api/web-contents.ts
Expand Up @@ -500,6 +500,7 @@ WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event,
if (!this._windowOpenHandler) {
return null;
}

const response = this._windowOpenHandler(details);

if (typeof response !== 'object') {
Expand Down Expand Up @@ -656,7 +657,13 @@ WebContents.prototype._init = function () {
postBody,
disposition
};
const options = this._callWindowOpenHandler(event, details);
let options: ReturnType<typeof this._callWindowOpenHandler>;
try {
options = this._callWindowOpenHandler(event, details);
} catch (err) {
event.preventDefault();
throw err;
}
if (!event.defaultPrevented) {
openGuestWindow({
event,
Expand Down Expand Up @@ -684,7 +691,14 @@ WebContents.prototype._init = function () {
referrer,
postBody
};
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
let result: ReturnType<typeof this._callWindowOpenHandler>;
try {
result = this._callWindowOpenHandler(event, details);
} catch (err) {
event.preventDefault();
throw err;
}
windowOpenOverriddenOptions = result;
if (!event.defaultPrevented) {
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
// Allow setting of backgroundColor as a webPreference even though
Expand Down
64 changes: 58 additions & 6 deletions spec-main/guest-window-manager-spec.ts
Expand Up @@ -79,6 +79,58 @@ describe('webContents.setWindowOpenHandler', () => {

afterEach(closeAllWindows);

it('does not fire window creation events if the handler callback throws an error', (done) => {
const error = new Error('oh no');
const listeners = process.listeners('uncaughtException');
process.removeAllListeners('uncaughtException');
process.on('uncaughtException', (thrown) => {
try {
expect(thrown).to.equal(error);
done();
} catch (e) {
done(e);
} finally {
process.removeAllListeners('uncaughtException');
listeners.forEach((listener) => process.on('uncaughtException', listener));
}
});

browserWindow.webContents.on('new-window', () => {
assert.fail('new-window should not be called with an overridden window.open');
});

browserWindow.webContents.on('did-create-window', () => {
assert.fail('did-create-window should not be called with an overridden window.open');
});

browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");

browserWindow.webContents.setWindowOpenHandler(() => {
throw error;
});
});

it('does not fire window creation events if the handler callback returns a bad result', async () => {
const bad = new Promise((resolve) => {
browserWindow.webContents.setWindowOpenHandler(() => {
setTimeout(resolve);
return [1, 2, 3] as any;
});
});

browserWindow.webContents.on('new-window', () => {
assert.fail('new-window should not be called with an overridden window.open');
});

browserWindow.webContents.on('did-create-window', () => {
assert.fail('did-create-window should not be called with an overridden window.open');
});

browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");

await bad;
});

it('does not fire window creation events if an override returns action: deny', async () => {
const denied = new Promise((resolve) => {
browserWindow.webContents.setWindowOpenHandler(() => {
Expand All @@ -87,11 +139,11 @@ describe('webContents.setWindowOpenHandler', () => {
});
});
browserWindow.webContents.on('new-window', () => {
assert.fail('new-window should not to be called with an overridden window.open');
assert.fail('new-window should not 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');
assert.fail('did-create-window should not be called with an overridden window.open');
});

browserWindow.webContents.executeJavaScript("window.open('about:blank', '', 'show=no') && true");
Expand All @@ -107,11 +159,11 @@ describe('webContents.setWindowOpenHandler', () => {
});
});
browserWindow.webContents.on('new-window', () => {
assert.fail('new-window should not to be called with an overridden window.open');
assert.fail('new-window should not 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');
assert.fail('did-create-window should not be called with an overridden window.open');
});

await browserWindow.webContents.loadURL('data:text/html,<a target="_blank" href="http://example.com" style="display: block; width: 100%; height: 100%; position: fixed; left: 0; top: 0;">link</a>');
Expand All @@ -129,11 +181,11 @@ describe('webContents.setWindowOpenHandler', () => {
});
});
browserWindow.webContents.on('new-window', () => {
assert.fail('new-window should not to be called with an overridden window.open');
assert.fail('new-window should not 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');
assert.fail('did-create-window should not be called with an overridden window.open');
});

await browserWindow.webContents.loadURL('data:text/html,<a href="http://example.com" style="display: block; width: 100%; height: 100%; position: fixed; left: 0; top: 0;">link</a>');
Expand Down

0 comments on commit e953380

Please sign in to comment.