package server
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"fmt"
"time"
)
const (
nonceLifetime = time .Hour
nonceLength = 40
nonceKeyLength = 64
)
func NewNonceHash () (*NonceHash , error ) {
key := make ([]byte , nonceKeyLength )
if _ , err := rand .Read (key ); err != nil {
return nil , err
}
return &NonceHash {key }, nil
}
type NonceHash struct {
key []byte
}
func (n *NonceHash ) Generate () (string , error ) {
nonce := make ([]byte , 8 , nonceLength )
binary .BigEndian .PutUint64 (nonce , uint64 (time .Now ().UnixMilli ()))
hash := hmac .New (sha256 .New , n .key )
if _ , err := hash .Write (nonce [:8 ]); err != nil {
return "" , fmt .Errorf ("%w: %v" , errFailedToGenerateNonce , err )
}
nonce = hash .Sum (nonce )
return hex .EncodeToString (nonce ), nil
}
func (n *NonceHash ) Validate (nonce string ) error {
b , err := hex .DecodeString (nonce )
if err != nil || len (b ) != nonceLength {
return fmt .Errorf ("%w: %v" , errInvalidNonce , err )
}
if ts := time .UnixMilli (int64 (binary .BigEndian .Uint64 (b ))); time .Since (ts ) > nonceLifetime {
return errInvalidNonce
}
hash := hmac .New (sha256 .New , n .key )
if _, err = hash .Write (b [:8 ]); err != nil {
return fmt .Errorf ("%w: %v" , errInvalidNonce , err )
}
if !hmac .Equal (b [8 :], hash .Sum (nil )) {
return errInvalidNonce
}
return nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .