Add per-request CSP nonces (drop script unsafe-inline), post-deploy /api/health gate, bump next-auth to beta.32, and remove unused motion/cache/permission helpers. Co-authored-by: Cursor <[email protected]>
37 lines
1.2 KiB
TypeScript
37 lines
1.2 KiB
TypeScript
/**
|
|
* Build a Content-Security-Policy value.
|
|
* Scripts: nonce for Next.js / first-party inline; host allowlists for captcha,
|
|
* Cloudflare Insights, and TinyMCE CDN. style-src keeps 'unsafe-inline' for
|
|
* theme CSS variables (ThemeVars) — nonce styles are a follow-up.
|
|
*/
|
|
export function buildContentSecurityPolicy(nonce: string): string {
|
|
const isDev = process.env.NODE_ENV === "development";
|
|
const scriptSrc = [
|
|
"'self'",
|
|
`'nonce-${nonce}'`,
|
|
"https://challenges.cloudflare.com",
|
|
"https://www.google.com/recaptcha/",
|
|
"https://www.gstatic.com/recaptcha/",
|
|
"https://static.cloudflareinsights.com",
|
|
"https://cdn.jsdelivr.net",
|
|
...(isDev ? ["'unsafe-eval'"] : []),
|
|
].join(" ");
|
|
|
|
return [
|
|
"default-src 'self'",
|
|
`script-src ${scriptSrc}`,
|
|
"style-src 'self' 'unsafe-inline'",
|
|
"img-src 'self' data: blob: https:",
|
|
"frame-src 'self' https://challenges.cloudflare.com https://www.google.com/recaptcha/",
|
|
"connect-src 'self' https: wss:",
|
|
"font-src 'self' data:",
|
|
"object-src 'none'",
|
|
"base-uri 'self'",
|
|
"form-action 'self'",
|
|
].join("; ");
|
|
}
|
|
|
|
export function createCspNonce(): string {
|
|
return Buffer.from(crypto.randomUUID()).toString("base64");
|
|
}
|