update
This commit is contained in:
93
backend/auth.go
Normal file
93
backend/auth.go
Normal file
@@ -0,0 +1,93 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user