github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/keyring/service.go (about)

     1  package keyring
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  )
     8  
     9  var (
    10  	ErrFieldRequired = errors.New("field required")
    11  )
    12  
    13  // Keyring handle the encryption/decryption keys
    14  type Keyring interface {
    15  	// CredentialsEncryptorKey returns the key used to encrypt credentials values,
    16  	// stored in accounts.
    17  	CredentialsEncryptorKey() *NACLKey
    18  	// CredentialsDecryptorKey returns the key used to decrypt credentials values,
    19  	// stored in accounts.
    20  	CredentialsDecryptorKey() *NACLKey
    21  }
    22  
    23  // Config used to setup a [Keyring] service.
    24  type Config struct {
    25  	EncryptorKeyPath string `mapstructure:"credentials_encryptor_key"`
    26  	DecryptorKeyPath string `mapstructure:"credentials_decryptor_key"`
    27  }
    28  
    29  // Service contains security keys used for various encryption or signing of
    30  // critical assets.
    31  type Service struct {
    32  	credsEncryptor *NACLKey
    33  	credsDecryptor *NACLKey
    34  }
    35  
    36  func NewFromConfig(conf Config) (Keyring, error) {
    37  	if conf.DecryptorKeyPath == "" || conf.EncryptorKeyPath == "" {
    38  		return NewStub()
    39  	}
    40  
    41  	return NewService(conf)
    42  }
    43  
    44  // NewService instantiate a new [Keyring].
    45  func NewService(conf Config) (*Service, error) {
    46  	if conf.EncryptorKeyPath == "" {
    47  		return nil, fmt.Errorf("credentials_encryptor_key: %w", ErrFieldRequired)
    48  	}
    49  
    50  	if conf.DecryptorKeyPath == "" {
    51  		return nil, fmt.Errorf("credentials_decryptor_key: %w", ErrFieldRequired)
    52  	}
    53  
    54  	credsEncryptor, err := decodeKeyFromPath(conf.EncryptorKeyPath)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	credsDecryptor, err := decodeKeyFromPath(conf.DecryptorKeyPath)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	return &Service{credsEncryptor, credsDecryptor}, nil
    65  }
    66  
    67  func (s *Service) CredentialsEncryptorKey() *NACLKey {
    68  	return s.credsEncryptor
    69  }
    70  
    71  func (s *Service) CredentialsDecryptorKey() *NACLKey {
    72  	return s.credsDecryptor
    73  }
    74  
    75  func decodeKeyFromPath(path string) (*NACLKey, error) {
    76  	keyBytes, err := os.ReadFile(path)
    77  	if err != nil {
    78  		return nil, fmt.Errorf("failed to open file %q: %w", path, err)
    79  	}
    80  
    81  	creds, err := UnmarshalNACLKey(keyBytes)
    82  	if err != nil {
    83  		return nil, fmt.Errorf("failed to unmarshal NACL key: %w", err)
    84  	}
    85  
    86  	return creds, nil
    87  }