Electron: Disable navigation to external URLs (#3965)

This commit is contained in:
Alexander Zinchuk 2023-12-12 12:34:18 +01:00
parent 066cd6960b
commit b901ce82a7
3 changed files with 55 additions and 9 deletions

View File

@ -1,17 +1,39 @@
import { getLastWindow } from './utils';
import { checkIsWebContentsUrlAllowed, getLastWindow } from './utils';
let localStorage: Record<string, any> | undefined;
export async function captureLocalStorage(): Promise<void> {
localStorage = await (getLastWindow())?.webContents.executeJavaScript('({ ...localStorage });');
}
const lastWindow = getLastWindow();
export async function restoreLocalStorage(): Promise<void> {
if (!localStorage) {
if (!lastWindow) {
return;
}
await getLastWindow()?.webContents.executeJavaScript(
const contents = lastWindow.webContents;
const contentsUrl = contents.getURL();
if (!checkIsWebContentsUrlAllowed(contentsUrl)) {
return;
}
localStorage = await contents.executeJavaScript('({ ...localStorage });');
}
export async function restoreLocalStorage(): Promise<void> {
const lastWindow = getLastWindow();
if (!lastWindow || !localStorage) {
return;
}
const contents = lastWindow.webContents;
const contentsUrl = contents.getURL();
if (!checkIsWebContentsUrlAllowed(contentsUrl)) {
return;
}
await contents.executeJavaScript(
Object.keys(localStorage).map(
(key: string) => `localStorage.setItem('${key}', JSON.stringify(${localStorage![key]}))`,
).join(';'),

View File

@ -5,6 +5,10 @@ import fs from 'fs';
import type { TrafficLightPosition } from '../types/electron';
import { BASE_URL, PRODUCTION_URL } from '../config';
const ALLOWED_URL_ORIGINS = [BASE_URL!, PRODUCTION_URL].map((url) => (new URL(url).origin));
export const IS_MAC_OS = process.platform === 'darwin';
export const IS_WINDOWS = process.platform === 'win32';
export const IS_LINUX = process.platform === 'linux';
@ -56,6 +60,20 @@ export function getAppTitle(chatTitle?: string): string {
return `${chatTitle} · ${appName}`;
}
export function checkIsWebContentsUrlAllowed(url: string): boolean {
if (!app.isPackaged) {
return true;
}
const parsedUrl = new URL(url);
if (parsedUrl.pathname === encodeURI(`${__dirname}/index.html`)) {
return true;
}
return ALLOWED_URL_ORIGINS.includes(parsedUrl.origin);
}
export const TRAFFIC_LIGHT_POSITION: Record<TrafficLightPosition, Point> = {
standard: { x: 10, y: 20 },
lowered: { x: 10, y: 52 },

View File

@ -12,8 +12,8 @@ import { processDeeplink } from './deeplink';
import { captureLocalStorage, restoreLocalStorage } from './localStorage';
import tray from './tray';
import {
forceQuit, getAppTitle, getCurrentWindow, getLastWindow, hasExtraWindows, IS_FIRST_RUN, IS_MAC_OS,
IS_PREVIEW, IS_WINDOWS, reloadWindows, store, TRAFFIC_LIGHT_POSITION, windows,
checkIsWebContentsUrlAllowed, forceQuit, getAppTitle, getCurrentWindow, getLastWindow, hasExtraWindows,
IS_FIRST_RUN, IS_MAC_OS, IS_PREVIEW, IS_WINDOWS, reloadWindows, store, TRAFFIC_LIGHT_POSITION, windows,
} from './utils';
import windowStateKeeper from './windowState';
@ -80,6 +80,12 @@ export function createWindow(url?: string) {
return deviceType === 'hid' && ALLOWED_DEVICE_ORIGINS.includes(origin);
});
window.webContents.on('will-navigate', (event, newUrl) => {
if (!checkIsWebContentsUrlAllowed(newUrl)) {
event.preventDefault();
}
});
window.on('page-title-updated', (event: Event) => {
event.preventDefault();
});
@ -139,7 +145,7 @@ export function createWindow(url?: string) {
}
function loadWindowUrl(window: BrowserWindow, url?: string, hash?: string): void {
if (url) {
if (url && checkIsWebContentsUrlAllowed(url)) {
window.loadURL(url);
} else if (!app.isPackaged) {
window.loadURL(`http://localhost:1234${hash}`);