mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-11 18:24:43 +02:00
Desktop: Security: Open more target="_blank" links in a browser (#11212)
This commit is contained in:
parent
591c458a4f
commit
9d8cd1d707
@ -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,14 +232,35 @@ export default class ElectronAppWrapper {
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// will-frame-navigate is fired by clicking on a link within the BrowserWindow.
|
||||
this.win_.webContents.on('will-frame-navigate', event => {
|
||||
// If the link changes the URL of the browser window,
|
||||
if (event.isMainFrame) {
|
||||
event.preventDefault();
|
||||
void bridge().openExternal(event.url);
|
||||
}
|
||||
});
|
||||
const addWindowEventHandlers = (webContents: WebContents) => {
|
||||
// will-frame-navigate is fired by clicking on a link within the BrowserWindow.
|
||||
webContents.on('will-frame-navigate', event => {
|
||||
// If the link changes the URL of the browser window,
|
||||
if (event.isMainFrame) {
|
||||
event.preventDefault();
|
||||
void bridge().openExternal(event.url);
|
||||
}
|
||||
});
|
||||
|
||||
// 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) => {
|
||||
|
@ -136,50 +136,55 @@ 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 }) => {
|
||||
const mainScreen = new MainScreen(mainWindow);
|
||||
await mainScreen.waitFor();
|
||||
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();
|
||||
|
||||
// Mock openExternal
|
||||
const nextExternalUrlPromise = electronApp.evaluate(({ shell }) => {
|
||||
return new Promise<string>(resolve => {
|
||||
const openExternal = async (url: string) => {
|
||||
resolve(url);
|
||||
};
|
||||
shell.openExternal = openExternal;
|
||||
// Mock openExternal
|
||||
const nextExternalUrlPromise = electronApp.evaluate(({ shell }) => {
|
||||
return new Promise<string>(resolve => {
|
||||
const openExternal = async (url: string) => {
|
||||
resolve(url);
|
||||
};
|
||||
shell.openExternal = openExternal;
|
||||
});
|
||||
});
|
||||
|
||||
// Create a test link
|
||||
const testLinkTitle = 'This is a test link!';
|
||||
const linkHref = 'https://joplinapp.org/';
|
||||
|
||||
await mainWindow.evaluate(({ testLinkTitle, linkHref, target }) => {
|
||||
const testLink = document.createElement('a');
|
||||
testLink.textContent = testLinkTitle;
|
||||
testLink.onclick = () => {
|
||||
// We need to navigate by setting location.href -- clicking on a link
|
||||
// directly within the main window (i.e. not in a PDF viewer) doesn't
|
||||
// navigate.
|
||||
location.href = linkHref;
|
||||
};
|
||||
testLink.href = '#';
|
||||
|
||||
// Display on top of everything
|
||||
testLink.style.zIndex = '99999';
|
||||
testLink.style.position = 'fixed';
|
||||
testLink.style.top = '0';
|
||||
testLink.style.left = '0';
|
||||
if (target) {
|
||||
testLink.target = target;
|
||||
}
|
||||
|
||||
document.body.appendChild(testLink);
|
||||
}, { testLinkTitle, linkHref, target });
|
||||
|
||||
const testLink = mainWindow.getByText(testLinkTitle);
|
||||
await expect(testLink).toBeVisible();
|
||||
await testLink.click({ noWaitAfter: true });
|
||||
|
||||
expect(await nextExternalUrlPromise).toBe(linkHref);
|
||||
});
|
||||
|
||||
// Create a test link
|
||||
const testLinkTitle = 'This is a test link!';
|
||||
const linkHref = 'https://joplinapp.org/';
|
||||
|
||||
await mainWindow.evaluate(({ testLinkTitle, linkHref }) => {
|
||||
const testLink = document.createElement('a');
|
||||
testLink.textContent = testLinkTitle;
|
||||
testLink.onclick = () => {
|
||||
// We need to navigate by setting location.href -- clicking on a link
|
||||
// directly within the main window (i.e. not in a PDF viewer) doesn't
|
||||
// navigate.
|
||||
location.href = linkHref;
|
||||
};
|
||||
testLink.href = '#';
|
||||
|
||||
// Display on top of everything
|
||||
testLink.style.zIndex = '99999';
|
||||
testLink.style.position = 'fixed';
|
||||
testLink.style.top = '0';
|
||||
testLink.style.left = '0';
|
||||
|
||||
document.body.appendChild(testLink);
|
||||
}, { testLinkTitle, linkHref });
|
||||
|
||||
const testLink = mainWindow.getByText(testLinkTitle);
|
||||
await expect(testLink).toBeVisible();
|
||||
await testLink.click({ noWaitAfter: true });
|
||||
|
||||
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');
|
||||
|
Loading…
Reference in New Issue
Block a user