passkey_session_store.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package repository
  2. import (
  3. "context"
  4. "crypto/rand"
  5. "encoding/base64"
  6. "encoding/json"
  7. "fmt"
  8. "strings"
  9. "time"
  10. "github.com/Wei-Shaw/sub2api/internal/service"
  11. "github.com/redis/go-redis/v9"
  12. )
  13. const passkeySessionPrefix = "passkey:session:"
  14. type passkeySessionStore struct {
  15. redis *redis.Client
  16. }
  17. func NewPasskeySessionStore(redisClient *redis.Client) service.PasskeySessionStore {
  18. return &passkeySessionStore{redis: redisClient}
  19. }
  20. func (s *passkeySessionStore) Store(
  21. ctx context.Context,
  22. session *service.PasskeySession,
  23. ttl time.Duration,
  24. ) (string, error) {
  25. if session == nil || ttl <= 0 {
  26. return "", fmt.Errorf("invalid passkey session")
  27. }
  28. random := make([]byte, 32)
  29. if _, err := rand.Read(random); err != nil {
  30. return "", fmt.Errorf("generate passkey session token: %w", err)
  31. }
  32. token := base64.RawURLEncoding.EncodeToString(random)
  33. payload, err := json.Marshal(session)
  34. if err != nil {
  35. return "", fmt.Errorf("encode passkey session: %w", err)
  36. }
  37. if err = s.redis.Set(ctx, passkeySessionPrefix+token, payload, ttl).Err(); err != nil {
  38. return "", fmt.Errorf("store passkey session: %w", err)
  39. }
  40. return token, nil
  41. }
  42. func (s *passkeySessionStore) Consume(
  43. ctx context.Context,
  44. token string,
  45. ) (*service.PasskeySession, error) {
  46. token = strings.TrimSpace(token)
  47. if token == "" || len(token) > 128 {
  48. return nil, service.ErrPasskeySession
  49. }
  50. payload, err := s.redis.GetDel(ctx, passkeySessionPrefix+token).Bytes()
  51. if err == redis.Nil {
  52. return nil, service.ErrPasskeySession
  53. }
  54. if err != nil {
  55. return nil, fmt.Errorf("consume passkey session: %w", err)
  56. }
  57. var session service.PasskeySession
  58. if err = json.Unmarshal(payload, &session); err != nil {
  59. return nil, service.ErrPasskeySession
  60. }
  61. return &session, nil
  62. }