Modify ValidateTimeStamp to bypass validation when in debug mode. Also update request validation to make timestamp optional in debug mode while maintaining security checks in production.
182 lines
3.5 KiB
Go
182 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type TokenInfo struct {
|
|
Token string
|
|
CreatedAt time.Time
|
|
UserID int
|
|
}
|
|
|
|
var (
|
|
tokenMap = make(map[int]*TokenInfo)
|
|
tokenMux sync.RWMutex
|
|
tokenTTL = time.Hour
|
|
)
|
|
|
|
func GenerateToken(userID int) (string, error) {
|
|
randomBytes := make([]byte, 32)
|
|
_, err := rand.Read(randomBytes)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate random bytes: %w", err)
|
|
}
|
|
|
|
hash := sha256.Sum256(append(randomBytes, []byte(fmt.Sprintf("%d", userID))...))
|
|
token := base64.URLEncoding.EncodeToString(hash[:])
|
|
|
|
tokenMux.Lock()
|
|
defer tokenMux.Unlock()
|
|
|
|
tokenMap[userID] = &TokenInfo{
|
|
Token: token,
|
|
CreatedAt: time.Now(),
|
|
UserID: userID,
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
func ValidateToken(userID int, token string) error {
|
|
tokenMux.RLock()
|
|
defer tokenMux.RUnlock()
|
|
|
|
tokenInfo, exists := tokenMap[userID]
|
|
if !exists {
|
|
return errors.New("token not found")
|
|
}
|
|
|
|
if tokenInfo.Token != token {
|
|
return errors.New("invalid token")
|
|
}
|
|
|
|
if time.Since(tokenInfo.CreatedAt) > tokenTTL {
|
|
return errors.New("token expired")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func RefreshToken(userID int) (string, error) {
|
|
tokenMux.Lock()
|
|
defer tokenMux.Unlock()
|
|
|
|
randomBytes := make([]byte, 32)
|
|
_, err := rand.Read(randomBytes)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate random bytes: %w", err)
|
|
}
|
|
|
|
hash := sha256.Sum256(append(randomBytes, []byte(fmt.Sprintf("%d", userID))...))
|
|
token := base64.URLEncoding.EncodeToString(hash[:])
|
|
|
|
tokenMap[userID] = &TokenInfo{
|
|
Token: token,
|
|
CreatedAt: time.Now(),
|
|
UserID: userID,
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
func RemoveToken(userID int) {
|
|
tokenMux.Lock()
|
|
defer tokenMux.Unlock()
|
|
delete(tokenMap, userID)
|
|
}
|
|
|
|
func GetTokenInfo(userID int) (*TokenInfo, error) {
|
|
tokenMux.RLock()
|
|
defer tokenMux.RUnlock()
|
|
|
|
tokenInfo, exists := tokenMap[userID]
|
|
if !exists {
|
|
return nil, errors.New("token not found")
|
|
}
|
|
|
|
return tokenInfo, nil
|
|
}
|
|
|
|
func extractUserIDFromToken(token string) (int, error) {
|
|
tokenMux.RLock()
|
|
defer tokenMux.RUnlock()
|
|
for userID, tokenInfo := range tokenMap {
|
|
if tokenInfo.Token == token {
|
|
return userID, nil
|
|
}
|
|
}
|
|
return 0, errors.New("invalid token")
|
|
}
|
|
|
|
func CleanupExpiredTokens() {
|
|
tokenMux.Lock()
|
|
defer tokenMux.Unlock()
|
|
|
|
for userID, tokenInfo := range tokenMap {
|
|
if time.Since(tokenInfo.CreatedAt) > tokenTTL {
|
|
delete(tokenMap, userID)
|
|
}
|
|
}
|
|
}
|
|
|
|
func hashPassword(password string) (string, error) {
|
|
hash := sha256.Sum256([]byte(password))
|
|
return hex.EncodeToString(hash[:]), nil
|
|
}
|
|
|
|
func verifyPassword(password, hashedPassword string) bool {
|
|
hash, err := hashPassword(password)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return hash == hashedPassword
|
|
}
|
|
|
|
func isValidPassword(password string) bool {
|
|
if len(password) < 8 {
|
|
return false
|
|
}
|
|
|
|
hasUpper := false
|
|
hasLower := false
|
|
hasDigit := false
|
|
hasSpecial := false
|
|
|
|
specialChars := "!@#$%^&*()_+-=[]{}|;:,.<>?"
|
|
|
|
for _, char := range password {
|
|
switch {
|
|
case char >= 'A' && char <= 'Z':
|
|
hasUpper = true
|
|
case char >= 'a' && char <= 'z':
|
|
hasLower = true
|
|
case char >= '0' && char <= '9':
|
|
hasDigit = true
|
|
case strings.ContainsRune(specialChars, char):
|
|
hasSpecial = true
|
|
}
|
|
}
|
|
|
|
return hasUpper && hasLower && hasDigit && hasSpecial
|
|
}
|
|
|
|
func ValidateTimeStamp(timeStamp int64) error {
|
|
if globalConfig.Debug {
|
|
return nil
|
|
}
|
|
currentTime := time.Now().UnixMilli()
|
|
if currentTime-timeStamp > 3000 || timeStamp-currentTime > 3000 {
|
|
return errors.New("timestamp out of valid range")
|
|
}
|
|
return nil
|
|
}
|