...

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

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

     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())) /* #nosec G115  value from ENV and ENV is considered trusted */
    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())) /* #nosec G115  value from ENV and ENV is considered trusted */
    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  // generate a random string with length and charset limitations of barcode 128 A.
    81  func barcode128A() (string, error) {
    82  	barcodePrefixLen := uint8(len(config.BarcodePrefix())) /* #nosec G115  value from ENV and ENV is considered trusted */
    83  	length := config.GetBarcodeLength() - barcodePrefixLen
    84  	charset := config.GetBarcodeCharset()
    85  
    86  	// read cryptographically secure pseudorandom numbers and write them to bytes
    87  	bytes := make([]byte, length)
    88  	_, err := rand.Read(bytes)
    89  	if err != nil {
    90  		return "", err
    91  	}
    92  
    93  	// map characters in our charset due to the limitations of barcode.
    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