2026-04-28 21:11:37 +03:00
|
|
|
package metastore
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/dgraph-io/badger/v4"
|
|
|
|
|
|
|
|
|
|
"warpbox/lib/helpers"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (store *Store) CreateSession(userID string, ttl time.Duration) (Session, error) {
|
|
|
|
|
userID = strings.TrimSpace(userID)
|
|
|
|
|
if userID == "" {
|
|
|
|
|
return Session{}, fmt.Errorf("%w: user id cannot be empty", ErrInvalid)
|
|
|
|
|
}
|
|
|
|
|
if ttl <= 0 {
|
|
|
|
|
return Session{}, fmt.Errorf("%w: session ttl must be positive", ErrInvalid)
|
|
|
|
|
}
|
|
|
|
|
token, err := helpers.RandomHexID(32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Session{}, err
|
|
|
|
|
}
|
2026-04-28 21:42:36 +03:00
|
|
|
csrfToken, err := helpers.RandomHexID(32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Session{}, err
|
|
|
|
|
}
|
2026-04-28 21:11:37 +03:00
|
|
|
now := time.Now().UTC()
|
|
|
|
|
session := Session{
|
|
|
|
|
Token: token,
|
2026-04-28 21:42:36 +03:00
|
|
|
CSRFToken: csrfToken,
|
2026-04-28 21:11:37 +03:00
|
|
|
UserID: userID,
|
|
|
|
|
CreatedAt: now,
|
|
|
|
|
ExpiresAt: now.Add(ttl),
|
|
|
|
|
}
|
|
|
|
|
err = store.db.Update(func(txn *badger.Txn) error {
|
|
|
|
|
return putJSON(txn, sessionKey(token), session)
|
|
|
|
|
})
|
|
|
|
|
return session, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (store *Store) GetSession(token string) (Session, bool, error) {
|
|
|
|
|
token = strings.TrimSpace(token)
|
|
|
|
|
if token == "" {
|
|
|
|
|
return Session{}, false, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var session Session
|
|
|
|
|
err := store.db.View(func(txn *badger.Txn) error {
|
|
|
|
|
return getJSON(txn, sessionKey(token), &session)
|
|
|
|
|
})
|
|
|
|
|
if errors.Is(err, ErrNotFound) {
|
|
|
|
|
return Session{}, false, nil
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Session{}, false, err
|
|
|
|
|
}
|
|
|
|
|
if time.Now().UTC().After(session.ExpiresAt) {
|
|
|
|
|
_ = store.DeleteSession(token)
|
|
|
|
|
return Session{}, false, nil
|
|
|
|
|
}
|
|
|
|
|
return session, true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (store *Store) DeleteSession(token string) error {
|
|
|
|
|
return store.db.Update(func(txn *badger.Txn) error {
|
|
|
|
|
err := txn.Delete(sessionKey(token))
|
|
|
|
|
if errors.Is(err, badger.ErrKeyNotFound) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return err
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func sessionKey(token string) []byte {
|
|
|
|
|
return []byte("session/" + strings.TrimSpace(token))
|
|
|
|
|
}
|