75 lines
1.8 KiB
Go
75 lines
1.8 KiB
Go
package auth
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
// HashPassword returns a bcrypt hash for the given plain text password.
|
|
func HashPassword(password string) (string, error) {
|
|
if password == "" {
|
|
return "", errors.New("empty password")
|
|
}
|
|
b, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(b), nil
|
|
}
|
|
|
|
// CheckPassword verifies a bcrypt hash against the given plain text password.
|
|
func CheckPassword(hash, password string) bool {
|
|
if hash == "" || password == "" {
|
|
return false
|
|
}
|
|
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil
|
|
}
|
|
|
|
// MakeSessionToken builds a simple HMAC-signed token: username|expUnix|sigHex
|
|
func MakeSessionToken(username string, ttl time.Duration, secret []byte) (string, time.Time) {
|
|
if ttl <= 0 {
|
|
ttl = 24 * time.Hour
|
|
}
|
|
exp := time.Now().Add(ttl).UTC()
|
|
payload := username + "|" + strconv.FormatInt(exp.Unix(), 10)
|
|
mac := hmac.New(sha256.New, secret)
|
|
mac.Write([]byte(payload))
|
|
sig := hex.EncodeToString(mac.Sum(nil))
|
|
return payload + "|" + sig, exp
|
|
}
|
|
|
|
// ParseSessionToken validates token and returns username if valid.
|
|
func ParseSessionToken(token string, secret []byte) (string, bool) {
|
|
parts := strings.Split(token, "|")
|
|
if len(parts) != 3 {
|
|
return "", false
|
|
}
|
|
username := parts[0]
|
|
expStr := parts[1]
|
|
sigHex := parts[2]
|
|
// recompute
|
|
payload := fmt.Sprintf("%s|%s", username, expStr)
|
|
mac := hmac.New(sha256.New, secret)
|
|
mac.Write([]byte(payload))
|
|
if hex.EncodeToString(mac.Sum(nil)) != sigHex {
|
|
return "", false
|
|
}
|
|
// expiry check
|
|
expUnix, err := strconv.ParseInt(expStr, 10, 64)
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
if time.Now().UTC().After(time.Unix(expUnix, 0)) {
|
|
return "", false
|
|
}
|
|
return username, true
|
|
}
|