// A Content Security Policy for every page: scripts only from this site with the request's nonce (Next.js adds it to // its own scripts), so HTML that slips into a page, such as a product's description, can't run anything. Uploads go // from the browser straight to catalogs, so connect-src allows any https address (and local ones, for development). import { NextResponse, type NextRequest } from "next/server"; export function proxy(request: NextRequest) { const nonce = Buffer.from(crypto.randomUUID()).toString("base64"); const dev = process.env.NODE_ENV === "development"; const policy = [ "default-src 'self'", `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'${dev ? " 'unsafe-eval'" : ""}`, // Descriptions keep their style attributes (the API's allowlist limits them to colors, sizes and alignment). "style-src 'self' 'unsafe-inline'", "img-src 'self' https: data: blob:", "font-src 'self'", `connect-src 'self' https: http://localhost:* http://127.0.0.1:*${dev ? " ws:" : ""}`, "object-src 'none'", "base-uri 'self'", "form-action 'self'", "frame-ancestors 'none'", ].join("; "); const headers = new Headers(request.headers); headers.set("x-nonce", nonce); headers.set("Content-Security-Policy", policy); const response = NextResponse.next({ request: { headers } }); response.headers.set("Content-Security-Policy", policy); return response; } export const config = { matcher: [ { source: "/((?!api|_next/static|_next/image|icon.svg|favicon.ico).*)", missing: [ { type: "header", key: "next-router-prefetch" }, { type: "header", key: "purpose", value: "prefetch" }, ], }, ], };