package main 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(6172749) } // 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) }