fix(video): logo overlays must belong to the workspace; drop debug stderr

- produceVideo checks every logo overlay key against the workspace's
  media_assets, group_assets or branding logo before queueing; a
  well-formed content address alone no longer suffices.
- Remove MEDIA_DEBUG_STDERR=1 from the production compose: it wrote raw
  ffmpeg stderr to an unrotated file, bypassing redaction.
This commit is contained in:
hacklab 2026-10-15 15:09:07 +02:00
parent dd5a6c8b35
commit 1b58768738
4 changed files with 41 additions and 1 deletions

View file

@ -381,6 +381,7 @@ export class VideoService {
const created = await this.dependencies.tenantTransaction(workspaceId, async (client) => {
const source = await client.query("SELECT * FROM video_assets WHERE id = $1", [assetId]);
if (source.rowCount !== 1) throw new NotFoundException(`video ${assetId} not found`);
await assertLogoKeysOwned(client, workspaceId, request);
const jobResult = await client.query(
`INSERT INTO video_processing_jobs (workspace_id, video_asset_id, state, kind, input_json)
VALUES ($1, $2, 'queued', $3, $4::jsonb) RETURNING *`,
@ -595,3 +596,25 @@ function decodeCursor(cursor: string): VideoCursor {
function isUuid(value: string): boolean {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
}
/**
* Storage keys are content-addressed in one shared bucket, so a well-formed key
* alone proves nothing about who owns the object. A logo overlay may only use
* an image this workspace holds: an attachment, a group asset or its branding.
*/
async function assertLogoKeysOwned(
client: { query: (sql: string, values: unknown[]) => Promise<{ rowCount: number | null }> },
workspaceId: string,
request: ProduceRequest,
): Promise<void> {
const keys = [...new Set((request.overlays ?? []).flatMap((overlay) => (overlay.logoStorageKey === undefined ? [] : [overlay.logoStorageKey])))];
for (const key of keys) {
const owned = await client.query(
`SELECT 1 WHERE EXISTS (SELECT 1 FROM media_assets WHERE storage_key = $1 AND workspace_id = $2)
OR EXISTS (SELECT 1 FROM group_assets WHERE asset_id = $1 AND workspace_id = $2)
OR EXISTS (SELECT 1 FROM workspaces WHERE id = $2 AND branding->>'logoAssetKey' = $1)`,
[key, workspaceId],
);
if (owned.rowCount !== 1) throw new BadRequestException("logoStorageKey is not an image of this collective");
}
}