Update dependencies

This update includes a newer version of the RTMP server that supports
the enhances RTMP specification, i.e. HEVC, VP9, and AV1.
This commit is contained in:
Ingo Oppermann
2024-01-12 12:35:07 +01:00
parent d1f3538217
commit 574ebdf277
562 changed files with 14318 additions and 16394 deletions

View File

@@ -17,7 +17,7 @@ and corresponding updates for existing programs.
## Parsing and Validation Options
Under the hood, a new `validator` struct takes care of validating the claims. A
Under the hood, a new `Validator` struct takes care of validating the claims. A
long awaited feature has been the option to fine-tune the validation of tokens.
This is now possible with several `ParserOption` functions that can be appended
to most `Parse` functions, such as `ParseWithClaims`. The most important options
@@ -68,6 +68,16 @@ type Claims interface {
}
```
Users that previously directly called the `Valid` function on their claims,
e.g., to perform validation independently of parsing/verifying a token, can now
use the `jwt.NewValidator` function to create a `Validator` independently of the
`Parser`.
```go
var v = jwt.NewValidator(jwt.WithLeeway(5*time.Second))
v.Validate(myClaims)
```
### Supported Claim Types and Removal of `StandardClaims`
The two standard claim types supported by this library, `MapClaims` and
@@ -169,7 +179,7 @@ be a drop-in replacement, if you're having troubles migrating, please open an
issue.
You can replace all occurrences of `github.com/dgrijalva/jwt-go` or
`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v5`, either manually
`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually
or by using tools such as `sed` or `gofmt`.
And then you'd typically run:

View File

@@ -62,7 +62,7 @@ func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interf
case *ecdsa.PublicKey:
ecdsaKey = k
default:
return ErrInvalidKeyType
return newError("ECDSA verify expects *ecsda.PublicKey", ErrInvalidKeyType)
}
if len(sig) != 2*m.KeySize {
@@ -96,7 +96,7 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte
case *ecdsa.PrivateKey:
ecdsaKey = k
default:
return nil, ErrInvalidKeyType
return nil, newError("ECDSA sign expects *ecsda.PrivateKey", ErrInvalidKeyType)
}
// Create the hasher

View File

@@ -1,11 +1,10 @@
package jwt
import (
"errors"
"crypto"
"crypto/ed25519"
"crypto/rand"
"errors"
)
var (
@@ -39,7 +38,7 @@ func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key inte
var ok bool
if ed25519Key, ok = key.(ed25519.PublicKey); !ok {
return ErrInvalidKeyType
return newError("Ed25519 verify expects ed25519.PublicKey", ErrInvalidKeyType)
}
if len(ed25519Key) != ed25519.PublicKeySize {
@@ -61,7 +60,7 @@ func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) ([]by
var ok bool
if ed25519Key, ok = key.(crypto.Signer); !ok {
return nil, ErrInvalidKeyType
return nil, newError("Ed25519 sign expects crypto.Signer", ErrInvalidKeyType)
}
if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok {

View File

@@ -22,7 +22,7 @@ func (je joinedError) Is(err error) bool {
// wrappedErrors is a workaround for wrapping multiple errors in environments
// where Go 1.20 is not available. It basically uses the already implemented
// functionatlity of joinedError to handle multiple errors with supplies a
// functionality of joinedError to handle multiple errors with supplies a
// custom error message that is identical to the one we produce in Go 1.20 using
// multiple %w directives.
type wrappedErrors struct {

View File

@@ -59,7 +59,7 @@ func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interfa
// Verify the key is the right type
keyBytes, ok := key.([]byte)
if !ok {
return ErrInvalidKeyType
return newError("HMAC verify expects []byte", ErrInvalidKeyType)
}
// Can we use the specified hashing method?
@@ -91,7 +91,7 @@ func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interfa
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) {
if keyBytes, ok := key.([]byte); ok {
if !m.Hash.Available() {
return nil, ErrHashUnavailable
return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType)
}
hasher := hmac.New(m.Hash.New, keyBytes)

View File

@@ -32,7 +32,7 @@ func (m *signingMethodNone) Verify(signingString string, sig []byte, key interfa
return NoneSignatureTypeDisallowedError
}
// If signing method is none, signature must be an empty string
if string(sig) != "" {
if len(sig) != 0 {
return newError("'none' signing method with non-empty signature", ErrTokenUnverifiable)
}

View File

@@ -18,7 +18,7 @@ type Parser struct {
// Skip claims validation during token parsing.
skipClaimsValidation bool
validator *validator
validator *Validator
decodeStrict bool
@@ -28,7 +28,7 @@ type Parser struct {
// NewParser creates a new Parser with the specified options
func NewParser(options ...ParserOption) *Parser {
p := &Parser{
validator: &validator{},
validator: &Validator{},
}
// Loop through our parsing options and apply them
@@ -74,24 +74,40 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
}
}
// Lookup key
var key interface{}
if keyFunc == nil {
// keyFunc was not provided. short circuiting validation
return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
}
if key, err = keyFunc(token); err != nil {
return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
}
// Decode signature
token.Signature, err = p.DecodeSegment(parts[2])
if err != nil {
return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
}
text := strings.Join(parts[0:2], ".")
// Perform signature validation
if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
// Lookup key(s)
if keyFunc == nil {
// keyFunc was not provided. short circuiting validation
return token, newError("no keyfunc was provided", ErrTokenUnverifiable)
}
got, err := keyFunc(token)
if err != nil {
return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
}
switch have := got.(type) {
case VerificationKeySet:
if len(have.Keys) == 0 {
return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
}
// Iterate through keys and verify signature, skipping the rest when a match is found.
// Return the last error if no match is found.
for _, key := range have.Keys {
if err = token.Method.Verify(text, token.Signature, key); err == nil {
break
}
}
default:
err = token.Method.Verify(text, token.Signature, have)
}
if err != nil {
return token, newError("", ErrTokenSignatureInvalid, err)
}
@@ -99,7 +115,7 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
if !p.skipClaimsValidation {
// Make sure we have at least a default validator
if p.validator == nil {
p.validator = newValidator()
p.validator = NewValidator()
}
if err := p.validator.Validate(claims); err != nil {
@@ -117,8 +133,8 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
//
// WARNING: Don't use this method unless you know what you're doing.
//
// It's only ever useful in cases where you know the signature is valid (because it has
// been checked previously in the stack) and you want to extract values from it.
// It's only ever useful in cases where you know the signature is valid (since it has already
// been or will be checked elsewhere in the stack) and you want to extract values from it.
func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
parts = strings.Split(tokenString, ".")
if len(parts) != 3 {
@@ -130,9 +146,6 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
// parse Header
var headerBytes []byte
if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
return token, parts, newError("tokenstring should not contain 'bearer '", ErrTokenMalformed)
}
return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
}
if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
@@ -140,23 +153,33 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
}
// parse Claims
var claimBytes []byte
token.Claims = claims
if claimBytes, err = p.DecodeSegment(parts[1]); err != nil {
claimBytes, err := p.DecodeSegment(parts[1])
if err != nil {
return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err)
}
dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
if p.useJSONNumber {
dec.UseNumber()
}
// JSON Decode. Special case for map type to avoid weird pointer behavior
if c, ok := token.Claims.(MapClaims); ok {
err = dec.Decode(&c)
// If `useJSONNumber` is enabled then we must use *json.Decoder to decode
// the claims. However, this comes with a performance penalty so only use
// it if we must and, otherwise, simple use json.Unmarshal.
if !p.useJSONNumber {
// JSON Unmarshal. Special case for map type to avoid weird pointer behavior.
if c, ok := token.Claims.(MapClaims); ok {
err = json.Unmarshal(claimBytes, &c)
} else {
err = json.Unmarshal(claimBytes, &claims)
}
} else {
err = dec.Decode(&claims)
dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
dec.UseNumber()
// JSON Decode. Special case for map type to avoid weird pointer behavior.
if c, ok := token.Claims.(MapClaims); ok {
err = dec.Decode(&c)
} else {
err = dec.Decode(&claims)
}
}
// Handle decode error
if err != nil {
return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err)
}

View File

@@ -58,6 +58,14 @@ func WithIssuedAt() ParserOption {
}
}
// WithExpirationRequired returns the ParserOption to make exp claim required.
// By default exp claim is optional.
func WithExpirationRequired() ParserOption {
return func(p *Parser) {
p.validator.requireExp = true
}
}
// WithAudience configures the validator to require the specified audience in
// the `aud` claim. Validation will fail if the audience is not listed in the
// token or the `aud` claim is missing.

View File

@@ -51,7 +51,7 @@ func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interfac
var ok bool
if rsaKey, ok = key.(*rsa.PublicKey); !ok {
return ErrInvalidKeyType
return newError("RSA verify expects *rsa.PublicKey", ErrInvalidKeyType)
}
// Create hasher
@@ -73,7 +73,7 @@ func (m *SigningMethodRSA) Sign(signingString string, key interface{}) ([]byte,
// Validate type of key
if rsaKey, ok = key.(*rsa.PrivateKey); !ok {
return nil, ErrInvalidKey
return nil, newError("RSA sign expects *rsa.PrivateKey", ErrInvalidKeyType)
}
// Create the hasher

View File

@@ -88,7 +88,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key inter
case *rsa.PublicKey:
rsaKey = k
default:
return ErrInvalidKey
return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType)
}
// Create hasher
@@ -115,7 +115,7 @@ func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byt
case *rsa.PrivateKey:
rsaKey = k
default:
return nil, ErrInvalidKeyType
return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType)
}
// Create the hasher

View File

@@ -1,6 +1,7 @@
package jwt
import (
"crypto"
"encoding/base64"
"encoding/json"
)
@@ -9,8 +10,21 @@ import (
// the key for verification. The function receives the parsed, but unverified
// Token. This allows you to use properties in the Header of the token (such as
// `kid`) to identify which key to use.
//
// The returned interface{} may be a single key or a VerificationKeySet containing
// multiple keys.
type Keyfunc func(*Token) (interface{}, error)
// VerificationKey represents a public or secret key for verifying a token's signature.
type VerificationKey interface {
crypto.PublicKey | []uint8
}
// VerificationKeySet is a set of public or secret keys. It is used by the parser to verify a token.
type VerificationKeySet struct {
Keys []VerificationKey
}
// Token represents a JWT Token. Different fields will be used depending on
// whether you're creating or parsing/verifying a token.
type Token struct {

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"math"
"reflect"
"strconv"
"time"
)
@@ -121,14 +120,14 @@ func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) {
for _, vv := range v {
vs, ok := vv.(string)
if !ok {
return &json.UnsupportedTypeError{Type: reflect.TypeOf(vv)}
return ErrInvalidType
}
aud = append(aud, vs)
}
case nil:
return nil
default:
return &json.UnsupportedTypeError{Type: reflect.TypeOf(v)}
return ErrInvalidType
}
*s = aud

View File

@@ -28,13 +28,12 @@ type ClaimsValidator interface {
Validate() error
}
// validator is the core of the new Validation API. It is automatically used by
// Validator is the core of the new Validation API. It is automatically used by
// a [Parser] during parsing and can be modified with various parser options.
//
// Note: This struct is intentionally not exported (yet) as we want to
// internally finalize its API. In the future, we might make it publicly
// available.
type validator struct {
// The [NewValidator] function should be used to create an instance of this
// struct.
type Validator struct {
// leeway is an optional leeway that can be provided to account for clock skew.
leeway time.Duration
@@ -42,6 +41,9 @@ type validator struct {
// validation. If unspecified, this defaults to time.Now.
timeFunc func() time.Time
// requireExp specifies whether the exp claim is required
requireExp bool
// verifyIat specifies whether the iat (Issued At) claim will be verified.
// According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this
// only specifies the age of the token, but no validation check is
@@ -62,16 +64,28 @@ type validator struct {
expectedSub string
}
// newValidator can be used to create a stand-alone validator with the supplied
// NewValidator can be used to create a stand-alone validator with the supplied
// options. This validator can then be used to validate already parsed claims.
func newValidator(opts ...ParserOption) *validator {
//
// Note: Under normal circumstances, explicitly creating a validator is not
// needed and can potentially be dangerous; instead functions of the [Parser]
// class should be used.
//
// The [Validator] is only checking the *validity* of the claims, such as its
// expiration time, but it does NOT perform *signature verification* of the
// token.
func NewValidator(opts ...ParserOption) *Validator {
p := NewParser(opts...)
return p.validator
}
// Validate validates the given claims. It will also perform any custom
// validation if claims implements the [ClaimsValidator] interface.
func (v *validator) Validate(claims Claims) error {
//
// Note: It will NOT perform any *signature verification* on the token that
// contains the claims and expects that the [Claim] was already successfully
// verified.
func (v *Validator) Validate(claims Claims) error {
var (
now time.Time
errs []error = make([]error, 0, 6)
@@ -86,8 +100,9 @@ func (v *validator) Validate(claims Claims) error {
}
// We always need to check the expiration time, but usage of the claim
// itself is OPTIONAL.
if err = v.verifyExpiresAt(claims, now, false); err != nil {
// itself is OPTIONAL by default. requireExp overrides this behavior
// and makes the exp claim mandatory.
if err = v.verifyExpiresAt(claims, now, v.requireExp); err != nil {
errs = append(errs, err)
}
@@ -149,7 +164,7 @@ func (v *validator) Validate(claims Claims) error {
//
// Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) error {
func (v *Validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) error {
exp, err := claims.GetExpirationTime()
if err != nil {
return err
@@ -170,7 +185,7 @@ func (v *validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool)
//
// Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) error {
func (v *Validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) error {
iat, err := claims.GetIssuedAt()
if err != nil {
return err
@@ -191,7 +206,7 @@ func (v *validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool)
//
// Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) error {
func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) error {
nbf, err := claims.GetNotBefore()
if err != nil {
return err
@@ -211,7 +226,7 @@ func (v *validator) verifyNotBefore(claims Claims, cmp time.Time, required bool)
//
// Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *validator) verifyAudience(claims Claims, cmp string, required bool) error {
func (v *Validator) verifyAudience(claims Claims, cmp string, required bool) error {
aud, err := claims.GetAudience()
if err != nil {
return err
@@ -247,7 +262,7 @@ func (v *validator) verifyAudience(claims Claims, cmp string, required bool) err
//
// Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *validator) verifyIssuer(claims Claims, cmp string, required bool) error {
func (v *Validator) verifyIssuer(claims Claims, cmp string, required bool) error {
iss, err := claims.GetIssuer()
if err != nil {
return err
@@ -267,7 +282,7 @@ func (v *validator) verifyIssuer(claims Claims, cmp string, required bool) error
//
// Additionally, if any error occurs while retrieving the claim, e.g., when its
// the wrong type, an ErrTokenUnverifiable error will be returned.
func (v *validator) verifySubject(claims Claims, cmp string, required bool) error {
func (v *Validator) verifySubject(claims Claims, cmp string, required bool) error {
sub, err := claims.GetSubject()
if err != nil {
return err