...

Source file src/edge-infra.dev/pkg/edge/iam/storage/database/storage_barcode.go

Documentation: edge-infra.dev/pkg/edge/iam/storage/database

     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  	// as we are just issuing, setting 'used' field to false
    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  	// client used this BarcodeCode, setting 'used' field to true
    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  	// ToDo (must): update should not need all other fields except the one we want to update.
    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  	// used SET because, we update this key twice, when issued and used
    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  // CreateBarcodeUser creates record with key: barcode-user:subject value: barcode key into DB.
    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  	// 'Set' because this keep getting updated as and when user prints barcode
    89  	// if err := s.RedisDB.Set(key, barcodeKey, config.GetBarcodeUserTTL()).Err(); err != nil {
    90  	// 	return errors.WithStack(err)
    91  	// }
    92  	return nil
    93  }
    94  
    95  // GetBarcodeUser checks if the subject already has barcode and fetches the barcode key if present.
    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  	// check if the barcode-code has been used
   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  	// ToDo (must): update should not need all other fields except the one we want to update.
   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  		// used SET because, we update this key twice, when issued and used
   232  		if err := s.RedisDB.Set(key, encryptedValue, config.GetBarcodeCodeTTL()).Err(); err != nil {
   233  			return errors.WithStack(err)
   234  		}
   235  	} else {
   236  		// used SET because, we update this key twice, when issued and used
   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