import { NextResponse } from "next/server"; import { getToken } from "next-auth/jwt"; import { env } from "@/env"; import { buildContentSecurityPolicy, createCspNonce } from "@/lib/csp"; import { shouldRedirectAdminRequest } from "@/lib/proxy-access"; const SECURITY_HEADERS: Record = { "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "X-XSS-Protection": "0", "Referrer-Policy": "strict-origin-when-cross-origin", "Permissions-Policy": "camera=(), microphone=(), geolocation=()", "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload", }; export const proxy = async (req: import("next/server").NextRequest) => { const token = await getToken({ req, secret: env.AUTH_SECRET, secureCookie: true, }); if (shouldRedirectAdminRequest(req.nextUrl.pathname, token)) { return NextResponse.redirect(new URL("/login", req.url)); } const nonce = createCspNonce(); const csp = buildContentSecurityPolicy(nonce); const headers = new Headers(req.headers); headers.set("x-pathname", req.nextUrl.pathname); headers.set("x-nonce", nonce); const ip = req.headers.get("cf-connecting-ip") ?? req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? ""; if (ip) headers.set("x-real-client-ip", ip); if (token) { headers.set( "Cache-Control", "private, no-cache, no-store, max-age=0, must-revalidate", ); } else { headers.set( "Cache-Control", "public, max-age=60, s-maxage=300, stale-while-revalidate=300", ); } const response = NextResponse.next({ request: { headers } }); for (const [key, value] of Object.entries(SECURITY_HEADERS)) { response.headers.set(key, value); } response.headers.set("Content-Security-Policy", csp); return response; }; export const config = { matcher: ["/((?!api|_next/static|_next/image|assets|favicon.ico).*)"], };