55 lines
2.7 KiB
TypeScript
55 lines
2.7 KiB
TypeScript
import type { Handle } from '@sveltejs/kit'
|
|
import { sequence } from '@sveltejs/kit/hooks'
|
|
import { site } from '$lib/config/site'
|
|
|
|
import { handleErrorWithSentry, sentryHandle } from '@sentry/sveltekit'
|
|
import * as Sentry from '@sentry/sveltekit'
|
|
import { PUBLIC_SENTRY_KEY, PUBLIC_SENTRY_PROJECT_ID, PUBLIC_SENTRY_ORG_ID, URARA_SITE_DOMAIN } from '$env/static/public'
|
|
|
|
import { csp } from './cspDirectives'
|
|
|
|
Sentry.init({
|
|
dsn: `https://${PUBLIC_SENTRY_KEY}@${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/${PUBLIC_SENTRY_PROJECT_ID}`,
|
|
tracesSampleRate: 1.0
|
|
})
|
|
|
|
export const cspHandle: Handle = async ({ event, resolve }) => {
|
|
if (!csp) {
|
|
throw new Error('csp is undefined')
|
|
}
|
|
const response = await resolve(event)
|
|
|
|
// Permission fullscreen necessary for maps fullscreen
|
|
const headers = {
|
|
'X-Frame-Options': 'SAMEORIGIN',
|
|
'Referrer-Policy': 'no-referrer',
|
|
'Permissions-Policy': `accelerometer=(), autoplay=(), camera=(), document-domain=(self, 'js-profiling'), encrypted-media=(), fullscreen=(self ${URARA_SITE_DOMAIN}), gyroscope=(), interest-cohort=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), sync-xhr=(), usb=(), xr-spatial-tracking=(), geolocation=()`,
|
|
'X-Content-Type-Options': 'nosniff',
|
|
// 'Content-Security-Policy-Report-Only': csp,
|
|
'Content-Security-Policy': csp,
|
|
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload',
|
|
'Expect-CT': `max-age=86400, report-uri="https://${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/api/${PUBLIC_SENTRY_PROJECT_ID}/security/?sentry_key=${PUBLIC_SENTRY_KEY}"`,
|
|
'Report-To': `{group: "csp-endpoint", "max_age": 10886400, "endpoints": [{"url": "https://${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/api/${PUBLIC_SENTRY_PROJECT_ID}/security/?sentry_key=${PUBLIC_SENTRY_KEY}"}]}`
|
|
}
|
|
|
|
Object.entries(headers).forEach(([key, value]) => {
|
|
response.headers.set(key, value)
|
|
})
|
|
return response
|
|
}
|
|
|
|
export const langHandle: Handle = async ({ event, resolve }) =>
|
|
await resolve(event, {
|
|
transformPageChunk: ({ html }) => html.replace('<html lang="en">', `<html lang="${site.lang ?? 'en'}">`)
|
|
})
|
|
|
|
// If you have custom handlers, make sure to place them after `sentryHandle()` in the `sequence` function.
|
|
export const handle: Handle = sequence(sentryHandle(), cspHandle, langHandle)
|
|
|
|
// If you have a custom error handler, pass it to `handleErrorWithSentry`
|
|
export const handleError = handleErrorWithSentry()
|
|
// https://gist.github.com/acoyfellow/d8e86979c66ebea25e1643594e38be73
|
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
|
// https://scotthelme.co.uk/content-security-policy-an-introduction/
|
|
// scanner: https://securityheaders.com/
|