v0.324.0: the database password comes back with the data (R-1106, R-127b, R-926); restic 0.19.1 (R-1107); R-1108, R-1065, R-1017; dashboard hardening (R-983, R-976)
gates / gates (push) Successful in 44s

This commit is contained in:
2026-10-16 22:46:00 +02:00
parent 00a0d91976
commit f75b3aa778
212 changed files with 2414 additions and 398 deletions
+19 -2
View File
@@ -74,8 +74,11 @@ type Server struct {
sessionsMu sync.RWMutex
loginAttempts map[string]*loginAttempt
loginAttemptMu sync.Mutex
done chan struct{}
closeOnce sync.Once
// passwordCompare replaces bcrypt's compare at the dashboard sign-in in tests (R-983: a slow compare makes the
// parallel-try race measurable). nil → bcrypt.
passwordCompare func(hash, pw []byte) error
done chan struct{}
closeOnce sync.Once
// Guest launcher share (v0.165.0): its OWN per-IP brute-force limiter for the optional share
// password gate — deliberately separate from loginAttempts (the admin login), so a guest and the
@@ -89,6 +92,11 @@ type Server struct {
claimAttempts map[string]*claimAttempt
claimGlobal claimAttempt
claimClock func() time.Time
// R-983 (v0.324.0): the reset-code request's own limit, under claimMu and claimClock — when each visitor last
// reached the hub, and when the box last did (a sliding window). resetRequestFn replaces the hub call in tests.
resetReqVisitor map[string]time.Time
resetReqGlobal []time.Time
resetRequestFn func()
// Guard for FileBrowser sync — prevents concurrent file writes (H5 fix)
fileBrowserMu sync.Mutex
@@ -975,6 +983,15 @@ func (s *Server) CatchAllMiddleware(next http.Handler) http.Handler {
s.ServeFamilyGateAuth(w, r)
return
}
// R-983 (v0.324.0): no page of ours may be shown inside another page's frame. Every app on *.<domain> is
// SAME-SITE with the dashboard, so the Lax session cookie goes along into a frame an app page draws — a page
// on any app host could lay the signed-in dashboard under its own buttons. Nothing frames the dashboard
// legitimately (no iframe in the controller, the catalog, the hub or the website, checked 2026-10-16), so
// DENY rather than SAMEORIGIN. The two forwardAuth answers above are left exactly as they were: traefik
// reads them, and their headers must not leak onto an app's own responses. Pinned by
// TestR983_DashboardRefusesFraming.
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Content-Security-Policy", "frame-ancestors 'none'")
if strings.EqualFold(host, controllerHost) {
switch r.URL.Path { // v0.287.0: the family sign-in pages, outside the dashboard's own auth on purpose
case familyStartPath: