81 lines
1.5 KiB
Go
81 lines
1.5 KiB
Go
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
|
|
}
|