diff options
Diffstat (limited to 'pkg/session')
| -rw-r--r-- | pkg/session/memory.go | 95 | ||||
| -rw-r--r-- | pkg/session/service.go | 20 |
2 files changed, 115 insertions, 0 deletions
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 +} |
