@@ -0,0 +1,53 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"time"
|
||||
|
||||
"gardomatic.kleiax.de/internal/platform/validate"
|
||||
)
|
||||
|
||||
const (
|
||||
// ScopeActivation identifies account activation tokens.
|
||||
ScopeActivation = "activation"
|
||||
// ScopeAuthentication identifies bearer authentication tokens.
|
||||
ScopeAuthentication = "authentication"
|
||||
// ScopePasswordReset identifies password reset tokens.
|
||||
ScopePasswordReset = "password-reset"
|
||||
)
|
||||
|
||||
// Token carries a one-time plaintext token and the hash persisted by storage.
|
||||
type Token struct {
|
||||
Plaintext string `json:"token"`
|
||||
Hash []byte `json:"-"`
|
||||
UserID int `json:"-"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Scope string `json:"-"`
|
||||
}
|
||||
|
||||
// NewToken creates a cryptographically random token for a user and scope.
|
||||
func NewToken(userID int, ttl time.Duration, scope string) Token {
|
||||
token := Token{
|
||||
Plaintext: rand.Text(),
|
||||
UserID: userID,
|
||||
Expiry: time.Now().Add(ttl),
|
||||
Scope: scope,
|
||||
}
|
||||
|
||||
hash := sha256.Sum256([]byte(token.Plaintext))
|
||||
token.Hash = hash[:]
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
// Validate adds token consistency errors to v.
|
||||
func (tk Token) Validate(v *validate.Validator) {
|
||||
ValidateTokenPlaintext(v, tk.Plaintext)
|
||||
}
|
||||
|
||||
// ValidateTokenPlaintext checks the expected format of a user-supplied token.
|
||||
func ValidateTokenPlaintext(v *validate.Validator, tokenPlaintext string) {
|
||||
v.Check(tokenPlaintext != "", "token", "must be provided")
|
||||
v.Check(len(tokenPlaintext) == 26, "token", "must be 26 bytes long")
|
||||
}
|
||||
Reference in New Issue
Block a user