add back hooks

This commit is contained in:
Jesse Winton
2025-04-09 13:09:37 -04:00
parent 104b5366f3
commit 496ed81c80

126
src/hooks.server.ts Normal file
View File

@@ -0,0 +1,126 @@
import type { Handle } from '@sveltejs/kit';
import redirects from './redirects.json';
import { sequence } from '@sveltejs/kit/hooks';
import { BANNER_KEY } from '$lib/constants';
import { dev } from '$app/environment';
const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect]));
const redirecter: Handle = async ({ event, resolve }) => {
const currentPath = event.url.pathname;
if (redirectMap.has(currentPath)) {
return new Response(null, {
status: 308,
headers: {
location: redirectMap.get(currentPath) ?? ''
}
});
}
return await resolve(event);
};
const securityheaders: Handle = async ({ event, resolve }) => {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
(event.locals as { nonce: string }).nonce = nonce;
const response = await resolve(event, {
transformPageChunk: ({ html }) => {
return html.replace(/%sveltekit.nonce%/g, nonce);
}
});
// `true` if deployed via Coolify.
const isPreview = !!process.env.COOLIFY_FQDN;
// COOLIFY_FQDN already includes `http`.
const previewDomain = isPreview ? `${process.env.COOLIFY_FQDN}` : null;
const join = (arr: string[]) => arr.join(' ');
const cspDirectives: Record<string, string> = {
'default-src': "'self'",
'script-src': join([
"'self'",
'blob:',
"'unsafe-inline'",
"'unsafe-eval'",
'https://*.posthog.com',
'https://*.plausible.io',
'https://*.reo.dev',
'https://plausible.io',
'https://js.zi-scripts.com',
'https://ws.zoominfo.com'
]),
'style-src': "'self' 'unsafe-inline'",
'img-src': "'self' data: https:",
'font-src': "'self'",
'object-src': "'none'",
'base-uri': "'self'",
'form-action': "'self'",
'frame-ancestors': join(["'self'", 'https://www.youtube.com', 'https://*.vimeo.com']),
'block-all-mixed-content': '',
'upgrade-insecure-requests': '',
'connect-src': join([
"'self'",
'https://*.appwrite.io',
'https://*.appwrite.org',
'https://*.posthog.com',
'https://*.sentry.io',
'https://*.plausible.io',
'https://plausible.io',
'https://*.reo.dev',
'https://js.zi-scripts.com',
'https://aorta.clickagy.com',
'https://hemsync.clickagy.com',
'https://ws.zoominfo.com '
]),
'frame-src': join([
"'self'",
'https://www.youtube.com',
'https://status.appwrite.online',
'https://www.youtube-nocookie.com',
'https://player.vimeo.com',
'https://hemsync.clickagy.com'
])
};
if (isPreview) {
delete cspDirectives['block-all-mixed-content'];
delete cspDirectives['upgrade-insecure-requests'];
['default-src', 'script-src', 'style-src', 'img-src', 'font-src', 'connect-src'].forEach(
(key) => {
cspDirectives[key] += ` ${previewDomain}`;
}
);
}
const cspDirectivesString = Object.entries(cspDirectives)
.map(([key, value]) => `${key} ${value}`.trim())
.join('; ');
// Set security headers
response.headers.set('Content-Security-Policy', cspDirectivesString);
// HTTP Strict Transport Security
// max-age is set to 1 year in seconds
response.headers.set(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload'
);
// X-Content-Type-Options
response.headers.set('X-Content-Type-Options', 'nosniff');
// X-Frame-Options
response.headers.set('X-Frame-Options', 'DENY');
return response;
};
const bannerRewriter: Handle = async ({ event, resolve }) => {
const response = await resolve(event, {
transformPageChunk: ({ html }) => html.replace('%aw_banner_key%', BANNER_KEY)
});
return response;
};
export const handle = sequence(redirecter, bannerRewriter, securityheaders);