package auth import ( "crypto/rand" "crypto/subtle" "encoding/base64" "errors" "os" "sync" "time" ) const sessionCookie = "tk_admin_session" // Config holds admin credentials from the environment. type Config struct { Username string Password string Enabled bool } // Load reads admin auth settings. Admin is enabled when both user and password are set. func Load() Config { user := os.Getenv("ADMIN_USER") pass := os.Getenv("ADMIN_PASSWORD") return Config{ Username: user, Password: pass, Enabled: user != "" && pass != "", } } // Sessions tracks active login tokens in memory. type Sessions struct { mu sync.RWMutex tokens map[string]time.Time ttl time.Duration } // NewSessions creates a session store. func NewSessions() *Sessions { return &Sessions{ tokens: make(map[string]time.Time), ttl: 24 * time.Hour, } } // Create issues a new session token. func (s *Sessions) Create() (string, error) { b := make([]byte, 32) if _, err := rand.Read(b); err != nil { return "", err } token := base64.RawURLEncoding.EncodeToString(b) exp := time.Now().Add(s.ttl) s.mu.Lock() s.tokens[token] = exp s.mu.Unlock() return token, nil } // Valid reports whether a session token is still active. func (s *Sessions) Valid(token string) bool { if token == "" { return false } s.mu.RLock() exp, ok := s.tokens[token] s.mu.RUnlock() if !ok || time.Now().After(exp) { return false } return true } // Delete removes a session token. func (s *Sessions) Delete(token string) { s.mu.Lock() delete(s.tokens, token) s.mu.Unlock() } // CookieName returns the session cookie name. func CookieName() string { return sessionCookie } // CheckCredentials compares username and password to config using constant-time compare. func CheckCredentials(cfg Config, username, password string) bool { if !cfg.Enabled { return false } uOK := subtle.ConstantTimeCompare([]byte(username), []byte(cfg.Username)) == 1 pOK := subtle.ConstantTimeCompare([]byte(password), []byte(cfg.Password)) == 1 return uOK && pOK } // ErrDisabled is returned when admin auth is not configured. var ErrDisabled = errors.New("admin auth is not configured")