csp, hooks, sentry

This commit is contained in:
matthieu42morin 2024-04-29 05:02:00 +02:00
parent a902adaf43
commit 4199070dfd
3 changed files with 108 additions and 99 deletions

View File

@ -1,83 +1,83 @@
// https://gist.github.com/acoyfellow/d8e86979c66ebea25e1643594e38be73, Rodney Lab // https://gist.github.com/acoyfellow/d8e86979c66ebea25e1643594e38be73, Rodney Lab
import { import {
PUBLIC_SITE_DOMAIN, URARA_SITE_DOMAIN,
PUBLIC_SENTRY_KEY, PUBLIC_SENTRY_KEY,
PUBLIC_SENTRY_PROJECT_ID, PUBLIC_SENTRY_PROJECT_ID,
PUBLIC_SENTRY_ORG_ID, PUBLIC_SENTRY_ORG_ID,
PUBLIC_WORKER_URL PUBLIC_WORKER_URL,
URARA_SITE_PROTOCOL
} from '$env/static/public' } from '$env/static/public'
const rootDomain = PUBLIC_SITE_DOMAIN // or your server IP for dev console.log(`${URARA_SITE_PROTOCOL}${URARA_SITE_DOMAIN}`)
const directives = { const directives = {
'base-uri': ["'self'"], 'base-uri': ["'self'"],
'child-src': ["'self'", 'blob:'], 'child-src': ["'self'", 'blob:'],
// 'connect-src': ["'self'", 'ws://localhost:*'], 'connect-src': [
'connect-src': [ "'self'",
"'self'", 'ws://localhost:*',
'ws://localhost:*', 'https://*.sentry.io',
'https://*.sentry.io', 'https://hcaptcha.com',
'https://hcaptcha.com', 'https://*.hcaptcha.com',
'https://*.hcaptcha.com', 'https://*.cartocdn.com',
'https://*.cartocdn.com', URARA_SITE_DOMAIN,
PUBLIC_SITE_DOMAIN, PUBLIC_WORKER_URL
PUBLIC_WORKER_URL ],
], 'img-src': ["'self'", 'data:', 'https://images.unsplash.com', `${URARA_SITE_PROTOCOL}${URARA_SITE_DOMAIN}`],
'img-src': ["'self'", 'data:', 'https://images.unsplash.com'], 'font-src': ["'self'", 'data:'],
'font-src': ["'self'", 'data:'], 'form-action': ["'self'"],
'form-action': ["'self'"], 'frame-ancestors': ["'self'"],
'frame-ancestors': ["'self'"], 'frame-src': [
'frame-src': [ "'self'",
"'self'", // "https://*.stripe.com",
// "https://*.stripe.com", // "https://*.facebook.com",
// "https://*.facebook.com", // "https://*.facebook.net",
// "https://*.facebook.net", 'https://hcaptcha.com',
'https://hcaptcha.com', 'https://*.hcaptcha.com',
'https://*.hcaptcha.com', 'https://www.openstreetmap.org',
'https://www.openstreetmap.org', 'https://*.cartocdn.com'
'https://*.cartocdn.com' ],
], 'manifest-src': ["'self'"],
'manifest-src': ["'self'"], 'media-src': ["'self'", 'data:'],
'media-src': ["'self'", 'data:'], 'object-src': ["'none'"],
'object-src': ["'none'"], // 'style-src': ["'self'", "'unsafe-inline'"],
// 'style-src': ["'self'", "'unsafe-inline'"], 'style-src': ["'self'", "'unsafe-inline'", 'https://hcaptcha.com', 'https://*.hcaptcha.com'],
'style-src': ["'self'", "'unsafe-inline'", 'https://hcaptcha.com', 'https://*.hcaptcha.com'], 'default-src': [
'default-src': [ "'self'",
"'self'", URARA_SITE_DOMAIN,
PUBLIC_SITE_DOMAIN, `ws://${URARA_SITE_DOMAIN}`,
`ws://${PUBLIC_SITE_DOMAIN}`, // 'https://*.google.com',
// 'https://*.google.com', // 'https://*.googleapis.com',
// 'https://*.googleapis.com', // 'https://*.firebase.com',
// 'https://*.firebase.com', // 'https://*.gstatic.com',
// 'https://*.gstatic.com', // 'https://*.cloudfunctions.net',
// 'https://*.cloudfunctions.net', // 'https://*.algolia.net',
// 'https://*.algolia.net', // 'https://*.facebook.com',
// 'https://*.facebook.com', // 'https://*.facebook.net',
// 'https://*.facebook.net', // 'https://*.stripe.com',
// 'https://*.stripe.com', 'https://*.sentry.io'
'https://*.sentry.io' ],
], 'script-src': [
'script-src': [ "'self'",
"'self'", "'unsafe-inline'",
"'unsafe-inline'", // 'https://*.stripe.com',
// 'https://*.stripe.com', // 'https://*.facebook.com',
// 'https://*.facebook.com', // 'https://*.facebook.net',
// 'https://*.facebook.net', 'https://hcaptcha.com',
'https://hcaptcha.com', 'https://*.hcaptcha.com',
'https://*.hcaptcha.com', 'https://*.sentry.io',
'https://*.sentry.io', // 'https://polyfill.io',
// 'https://polyfill.io', 'https://*.cartocdn.com'
'https://*.cartocdn.com' ],
], 'worker-src': ["'self'", 'blob:'],
'worker-src': ["'self'", 'blob:'], //report-to can throw "Content-Security-Policy: Couldnt process unknown directive report-to", leave it for older browsers.
//report-to can throw "Content-Security-Policy: Couldnt process unknown directive report-to", leave it for older browsers. 'report-to': ["'csp-endpoint'"],
'report-to': ["'csp-endpoint'"], 'report-uri': [
'report-uri': [ `https://${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/api/${PUBLIC_SENTRY_PROJECT_ID}/security/?sentry_key=${PUBLIC_SENTRY_KEY}`
`https://${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/api/${PUBLIC_SENTRY_PROJECT_ID}/security/?sentry_key=${PUBLIC_SENTRY_KEY}` ]
]
} }
export const csp = Object.entries(directives) export const csp = Object.entries(directives)
.map(([key, arr]) => key + ' ' + arr.join(' ')) .map(([key, arr]) => key + ' ' + arr.join(' '))
.join('; ') .join('; ')

View File

@ -4,44 +4,44 @@ import { site } from '$lib/config/site'
import { handleErrorWithSentry, sentryHandle } from '@sentry/sveltekit' import { handleErrorWithSentry, sentryHandle } from '@sentry/sveltekit'
import * as Sentry from '@sentry/sveltekit' import * as Sentry from '@sentry/sveltekit'
import { PUBLIC_SENTRY_KEY, PUBLIC_SENTRY_PROJECT_ID, PUBLIC_SENTRY_ORG_ID } from '$env/static/public' import { PUBLIC_SENTRY_KEY, PUBLIC_SENTRY_PROJECT_ID, PUBLIC_SENTRY_ORG_ID, URARA_SITE_DOMAIN } from '$env/static/public'
import { csp } from './cspDirectives' import { csp } from './cspDirectives'
Sentry.init({ Sentry.init({
dsn: `https://${PUBLIC_SENTRY_KEY}@${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/${PUBLIC_SENTRY_PROJECT_ID}`, dsn: `https://${PUBLIC_SENTRY_KEY}@${PUBLIC_SENTRY_ORG_ID}.ingest.us.sentry.io/${PUBLIC_SENTRY_PROJECT_ID}`,
tracesSampleRate: 1.0 tracesSampleRate: 1.0
}) })
export const cspHandle: Handle = async ({ event, resolve }) => { export const cspHandle: Handle = async ({ event, resolve }) => {
if (!csp) { if (!csp) {
throw new Error('csp is undefined') throw new Error('csp is undefined')
} }
const response = await resolve(event) const response = await resolve(event)
// Permission fullscreen necessary for maps fullscreen // Permission fullscreen necessary for maps fullscreen
const headers = { const headers = {
'X-Frame-Options': 'SAMEORIGIN', 'X-Frame-Options': 'SAMEORIGIN',
'Referrer-Policy': 'no-referrer', 'Referrer-Policy': 'no-referrer',
'Permissions-Policy': `accelerometer=(), autoplay=(), camera=(), document-domain=(self, 'js-profiling'), encrypted-media=(), fullscreen=(self ${PUBLIC_SITE_DOMAIN}), gyroscope=(), interest-cohort=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), sync-xhr=(), usb=(), xr-spatial-tracking=(), geolocation=()`, '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', 'X-Content-Type-Options': 'nosniff',
// 'Content-Security-Policy-Report-Only': csp, // 'Content-Security-Policy-Report-Only': csp,
'Content-Security-Policy': csp, 'Content-Security-Policy': csp,
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload', '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}"`, '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}"}]}` '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]) => { Object.entries(headers).forEach(([key, value]) => {
response.headers.set(key, value) response.headers.set(key, value)
}) })
return response return response
} }
export const langHandle: Handle = async ({ event, resolve }) => export const langHandle: Handle = async ({ event, resolve }) =>
await resolve(event, { await resolve(event, {
transformPageChunk: ({ html }) => html.replace('<html lang="en">', `<html lang="${site.lang ?? 'en'}">`) 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. // If you have custom handlers, make sure to place them after `sentryHandle()` in the `sequence` function.
export const handle: Handle = sequence(sentryHandle(), cspHandle, langHandle) export const handle: Handle = sequence(sentryHandle(), cspHandle, langHandle)

9
src/lib/constants.ts Normal file
View File

@ -0,0 +1,9 @@
export const cookies = {
NECESSARY: 'mattmor-necessary',
ANALYTICAL: 'mattmor-analytical',
TARGETING: 'mattmor-targeting',
VISITED: 'mattmor-marketing-website-visited'
};
export const COPYRIGHT_ENTITY = '\u00a9'; // (c)
export const H_ELLIPSIS_ENTITY = '\u2026'; // ...
export const VERTICAL_LINE_ENTITY = '\u007c'; // |