1 package database
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "time"
8
9 "github.com/go-redis/redis"
10 "github.com/pkg/errors"
11
12 "edge-infra.dev/pkg/edge/iam/barcode"
13 "edge-infra.dev/pkg/edge/iam/config"
14 "edge-infra.dev/pkg/edge/iam/crypto"
15 iamErrors "edge-infra.dev/pkg/edge/iam/errors"
16 )
17
18 type BarcodeUser struct {
19 Key string `json:"key"`
20 }
21
22 func (s *Store) CreateBarcodeCode(_ context.Context, signature, subject, issuedBy, clientID, barcodeType, challenge string) (err error) {
23
24 return s.createOrUpdateBarcodeCode(signature, subject, issuedBy, clientID, barcodeType, challenge, false)
25 }
26
27 func (s *Store) InvalidateBarcodeCode(_ context.Context, signature, subject, issuedBy, clientID, barcodeType, challenge string) (err error) {
28
29 return s.createOrUpdateBarcodeCode(signature, subject, issuedBy, clientID, barcodeType, challenge, true)
30 }
31
32 func (s *Store) CreateBarcodeKey(_ context.Context, challenge, barcodeKey string) (err error) {
33 key := keyFrom(KeyPrefixBarcodeKey, challenge)
34
35 payload := &barcode.BarcodeKey{
36 BarcodeKey: barcodeKey,
37 }
38
39 value, err := json.Marshal(payload)
40 if err != nil {
41 return errors.WithStack(err)
42 }
43
44
45 if err := s.RedisDB.Set(key, string(value), config.GetBarcodeCodeTTL()).Err(); err != nil {
46 return errors.WithStack(err)
47 }
48 return nil
49 }
50
51 func (s *Store) GetBarcodeKey(_ context.Context, challenge string) (barcodeKey *barcode.BarcodeKey, err error) {
52 key := keyFrom(KeyPrefixBarcodeKey, challenge)
53
54 cmd := s.RedisDB.Get(key)
55 if cmd.Err() == redis.Nil {
56 return nil, errors.WithMessage(cmd.Err(), "barcode code not found")
57 }
58
59 data, _ := cmd.Bytes()
60 err = json.Unmarshal(data, &barcodeKey)
61 if err != nil {
62 return nil, errors.WithMessage(err, "barcode schema not valid")
63 }
64
65 return barcodeKey, nil
66 }
67
68 func (s *Store) DeleteBarcodeKey(_ context.Context, challenge string) (err error) {
69 key := keyFrom(KeyPrefixBarcodeKey, challenge)
70 err = s.RedisDB.Del(key).Err()
71 if err != nil {
72 return errors.Wrap(err, fmt.Sprintf("Failed to delete key '%v'", key))
73 }
74 return nil
75 }
76
77
78 func (s *Store) CreateBarcodeUser(ctx context.Context, subject, barcodeKey string) (err error) {
79 key := keyFrom(KeyPrefixBarcodeUser, subject)
80 value, err := json.Marshal(&BarcodeUser{Key: barcodeKey})
81 if err != nil {
82 return errors.WithStack(err)
83 }
84
85 if err := s.updateDoc(ctx, key, value, WithExpiration(config.GetBarcodeUserTTL())); err != nil {
86 return errors.WithStack(err)
87 }
88
89
90
91
92 return nil
93 }
94
95
96 func (s *Store) GetBarcodeUser(ctx context.Context, subject string) (barCodeKey string, err error) {
97 key := keyFrom(KeyPrefixBarcodeUser, subject)
98 var doc *Doc
99 if doc, err = s.getDoc(ctx, key); err != nil {
100 return "", err
101 }
102 if doc == nil {
103 return "", errors.New("no barcode issued for this user")
104 }
105 var barcodeUser *BarcodeUser
106 if err = json.Unmarshal(doc.Value, &barcodeUser); err != nil {
107 return "", err
108 }
109
110 return barcodeUser.Key, nil
111 }
112
113 func (s *Store) DeleteBarcodeCode(_ context.Context, code string) (err error) {
114 key := keyFrom(KeyPrefixBarcodeCode, code)
115 err = s.RedisDB.Del(key).Err()
116 if err != nil {
117 return errors.Wrap(err, fmt.Sprintf("Failed to delete key '%v'", key))
118 }
119 return nil
120 }
121
122 func (s *Store) GetBarcodeCode(_ context.Context, signature string) (barcodeCode *barcode.Code, err error) {
123 key := keyFrom(KeyPrefixBarcodeCode, signature)
124
125 cmd := s.RedisDB.Get(key)
126 if cmd.Err() == redis.Nil {
127 return nil, errors.WithMessage(cmd.Err(), "barcode code not found")
128 }
129
130 data, _ := cmd.Bytes()
131
132 if config.EncryptionEnabled() {
133 encryptedValue, err := crypto.DecryptRedis(string(data), config.EncryptionKey())
134 if err != nil {
135 return nil, errors.WithMessage(cmd.Err(), "error decrypting barcode code")
136 }
137
138 err = json.Unmarshal(encryptedValue, &barcodeCode)
139 if err != nil {
140 return nil, errors.WithMessage(err, "barcode schema not valid")
141 }
142 } else {
143 err = json.Unmarshal(data, &barcodeCode)
144 if err != nil {
145 return nil, errors.WithMessage(err, "barcode schema not valid")
146 }
147 }
148
149
150 if barcodeCode.Used {
151 return nil, iamErrors.ErrUsedBarcodeCode
152 }
153 return barcodeCode, nil
154 }
155
156 func (s *Store) CreateBarcode(ctx context.Context, key, secret, subject string) (err error) {
157 key = keyFrom(KeyPrefixBarcode, key)
158
159 payload := &barcode.Barcode{
160 Subject: subject,
161 Secret: secret,
162 CreatedAt: time.Now().UTC(),
163 }
164
165 value, err := json.Marshal(payload)
166 if err != nil {
167 return errors.WithStack(err)
168 }
169
170 if err := s.createDoc(ctx, key, value, WithExpiration(config.GetBarcodeCodeTTL())); err != nil {
171 return errors.WithStack(err)
172 }
173
174 return nil
175 }
176
177 func (s *Store) GetBarcode(ctx context.Context, key string) (barcode *barcode.Barcode, err error) {
178 key = keyFrom(KeyPrefixBarcode, key)
179
180 var doc *Doc
181 if doc, err = s.getDoc(ctx, key); err != nil {
182 return nil, err
183 }
184 if doc == nil {
185 return nil, errors.New("barcode not found")
186 }
187 data := doc.Value
188 err = json.Unmarshal(data, &barcode)
189 if err != nil {
190 return nil, errors.WithMessage(err, "barcode schema not valid")
191 }
192
193 return barcode, nil
194 }
195
196 func (s *Store) DeleteBarcode(ctx context.Context, key string) (err error) {
197 key = keyFrom(KeyPrefixBarcode, key)
198
199 err = s.deleteDoc(ctx, key)
200 if err != nil {
201 return errors.WithMessage(err, "barcode failed to delete")
202 }
203
204 return nil
205 }
206
207 func (s *Store) createOrUpdateBarcodeCode(signature, subject, issuedBy, clientID, barcodeType, challenge string, used bool) (err error) {
208 key := keyFrom(KeyPrefixBarcodeCode, signature)
209
210 payload := &barcode.Code{
211 Subject: subject,
212 ClientID: clientID,
213 Used: used,
214 CreatedAt: time.Now().UTC(),
215 IssuedBy: issuedBy,
216 Type: barcodeType,
217 Challenge: challenge,
218 }
219
220 value, err := json.Marshal(payload)
221 if err != nil {
222 return errors.WithStack(err)
223 }
224
225 if config.EncryptionEnabled() {
226 encryptedValue, err := crypto.EncryptRedis(value, config.EncryptionKey())
227 if err != nil {
228 return errors.WithStack(err)
229 }
230
231
232 if err := s.RedisDB.Set(key, encryptedValue, config.GetBarcodeCodeTTL()).Err(); err != nil {
233 return errors.WithStack(err)
234 }
235 } else {
236
237 if err := s.RedisDB.Set(key, string(value), config.GetBarcodeCodeTTL()).Err(); err != nil {
238 return errors.WithStack(err)
239 }
240 }
241 return nil
242 }
243
View as plain text