Some checks failed
CI / Semgrep Security Scan (pull_request) Successful in 25s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m6s
SDD Gate / RTM Check (pull_request) Successful in 14s
SDD Gate / Contract Validate (pull_request) Successful in 23s
SDD Gate / Constitution Impact (pull_request) Successful in 21s
CI / Unit & Component Tests (pull_request) Failing after 3m19s
CI / OCR Service Tests (pull_request) Successful in 22s
CI / Backend Unit Tests (pull_request) Successful in 4m49s
CI / fail2ban Regex (pull_request) Successful in 47s
Architect/Developer review suggestion: flag that other WRITE_ALL-gated author loads (e.g. documents/[id]/edit) still inline the throw-403 guard and can adopt requireWriteAll so it doesn't diverge. Comment-only. Addresses PR #832 review (Architect suggestion). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
31 lines
1.3 KiB
TypeScript
31 lines
1.3 KiB
TypeScript
import { error } from '@sveltejs/kit';
|
|
|
|
/**
|
|
* Server-side permission predicates derived from the authenticated user in `locals`.
|
|
*
|
|
* The user shape is intentionally narrowed to the only field these checks read
|
|
* (`groups[].permissions`) so the helper works against `App.Locals` without importing it.
|
|
*/
|
|
type PermissionLocals = {
|
|
user?: { groups?: { permissions: string[] }[] } | null;
|
|
};
|
|
|
|
/** True when any of the user's groups grants WRITE_ALL. False for anonymous users. */
|
|
export function hasWriteAll(locals: PermissionLocals): boolean {
|
|
return locals.user?.groups?.some((group) => group.permissions.includes('WRITE_ALL')) ?? false;
|
|
}
|
|
|
|
/**
|
|
* Throws a 403 unless the user holds WRITE_ALL. Anonymous users are rejected too
|
|
* — `hasWriteAll` returns false for a null user, so a single check covers both
|
|
* the unauthenticated and the under-privileged case. Server-side gate; the
|
|
* frontend canWrite flag only hides entry-point buttons.
|
|
*
|
|
* Other WRITE_ALL-gated author loads (e.g. `documents/[id]/edit`) still inline
|
|
* `if (!hasWriteAll(locals)) throw error(403)` — they can adopt this helper so
|
|
* the guard doesn't quietly diverge across routes.
|
|
*/
|
|
export function requireWriteAll(locals: PermissionLocals): void {
|
|
if (!hasWriteAll(locals)) throw error(403, 'Forbidden');
|
|
}
|