// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package server

import (
	
	
	
	
	
	
	
)

const (
	nonceLifetime  = time.Hour // See: https://tools.ietf.org/html/rfc5766#section-4
	nonceLength    = 40
	nonceKeyLength = 64
)

// NewNonceHash creates a NonceHash.
func () (*NonceHash, error) {
	 := make([]byte, nonceKeyLength)
	if ,  := rand.Read();  != nil {
		return nil, 
	}

	return &NonceHash{}, nil
}

// NonceHash is used to create and verify nonces.
type NonceHash struct {
	key []byte
}

// Generate a nonce.
func ( *NonceHash) () (string, error) {
	 := make([]byte, 8, nonceLength)
	binary.BigEndian.PutUint64(, uint64(time.Now().UnixMilli())) // nolint:gosec // G115

	 := hmac.New(sha256.New, .key)
	if ,  := .Write([:8]);  != nil {
		return "", fmt.Errorf("%w: %v", errFailedToGenerateNonce, ) //nolint:errorlint
	}
	 = .Sum()

	return hex.EncodeToString(), nil
}

// Validate checks that nonce is signed and is not expired.
func ( *NonceHash) ( string) error {
	,  := hex.DecodeString()
	if  != nil || len() != nonceLength {
		return fmt.Errorf("%w: %v", errInvalidNonce, ) //nolint:errorlint
	}

	if  := time.UnixMilli(int64(binary.BigEndian.Uint64())); time.Since() > nonceLifetime { // nolint:gosec // G115
		return errInvalidNonce
	}

	 := hmac.New(sha256.New, .key)
	if _,  = .Write([:8]);  != nil {
		return fmt.Errorf("%w: %v", errInvalidNonce, ) //nolint:errorlint
	}
	if !hmac.Equal([8:], .Sum(nil)) {
		return errInvalidNonce
	}

	return nil
}