...
1 package barcode
2
3 import (
4 "crypto/rand"
5 "time"
6
7 "github.com/ory/fosite"
8 "github.com/ory/x/errorsx"
9 "golang.org/x/crypto/bcrypt"
10
11 "edge-infra.dev/pkg/edge/iam/config"
12
13 iamErrors "edge-infra.dev/pkg/edge/iam/errors"
14 )
15
16 type OpaqueStrategy struct {
17 }
18
19 func (s *OpaqueStrategy) GetKey(barcode string) string {
20 barcodePrefixLen := uint8(len(config.BarcodePrefix()))
21 key := barcode[len(config.BarcodePrefix()) : barcodePrefixLen+config.GetBarcodeKeyLength()]
22 return key
23 }
24
25 func getSecret(barcode string) string {
26 barcodePrefixLen := uint8(len(config.BarcodePrefix()))
27 secret := barcode[barcodePrefixLen+config.GetBarcodeKeyLength():]
28 return secret
29 }
30
31 func (s *OpaqueStrategy) Verify(barcode string, barcodeData *Barcode) error {
32 err := compareHashAndSecret(barcode, barcodeData)
33 if err != nil {
34 return err
35 }
36
37 return isExpired(barcodeData)
38 }
39
40 func (s *OpaqueStrategy) Generate() (string, error) {
41 return barcode128A()
42 }
43
44 func isExpired(barcodeData *Barcode) error {
45 expires := barcodeExpiresAt(barcodeData)
46 if expires.Before(time.Now().UTC()) {
47 return iamErrors.ErrExpiredBarcode
48 }
49 return nil
50 }
51 func barcodeExpiresAt(barcodeData *Barcode) time.Time {
52 return barcodeData.CreatedAt.UTC().
53 Add(config.GetBarcodeLifeSpan()).
54 Round(time.Second)
55 }
56 func accessExpiresAt() time.Time {
57 return time.Now().UTC().
58 Add(config.AccessTokenLifespan()).
59 Round(time.Second)
60 }
61
62 func refreshExpiresAt() time.Time {
63 return time.Now().UTC().
64 Add(config.RefreshTokenLifespan()).
65 Round(time.Second)
66 }
67
68 func compareHashAndSecret(barcode string, barcodeData *Barcode) error {
69 hash := barcodeData.Secret
70 secret := getSecret(barcode)
71 if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(secret)); err != nil {
72 hint := "Cannot accept barcode, try signing in another way."
73 return errorsx.WithStack(fosite.ErrAccessDenied.
74 WithHint(hint).
75 WithDebug(err.Error()))
76 }
77 return nil
78 }
79
80
81 func barcode128A() (string, error) {
82 barcodePrefixLen := uint8(len(config.BarcodePrefix()))
83 length := config.GetBarcodeLength() - barcodePrefixLen
84 charset := config.GetBarcodeCharset()
85
86
87 bytes := make([]byte, length)
88 _, err := rand.Read(bytes)
89 if err != nil {
90 return "", err
91 }
92
93
94 for i, v := range bytes {
95 bytes[i] = charset[v%byte(len(charset))]
96 }
97
98 return config.BarcodePrefix() + string(bytes), nil
99 }
100
View as plain text