UNPKG

@nosecone/sveltekit

Version:

Protect your SvelteKit application with secure headers

97 lines (94 loc) 3.13 kB
import nosecone, { defaults as defaults$1, CONTENT_SECURITY_POLICY_DIRECTIVES, NoseconeValidationError, QUOTED } from 'nosecone'; export { default, default as nosecone, withVercelToolbar } from 'nosecone'; /** * Nosecone SvelteKit defaults. */ const defaults = { ...defaults$1, directives: { ...defaults$1.contentSecurityPolicy.directives, scriptSrc: ["'strict-dynamic'"], }, }; /** * Create a SvelteKit hook that sets secure headers on every request. * * @param options * Configuration to provide to Nosecone. * @returns * SvelteKit hook that sets secure headers. */ function createHook(options = defaults) { return async ({ event, resolve }) => { const response = await resolve(event); const headers = nosecone(options); for (const [headerName, headerValue] of headers.entries()) { // Only add headers that aren't already set. For example, SvelteKit will // likely have added `Content-Security-Policy` if configured with `csp` if (!response.headers.has(headerName)) { response.headers.set(headerName, headerValue); } } return response; }; } function unquote(value) { for (const [unquoted, quoted] of QUOTED) { if (value === quoted) { return unquoted; } } return value; } function resolveValue(v) { if (typeof v === "function") { return v(); } else { return v; } } function directivesToSvelteKitConfig(directives) { const sveltekitDirectives = {}; for (const [optionKey, optionValues] of Object.entries(directives)) { const key = CONTENT_SECURITY_POLICY_DIRECTIVES.get( // @ts-expect-error because we're validating this option key optionKey); if (!key) { throw new NoseconeValidationError(`${optionKey} is not a Content-Security-Policy directive`); } // Skip anything falsey if (!optionValues) { continue; } // TODO: What do we want to do if array is empty? I think they work differently for some directives const resolvedValues = Array.isArray(optionValues) ? new Set(optionValues.map(resolveValue)) : new Set(); // TODO: Add validations for SvelteKit CSP directives const values = Array.from(resolvedValues); if (key === "upgrade-insecure-requests") { sveltekitDirectives[key] = true; } else { // @ts-ignore because we're mapping to SvelteKit options sveltekitDirectives[key] = values.map(unquote); } } return sveltekitDirectives; } /** * Create a SvelteKit Content Security Policy configuration. * * @param options * Configuration. * @returns * SvelteKit Content Security Policy configuration. */ function csp(options) { return { mode: options?.mode ? options.mode : "auto", directives: directivesToSvelteKitConfig(options?.directives ?? defaults.contentSecurityPolicy.directives) || {}, }; } export { createHook, csp, defaults };