start to move session stores into there own key value in memory store

This commit is contained in:
Gregory Wells
2026-06-08 18:16:07 -04:00
parent 3b31adf3e2
commit f6016bbdb1
9 changed files with 62 additions and 60 deletions
-8
View File
@@ -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")
-7
View File
@@ -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[:])
}
-4
View File
@@ -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 &copy, nil
}
+3 -1
View File
@@ -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
}
-7
View File
@@ -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
}
+10
View File
@@ -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
}
+8
View File
@@ -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")
+11
View File
@@ -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[:])
}
@@ -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
}