Files
ddc/internal/auth/sessions.go
T
2026-10-25 20:24:50 -04:00

76 lines
1.5 KiB
Go
Executable File

package auth
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"sync"
"time"
)
const tokenBytes = 32
type SessionStore struct {
mutex sync.Mutex
ttl time.Duration
expirations map[string]time.Time
}
func NewSessionStore(ttl time.Duration) *SessionStore {
return &SessionStore{ttl: ttl, expirations: make(map[string]time.Time)}
}
func (store *SessionStore) Create() (string, error) {
buffer := make([]byte, tokenBytes)
if _, err := rand.Read(buffer); err != nil {
return "", err
}
token := base64.RawURLEncoding.EncodeToString(buffer)
store.mutex.Lock()
defer store.mutex.Unlock()
now := time.Now()
store.removeExpired(now)
store.expirations[hashToken(token)] = now.Add(store.ttl)
return token, nil
}
func (store *SessionStore) Valid(token string) bool {
if token == "" {
return false
}
key := hashToken(token)
store.mutex.Lock()
defer store.mutex.Unlock()
expiresAt, found := store.expirations[key]
if !found {
return false
}
if time.Now().After(expiresAt) {
delete(store.expirations, key)
return false
}
return true
}
func (store *SessionStore) Delete(token string) {
store.mutex.Lock()
defer store.mutex.Unlock()
delete(store.expirations, hashToken(token))
}
func (store *SessionStore) removeExpired(now time.Time) {
for key, expiresAt := range store.expirations {
if now.After(expiresAt) {
delete(store.expirations, key)
}
}
}
func hashToken(token string) string {
sum := sha256.Sum256([]byte(token))
return hex.EncodeToString(sum[:])
}