feat(ST-1110.3): add proxy.ts demo-guard for non-GET API routes

This commit is contained in:
Janpeter Visser 2026-04-29 18:17:45 +02:00
parent 8a9fb9d32b
commit f1d2b11c0f

View file

@ -1,17 +1,40 @@
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { sessionOptions } from '@/lib/session'
import { getIronSession } from 'iron-session'
import { sessionOptions, type SessionData } from '@/lib/session'
const protectedRoutes = ['/dashboard', '/products', '/todos', '/settings', '/solo']
const authRoutes = ['/login', '/register']
export function proxy(request: NextRequest) {
const path = request.nextUrl.pathname
const isProtected = protectedRoutes.some(r => path.startsWith(r))
const isAuthRoute = authRoutes.some(r => path.startsWith(r))
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS'])
// Check cookie existence only — full session validation happens in layout.tsx
// Paden die demo MAY aanroepen ook al zijn het non-GET — worden ingevuld na ST-1110.4
const DEMO_WRITE_ALLOWLIST = [
'/api/cron/', // machine-auth, irrelevant for demo
]
export async function proxy(request: NextRequest) {
const { pathname, method } = { pathname: request.nextUrl.pathname, method: request.method }
// Demo-guard: block non-GET API writes for demo users (defense in depth)
if (
pathname.startsWith('/api/') &&
!SAFE_METHODS.has(method) &&
!DEMO_WRITE_ALLOWLIST.some(p => pathname.startsWith(p))
) {
const session = await getIronSession<SessionData>(request.cookies, sessionOptions)
if (session.isDemo) {
return NextResponse.json(
{ error: 'Niet beschikbaar in demo-modus' },
{ status: 403 }
)
}
}
// Route protection: check cookie existence only — full validation in layout.tsx
const hasSession = !!request.cookies.get(sessionOptions.cookieName)?.value
const isProtected = protectedRoutes.some(r => pathname.startsWith(r))
const isAuthRoute = authRoutes.some(r => pathname.startsWith(r))
if (isProtected && !hasSession) {
return NextResponse.redirect(new URL('/login', request.url))
@ -25,5 +48,5 @@ export function proxy(request: NextRequest) {
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}