import { shell } from 'electron' import { existsSync, statSync } from 'fs' import { extname, isAbsolute } from 'path' /** * Open/reveal helpers used by the shell:* IPC handlers. * * The renderer supplies the path (it originates from yt-dlp's after-move print), * but the IPC boundary must not trust it blindly: a compromised renderer could * otherwise call openPath() on an arbitrary executable and have the OS run it. * So openPath is confined to existing files with a known media extension — * never .exe/.bat/.ps1/etc. */ const OPENABLE_EXTENSIONS = new Set([ // video '.mp4', '.mkv', '.webm', '.mov', '.avi', '.flv', '.ts', '.m4v', '.3gp', '.ogv', // audio '.mp3', '.m4a', '.opus', '.ogg', '.oga', '.aac', '.flac', '.wav', '.wma', // subtitle sidecars (plain text — safe to open) '.vtt', '.srt' ]) /** Open a downloaded media file with its default app. Returns '' on success, * or an error string (matching shell.openPath's contract). */ export async function safeOpenPath(p: unknown): Promise { if (typeof p !== 'string' || !isAbsolute(p)) return 'Invalid path.' if (!OPENABLE_EXTENSIONS.has(extname(p).toLowerCase())) { return 'Refusing to open this file type.' } try { if (!statSync(p).isFile()) return 'Not a file.' } catch { return 'File not found.' } return shell.openPath(p) } /** Reveal a path in the OS file manager. No-op for missing/invalid paths. */ export function safeShowInFolder(p: unknown): void { if (typeof p !== 'string' || !isAbsolute(p) || !existsSync(p)) return shell.showItemInFolder(p) }