...

Source file src/edge-infra.dev/pkg/edge/iam/barcode/strategy_signed.go

Documentation: edge-infra.dev/pkg/edge/iam/barcode

     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  	// sha512.digest.Write() always returns nil for err, the panic should never happen
    80  	_, err := h.Write(data)
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  	return h.Sum(nil)
    85  }
    86  

View as plain text