Files
oslstats/internal/store/store.go

93 lines
2.1 KiB
Go

// Package store provides a session store for caching data
package store
import (
"crypto/rand"
"encoding/base64"
"fmt"
"sync"
"time"
)
// RedirectTrack represents a single redirect attempt tracking entry
type RedirectTrack struct {
IP string // Client IP (X-Forwarded-For aware)
UserAgent string // Full User-Agent string for debugging
Path string // Request path (without query params)
Attempts int // Number of redirect attempts
FirstSeen time.Time // When first redirect was tracked
ExpiresAt time.Time // When to clean up this entry
}
type Store struct {
sessions sync.Map // key: string, value: *RegistrationSession
redirectTracks sync.Map // key: string, value: *RedirectTrack
cleanup *time.Ticker
tokenchecks sync.Map // key: int, value: *TokenCheck
}
func NewStore() *Store {
s := &Store{
cleanup: time.NewTicker(1 * time.Minute),
}
// Background cleanup of expired sessions
go func() {
for range s.cleanup.C {
s.cleanupExpired()
}
}()
return s
}
func (s *Store) Delete(id string) {
s.sessions.Delete(id)
}
func (s *Store) cleanupExpired() {
now := time.Now()
// Clean up expired registration sessions
s.sessions.Range(func(key, value any) bool {
session := value.(*RegistrationSession)
if now.After(session.ExpiresAt) {
s.sessions.Delete(key)
}
return true
})
// Clean up expired redirect tracks
s.redirectTracks.Range(func(key, value any) bool {
track := value.(*RedirectTrack)
if now.After(track.ExpiresAt) {
s.redirectTracks.Delete(key)
}
return true
})
s.tokenchecks.Range(func(key, value any) bool {
check := value.(*TokenCheck)
if now.After(check.ExpiresAt) {
s.tokenchecks.Delete(key)
}
return true
})
}
func generateID() string {
b := make([]byte, 32)
_, _ = rand.Read(b)
return base64.RawURLEncoding.EncodeToString(b)
}
// redirectKey generates a unique key for tracking redirects
// Uses IP + first 100 chars of UA + path as key (not hashed for debugging)
func redirectKey(ip, userAgent, path string) string {
ua := userAgent
if len(ua) > 100 {
ua = ua[:100]
}
return fmt.Sprintf("%s:%s:%s", ip, ua, path)
}