feat(aether): initial commit – self-hosted Cloud, Phasen 1–7
Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
31a027c93a
225 files changed
+38042
No files matched your search
@@ -0,0 +1,55 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SecurityHeaders adds security headers that the app controls.
|
||||
// HSTS is intentionally omitted — it belongs on the edge reverse proxy.
|
||||
//
|
||||
// frameSrc nennt zusätzliche Ursprünge, die in einem Rahmen erscheinen dürfen.
|
||||
// Gebraucht für den Office-Server: Seine Bedienoberfläche läuft in einem
|
||||
// <iframe>, und `default-src 'self'` deckt auch `frame-src` ab – ohne
|
||||
// Ausnahme blockt der Browser sie, noch bevor eine Anfrage hinausgeht.
|
||||
// Gemessen als „Framing 'http://…:9980/' violates … default-src 'self'".
|
||||
//
|
||||
// Bewusst **nur der eine konfigurierte Ursprung** und kein Platzhalter: Die
|
||||
// Ausnahme soll so schmal sein wie der Anlass.
|
||||
func SecurityHeaders(frameSrc ...string) func(http.Handler) http.Handler {
|
||||
frame := "frame-src 'self'"
|
||||
for _, raw := range frameSrc {
|
||||
if origin := originOf(raw); origin != "" {
|
||||
frame += " " + origin
|
||||
}
|
||||
}
|
||||
csp := "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; " +
|
||||
"img-src 'self' data: blob:; " + frame
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h := w.Header()
|
||||
h.Set("X-Content-Type-Options", "nosniff")
|
||||
h.Set("X-Frame-Options", "DENY")
|
||||
h.Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||
h.Set("Content-Security-Policy", csp)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// originOf reduziert eine Adresse auf Schema und Host. Ein Pfad in einer
|
||||
// CSP-Quelle wäre nicht falsch, aber enger als gemeint – und ein Tippfehler
|
||||
// darin fiele erst auf, wenn der Rahmen leer bleibt.
|
||||
func originOf(raw string) string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return ""
|
||||
}
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil || u.Scheme == "" || u.Host == "" {
|
||||
return ""
|
||||
}
|
||||
return u.Scheme + "://" + u.Host
|
||||
}
|
||||
Reference in new issue
Block a user