Files
shooting-event/backend/auth.go

94 lines
2.2 KiB
Go
Raw Normal View History

2026-04-01 11:47:03 +04:00
package main
import (
"crypto/rand"
"crypto/subtle"
"encoding/hex"
"net/http"
"strings"
"time"
"github.com/labstack/echo/v4"
)
func (a *App) isAdminRequest(c echo.Context) bool {
header := strings.TrimSpace(c.Request().Header.Get(echo.HeaderAuthorization))
if header == "" || !strings.HasPrefix(strings.ToLower(header), "bearer ") {
return false
}
token := strings.TrimSpace(header[7:])
if token == "" {
return false
}
return a.sessions.ValidateToken(token)
}
func (a *App) adminOnly(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
a.sessions.PurgeExpired()
header := strings.TrimSpace(c.Request().Header.Get(echo.HeaderAuthorization))
if header == "" || !strings.HasPrefix(strings.ToLower(header), "bearer ") {
return writeError(c, http.StatusUnauthorized, "missing admin token")
}
token := strings.TrimSpace(header[7:])
if token == "" || !a.sessions.ValidateToken(token) {
return writeError(c, http.StatusUnauthorized, "invalid or expired admin token")
}
return next(c)
}
}
func (a *App) verifyAdmin(username, password string) bool {
u := strings.TrimSpace(username)
p := strings.TrimSpace(password)
if u == "" || p == "" {
return false
}
userMatch := subtle.ConstantTimeCompare([]byte(u), []byte(a.cfg.AdminUser)) == 1
passMatch := subtle.ConstantTimeCompare([]byte(p), []byte(a.cfg.AdminPass)) == 1
return userMatch && passMatch
}
func (s *SessionStore) CreateToken() (string, time.Time, error) {
raw := make([]byte, 32)
if _, err := rand.Read(raw); err != nil {
return "", time.Time{}, err
}
token := hex.EncodeToString(raw)
expires := time.Now().UTC().Add(s.duration)
s.mu.Lock()
s.tokens[token] = expires
s.mu.Unlock()
return token, expires, nil
}
func (s *SessionStore) ValidateToken(token string) bool {
s.mu.RLock()
expires, ok := s.tokens[token]
s.mu.RUnlock()
if !ok {
return false
}
return time.Now().UTC().Before(expires)
}
func (s *SessionStore) DeleteToken(token string) {
s.mu.Lock()
delete(s.tokens, token)
s.mu.Unlock()
}
func (s *SessionStore) PurgeExpired() {
now := time.Now().UTC()
s.mu.Lock()
for token, expiry := range s.tokens {
if now.After(expiry) {
delete(s.tokens, token)
}
}
s.mu.Unlock()
}