-
Notifications
You must be signed in to change notification settings - Fork 8
/
store_redis.go
87 lines (76 loc) · 1.88 KB
/
store_redis.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package passwordless
import (
"context"
"time"
"github.com/go-redis/redis/v8"
"github.com/pzduniak/mcf"
)
const (
redisPrefix = "passwordless-token::"
)
// RedisStore is a Store that keeps tokens in Redis.
type RedisStore struct {
client redis.UniversalClient
}
// NewRedisStore creates and returns a new `RedisStore`.
func NewRedisStore(client redis.UniversalClient) *RedisStore {
return &RedisStore{
client: client,
}
}
func redisKey(uid string) string {
return redisPrefix + uid
}
// Store a generated token in redis for a user.
func (s RedisStore) Store(ctx context.Context, token, uid string, ttl time.Duration) error {
hashToken, err := mcf.Create([]byte(token))
if err != nil {
return err
}
r := s.client.Set(ctx, redisKey(uid), hashToken, ttl)
if r.Err() != nil {
return r.Err()
}
return nil
}
// Exists checks to see if a token exists.
func (s RedisStore) Exists(ctx context.Context, uid string) (bool, time.Time, error) {
dur, err := s.client.TTL(ctx, redisKey(uid)).Result()
if err != nil {
if err == redis.Nil {
return false, time.Time{}, nil
}
return false, time.Time{}, err
}
expiry := time.Now().Add(dur)
if time.Now().After(expiry) {
return false, time.Time{}, nil
}
return true, expiry, nil
}
// Verify checks to see if a token exists and is valid for a user.
func (s RedisStore) Verify(ctx context.Context, token, uid string) (bool, error) {
r, err := s.client.Get(ctx, redisKey(uid)).Result()
if err != nil {
if err == redis.Nil {
return false, ErrTokenNotFound
}
return false, err
}
valid, err := mcf.Verify([]byte(token), []byte(r))
if err != nil {
return false, err
}
if !valid {
return false, nil
}
return true, nil
}
// Delete removes a key from the store.
func (s RedisStore) Delete(ctx context.Context, uid string) error {
_, err := s.client.Del(ctx, redisKey(uid)).Result()
if err != nil {
return err
}
return nil
}