From 84f0a2add4081ac2a0ff9f7b5144ac4484b61502 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Wed, 29 Apr 2026 18:19:49 +0200 Subject: [PATCH] feat(ST-1110.3+4): demo-guard proxy + block demo in QR-pairing - proxy.ts: gebruik unsealData ipv getIronSession (middleware-compatibel) - pair/start: isDemo-check via cookies() guard - pair/claim: check pairing.user.is_demo na DB-read; 403 + clearPairCookie --- app/api/auth/pair/claim/route.ts | 5 +++++ app/api/auth/pair/start/route.ts | 8 ++++++++ proxy.ts | 17 ++++++++++------- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/api/auth/pair/claim/route.ts b/app/api/auth/pair/claim/route.ts index 69b4b89..555cd39 100644 --- a/app/api/auth/pair/claim/route.ts +++ b/app/api/auth/pair/claim/route.ts @@ -80,6 +80,11 @@ export async function POST(request: Request) { return Response.json({ error: 'Pairing zonder user' }, { status: 500 }) } + if (pairing.user?.is_demo) { + await clearPairCookie() + return Response.json({ error: 'Niet beschikbaar in demo-modus' }, { status: 403 }) + } + const session = await getIronSession(await cookies(), sessionOptions) session.userId = pairing.user_id session.isDemo = pairing.user?.is_demo ?? false diff --git a/app/api/auth/pair/start/route.ts b/app/api/auth/pair/start/route.ts index 2062887..30ef836 100644 --- a/app/api/auth/pair/start/route.ts +++ b/app/api/auth/pair/start/route.ts @@ -9,6 +9,8 @@ // // Rate-limit: 10 pogingen per IP per minuut (lib/rate-limit.ts → 'pair-start'). +import { getIronSession } from 'iron-session' +import { cookies } from 'next/headers' import { prisma } from '@/lib/prisma' import { generateMobileSecret, @@ -17,6 +19,7 @@ import { } from '@/lib/auth/pairing' import { setPairCookie } from '@/lib/auth/pair-cookie' import { checkRateLimit } from '@/lib/rate-limit' +import { SessionData, sessionOptions } from '@/lib/session' export const runtime = 'nodejs' @@ -34,6 +37,11 @@ function getClientIp(request: Request): string { } export async function POST(request: Request) { + const session = await getIronSession(await cookies(), sessionOptions) + if (session.isDemo) { + return Response.json({ error: 'Niet beschikbaar in demo-modus' }, { status: 403 }) + } + const ip = getClientIp(request) if (!checkRateLimit(`pair-start:${ip}`)) { return Response.json( diff --git a/proxy.ts b/proxy.ts index 53ae423..afbfd55 100644 --- a/proxy.ts +++ b/proxy.ts @@ -1,6 +1,6 @@ import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' -import { getIronSession } from 'iron-session' +import { unsealData } from 'iron-session' import { sessionOptions, type SessionData } from '@/lib/session' const protectedRoutes = ['/dashboard', '/products', '/todos', '/settings', '/solo'] @@ -22,12 +22,15 @@ export async function proxy(request: NextRequest) { !SAFE_METHODS.has(method) && !DEMO_WRITE_ALLOWLIST.some(p => pathname.startsWith(p)) ) { - const session = await getIronSession(request.cookies, sessionOptions) - if (session.isDemo) { - return NextResponse.json( - { error: 'Niet beschikbaar in demo-modus' }, - { status: 403 } - ) + const raw = request.cookies.get(sessionOptions.cookieName)?.value + if (raw) { + const session = await unsealData(raw, { password: sessionOptions.password as string }) + if (session.isDemo) { + return NextResponse.json( + { error: 'Niet beschikbaar in demo-modus' }, + { status: 403 } + ) + } } }