mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:01:08 +02:00
feat(security): add unified CSP headers to all 17 web apps
Create @manacore/shared-utils/security-headers with setSecurityHeaders() utility that sets standard security headers (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy). CSP includes stats.mana.how (Umami) and glitchtip.mana.how by default. Each app passes its own connectSrc origins (auth URL, backend URL, etc.). Previously only Calendar and Storage had CSP headers - now all 17 web apps have consistent security headers via the shared utility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
79544160b7
commit
f5ee3aae20
19 changed files with 246 additions and 58 deletions
|
|
@ -8,7 +8,8 @@
|
|||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./analytics": "./src/analytics.ts",
|
||||
"./analytics-server": "./src/analytics-server.ts"
|
||||
"./analytics-server": "./src/analytics-server.ts",
|
||||
"./security-headers": "./src/security-headers.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"type-check": "tsc --noEmit",
|
||||
|
|
|
|||
66
packages/shared-utils/src/security-headers.ts
Normal file
66
packages/shared-utils/src/security-headers.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* Shared security headers for SvelteKit web apps.
|
||||
*
|
||||
* Sets standard security headers (CSP, X-Frame-Options, etc.)
|
||||
* with Umami analytics and GlitchTip error tracking pre-configured.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { setSecurityHeaders } from '@manacore/shared-utils/security-headers';
|
||||
*
|
||||
* const response = await resolve(event, { transformPageChunk: ... });
|
||||
* setSecurityHeaders(response, {
|
||||
* connectSrc: [authUrl, backendUrl],
|
||||
* });
|
||||
* return response;
|
||||
* ```
|
||||
*/
|
||||
|
||||
interface SecurityHeadersOptions {
|
||||
/** Additional connect-src origins (auth URL, backend URL, etc.) */
|
||||
connectSrc?: string[];
|
||||
/** Additional script-src origins */
|
||||
scriptSrc?: string[];
|
||||
/** Additional img-src origins */
|
||||
imgSrc?: string[];
|
||||
/** Additional font-src origins */
|
||||
fontSrc?: string[];
|
||||
/** Override frame-ancestors (default: 'none') */
|
||||
frameAncestors?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set standard security headers on a Response object.
|
||||
* Includes Umami (stats.mana.how) and GlitchTip (glitchtip.mana.how) by default.
|
||||
*/
|
||||
export function setSecurityHeaders(response: Response, options: SecurityHeadersOptions = {}): void {
|
||||
const {
|
||||
connectSrc = [],
|
||||
scriptSrc = [],
|
||||
imgSrc = [],
|
||||
fontSrc = [],
|
||||
frameAncestors = "'none'",
|
||||
} = options;
|
||||
|
||||
// Standard security headers
|
||||
response.headers.set('X-Frame-Options', 'DENY');
|
||||
response.headers.set('X-Content-Type-Options', 'nosniff');
|
||||
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
|
||||
|
||||
// Content Security Policy
|
||||
const cspDirectives = [
|
||||
"default-src 'self'",
|
||||
`script-src 'self' 'unsafe-inline' https://stats.mana.how https://glitchtip.mana.how ${scriptSrc.join(' ')}`.trim(),
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
`img-src 'self' data: https: ${imgSrc.join(' ')}`.trim(),
|
||||
`connect-src 'self' https://stats.mana.how https://glitchtip.mana.how ${connectSrc.join(' ')}`.trim(),
|
||||
`font-src 'self' ${fontSrc.join(' ')}`.trim(),
|
||||
"object-src 'none'",
|
||||
"base-uri 'self'",
|
||||
"form-action 'self'",
|
||||
`frame-ancestors ${frameAncestors}`,
|
||||
];
|
||||
|
||||
response.headers.set('Content-Security-Policy', cspDirectives.join('; '));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue