forked from johnsto/go-passwordless
/
store_memcache.go
78 lines (66 loc) · 1.9 KB
/
store_memcache.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
package appengine
import (
"time"
"github.com/johnsto/go-passwordless"
"context"
"github.com/gyepisam/mcf"
_ "github.com/gyepisam/mcf/scrypt"
"google.golang.org/appengine/memcache"
)
type MemcacheStore struct {
KeyPrefix string
}
type item struct {
hashToken string `json:"token"`
expiresAt time.Time `json:"expires_at"`
}
func (s MemcacheStore) Store(ctx context.Context, token, uid string, ttl time.Duration) error {
hashToken, err := mcf.Create(token)
if err != nil {
return err
}
expiresAt := time.Now().Add(ttl)
return memcache.JSON.Set(ctx, &memcache.Item{
Key: s.KeyPrefix + uid,
Object: item{hashToken, expiresAt},
Expiration: ttl,
})
}
// Exists returns true if a token for the specified user exists.
func (s MemcacheStore) Exists(ctx context.Context, uid string) (bool, time.Time, error) {
v := item{}
_, err := memcache.JSON.Get(ctx, s.KeyPrefix+uid, &v)
if err == memcache.ErrCacheMiss {
// No known token for this user
return false, time.Time{}, nil
} else {
// Token exists and is still valid
return true, v.expiresAt, nil
}
}
func (s MemcacheStore) Verify(ctx context.Context, token, uid string) (bool, error) {
v := item{}
_, err := memcache.JSON.Get(ctx, s.KeyPrefix+uid, &v)
if err == memcache.ErrCacheMiss {
// No token in database
return false, passwordless.ErrTokenNotFound
} else if err != nil {
return false, err
}
if time.Now().After(v.expiresAt) {
// Token has actually expired (even if still present in memcache)
return false, passwordless.ErrTokenNotFound
} else if valid, err := mcf.Verify(token, v.hashToken); err != nil {
// Couldn't validate token
return false, err
} else if !valid {
// Token does not validate against hashed token
return false, nil
} else {
// Token is valid!
return true, nil
}
}
func (s MemcacheStore) Delete(ctx context.Context, uid string) error {
return memcache.Delete(ctx, s.KeyPrefix+uid)
}