fix(storage): purge raw audio when its history entry or meeting is deleted
This commit is contained in:
parent
4807a5283d
commit
ed790e672b
10 changed files with 1073 additions and 39 deletions
45
server/supabase/functions/audio-purge/policy.ts
Normal file
45
server/supabase/functions/audio-purge/policy.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// server/supabase/functions/audio-purge/policy.ts
|
||||
// Pure rules for which queued storage keys the service-role worker may remove.
|
||||
// storage_key is client-written (RLS only pins its first segment), so the
|
||||
// worker re-checks it before acting with service-role storage access.
|
||||
|
||||
export const AUDIO_BUCKET = 'audio'
|
||||
export const MAX_STORAGE_KEY_LENGTH = 1024
|
||||
|
||||
export interface PurgeQueueEntry {
|
||||
id: number
|
||||
userId: string
|
||||
storageKey: string
|
||||
leaseToken: string
|
||||
}
|
||||
|
||||
export interface PurgePlan {
|
||||
/** Entries whose object may be removed from the audio bucket. */
|
||||
removable: PurgeQueueEntry[]
|
||||
/** Entries dropped without touching storage (key outside the owner's prefix). */
|
||||
rejected: PurgeQueueEntry[]
|
||||
}
|
||||
|
||||
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
||||
// deno-lint-ignore no-control-regex
|
||||
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/
|
||||
|
||||
/** True when key is a plain object path inside the owner's own audio prefix. */
|
||||
export function isPurgeableStorageKey(userId: string, key: string): boolean {
|
||||
if (!UUID_PATTERN.test(userId)) return false
|
||||
if (key.length === 0 || key.length > MAX_STORAGE_KEY_LENGTH) return false
|
||||
if (key.includes('\\') || CONTROL_CHARACTERS.test(key)) return false
|
||||
const segments = key.split('/')
|
||||
if (segments.length < 2 || segments[0] !== userId) return false
|
||||
return segments.every((segment) => segment.length > 0 && segment !== '.' && segment !== '..')
|
||||
}
|
||||
|
||||
export function planPurge(entries: readonly PurgeQueueEntry[]): PurgePlan {
|
||||
const removable: PurgeQueueEntry[] = []
|
||||
const rejected: PurgeQueueEntry[] = []
|
||||
for (const entry of entries) {
|
||||
if (isPurgeableStorageKey(entry.userId, entry.storageKey)) removable.push(entry)
|
||||
else rejected.push(entry)
|
||||
}
|
||||
return { removable, rejected }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue