Phase 8: TypeScript migration, i18n rewrite, Activity Tree, Projects API, Heartbeats

This commit is contained in:
Rose
2026-04-29 11:50:00 +02:00
parent c705fad626
commit 255914c9f1
43 changed files with 17948 additions and 6899 deletions

View File

@@ -35,17 +35,26 @@ def safe_resolve(root: Path, requested: str) -> Path:
return resolved
def _security_headers(handler):
def _security_headers(handler, origin=None):
"""Add security headers to every response."""
handler.send_header('X-Content-Type-Options', 'nosniff')
handler.send_header('X-Frame-Options', 'DENY')
handler.send_header('Referrer-Policy', 'same-origin')
handler.send_header('Access-Control-Allow-Origin', origin or '*')
handler.send_header('Access-Control-Allow-Credentials', 'true' if origin else 'false')
handler.send_header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH,OPTIONS')
handler.send_header('Access-Control-Allow-Headers', 'Content-Type,Authorization,X-Requested-With')
handler.send_header('Vary', 'Origin')
connect_src = "'self'"
if origin:
connect_src += f" {origin}"
handler.send_header(
'Content-Security-Policy',
"default-src 'self'; "
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; "
"style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; "
"img-src 'self' data: https: blob:; font-src 'self' data: https://cdn.jsdelivr.net; connect-src 'self'; "
"img-src 'self' data: https: blob:; font-src 'self' data: https://cdn.jsdelivr.net; "
f"connect-src {connect_src}; "
"base-uri 'self'; form-action 'self'"
)
handler.send_header(
@@ -61,7 +70,8 @@ def j(handler, payload, status: int=200) -> None:
handler.send_header('Content-Type', 'application/json; charset=utf-8')
handler.send_header('Content-Length', str(len(body)))
handler.send_header('Cache-Control', 'no-store')
_security_headers(handler)
origin = handler.headers.get('Origin', None) or handler.headers.get('Referer', '').rsplit('/', 1)[0] if handler.headers.get('Referer', '') else None
_security_headers(handler, origin=origin)
handler.end_headers()
handler.wfile.write(body)
@@ -73,7 +83,8 @@ def t(handler, payload, status: int=200, content_type: str='text/plain; charset=
handler.send_header('Content-Type', content_type)
handler.send_header('Content-Length', str(len(body)))
handler.send_header('Cache-Control', 'no-store')
_security_headers(handler)
origin = handler.headers.get('Origin', None) or handler.headers.get('Referer', '').rsplit('/', 1)[0] if handler.headers.get('Referer', '') else None
_security_headers(handler, origin=origin)
handler.end_headers()
handler.wfile.write(body)