Phase 1 foundation. Local auth per ADR-0006: Argon2id passwords, opaque hashed session tokens with idle/absolute expiry, CSRF token plus Origin check on cookie sessions, per-IP token bucket and per-account exponential lockout, three roles enforced by middleware, personal API tokens for noemactl. Audit log writer used by every admin mutation. API: request ids, panic recovery, strict CSP and security headers, body limits, single JSON error envelope, health/ready/status, users, sessions, tokens, audit, token-protected /metrics. UI: embedded html/template pages (login, first-run setup, dashboard, system, users, account, audit, interpretation boundary), light/dark theme, dependency-free app.js with CSRF-aware fetch and SSE helper. Binaries: noemad with graceful shutdown, migrations at start, bootstrap admin from environment, supervised background tasks; noemactl with status, migrate, user create and meaningful exit codes.
24 lines
578 B
Go
24 lines
578 B
Go
package auth
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
)
|
|
|
|
// newToken returns a 256-bit random token in URL-safe base64 and its SHA-256,
|
|
// which is what gets stored. A database leak therefore does not leak sessions.
|
|
func newToken() (token string, hash []byte) {
|
|
b := make([]byte, 32)
|
|
if _, err := rand.Read(b); err != nil {
|
|
panic("auth: crypto/rand unavailable: " + err.Error())
|
|
}
|
|
token = base64.RawURLEncoding.EncodeToString(b)
|
|
return token, hashToken(token)
|
|
}
|
|
|
|
func hashToken(token string) []byte {
|
|
h := sha256.Sum256([]byte(token))
|
|
return h[:]
|
|
}
|