mirror of
https://github.com/navidrome/navidrome.git
synced 2026-04-28 03:19:38 +00:00
Some checks are pending
Pipeline: Test, Lint, Build / Get version info (push) Waiting to run
Pipeline: Test, Lint, Build / Lint Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test JS code (push) Waiting to run
Pipeline: Test, Lint, Build / Lint i18n files (push) Waiting to run
Pipeline: Test, Lint, Build / Check Docker configuration (push) Waiting to run
Pipeline: Test, Lint, Build / Build (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-1 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-2 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-3 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-4 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-5 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-6 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-7 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-8 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-9 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-10 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to GHCR (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build Windows installers (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Package/Release (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Blocked by required conditions
Introduced a typed Claims struct in core/auth to replace the raw map[string]any approach used for JWT claims throughout the codebase. This provides compile-time safety and better readability when creating, validating, and extracting JWT tokens. Also upgraded lestrrat-go/jwx from v2 to v3 and go-chi/jwtauth to v5.4.0, adapting all callers to the new API where token accessor methods now return tuples instead of bare values. Updated all affected handlers, middleware, and tests. Signed-off-by: Deluan <deluan@navidrome.org>
94 lines
1.9 KiB
Go
94 lines
1.9 KiB
Go
package auth
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/lestrrat-go/jwx/v3/jwt"
|
|
)
|
|
|
|
// Claims represents the typed JWT claims used throughout Navidrome,
|
|
// replacing the untyped map[string]any approach.
|
|
type Claims struct {
|
|
// Standard JWT claims
|
|
Issuer string
|
|
Subject string // username for session tokens
|
|
IssuedAt time.Time
|
|
ExpiresAt time.Time
|
|
|
|
// Custom claims
|
|
UserID string // "uid"
|
|
IsAdmin bool // "adm"
|
|
ID string // "id" - artwork/mediafile ID
|
|
Format string // "f" - audio format
|
|
BitRate int // "b" - audio bitrate
|
|
}
|
|
|
|
// ToMap converts Claims to a map[string]any for use with TokenAuth.Encode().
|
|
// Only non-zero fields are included.
|
|
func (c Claims) ToMap() map[string]any {
|
|
m := make(map[string]any)
|
|
if c.Issuer != "" {
|
|
m[jwt.IssuerKey] = c.Issuer
|
|
}
|
|
if c.Subject != "" {
|
|
m[jwt.SubjectKey] = c.Subject
|
|
}
|
|
if !c.IssuedAt.IsZero() {
|
|
m[jwt.IssuedAtKey] = c.IssuedAt.UTC().Unix()
|
|
}
|
|
if !c.ExpiresAt.IsZero() {
|
|
m[jwt.ExpirationKey] = c.ExpiresAt.UTC().Unix()
|
|
}
|
|
if c.UserID != "" {
|
|
m["uid"] = c.UserID
|
|
}
|
|
if c.IsAdmin {
|
|
m["adm"] = c.IsAdmin
|
|
}
|
|
if c.ID != "" {
|
|
m["id"] = c.ID
|
|
}
|
|
if c.Format != "" {
|
|
m["f"] = c.Format
|
|
}
|
|
if c.BitRate != 0 {
|
|
m["b"] = c.BitRate
|
|
}
|
|
return m
|
|
}
|
|
|
|
func (c Claims) WithExpiresAt(t time.Time) Claims {
|
|
c.ExpiresAt = t
|
|
return c
|
|
}
|
|
|
|
// ClaimsFromToken extracts Claims directly from a jwt.Token using token.Get().
|
|
func ClaimsFromToken(token jwt.Token) Claims {
|
|
var c Claims
|
|
c.Issuer, _ = token.Issuer()
|
|
c.Subject, _ = token.Subject()
|
|
c.IssuedAt, _ = token.IssuedAt()
|
|
c.ExpiresAt, _ = token.Expiration()
|
|
|
|
var uid string
|
|
if err := token.Get("uid", &uid); err == nil {
|
|
c.UserID = uid
|
|
}
|
|
var adm bool
|
|
if err := token.Get("adm", &adm); err == nil {
|
|
c.IsAdmin = adm
|
|
}
|
|
var id string
|
|
if err := token.Get("id", &id); err == nil {
|
|
c.ID = id
|
|
}
|
|
var f string
|
|
if err := token.Get("f", &f); err == nil {
|
|
c.Format = f
|
|
}
|
|
var b int
|
|
if err := token.Get("b", &b); err == nil {
|
|
c.BitRate = b
|
|
}
|
|
return c
|
|
}
|