Files
dozzle/internal/auth/simple.go
T
2026-08-04 11:46:28 -07:00

67 lines
1.7 KiB
Go

package auth
import (
"crypto/sha256"
"errors"
"maps"
"net/http"
"slices"
"time"
"github.com/go-chi/jwtauth/v5"
)
type simpleAuthContext struct {
UserDatabase UserDatabase
tokenAuth *jwtauth.JWTAuth
ttl time.Duration
}
var ErrInvalidCredentials = errors.New("invalid credentials")
func NewSimpleAuth(userDatabase UserDatabase, ttl time.Duration) *simpleAuthContext {
// Hash the users in a stable order. Ranging over the map directly makes the
// digest depend on Go's randomized map iteration order, so any users.yml with
// more than one user derives a different signing key on every start and
// silently invalidates every session on restart.
h := sha256.New()
for _, username := range slices.Sorted(maps.Keys(userDatabase.Users)) {
user := userDatabase.Users[username]
h.Write([]byte(user.Password))
h.Write([]byte(user.RolesConfigured))
}
tokenAuth := jwtauth.New("HS256", h.Sum(nil), nil)
return &simpleAuthContext{
UserDatabase: userDatabase,
tokenAuth: tokenAuth,
ttl: ttl,
}
}
func (a *simpleAuthContext) CreateToken(username, password string) (string, error) {
user := a.UserDatabase.FindByPassword(username, password)
if user == nil {
return "", ErrInvalidCredentials
}
claims := map[string]any{"username": user.Username, "email": user.Email, "name": user.Name, "filter": user.Filter, "roles": user.Roles}
jwtauth.SetIssuedNow(claims)
if a.ttl > 0 {
jwtauth.SetExpiryIn(claims, a.ttl)
}
_, tokenString, err := a.tokenAuth.Encode(claims)
if err != nil {
return "", err
}
return tokenString, nil
}
func (a *simpleAuthContext) AuthMiddleware(next http.Handler) http.Handler {
return jwtauth.Verifier(a.tokenAuth)(next)
}