MVP ready to test

This commit is contained in:
Timo Knuth
2025-10-28 17:20:37 +01:00
parent 91b78cb284
commit 2f0208ebf9
48 changed files with 6258 additions and 110 deletions

View File

@@ -2,6 +2,9 @@ import { NextRequest, NextResponse } from 'next/server';
import { cookies } from 'next/headers';
import { db } from '@/lib/db';
import { generateSlug } from '@/lib/hash';
import { createQRSchema, validateRequest } from '@/lib/validationSchemas';
import { csrfProtection } from '@/lib/csrf';
import { rateLimit, getClientIdentifier, RateLimits } from '@/lib/rateLimit';
// GET /api/qrs - List user's QR codes
export async function GET(request: NextRequest) {
@@ -48,9 +51,36 @@ const PLAN_LIMITS = {
// POST /api/qrs - Create a new QR code
export async function POST(request: NextRequest) {
try {
// CSRF Protection
const csrfCheck = csrfProtection(request);
if (!csrfCheck.valid) {
return NextResponse.json({ error: csrfCheck.error }, { status: 403 });
}
const userId = cookies().get('userId')?.value;
console.log('POST /api/qrs - userId from cookie:', userId);
// Rate Limiting (user-based)
const clientId = userId || getClientIdentifier(request);
const rateLimitResult = rateLimit(clientId, RateLimits.QR_CREATE);
if (!rateLimitResult.success) {
return NextResponse.json(
{
error: 'Too many requests. Please try again later.',
retryAfter: Math.ceil((rateLimitResult.reset - Date.now()) / 1000)
},
{
status: 429,
headers: {
'X-RateLimit-Limit': rateLimitResult.limit.toString(),
'X-RateLimit-Remaining': rateLimitResult.remaining.toString(),
'X-RateLimit-Reset': rateLimitResult.reset.toString(),
}
}
);
}
if (!userId) {
return NextResponse.json({ error: 'Unauthorized - no userId cookie' }, { status: 401 });
}
@@ -70,6 +100,15 @@ export async function POST(request: NextRequest) {
const body = await request.json();
console.log('Request body:', body);
// Validate request body with Zod (only for non-static QRs or simplified validation)
// Note: Static QRs have complex nested content structure, so we do basic validation
if (!body.isStatic) {
const validation = await validateRequest(createQRSchema, body);
if (!validation.success) {
return NextResponse.json(validation.error, { status: 400 });
}
}
// Check if this is a static QR request
const isStatic = body.isStatic === true;