Apply additional security recommendations (#2050)

* enable sandbox

* enable CSP (umami tentatively works?) and reduce amount of ipc APIs exposed

* remove csp from index
This commit is contained in:
Kendall Garner
2026-05-23 05:09:22 +00:00
committed by GitHub
parent 0de1e1aa3e
commit 7befd70e21
19 changed files with 179 additions and 190 deletions
+30 -12
View File
@@ -16,6 +16,7 @@ import {
protocol,
Rectangle,
screen,
session,
shell,
Tray,
} from 'electron';
@@ -33,16 +34,9 @@ import { store } from './features/core/settings';
import { canHandleVisualizerDisplayMedia } from './features/core/visualizer';
import MenuBuilder, { MenuPlaybackState } from './menu';
import './features';
import {
autoUpdaterLogInterface,
createLog,
disableAutoUpdates,
hotkeyToElectronAccelerator,
isLinux,
isMacOS,
isWindows,
} from './utils';
import { autoUpdaterLogInterface, createLog, hotkeyToElectronAccelerator } from './utils';
import { disableAutoUpdates, isLinux, isMacOS, isWindows } from '/@/main/env';
import { PlayerRepeat, PlayerStatus, PlayerType, TitleTheme } from '/@/shared/types/types';
const ALPHA_UPDATER_CONFIG: {
@@ -477,6 +471,15 @@ const createTray = () => {
tray.setContextMenu(contextMenu);
};
const validateUrl = (url: string): boolean => {
// Minor security, really. Enforce only loading websites (http/https). file://
// URLs and the like should've already been blocked, but this is another check.
// Note that arbitrary web URLs are still allowed under this scheme, although
// that should really only be hit by Subsonic share url (or if artist homepage
// is allowed for ND extensions)
return url.startsWith('http://') || url.startsWith('https://');
};
async function createWindow(first = true): Promise<void> {
if (isDevelopment) {
await installExtensions().catch(console.log);
@@ -518,7 +521,7 @@ async function createWindow(first = true): Promise<void> {
devTools: true,
nodeIntegration: false,
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
sandbox: true,
webSecurity: !store.get('ignore_cors'),
},
width: 1440,
@@ -730,7 +733,9 @@ async function createWindow(first = true): Promise<void> {
// Open URLs in the user's browser
mainWindow.webContents.setWindowOpenHandler((edata) => {
shell.openExternal(edata.url);
if (validateUrl(edata.url)) {
shell.openExternal(edata.url);
}
return { action: 'deny' };
});
@@ -770,7 +775,9 @@ async function createWindow(first = true): Promise<void> {
nativeTheme.themeSource = theme || 'dark';
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url);
if (validateUrl(details.url)) {
shell.openExternal(details.url);
}
return { action: 'deny' };
});
@@ -1017,6 +1024,17 @@ if (!singleInstance) {
return response;
});
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
"script-src 'self' 'unsafe-inline' https://umami.jeffvli.org; style-src 'self' 'unsafe-inline'; media-src 'self' http: https: data: blob:; img-src 'self' http: https: data: blob:; connect-src 'self' http: https: ws: wss:; default-src 'self';",
],
},
});
});
createWindow();
if (store.get('window_enable_tray', true)) {
createTray();