Semaine 1 — fuites et accès : - /archive rendu accessible via sidebar (était invisible) - Suppression pages orphelines : /chat, /graph, /support, test-title-suggestions - Fixes i18n : search-modal (clé non interpolée), sidebar tooltips, export PDF - 15 locales mises à jour Semaine 2 — garde-fous : - 8 erreurs TS fixees → ignoreBuildErrors: false (build type-safe) - reactStrictMode: true (dev-only, zero impact prod) - reserveUsageOrThrow → wrapper deprecie vers reserveAiUsageOrThrow - auth-guard.ts : requireAuthOrResponse() + requireAdminOrResponse() Tests 212/212 | Lint 0 erreur | Build OK | tsc 0 erreur
74 lines
2.2 KiB
TypeScript
74 lines
2.2 KiB
TypeScript
import { auth } from '@/auth'
|
|
import { NextResponse } from 'next/server'
|
|
import { prisma } from '@/lib/prisma'
|
|
|
|
export type AuthResult =
|
|
| { ok: true; userId: string }
|
|
| { ok: false; response: NextResponse }
|
|
|
|
/**
|
|
* Retrieves the authenticated user ID or throws an Unauthorized error.
|
|
* Use in Server Actions where throw semantics are preferred.
|
|
*
|
|
* @throws {Error} 'Unauthorized' if no valid session exists.
|
|
* @returns The authenticated user's ID string.
|
|
*/
|
|
export async function requireAuth(): Promise<string> {
|
|
const session = await auth()
|
|
if (!session?.user?.id) {
|
|
throw new Error('Unauthorized')
|
|
}
|
|
return session.user.id
|
|
}
|
|
|
|
/**
|
|
* Auth guard for API routes — returns a 401 NextResponse instead of throwing.
|
|
*
|
|
* Usage:
|
|
* ```ts
|
|
* const auth = await requireAuthOrResponse()
|
|
* if (!auth.ok) return auth.response
|
|
* const userId = auth.userId
|
|
* ```
|
|
*
|
|
* @param format 'plain' (default) returns `{ error: 'Unauthorized' }`.
|
|
* 'success' returns `{ success: false, error: 'Unauthorized' }`.
|
|
*/
|
|
export async function requireAuthOrResponse(
|
|
format: 'plain' | 'success' = 'plain',
|
|
): Promise<AuthResult> {
|
|
const session = await auth()
|
|
if (!session?.user?.id) {
|
|
const body = format === 'success'
|
|
? { success: false, error: 'Unauthorized' }
|
|
: { error: 'Unauthorized' }
|
|
return { ok: false, response: NextResponse.json(body, { status: 401 }) }
|
|
}
|
|
return { ok: true, userId: session.user.id }
|
|
}
|
|
|
|
/**
|
|
* Admin guard for API routes — checks user role in DB, returns 401/403 on failure.
|
|
*
|
|
* Usage:
|
|
* ```ts
|
|
* const auth = await requireAdminOrResponse()
|
|
* if (!auth.ok) return auth.response
|
|
* const userId = auth.userId
|
|
* ```
|
|
*/
|
|
export async function requireAdminOrResponse(): Promise<AuthResult> {
|
|
const session = await auth()
|
|
if (!session?.user?.id) {
|
|
return { ok: false, response: NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) }
|
|
}
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: session.user.id },
|
|
select: { role: true },
|
|
})
|
|
if (user?.role !== 'ADMIN') {
|
|
return { ok: false, response: NextResponse.json({ error: 'Forbidden' }, { status: 403 }) }
|
|
}
|
|
return { ok: true, userId: session.user.id }
|
|
}
|