Close exploitable gaps in booking/payment flows, enforce token versioning and account checks, gate sensitive payment data, and add middleware plus input validation across admin routes. Co-authored-by: Cursor <cursoragent@cursor.com>
45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
import { revalidateTag } from 'next/cache';
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { timingSafeEqual } from 'crypto';
|
|
|
|
// Constant-time string comparison to avoid leaking the secret via response timing.
|
|
function secretsMatch(provided: unknown, expected: string): boolean {
|
|
if (typeof provided !== 'string' || provided.length === 0) return false;
|
|
const a = Buffer.from(provided);
|
|
const b = Buffer.from(expected);
|
|
if (a.length !== b.length) return false;
|
|
return timingSafeEqual(a, b);
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
const { secret, tag } = body;
|
|
|
|
// Validate the revalidation secret. Reject if it is unset or left at an insecure default.
|
|
const revalidateSecret = process.env.REVALIDATE_SECRET;
|
|
if (!revalidateSecret || revalidateSecret === 'change-me' || revalidateSecret.length < 16) {
|
|
return NextResponse.json({ error: 'Revalidation is not configured' }, { status: 503 });
|
|
}
|
|
if (!secretsMatch(secret, revalidateSecret)) {
|
|
return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
|
|
}
|
|
|
|
// Validate tag(s) - supports single tag or array of tags
|
|
const allowedTags = ['events-sitemap', 'next-event'];
|
|
const tags: string[] = Array.isArray(tag) ? tag : [tag];
|
|
const invalidTags = tags.filter((t: string) => !allowedTags.includes(t));
|
|
if (tags.length === 0 || invalidTags.length > 0) {
|
|
return NextResponse.json({ error: 'Invalid tag' }, { status: 400 });
|
|
}
|
|
|
|
for (const t of tags) {
|
|
revalidateTag(t);
|
|
}
|
|
|
|
return NextResponse.json({ revalidated: true, tags, now: Date.now() });
|
|
} catch {
|
|
return NextResponse.json({ error: 'Failed to revalidate' }, { status: 500 });
|
|
}
|
|
}
|