1
0
Files
coconut-leaf/backend/utils/utils.go
2026-07-15 15:33:05 +08:00

94 lines
2.4 KiB
Go

package utils
import (
"crypto/sha256"
"encoding/hex"
"math/rand"
"regexp"
"strconv"
"strings"
"time"
"github.com/google/uuid"
)
var (
usernamePattern = regexp.MustCompile(`^[0-9A-Za-z]+$`)
passwordPattern = regexp.MustCompile(`^[!-~]+$`)
)
// IsValidUsername reports whether s is a valid username.
func IsValidUsername(s string) bool {
return usernamePattern.MatchString(s)
}
// IsValidPassword reports whether s is a valid password.
func IsValidPassword(s string) bool {
return passwordPattern.MatchString(s)
}
// ComputePasswordHash returns the lowercased SHA-256 hex digest of password.
func ComputePasswordHash(password string) string {
sum := sha256.Sum256([]byte(password))
return hex.EncodeToString(sum[:])
}
// GenerateUUID returns a new UUID string, preferring version 1 (mirroring
// python's uuid.uuid1()), falling back to a random version-4 UUID on error.
func GenerateUUID() string {
u, err := uuid.NewUUID()
if err != nil {
u = uuid.New()
}
return u.String()
}
// GenerateToken returns a SHA-256 hex digest of the username concatenated with
// a fresh UUID.
func GenerateToken(username string) string {
sum := sha256.Sum256([]byte(username + GenerateUUID()))
return hex.EncodeToString(sum[:])
}
// GenerateSalt returns a random salt in the inclusive range [0, 6172748).
func GenerateSalt() int {
return rand.Intn(6172748)
}
// ComputePasswordHashWithSalt returns the lowercased SHA-256 hex digest of
// passwordHashed concatenated with the decimal string form of salt.
func ComputePasswordHashWithSalt(passwordHashed string, salt int) string {
sum := sha256.Sum256([]byte(passwordHashed + strconv.Itoa(salt)))
return hex.EncodeToString(sum[:])
}
// GetCurrentTimestamp returns the current UNIX timestamp in seconds.
func GetCurrentTimestamp() int {
return int(time.Now().Unix())
}
// GetTokenExpireOn returns the timestamp 2 days from now, used as the token
// expiry.
func GetTokenExpireOn() int {
return GetCurrentTimestamp() + 60*60*24*2
}
// Str2Bool reports whether s, compared case-insensitively, equals "true".
func Str2Bool(s string) bool {
return strings.ToLower(s) == "true"
}
// GCD returns the greatest common divisor of a and b via the Euclidean
// algorithm.
func GCD(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
// LCM returns the least common multiple of a and b.
func LCM(a, b int) int {
return (a * b) / GCD(a, b)
}