aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/session/memory.go95
-rw-r--r--pkg/session/service.go20
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
+}