1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-26 18:58:21 +02:00

Desktop: Security: Open more target="_blank" links in a browser (#11212)

This commit is contained in:
Henry Heino 2024-10-15 08:38:33 -07:00 committed by GitHub
parent 591c458a4f
commit 9d8cd1d707
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 76 additions and 50 deletions

View File

@ -5,7 +5,7 @@ import type ShimType from '@joplin/lib/shim';
const shim: typeof ShimType = require('@joplin/lib/shim').default;
import { isCallbackUrl } from '@joplin/lib/callbackUrlUtils';
import { BrowserWindow, Tray, screen } from 'electron';
import { BrowserWindow, Tray, WebContents, screen } from 'electron';
import bridge from './bridge';
const url = require('url');
const path = require('path');
@ -232,8 +232,9 @@ export default class ElectronAppWrapper {
}, 3000);
}
const addWindowEventHandlers = (webContents: WebContents) => {
// will-frame-navigate is fired by clicking on a link within the BrowserWindow.
this.win_.webContents.on('will-frame-navigate', event => {
webContents.on('will-frame-navigate', event => {
// If the link changes the URL of the browser window,
if (event.isMainFrame) {
event.preventDefault();
@ -241,6 +242,26 @@ export default class ElectronAppWrapper {
}
});
// Override calls to window.open and links with target="_blank": Open most in a browser instead
// of Electron:
webContents.setWindowOpenHandler((event) => {
if (event.url === 'about:blank') {
// Script-controlled pages: Used for opening notes in new windows
return {
action: 'allow',
};
} else if (event.url.match(/^https?:\/\//)) {
void bridge().openExternal(event.url);
}
return { action: 'deny' };
});
webContents.on('did-create-window', (event) => {
addWindowEventHandlers(event.webContents);
});
};
addWindowEventHandlers(this.win_.webContents);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
this.win_.on('close', (event: any) => {
// If it's on macOS, the app is completely closed only if the user chooses to close the app (willQuitApp_ will be true)

View File

@ -136,7 +136,8 @@ test.describe('main', () => {
expect(fullSize[0] / resizedSize[0]).toBeCloseTo(fullSize[1] / resizedSize[1]);
});
test('clicking on an external link should try to launch a browser', async ({ electronApp, mainWindow }) => {
for (const target of ['', '_blank']) {
test(`clicking on an external link with target=${JSON.stringify(target)} should try to launch a browser`, async ({ electronApp, mainWindow }) => {
const mainScreen = new MainScreen(mainWindow);
await mainScreen.waitFor();
@ -154,7 +155,7 @@ test.describe('main', () => {
const testLinkTitle = 'This is a test link!';
const linkHref = 'https://joplinapp.org/';
await mainWindow.evaluate(({ testLinkTitle, linkHref }) => {
await mainWindow.evaluate(({ testLinkTitle, linkHref, target }) => {
const testLink = document.createElement('a');
testLink.textContent = testLinkTitle;
testLink.onclick = () => {
@ -170,9 +171,12 @@ test.describe('main', () => {
testLink.style.position = 'fixed';
testLink.style.top = '0';
testLink.style.left = '0';
if (target) {
testLink.target = target;
}
document.body.appendChild(testLink);
}, { testLinkTitle, linkHref });
}, { testLinkTitle, linkHref, target });
const testLink = mainWindow.getByText(testLinkTitle);
await expect(testLink).toBeVisible();
@ -180,6 +184,7 @@ test.describe('main', () => {
expect(await nextExternalUrlPromise).toBe(linkHref);
});
}
test('should start in safe mode if profile-dir/force-safe-mode-on-next-start exists', async ({ profileDirectory }) => {
await writeFile(join(profileDirectory, 'force-safe-mode-on-next-start'), 'true', 'utf8');