auth
auth/token.go
Update uuid import path, test for multiple profile updates. Test updating multiple profiles in one request (e.g., when profiles become compromised.) Update the uuid import path to use the new code.secondbit.org/uuid import path.
1 package auth
3 import (
4 "errors"
5 "time"
7 "code.secondbit.org/uuid"
8 )
10 var (
11 ErrTokenNotFound = errors.New("Token not found in TokenStore.")
12 ErrTokenAlreadyExists = errors.New("Token already exists in TokenStore.")
13 )
15 type Token struct {
16 AccessToken string
17 RefreshToken string
18 Created time.Time
19 ExpiresIn int32
20 TokenType string
21 Scope string
22 ProfileID uuid.ID
23 }
25 type TokenStore interface {
26 GetToken(token string, refresh bool) (Token, error)
27 SaveToken(token Token) error
28 RemoveToken(token string) error
29 GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error)
30 }
32 func (m *Memstore) GetToken(token string, refresh bool) (Token, error) {
33 if refresh {
34 t, err := m.lookupTokenByRefresh(token)
35 if err != nil {
36 return Token{}, err
37 }
38 token = t
39 }
40 m.tokenLock.RLock()
41 defer m.tokenLock.RUnlock()
42 result, ok := m.tokens[token]
43 if !ok {
44 return Token{}, ErrTokenNotFound
45 }
46 return result, nil
47 }
49 func (m *Memstore) SaveToken(token Token) error {
50 m.tokenLock.Lock()
51 defer m.tokenLock.Unlock()
52 _, ok := m.tokens[token.AccessToken]
53 if ok {
54 return ErrTokenAlreadyExists
55 }
56 m.tokens[token.AccessToken] = token
57 if token.RefreshToken != "" {
58 m.refreshTokenLookup[token.RefreshToken] = token.AccessToken
59 }
60 if _, ok = m.profileTokenLookup[token.ProfileID.String()]; ok {
61 m.profileTokenLookup[token.ProfileID.String()] = append(m.profileTokenLookup[token.ProfileID.String()], token.AccessToken)
62 } else {
63 m.profileTokenLookup[token.ProfileID.String()] = []string{token.AccessToken}
64 }
65 return nil
66 }
68 func (m *Memstore) RemoveToken(token string) error {
69 m.tokenLock.Lock()
70 defer m.tokenLock.Unlock()
71 t, ok := m.tokens[token]
72 if !ok {
73 return ErrTokenNotFound
74 }
75 delete(m.tokens, token)
76 if t.RefreshToken != "" {
77 delete(m.refreshTokenLookup, t.RefreshToken)
78 }
79 pos := -1
80 for p, item := range m.profileTokenLookup[t.ProfileID.String()] {
81 if item == token {
82 pos = p
83 break
84 }
85 }
86 if pos >= 0 {
87 m.profileTokenLookup[t.ProfileID.String()] = append(m.profileTokenLookup[t.ProfileID.String()][:pos], m.profileTokenLookup[t.ProfileID.String()][pos+1:]...)
88 }
89 return nil
90 }
92 func (m *Memstore) GetTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
93 ids, err := m.lookupTokensByProfileID(profileID.String())
94 if err != nil {
95 return []Token{}, err
96 }
97 if len(ids) > num+offset {
98 ids = ids[offset : num+offset]
99 } else if len(ids) > offset {
100 ids = ids[offset:]
101 } else {
102 return []Token{}, nil
103 }
104 tokens := []Token{}
105 for _, id := range ids {
106 token, err := m.GetToken(id, false)
107 if err != nil {
108 return []Token{}, err
109 }
110 tokens = append(tokens, token)
111 }
112 return tokens, nil
113 }