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
-10
View File
@@ -8,21 +8,11 @@ const send = (channel: string, ...args: any[]) => {
ipcRenderer.send(channel, ...args);
};
const invoke = (channel: string, ...args: any[]) => {
return ipcRenderer.invoke(channel, ...args);
};
const on = (channel: string, listener: (event: any, ...args: any[]) => void) => {
ipcRenderer.on(channel, listener);
};
const removeListener = (channel: string, listener: (event: any, ...args: any[]) => void) => {
ipcRenderer.removeListener(channel, listener);
};
export const ipc = {
invoke,
on,
removeAllListeners,
removeListener,
send,
+3 -3
View File
@@ -1,4 +1,4 @@
import { ipcRenderer, IpcRendererEvent, OpenDialogOptions, webFrame } from 'electron';
import { ipcRenderer, OpenDialogOptions, webFrame } from 'electron';
import { TitleTheme } from '/@/shared/types/types';
@@ -41,8 +41,8 @@ const setZoomFactor = (zoomFactor: number) => {
webFrame.setZoomFactor(zoomFactor / 100);
};
const fontError = (cb: (event: IpcRendererEvent, file: string) => void) => {
ipcRenderer.on('custom-font-error', cb);
const fontError = (cb: (file: string) => void) => {
ipcRenderer.on('custom-font-error', (_, file) => cb(file));
};
const themeSet = (theme: TitleTheme): void => {
+11 -15
View File
@@ -1,4 +1,4 @@
import { ipcRenderer, IpcRendererEvent } from 'electron';
import { ipcRenderer } from 'electron';
import { QueueSong } from '/@/shared/types/domain-types';
import { PlayerRepeat, PlayerStatus } from '/@/shared/types/types';
@@ -31,28 +31,24 @@ const updateSong = (song: QueueSong | undefined, imageUrl?: null | string) => {
ipcRenderer.send('update-song', song, imageUrl);
};
const requestSeek = (cb: (event: IpcRendererEvent, data: { offset: number }) => void) => {
ipcRenderer.on('request-seek', cb);
const requestSeek = (cb: (data: { offset: number }) => void) => {
ipcRenderer.on('request-seek', (_, data) => cb(data));
};
const requestPosition = (cb: (event: IpcRendererEvent, data: { position: number }) => void) => {
ipcRenderer.on('request-position', cb);
const requestPosition = (cb: (data: { position: number }) => void) => {
ipcRenderer.on('request-position', (_, data) => cb(data));
};
const requestToggleRepeat = (
cb: (event: IpcRendererEvent, data: { repeat: PlayerRepeat }) => void,
) => {
ipcRenderer.on('mpris-request-toggle-repeat', cb);
const requestToggleRepeat = (cb: (data: { repeat: PlayerRepeat }) => void) => {
ipcRenderer.on('mpris-request-toggle-repeat', (_, data) => cb(data));
};
const requestToggleShuffle = (
cb: (event: IpcRendererEvent, data: { shuffle: boolean }) => void,
) => {
ipcRenderer.on('mpris-request-toggle-shuffle', cb);
const requestToggleShuffle = (cb: (data: { shuffle: boolean }) => void) => {
ipcRenderer.on('mpris-request-toggle-shuffle', (_, data) => cb(data));
};
const requestVolume = (cb: (event: IpcRendererEvent, data: { volume: number }) => void) => {
ipcRenderer.on('request-volume', cb);
const requestVolume = (cb: (data: { volume: number }) => void) => {
ipcRenderer.on('request-volume', (_, data) => cb(data));
};
export const mpris = {
+37 -37
View File
@@ -1,4 +1,4 @@
import { ipcRenderer, IpcRendererEvent } from 'electron';
import { ipcRenderer } from 'electron';
import { PlayerData } from '/@/shared/types/domain-types';
@@ -102,76 +102,76 @@ const getAudioDevices = async () => {
return ipcRenderer.invoke('player-get-audio-devices');
};
const rendererAutoNext = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-auto-next', cb);
const rendererAutoNext = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-auto-next', (_, data) => cb(data));
};
const rendererCurrentTime = (cb: (event: IpcRendererEvent, data: number) => void) => {
ipcRenderer.on('renderer-player-current-time', cb);
const rendererCurrentTime = (cb: (data: number) => void) => {
ipcRenderer.on('renderer-player-current-time', (_, data) => cb(data));
};
const rendererNext = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-next', cb);
const rendererNext = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-next', (_, data) => cb(data));
};
const rendererPause = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-pause', cb);
const rendererPause = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-pause', (_, data) => cb(data));
};
const rendererPlay = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-play', cb);
const rendererPlay = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-play', (_, data) => cb(data));
};
const rendererPlayPause = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-play-pause', cb);
const rendererPlayPause = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-play-pause', (_, data) => cb(data));
};
const rendererPrevious = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-previous', cb);
const rendererPrevious = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-previous', (_, data) => cb(data));
};
const rendererStop = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-stop', cb);
const rendererStop = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-stop', (_, data) => cb(data));
};
const rendererSkipForward = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-skip-forward', cb);
const rendererSkipForward = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-skip-forward', (_, data) => cb(data));
};
const rendererSkipBackward = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-skip-backward', cb);
const rendererSkipBackward = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-skip-backward', (_, data) => cb(data));
};
const rendererVolumeUp = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-volume-up', cb);
const rendererVolumeUp = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-volume-up', (_, data) => cb(data));
};
const rendererVolumeDown = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-volume-down', cb);
const rendererVolumeDown = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-volume-down', (_, data) => cb(data));
};
const rendererVolumeMute = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-volume-mute', cb);
const rendererVolumeMute = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-volume-mute', (_, data) => cb(data));
};
const rendererToggleRepeat = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-toggle-repeat', cb);
const rendererToggleRepeat = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-toggle-repeat', (_, data) => cb(data));
};
const rendererToggleShuffle = (cb: (event: IpcRendererEvent, data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-toggle-shuffle', cb);
const rendererToggleShuffle = (cb: (data: PlayerData) => void) => {
ipcRenderer.on('renderer-player-toggle-shuffle', (_, data) => cb(data));
};
const rendererQuit = (cb: (event: IpcRendererEvent) => void) => {
ipcRenderer.on('renderer-player-quit', cb);
const rendererQuit = (cb: () => void) => {
ipcRenderer.on('renderer-player-quit', () => cb());
};
const rendererError = (cb: (event: IpcRendererEvent, data: string) => void) => {
ipcRenderer.on('renderer-player-error', cb);
const rendererError = (cb: (data: string) => void) => {
ipcRenderer.on('renderer-player-error', (_, data) => cb(data));
};
const rendererPlayerFallback = (cb: (event: IpcRendererEvent, data: boolean) => void) => {
ipcRenderer.on('renderer-player-fallback', cb);
const rendererPlayerFallback = (cb: (data: boolean) => void) => {
ipcRenderer.on('renderer-player-fallback', (_, data) => cb(data));
};
export const mpvPlayer = {
+11 -16
View File
@@ -1,33 +1,28 @@
import { ipcRenderer, IpcRendererEvent } from 'electron';
import { ipcRenderer } from 'electron';
import { QueueSong } from '/@/shared/types/domain-types';
import { PlayerStatus } from '/@/shared/types/types';
const requestFavorite = (
cb: (
event: IpcRendererEvent,
data: { favorite: boolean; id: string; serverId: string },
) => void,
cb: (data: { favorite: boolean; id: string; serverId: string }) => void,
) => {
ipcRenderer.on('request-favorite', cb);
ipcRenderer.on('request-favorite', (_, data) => cb(data));
};
const requestPosition = (cb: (event: IpcRendererEvent, data: { position: number }) => void) => {
ipcRenderer.on('request-position', cb);
const requestPosition = (cb: (data: { position: number }) => void) => {
ipcRenderer.on('request-position', (_, data) => cb(data));
};
const requestRating = (
cb: (event: IpcRendererEvent, data: { id: string; rating: number; serverId: string }) => void,
) => {
ipcRenderer.on('request-rating', cb);
const requestRating = (cb: (data: { id: string; rating: number; serverId: string }) => void) => {
ipcRenderer.on('request-rating', (_, data) => cb(data));
};
const requestSeek = (cb: (event: IpcRendererEvent, data: { offset: number }) => void) => {
ipcRenderer.on('request-seek', cb);
const requestSeek = (cb: (data: { offset: number }) => void) => {
ipcRenderer.on('request-seek', (_, data) => cb(data));
};
const requestVolume = (cb: (event: IpcRendererEvent, data: { volume: number }) => void) => {
ipcRenderer.on('request-volume', cb);
const requestVolume = (cb: (data: { volume: number }) => void) => {
ipcRenderer.on('request-volume', (_, data) => cb(data));
};
const setRemoteEnabled = (enabled: boolean): Promise<null | string> => {
+32 -33
View File
@@ -1,6 +1,6 @@
import { ipcRenderer, IpcRendererEvent, webFrame } from 'electron';
import { ipcRenderer, webFrame } from 'electron';
import { disableAutoUpdates, isLinux, isMacOS, isWindows } from '../main/utils';
import { disableAutoUpdates, isLinux, isMacOS, isWindows } from '../main/env';
const openItem = async (path: string) => {
return ipcRenderer.invoke('open-item', path);
@@ -10,29 +10,14 @@ const openApplicationDirectory = async () => {
return ipcRenderer.invoke('open-application-directory');
};
const playerErrorListener = (cb: (event: IpcRendererEvent, data: { code: number }) => void) => {
ipcRenderer.on('player-error-listener', cb);
const playerErrorListener = (cb: (data: { code: number }) => void) => {
ipcRenderer.on('player-error-listener', (_, data) => cb(data));
};
const mainMessageListener = (
cb: (
event: IpcRendererEvent,
data: { message: string; type: 'error' | 'info' | 'success' | 'warning' },
) => void,
cb: (data: { message: string; type: 'error' | 'info' | 'success' | 'warning' }) => void,
) => {
ipcRenderer.on('toast-from-main', cb);
};
const logger = (
cb: (
event: IpcRendererEvent,
data: {
message: string;
type: 'debug' | 'error' | 'info' | 'verbose' | 'warning';
},
) => void,
) => {
ipcRenderer.send('logger', cb);
ipcRenderer.on('toast-from-main', (_, data) => cb(data));
};
const download = (url: string) => {
@@ -43,6 +28,14 @@ const checkForUpdates = (): Promise<{ updateAvailable: boolean; version?: string
return ipcRenderer.invoke('app-check-for-updates');
};
const startPowerSaveBlocker = (full: boolean) => {
return ipcRenderer.invoke('power-save-blocker-start', { full });
};
const stopPowerSaveBlocker = () => {
return ipcRenderer.invoke('power-save-blocker-stop');
};
const forceGarbageCollection = (): boolean => {
try {
if (typeof global.gc === 'function') {
@@ -61,28 +54,32 @@ const forceGarbageCollection = (): boolean => {
}
};
const rendererOpenSettings = (cb: (event: IpcRendererEvent) => void) => {
ipcRenderer.on('renderer-open-settings', cb);
const rendererOpenSettings = (cb: () => void) => {
ipcRenderer.on('renderer-open-settings', () => cb());
};
const rendererOpenCommandPalette = (cb: (event: IpcRendererEvent) => void) => {
ipcRenderer.on('renderer-open-command-palette', cb);
const rendererOpenCommandPalette = (cb: () => void) => {
ipcRenderer.on('renderer-open-command-palette', () => cb());
};
const rendererOpenManageServers = (cb: (event: IpcRendererEvent) => void) => {
ipcRenderer.on('renderer-open-manage-servers', cb);
const rendererOpenManageServers = (cb: () => void) => {
ipcRenderer.on('renderer-open-manage-servers', () => cb());
};
const rendererTogglePrivateMode = (cb: (event: IpcRendererEvent) => void) => {
const rendererTogglePrivateMode = (cb: () => void) => {
ipcRenderer.on('renderer-toggle-private-mode', cb);
};
const rendererToggleSidebar = (cb: (event: IpcRendererEvent) => void) => {
ipcRenderer.on('renderer-toggle-sidebar', cb);
const rendererToggleSidebar = (cb: () => void) => {
ipcRenderer.on('renderer-toggle-sidebar', () => cb());
};
const rendererOpenReleaseNotes = (cb: (event: IpcRendererEvent) => void) => {
ipcRenderer.on('renderer-open-release-notes', cb);
const rendererOpenReleaseNotes = (cb: () => void) => {
ipcRenderer.on('renderer-open-release-notes', () => cb());
};
const rendererUpdateAvailable = (cb: (version: string) => void) => {
ipcRenderer.on('update-available', (_, version) => cb(version));
};
export const utils = {
@@ -93,7 +90,6 @@ export const utils = {
isLinux,
isMacOS,
isWindows,
logger,
mainMessageListener,
openApplicationDirectory,
openItem,
@@ -104,6 +100,9 @@ export const utils = {
rendererOpenSettings,
rendererTogglePrivateMode,
rendererToggleSidebar,
rendererUpdateAvailable,
startPowerSaveBlocker,
stopPowerSaveBlocker,
};
export type Utils = typeof utils;