UNPKG

@nosecone/sveltekit

Version:

Protect your SvelteKit application with secure headers

84 lines (81 loc) 2.89 kB
import nosecone, { defaults as defaults$1, CONTENT_SECURITY_POLICY_DIRECTIVES, NoseconeValidationError, QUOTED } from 'nosecone'; export { default, withVercelToolbar } from 'nosecone'; 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 A 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; } function csp(options = { mode: "auto" }) { return { mode: options.mode ? options.mode : "auto", directives: directivesToSvelteKitConfig(options.directives ?? defaults.contentSecurityPolicy.directives), }; } export { createHook, csp, defaults };