diff --git a/src/databases/officer_db/src/queries/soulseek.ts b/src/databases/officer_db/src/queries/soulseek.ts index b85f6ebd..0d250ecc 100644 --- a/src/databases/officer_db/src/queries/soulseek.ts +++ b/src/databases/officer_db/src/queries/soulseek.ts @@ -192,12 +192,26 @@ export async function getSoulseekBrowseDirs(params: BrowseDirPageParams): Promis } /** One cached folder's files. Scoped by user so a guessed dir id can't read another account's cache. */ -export async function getSoulseekBrowseDirFiles(userId: number, dirId: number): Promise { +type DirFilesParams = { userId: number; username: string; dirId: number }; + +// Joined and scoped by BOTH owner and peer: a dir id alone would happily return another peer's folder +// (ids are global), so the username in the request URL has to be part of the predicate, not decoration. +export async function getSoulseekBrowseDirFiles({ + userId, + username, + dirId, +}: DirFilesParams): Promise { const [row] = await db .select({ files: soulseekBrowseDirs.files }) .from(soulseekBrowseDirs) .innerJoin(soulseekBrowseSnapshots, eq(soulseekBrowseDirs.snapshotId, soulseekBrowseSnapshots.id)) - .where(and(eq(soulseekBrowseDirs.id, dirId), eq(soulseekBrowseSnapshots.userId, userId))) + .where( + and( + eq(soulseekBrowseDirs.id, dirId), + eq(soulseekBrowseSnapshots.userId, userId), + eq(soulseekBrowseSnapshots.username, username), + ), + ) .limit(1); return row ? (row.files as BrowsedFile[]) : null; } diff --git a/src/servers/sidecar/slskd/officer.ts b/src/servers/sidecar/slskd/officer.ts index 831ca6d9..e07994fa 100644 --- a/src/servers/sidecar/slskd/officer.ts +++ b/src/servers/sidecar/slskd/officer.ts @@ -127,7 +127,7 @@ async function handleBrowse({ req, url, userId, segments }: BrowseRouteParams): if (req.method !== 'GET') return methodNotAllowed(); const dirId = Number(segments[3]); if (!Number.isInteger(dirId) || dirId <= 0) return badRequest('invalid directory id'); - const files = await getSoulseekBrowseDirFiles(userId, dirId); + const files = await getSoulseekBrowseDirFiles({ userId, username, dirId }); return files ? Response.json(files) : notFound(); }