package auth import ( "encoding/json" "time" "github.com/google/uuid" ) // nowFn is the clock for TOTP validation. It is a variable so a test can pin time; production uses // the wall clock. Session expiry math runs on the database clock, not this one. var nowFn = time.Now func reasonJSON(reason string) []byte { b, _ := json.Marshal(map[string]string{"reason": reason}) return b } // lockedJSON is the lockout audit payload. It carries the number of distinct source addresses behind // the failures so an operator reading the trail can tell a single noisy client from a distributed run, // which is the signal the old per ip lock scope used to imply and no longer does. func lockedJSON(reason string, sourceIPs int) []byte { b, _ := json.Marshal(map[string]any{"reason": reason, "distinct_source_ips": sourceIPs}) return b } func reasonRole(role string) []byte { b, _ := json.Marshal(map[string]string{"role": role}) return b } func nullStr(s string) *string { if s == "" { return nil } return &s } // mustUUID parses a uuid that originates from validated server state (a session row), where it is // always well formed. An unparseable value yields uuid.Nil, which matches no real row. func mustUUID(s string) uuid.UUID { id, err := uuid.Parse(s) if err != nil { return uuid.Nil } return id } func orgPtr(s string) *uuid.UUID { if s == "" { return nil } id, err := uuid.Parse(s) if err != nil { return nil } return &id }