...
1 package barcode
2
3 import (
4 "crypto/hmac"
5 "crypto/sha512"
6 "encoding/base64"
7 "encoding/json"
8 "fmt"
9 "strings"
10 "time"
11
12 fHMAC "github.com/ory/fosite/token/hmac"
13
14 "edge-infra.dev/pkg/edge/iam/config"
15 iamErrors "edge-infra.dev/pkg/edge/iam/errors"
16 )
17
18 type SignedStrategy struct {
19 HMACStrategy *fHMAC.HMACStrategy
20 }
21
22 type Payload struct {
23 Subject string `json:"sub"`
24 IssuedBy string `json:"iby"`
25 IssuedAt int64 `json:"iat"`
26 ExpiresAt int64 `json:"exp"`
27 }
28
29 var b64 = base64.URLEncoding.WithPadding(base64.NoPadding)
30
31 func (s *SignedStrategy) Generate(subjectAlias, issuerAlias string) (string, error) {
32 var signingKey [32]byte
33 copy(signingKey[:], s.HMACStrategy.GlobalSecret)
34 payload := Payload{
35 Subject: subjectAlias,
36 IssuedBy: issuerAlias,
37 IssuedAt: time.Now().Unix(),
38 ExpiresAt: time.Now().Add(config.GetEmergencyBarcodeLifeSpan()).Unix(),
39 }
40 payloadBytes, _ := json.Marshal(payload)
41 signature := s.generateHMAC(payloadBytes, &signingKey)
42 encodedSignature := b64.EncodeToString(signature)
43 encodedToken := fmt.Sprintf("%s.%s.%s", config.BarcodePrefix(), b64.EncodeToString(payloadBytes), encodedSignature)
44 return encodedToken, nil
45 }
46 func (s *SignedStrategy) Verify(signedBarcode string) (*Payload, error) {
47 var parts = strings.Split(signedBarcode, ".")
48 if len(parts) != 3 {
49 return nil, iamErrors.ErrUnrecognisedBarcode
50 }
51 unprefixedBarcode := strings.Join(parts[1:], ".")
52 err := s.HMACStrategy.Validate(unprefixedBarcode)
53 if err != nil {
54 return nil, err
55 }
56 payload, _ := decodeTokenPayload(parts[1])
57 expires := time.Unix(payload.ExpiresAt, 0)
58 remainder := time.Until(expires)
59 if remainder <= 0 {
60 return nil, iamErrors.ErrExpiredEBC
61 }
62 return payload, nil
63 }
64 func decodeTokenPayload(b64Payload string) (*Payload, error) {
65 var payload Payload
66 decodedTokenPayload, err := b64.DecodeString(b64Payload)
67 if err != nil {
68 return nil, err
69 }
70 err = json.Unmarshal(decodedTokenPayload, &payload)
71 if err != nil {
72 return nil, err
73 }
74 return &payload, nil
75 }
76 func (s *SignedStrategy) generateHMAC(data []byte, key *[32]byte) []byte {
77 hasher := sha512.New512_256
78 h := hmac.New(hasher, key[:])
79
80 _, err := h.Write(data)
81 if err != nil {
82 panic(err)
83 }
84 return h.Sum(nil)
85 }
86
View as plain text