package main import ( "crypto/rand" "encoding/hex" "sync" "time" ) type tokenStore struct { mu sync.Mutex tokens map[string]time.Time } func newTokenStore() *tokenStore { return &tokenStore{tokens: make(map[string]time.Time)} } func (ts *tokenStore) Create() string { ts.mu.Lock() defer ts.mu.Unlock() b := make([]byte, 16) rand.Read(b) tok := hex.EncodeToString(b) ts.tokens[tok] = time.Now().Add(24 * time.Hour) return tok } func (ts *tokenStore) Check(tok string) bool { ts.mu.Lock() defer ts.mu.Unlock() exp, ok := ts.tokens[tok] if !ok { return false } if time.Now().After(exp) { delete(ts.tokens, tok) return false } return true } // userTokenStore embeds tokenStore but also tracks the user_id per token. type userTokenStore struct { mu sync.Mutex tokens map[string]userTokenEntry } type userTokenEntry struct { UserID string ExpiresAt time.Time } func newUserTokenStore() *userTokenStore { return &userTokenStore{tokens: make(map[string]userTokenEntry)} } func (uts *userTokenStore) Create(userID string) string { uts.mu.Lock() defer uts.mu.Unlock() b := make([]byte, 16) rand.Read(b) tok := hex.EncodeToString(b) uts.tokens[tok] = userTokenEntry{UserID: userID, ExpiresAt: time.Now().Add(24 * time.Hour)} return tok } func (uts *userTokenStore) Check(tok string) (string, bool) { uts.mu.Lock() defer uts.mu.Unlock() entry, ok := uts.tokens[tok] if !ok { return "", false } if time.Now().After(entry.ExpiresAt) { delete(uts.tokens, tok) return "", false } return entry.UserID, true }