From 4697556cac819c47d068819b9fc9c3b4ea84e279 Mon Sep 17 00:00:00 2001 From: Leonardo Bishop Date: Thu, 14 Aug 2025 18:07:12 +0100 Subject: Merge confplanner-web and replace fiber with native net/http --- pkg/session/memory.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ pkg/session/service.go | 20 +++++++++++ 2 files changed, 115 insertions(+) create mode 100644 pkg/session/memory.go create mode 100644 pkg/session/service.go (limited to 'pkg/session') diff --git a/pkg/session/memory.go b/pkg/session/memory.go new file mode 100644 index 0000000..96e416b --- /dev/null +++ b/pkg/session/memory.go @@ -0,0 +1,95 @@ +package session + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "sync" + "time" +) + +type memoryStore struct { + sessionsByToken map[string]*UserSession + sessionsBySID map[uint]*UserSession + nextSessionId uint + lock sync.RWMutex +} + +func NewMemoryStore() Service { + return &memoryStore{ + sessionsByToken: make(map[string]*UserSession), + sessionsBySID: make(map[uint]*UserSession), + } +} + +func (s *memoryStore) GetByToken(token string) *UserSession { + if token == "" { + return nil + } + + s.lock.RLock() + defer s.lock.RUnlock() + + return s.sessionsByToken[token] +} + +func (s *memoryStore) GetBySID(sid uint) *UserSession { + s.lock.RLock() + defer s.lock.RUnlock() + + return s.sessionsBySID[sid] +} + +func (s *memoryStore) Create(uid int32, username string, ip string, ua string) (*UserSession, error) { + token := generateSessionToken() + + s.lock.Lock() + defer s.lock.Unlock() + + sessionId := s.nextSessionId + s.nextSessionId++ + + _, sidExists := s.sessionsBySID[sessionId] + _, tokenExists := s.sessionsByToken[token] + + // should never realistically happen but still theoretically possible + if sidExists || tokenExists { + return nil, fmt.Errorf("session conflict") + } + + session := &UserSession{ + UserID: uid, + SessionID: sessionId, + Token: token, + Username: username, + IP: ip, + UserAgent: ua, + LoginTime: time.Now(), + } + s.sessionsByToken[token] = session + s.sessionsBySID[sessionId] = session + + return session, nil +} + +func (s *memoryStore) Destroy(sid uint) error { + s.lock.Lock() + defer s.lock.Unlock() + + session := s.sessionsBySID[sid] + if session == nil { + return fmt.Errorf("session does not exist") + } + + delete(s.sessionsBySID, sid) + delete(s.sessionsByToken, session.Token) + return nil +} + +func generateSessionToken() string { + b := make([]byte, 100) + if _, err := rand.Read(b); err != nil { + return "" + } + return hex.EncodeToString(b) +} diff --git a/pkg/session/service.go b/pkg/session/service.go new file mode 100644 index 0000000..83009bc --- /dev/null +++ b/pkg/session/service.go @@ -0,0 +1,20 @@ +package session + +import "time" + +type Service interface { + GetByToken(token string) *UserSession + GetBySID(sid uint) *UserSession + Create(uid int32, username string, ip string, ua string) (*UserSession, error) + Destroy(sid uint) error +} + +type UserSession struct { + UserID int32 + SessionID uint + Token string + Username string + IP string + LoginTime time.Time + UserAgent string +} -- cgit v1.2.3-70-g09d2