111 lines
2.3 KiB
Go
111 lines
2.3 KiB
Go
package session
|
|
|
|
import (
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
|
|
"astraltech.xyz/accountmanager/src/logging"
|
|
"astraltech.xyz/accountmanager/src/store"
|
|
)
|
|
|
|
const SessionCookieName = "session_token"
|
|
|
|
type SessionManager struct {
|
|
store store.KeyValueStore[*SessionData]
|
|
}
|
|
|
|
var instance *SessionManager
|
|
var once sync.Once
|
|
|
|
type StoreType int
|
|
|
|
const (
|
|
InMemory StoreType = iota
|
|
Redis
|
|
)
|
|
|
|
func GetSessionManager() *SessionManager {
|
|
once.Do(func() {
|
|
instance = &SessionManager{}
|
|
})
|
|
return instance
|
|
}
|
|
|
|
func (manager *SessionManager) SetStoreType(storeType StoreType, params ...any) {
|
|
logging.Infof("Changing session manager store type")
|
|
switch storeType {
|
|
case InMemory:
|
|
{
|
|
manager.store = store.NewMemoryStore[*SessionData]()
|
|
break
|
|
}
|
|
case Redis:
|
|
{
|
|
url, _ := params[0].(string)
|
|
prefix, _ := params[1].(string)
|
|
manager.store = store.NewRedisStore[*SessionData](url, prefix)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (manager *SessionManager) CreateSession(userID string) (cookie *http.Cookie, err error) {
|
|
logging.Debugf("Creating a new session for %s", userID)
|
|
token, err := GenerateSessionToken(32) // Use crypto/rand for this
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
CSRFToken, err := GenerateSessionToken(32)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
newSessionData := SessionData{
|
|
UserID: userID,
|
|
CSRFToken: CSRFToken,
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
}
|
|
err = manager.store.CreateExpiring(token, &newSessionData, time.Hour)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
newCookie := &http.Cookie{
|
|
Name: SessionCookieName,
|
|
Value: token,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
Secure: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
MaxAge: 3600,
|
|
}
|
|
return newCookie, nil
|
|
}
|
|
|
|
func (manager *SessionManager) GetSession(r *http.Request) (*SessionData, error) {
|
|
logging.Debug("Validating session from request")
|
|
cookie, err := r.Cookie(SessionCookieName)
|
|
if err != nil {
|
|
return nil, ErrSessionNotFound
|
|
}
|
|
token := cookie.Value
|
|
if token == "" {
|
|
return nil, ErrSessionNotFound
|
|
}
|
|
data, err := manager.store.Get(token)
|
|
if err != nil {
|
|
return nil, ErrSessionNotFound
|
|
}
|
|
|
|
if time.Now().After(data.ExpiresAt) {
|
|
_ = manager.store.Delete(token)
|
|
return nil, ErrSessionExpired
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func (manager *SessionManager) DeleteSession(sessionId string) error {
|
|
return manager.store.Delete(sessionId)
|
|
}
|