Organize src/ into concern folders (http, auth, admin, plugin-host, ui); co-locate tests, move plugin-api barrel into plugin-host, sync docs + AGENTS layout

This commit is contained in:
2026-06-24 00:23:55 +02:00
parent 6d316c4888
commit de22f51c12
113 changed files with 282 additions and 265 deletions
+38
View File
@@ -0,0 +1,38 @@
// Response security headers: set once per request in app.ts so every response — page,
// JSON, redirect, static, or error — carries them (writeHead merges with setHeader). A plugin route
// may override any of them per-response via RouteResult.headers (e.g. relax the CSP to ship its own JS).
// Strict default CSP for the zero-JS, server-rendered core:
// - script-src 'self' : the core ships no JS; a plugin may still serve its own /public/<id>/*.js for
// opt-in progressive enhancement. No 'unsafe-inline' ⇒ an injected <script>
// can't run (the main XSS sink).
// - style-src adds 'unsafe-inline' : a few partials carry inline style= attributes.
// - img-src adds data: : favicon + inline data URIs.
// - no form-action : the themed login form posts to Kratos' (often cross-origin) action URL.
// - frame-ancestors 'none' : clickjacking guard (the modern X-Frame-Options).
const CSP = [
"base-uri 'self'",
"default-src 'self'",
"frame-ancestors 'none'",
"img-src 'self' data:",
"object-src 'none'",
"script-src 'self'",
"style-src 'self' 'unsafe-inline'",
].join("; ");
export interface SecurityHeaderOptions {
secure?: boolean; // https deployment (mirrors SECURE_COOKIES) → also emit HSTS
}
export function securityHeaders(options: SecurityHeaderOptions = {}): Record<string, string> {
const headers: Record<string, string> = {
"content-security-policy": CSP,
"cross-origin-opener-policy": "same-origin",
"referrer-policy": "strict-origin-when-cross-origin",
"x-content-type-options": "nosniff",
"x-frame-options": "DENY",
};
// HSTS only over https — ignored (and meaningless) on the dev http origin.
if (options.secure) headers["strict-transport-security"] = "max-age=31536000; includeSubDomains";
return headers;
}