Merge pull request #401 from hobostay/fix/bug-fixes-security-and-reliability

Fix security and reliability issues
This commit is contained in:
Sid
2026-04-18 10:50:18 -07:00
committed by GitHub
4 changed files with 37 additions and 6 deletions
+31 -2
View File
@@ -490,7 +490,24 @@ export function registerIpcHandlers(
return { success: false, message: "No recorded video found" };
}
const latestVideo = videoFiles.sort().reverse()[0];
// Sort by most recently modified to reliably get the latest recording.
// Lexicographic sort is unreliable (e.g. recording-9.webm > recording-10.webm).
let latestVideo: string | null = null;
let latestMtimeMs = 0;
for (const file of videoFiles) {
try {
const stat = await fs.stat(path.join(RECORDINGS_DIR, file));
if (stat.mtimeMs > latestMtimeMs) {
latestMtimeMs = stat.mtimeMs;
latestVideo = file;
}
} catch {
// Skip inaccessible files.
}
}
if (!latestVideo) {
return { success: false, message: "No recorded video found" };
}
const videoPath = path.join(RECORDINGS_DIR, latestVideo);
return { success: true, path: videoPath };
@@ -618,7 +635,19 @@ export function registerIpcHandlers(
ipcMain.handle("open-external-url", async (_, url: string) => {
try {
await shell.openExternal(url);
const ALLOWED_SCHEMES = ["http:", "https:", "mailto:"];
let parsed: URL;
try {
parsed = new URL(url);
} catch {
return { success: false, error: "Invalid URL" };
}
if (!ALLOWED_SCHEMES.includes(parsed.protocol)) {
return { success: false, error: `Unsupported URL scheme: ${parsed.protocol}` };
}
await shell.openExternal(parsed.toString());
return { success: true };
} catch (error) {
console.error("Failed to open URL:", error);
@@ -499,7 +499,6 @@ export default function VideoEditor() {
aspectRatio,
webcamLayoutPreset,
webcamMaskShape,
webcamSizePreset,
webcamPosition,
exportQuality,
exportFormat,
+5 -2
View File
@@ -542,7 +542,10 @@ export class AudioProcessor {
}
private cloneWithTimestamp(src: AudioData, newTimestamp: number): AudioData {
const isPlanar = src.format?.includes("planar") ?? false;
if (!src.format) {
throw new Error("AudioData format is required for cloning");
}
const isPlanar = src.format.includes("planar");
const numPlanes = isPlanar ? src.numberOfChannels : 1;
let totalSize = 0;
@@ -559,7 +562,7 @@ export class AudioProcessor {
}
return new AudioData({
format: src.format!,
format: src.format,
sampleRate: src.sampleRate,
numberOfFrames: src.numberOfFrames,
numberOfChannels: src.numberOfChannels,
+1 -1
View File
@@ -424,7 +424,7 @@ export class VideoExporter {
})();
this.muxingPromises.push(muxingPromise);
this.encodeQueue--;
this.encodeQueue = Math.max(0, this.encodeQueue - 1);
},
error: (error) => {
console.error("[VideoExporter] Encoder error:", error);