From 4d694fdcc431ab62372a1a01fa09d35c9a52358e Mon Sep 17 00:00:00 2001 From: RyderAsking Date: Sat, 11 Jul 2026 04:29:05 +0530 Subject: [PATCH] fix(ipc): allow media in configured recordings directory --- electron/ipc/project/manager.test.ts | 17 +++++++++++++++++ electron/ipc/project/manager.ts | 12 ++++++++++++ 2 files changed, 29 insertions(+) diff --git a/electron/ipc/project/manager.test.ts b/electron/ipc/project/manager.test.ts index 508730924..3f0116914 100644 --- a/electron/ipc/project/manager.test.ts +++ b/electron/ipc/project/manager.test.ts @@ -82,6 +82,23 @@ describe("local media path policy", () => { await expect(isAllowedLocalMediaPath(pendingExportPath)).resolves.toBe(true); }); + it("allows media files in the configured recordings directory", async () => { + const configuredRecordingsDir = path.join(tempRoot, "Configured recordings"); + const recordingPath = path.join(configuredRecordingsDir, "recording-123.mic.wav"); + await fs.mkdir(configuredRecordingsDir, { recursive: true }); + await fs.writeFile(recordingPath, "audio"); + await fs.writeFile( + path.join(userDataPath, "recordings-settings.json"), + JSON.stringify({ recordingsDir: configuredRecordingsDir }), + ); + + const { resolveApprovedLocalMediaPath } = await import("./manager"); + + await expect(resolveApprovedLocalMediaPath(recordingPath)).resolves.toBe( + await fs.realpath(recordingPath), + ); + }); + it("approves media-server access for approved external files resolved through the URL policy", async () => { const downloadsPath = path.join(tempRoot, "Downloads"); const videoPath = path.join(downloadsPath, "external-video.mp4"); diff --git a/electron/ipc/project/manager.ts b/electron/ipc/project/manager.ts index 7828fa8b6..43dca6a04 100644 --- a/electron/ipc/project/manager.ts +++ b/electron/ipc/project/manager.ts @@ -100,6 +100,18 @@ export function isAllowedLocalReadPath(candidatePath: string) { // become fetchable inside the app. export async function isAllowedLocalMediaPath(candidatePath: string) { const normalizedCandidatePath = normalizePath(candidatePath); + // The recordings location can be changed in settings, so the compile-time + // default RECORDINGS_DIR alone is not sufficient for media created there. + // Canonicalize the configured root as well as the candidate to retain the + // symlink protection enforced by isAllowedLocalReadPath. + const recordingsDir = await getRecordingsDir(); + const canonicalRecordingsDir = await fs + .realpath(recordingsDir) + .catch(() => normalizePath(recordingsDir)); + if (isPathInsideDirectory(normalizedCandidatePath, canonicalRecordingsDir)) { + return true; + } + return isAllowedLocalReadPath(normalizedCandidatePath); }