controller: customer-claim password gate v0.122.0 (closes DRILL-day0-vm F-4/F-5)
The customer sets + owns the dashboard password via a hub-emailed one-time claim code. An unclaimed box (code hash present, no password) serves ONLY the claim page — every other route → claim page (302) or 401, so a Day-0 box is never open on the internet. A set password disables the gate (auth wins). Reset rides the same code engine (login "Elfelejtett jelszó"). Legacy-open (no password, no hash) shows a red transition banner until the hub delivers a hash. Report ACK caches the code state idempotently by generation; report carries claimed (set-only). --print-reset-code root escape hatch. Requires hub v0.50.0. Gate-coverage signature test + 4 red-proofs proven.
This commit is contained in:
@@ -50,6 +50,13 @@ type Server struct {
|
||||
done chan struct{}
|
||||
closeOnce sync.Once
|
||||
|
||||
// Customer-claim arc (v0.122.0, F-4): the claim/reset code brute-force limiter. Per-source
|
||||
// (IP) + a global counter; both must be clear. claimClock is the test clock seam (nil → time.Now).
|
||||
claimMu sync.Mutex
|
||||
claimAttempts map[string]*claimAttempt
|
||||
claimGlobal claimAttempt
|
||||
claimClock func() time.Time
|
||||
|
||||
// Guard for FileBrowser sync — prevents concurrent file writes (H5 fix)
|
||||
fileBrowserMu sync.Mutex
|
||||
|
||||
@@ -272,6 +279,14 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
switch {
|
||||
// Customer-claim arc (v0.122.0, F-4): the code-entry page + its handlers. Reachable pre-auth
|
||||
// (code-gated internally); CSRF via the pre-auth HMAC token (validated inside the handlers).
|
||||
case path == "/claim" && r.Method == http.MethodGet:
|
||||
s.handleClaimPage(w, r, "", r.URL.Query().Get("flash"))
|
||||
case path == "/claim" && r.Method == http.MethodPost:
|
||||
s.handleClaimSubmit(w, r)
|
||||
case path == "/claim/request-new-code" && r.Method == http.MethodPost:
|
||||
s.handleClaimRequestNewCode(w, r)
|
||||
case path == "/" || path == "/dashboard":
|
||||
s.dashboardHandler(w, r)
|
||||
case path == "/stacks":
|
||||
|
||||
Reference in New Issue
Block a user