From f6016bbdb1d1ab1a336e55a5e109363f98c662bb Mon Sep 17 00:00:00 2001 From: Gregory Wells Date: Mon, 8 Jun 2026 18:16:07 -0400 Subject: [PATCH] start to move session stores into there own key value in memory store --- src/session/session_errors.go | 8 --- src/session/session_helpers.go | 7 --- src/session/session_in_memory.go | 4 -- src/session/session_manager.go | 4 +- src/session/session_store.go | 7 --- src/store/store.go | 10 +++ src/store/store_errros.go | 8 +++ src/store/store_helpers.go | 11 ++++ .../session_redis.go => store/store_redis.go} | 63 +++++++++---------- 9 files changed, 62 insertions(+), 60 deletions(-) delete mode 100644 src/session/session_errors.go create mode 100644 src/store/store.go create mode 100644 src/store/store_errros.go create mode 100644 src/store/store_helpers.go rename src/{session/session_redis.go => store/store_redis.go} (54%) diff --git a/src/session/session_errors.go b/src/session/session_errors.go deleted file mode 100644 index 29f0ca0..0000000 --- a/src/session/session_errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package session - -import "errors" - -var ErrSessionNotFound = errors.New("session not found") -var ErrSessionAlreadyExists = errors.New("session already exists") -var ErrSessionExpired = errors.New("session expired") -var ErrSessionBackend = errors.New("session backend") diff --git a/src/session/session_helpers.go b/src/session/session_helpers.go index c7ab062..42b3e55 100644 --- a/src/session/session_helpers.go +++ b/src/session/session_helpers.go @@ -2,7 +2,6 @@ package session import ( "crypto/rand" - "crypto/sha256" "encoding/base64" ) @@ -16,9 +15,3 @@ func GenerateSessionToken(length int) (string, error) { token := base64.RawURLEncoding.EncodeToString(b) return token, nil } - -// more helper -func hashSession(session_id string) string { - tokenEncoded := sha256.Sum256([]byte(session_id)) - return base64.RawURLEncoding.EncodeToString(tokenEncoded[:]) -} diff --git a/src/session/session_in_memory.go b/src/session/session_in_memory.go index f031356..8e99dce 100644 --- a/src/session/session_in_memory.go +++ b/src/session/session_in_memory.go @@ -43,10 +43,6 @@ func (m *MemoryStore) Get(sessionID string) (*SessionData, error) { if exists == false { return nil, ErrSessionNotFound } - if time.Now().After(data.ExpiresAt) { - _ = m.Delete(sessionID) // ignore error - return nil, ErrSessionExpired - } copy := *data return ©, nil } diff --git a/src/session/session_manager.go b/src/session/session_manager.go index fcd65b0..f6a384d 100644 --- a/src/session/session_manager.go +++ b/src/session/session_manager.go @@ -6,12 +6,13 @@ import ( "time" "astraltech.xyz/accountmanager/src/logging" + "astraltech.xyz/accountmanager/src/store" ) const SessionCookieName = "session_token" type SessionManager struct { - store SessionStore + store store.Store[string, *SessionData] } var instance *SessionManager @@ -93,6 +94,7 @@ func (manager *SessionManager) GetSession(r *http.Request) (*SessionData, error) if err != nil { return nil, ErrSessionNotFound } + // TODO: handle token expiry here return data, nil } diff --git a/src/session/session_store.go b/src/session/session_store.go index 0b2a43b..b7e92e4 100644 --- a/src/session/session_store.go +++ b/src/session/session_store.go @@ -7,10 +7,3 @@ type SessionData struct { CSRFToken string `json:"csrftoken"` ExpiresAt time.Time `json:"expiresat"` } - -type SessionStore interface { - Create(sessionID string, session *SessionData) error - Get(sessionID string) (*SessionData, error) - Update(sessionID string, session *SessionData) error - Delete(sessionID string) error -} diff --git a/src/store/store.go b/src/store/store.go new file mode 100644 index 0000000..8819774 --- /dev/null +++ b/src/store/store.go @@ -0,0 +1,10 @@ +package store + +// A simple key value store that can either just be single instance in memory or a redis server (for now) + +type Store[Value any] interface { + Create(key string, value Value) error + Get(key string) (Value, error) + Update(key string, session Value) error + Delete(key string) error +} diff --git a/src/store/store_errros.go b/src/store/store_errros.go new file mode 100644 index 0000000..7cf5d3e --- /dev/null +++ b/src/store/store_errros.go @@ -0,0 +1,8 @@ +package store + +import "errors" + +var ErrKeyNotFound = errors.New("Key not found") +var ErrKeyAlreadyExists = errors.New("Key already exists") +var ErrKeyExpired = errors.New("Key expired") +var ErrKeyBackend = errors.New("Key backend") diff --git a/src/store/store_helpers.go b/src/store/store_helpers.go new file mode 100644 index 0000000..00e22ba --- /dev/null +++ b/src/store/store_helpers.go @@ -0,0 +1,11 @@ +package store + +import ( + "crypto/sha256" + "encoding/base64" +) + +func HashKey(key string) string { + tokenEncoded := sha256.Sum256([]byte(key)) + return base64.RawURLEncoding.EncodeToString(tokenEncoded[:]) +} diff --git a/src/session/session_redis.go b/src/store/store_redis.go similarity index 54% rename from src/session/session_redis.go rename to src/store/store_redis.go index 210ffb6..eeb9139 100644 --- a/src/session/session_redis.go +++ b/src/store/store_redis.go @@ -1,4 +1,4 @@ -package session +package store import ( "context" @@ -9,16 +9,17 @@ import ( "github.com/redis/go-redis/v9" ) -type RedisStore struct { +type RedisStore[Value any] struct { client *redis.Client ctx context.Context + prefix string } -func RedisHash(sessionID string) string { - return "selfservicedashboard_" + hashSession(sessionID) +func (m *RedisStore[Value]) RedisHash(value_to_hash string) string { + return m.prefix + HashKey(value_to_hash) } -func NewRedisStore() *RedisStore { +func NewRedisStore[Value any]() *RedisStore[Value] { logging.Debug("Creating new redis session store") // this will be replaced with a URL that can be parsed in the config file @@ -38,82 +39,78 @@ func NewRedisStore() *RedisStore { logging.Infof("Successfully connected to redis server %s", redis_server) } - store := &RedisStore{ + store := &RedisStore[Value]{ client: rdb, ctx: ctx, } return store } -func (m *RedisStore) Create(sessionID string, session *SessionData) (err error) { - hashedSession := RedisHash(sessionID) +func (m *RedisStore[Value]) Create(key string, value Value) (err error) { + hashedSession := m.RedisHash(key) - data, err := json.Marshal(*session) + data, err := json.Marshal(value) if err != nil { - return ErrSessionBackend + return ErrKeyBackend } created, err := m.client.SetNX(m.ctx, hashedSession, data, time.Hour).Result() if err != nil { logging.Error(err.Error()) - return ErrSessionBackend + return ErrKeyBackend } if !created { - return ErrSessionAlreadyExists + return ErrKeyAlreadyExists } return nil } -func (m *RedisStore) Get(sessionID string) (*SessionData, error) { - hashed := RedisHash(sessionID) +func (m *RedisStore[Value]) Get(sessionID string) (Value, error) { + hashed := m.RedisHash(sessionID) + var session_data Value data, err := m.client.Get(m.ctx, hashed).Bytes() if err == redis.Nil { - return nil, ErrSessionNotFound + return session_data, ErrKeyNotFound } else if err != nil { logging.Error(err.Error()) - return nil, ErrSessionBackend + return session_data, ErrKeyBackend } - var session_data SessionData - if err := json.Unmarshal(data, &session_data); err != nil { + if err := json.Unmarshal(data, session_data); err != nil { logging.Error(err.Error()) - return nil, ErrSessionBackend + return session_data, ErrKeyBackend } - if time.Now().After(session_data.ExpiresAt) { - _ = m.Delete(sessionID) - return nil, ErrSessionBackend - } - return &session_data, nil + return session_data, nil } -func (m *RedisStore) Update(sessionID string, session *SessionData) error { - hashedSession := RedisHash(sessionID) +func (m *RedisStore[Value]) Update(key string, value Value) error { + hashedSession := m.RedisHash(key) - data, err := json.Marshal(*session) + data, err := json.Marshal(value) if err != nil { - return ErrSessionBackend + return ErrKeyBackend } updated, err := m.client.SetXX(m.ctx, hashedSession, data, time.Hour).Result() if err != nil { logging.Error(err.Error()) - return ErrSessionBackend + return ErrKeyBackend } if !updated { - return ErrSessionNotFound + return ErrKeyNotFound } return nil } -func (m *RedisStore) Delete(sessionID string) error { - hashedSession := RedisHash(sessionID) +func (m *RedisStore[Value]) Delete(sessionID string) error { + hashedSession := m.RedisHash(sessionID) err := m.client.Del(m.ctx, hashedSession).Err() if err != nil { logging.Error(err.Error()) - return ErrSessionBackend + return ErrKeyBackend } return nil }