import { NextResponse, type NextRequest } from 'next/server'; import { createHash } from 'node:crypto'; const ADMIN_COOKIE = 'ci_admin'; /** * Request proxy (Next 16 name for middleware): exchanges `/admin…?token=` for the * httpOnly admin cookie and redirects to the same URL without the token, so the token never stays * in the address bar or in server logs beyond the first hit. */ export function proxy(req: NextRequest) { const url = req.nextUrl; if (url.pathname.startsWith('/admin') && url.searchParams.has('token')) { const token = url.searchParams.get('token') ?? ''; const expected = process.env.ADMIN_TOKEN ?? ''; const clean = url.clone(); clean.searchParams.delete('token'); const res = NextResponse.redirect(clean); if (expected && token === expected) { res.cookies.set(ADMIN_COOKIE, createHash('sha256').update(token).digest('hex'), { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV === 'production', path: '/', maxAge: 60 * 60 * 12 }); } return res; } return NextResponse.next(); } export const config = { matcher: ['/admin/:path*', '/admin'] };