fix(csp): allow Google Fonts, blob workers, and jsDelivr in CSP directives

This commit is contained in:
neon
2026-05-14 19:03:11 -06:00
parent 3138cf3a4d
commit da5d6cb31f
4 changed files with 281 additions and 42 deletions
@@ -0,0 +1,54 @@
const DEFAULT_TRUST_PROXY = 'loopback,linklocal,uniquelocal';
export function parseTrustProxy(value: string | undefined): string | boolean | number {
const raw = value?.trim();
if (!raw) return DEFAULT_TRUST_PROXY;
const normalized = raw.toLowerCase();
if (['false', '0', 'no', 'off'].includes(normalized)) return false;
if (['true', '1', 'yes', 'on'].includes(normalized)) return true;
const hopCount = Number(raw);
if (Number.isInteger(hopCount) && hopCount >= 0) return hopCount;
return raw;
}
export function parseBooleanEnv(value: string | undefined, fallback = false): boolean {
const raw = value?.trim();
if (!raw) return fallback;
const normalized = raw.toLowerCase();
if (['false', '0', 'no', 'off'].includes(normalized)) return false;
if (['true', '1', 'yes', 'on'].includes(normalized)) return true;
return fallback;
}
export interface CspOptions {
allowCloudflareInsights?: boolean;
}
const CLOUDFLARE_INSIGHTS_SCRIPT_SRC = 'https://static.cloudflareinsights.com';
const CLOUDFLARE_INSIGHTS_CONNECT_SRC = 'https://cloudflareinsights.com';
export function buildCspDirectives(options: CspOptions = {}) {
const { allowCloudflareInsights = false } = options;
const scriptSrc = ["'self'", "'wasm-unsafe-eval'", ...(allowCloudflareInsights ? [CLOUDFLARE_INSIGHTS_SCRIPT_SRC] : [])];
const connectSrc = ["'self'", 'ws:', 'wss:', 'https://cdn.jsdelivr.net', ...(allowCloudflareInsights ? [CLOUDFLARE_INSIGHTS_CONNECT_SRC] : [])];
return {
defaultSrc: ["'self'"],
scriptSrc,
styleSrc: ["'self'", "'unsafe-inline'", 'blob:', 'https://fonts.googleapis.com'],
imgSrc: ["'self'", 'data:', 'blob:'],
connectSrc,
mediaSrc: ["'self'", 'data:', 'blob:'],
fontSrc: ["'self'", 'data:', 'blob:', 'https://fonts.gstatic.com'],
objectSrc: ["'none'"],
frameSrc: ["'self'", 'blob:'],
frameAncestors: ["'self'"],
workerSrc: ["'self'", 'blob:'],
upgradeInsecureRequests: null,
};
}