package jwt

import (
	
	
	
)

// Claims must just have a Valid method that determines
// if the token is invalid for any supported reason
type Claims interface {
	Valid() error
}

// RegisteredClaims are a structured version of the JWT Claims Set,
// restricted to Registered Claim Names, as referenced at
// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
//
// This type can be used on its own, but then additional private and
// public claims embedded in the JWT will not be parsed. The typical usecase
// therefore is to embedded this in a user-defined claim type.
//
// See examples for how to use this with your own claim types.
type RegisteredClaims struct {
	// the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
	Issuer string `json:"iss,omitempty"`

	// the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
	Subject string `json:"sub,omitempty"`

	// the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
	Audience ClaimStrings `json:"aud,omitempty"`

	// the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
	ExpiresAt *NumericDate `json:"exp,omitempty"`

	// the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
	NotBefore *NumericDate `json:"nbf,omitempty"`

	// the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
	IssuedAt *NumericDate `json:"iat,omitempty"`

	// the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
	ID string `json:"jti,omitempty"`
}

// Valid validates time based claims "exp, iat, nbf".
// There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still
// be considered a valid claim.
func ( RegisteredClaims) () error {
	 := new(ValidationError)
	 := TimeFunc()

	// The claims below are optional, by default, so if they are set to the
	// default value in Go, let's not fail the verification for them.
	if !.VerifyExpiresAt(, false) {
		 := .Sub(.ExpiresAt.Time)
		.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, )
		.Errors |= ValidationErrorExpired
	}

	if !.VerifyIssuedAt(, false) {
		.Inner = ErrTokenUsedBeforeIssued
		.Errors |= ValidationErrorIssuedAt
	}

	if !.VerifyNotBefore(, false) {
		.Inner = ErrTokenNotValidYet
		.Errors |= ValidationErrorNotValidYet
	}

	if .valid() {
		return nil
	}

	return 
}

// VerifyAudience compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func ( *RegisteredClaims) ( string,  bool) bool {
	return verifyAud(.Audience, , )
}

// VerifyExpiresAt compares the exp claim against cmp (cmp < exp).
// If req is false, it will return true, if exp is unset.
func ( *RegisteredClaims) ( time.Time,  bool) bool {
	if .ExpiresAt == nil {
		return verifyExp(nil, , )
	}

	return verifyExp(&.ExpiresAt.Time, , )
}

// VerifyIssuedAt compares the iat claim against cmp (cmp >= iat).
// If req is false, it will return true, if iat is unset.
func ( *RegisteredClaims) ( time.Time,  bool) bool {
	if .IssuedAt == nil {
		return verifyIat(nil, , )
	}

	return verifyIat(&.IssuedAt.Time, , )
}

// VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf).
// If req is false, it will return true, if nbf is unset.
func ( *RegisteredClaims) ( time.Time,  bool) bool {
	if .NotBefore == nil {
		return verifyNbf(nil, , )
	}

	return verifyNbf(&.NotBefore.Time, , )
}

// VerifyIssuer compares the iss claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func ( *RegisteredClaims) ( string,  bool) bool {
	return verifyIss(.Issuer, , )
}

// StandardClaims are a structured version of the JWT Claims Set, as referenced at
// https://datatracker.ietf.org/doc/html/rfc7519#section-4. They do not follow the
// specification exactly, since they were based on an earlier draft of the
// specification and not updated. The main difference is that they only
// support integer-based date fields and singular audiences. This might lead to
// incompatibilities with other JWT implementations. The use of this is discouraged, instead
// the newer RegisteredClaims struct should be used.
//
// Deprecated: Use RegisteredClaims instead for a forward-compatible way to access registered claims in a struct.
type StandardClaims struct {
	Audience  string `json:"aud,omitempty"`
	ExpiresAt int64  `json:"exp,omitempty"`
	Id        string `json:"jti,omitempty"`
	IssuedAt  int64  `json:"iat,omitempty"`
	Issuer    string `json:"iss,omitempty"`
	NotBefore int64  `json:"nbf,omitempty"`
	Subject   string `json:"sub,omitempty"`
}

// Valid validates time based claims "exp, iat, nbf". There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still
// be considered a valid claim.
func ( StandardClaims) () error {
	 := new(ValidationError)
	 := TimeFunc().Unix()

	// The claims below are optional, by default, so if they are set to the
	// default value in Go, let's not fail the verification for them.
	if !.VerifyExpiresAt(, false) {
		 := time.Unix(, 0).Sub(time.Unix(.ExpiresAt, 0))
		.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, )
		.Errors |= ValidationErrorExpired
	}

	if !.VerifyIssuedAt(, false) {
		.Inner = ErrTokenUsedBeforeIssued
		.Errors |= ValidationErrorIssuedAt
	}

	if !.VerifyNotBefore(, false) {
		.Inner = ErrTokenNotValidYet
		.Errors |= ValidationErrorNotValidYet
	}

	if .valid() {
		return nil
	}

	return 
}

// VerifyAudience compares the aud claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func ( *StandardClaims) ( string,  bool) bool {
	return verifyAud([]string{.Audience}, , )
}

// VerifyExpiresAt compares the exp claim against cmp (cmp < exp).
// If req is false, it will return true, if exp is unset.
func ( *StandardClaims) ( int64,  bool) bool {
	if .ExpiresAt == 0 {
		return verifyExp(nil, time.Unix(, 0), )
	}

	 := time.Unix(.ExpiresAt, 0)
	return verifyExp(&, time.Unix(, 0), )
}

// VerifyIssuedAt compares the iat claim against cmp (cmp >= iat).
// If req is false, it will return true, if iat is unset.
func ( *StandardClaims) ( int64,  bool) bool {
	if .IssuedAt == 0 {
		return verifyIat(nil, time.Unix(, 0), )
	}

	 := time.Unix(.IssuedAt, 0)
	return verifyIat(&, time.Unix(, 0), )
}

// VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf).
// If req is false, it will return true, if nbf is unset.
func ( *StandardClaims) ( int64,  bool) bool {
	if .NotBefore == 0 {
		return verifyNbf(nil, time.Unix(, 0), )
	}

	 := time.Unix(.NotBefore, 0)
	return verifyNbf(&, time.Unix(, 0), )
}

// VerifyIssuer compares the iss claim against cmp.
// If required is false, this method will return true if the value matches or is unset
func ( *StandardClaims) ( string,  bool) bool {
	return verifyIss(.Issuer, , )
}

// ----- helpers

func verifyAud( []string,  string,  bool) bool {
	if len() == 0 {
		return !
	}
	// use a var here to keep constant time compare when looping over a number of claims
	 := false

	var  string
	for ,  := range  {
		if subtle.ConstantTimeCompare([]byte(), []byte()) != 0 {
			 = true
		}
		 =  + 
	}

	// case where "" is sent in one or many aud claims
	if len() == 0 {
		return !
	}

	return 
}

func verifyExp( *time.Time,  time.Time,  bool) bool {
	if  == nil {
		return !
	}
	return .Before(*)
}

func verifyIat( *time.Time,  time.Time,  bool) bool {
	if  == nil {
		return !
	}
	return .After(*) || .Equal(*)
}

func verifyNbf( *time.Time,  time.Time,  bool) bool {
	if  == nil {
		return !
	}
	return .After(*) || .Equal(*)
}

func verifyIss( string,  string,  bool) bool {
	if  == "" {
		return !
	}
	return subtle.ConstantTimeCompare([]byte(), []byte()) != 0
}