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 }