package backend import ( "context" "fmt" "github.com/blang/semver/v4" "github.com/gopasspw/gopass/pkg/debug" ) // CryptoBackend is a cryptographic backend. type CryptoBackend int const ( // Plain is a no-op crypto backend. Plain CryptoBackend = iota // GPGCLI is a gpg-cli based crypto backend. GPGCLI // Age - age-encryption.org. Age ) func (c CryptoBackend) String() string { if be, err := CryptoRegistry.BackendName(c); err == nil { return be } return "" } // Keyring is a public/private key manager. type Keyring interface { ListRecipients(ctx context.Context) ([]string, error) ListIdentities(ctx context.Context) ([]string, error) FindRecipients(ctx context.Context, needles ...string) ([]string, error) FindIdentities(ctx context.Context, needles ...string) ([]string, error) Fingerprint(ctx context.Context, id string) string FormatKey(ctx context.Context, id, tpl string) string ReadNamesFromKey(ctx context.Context, buf []byte) ([]string, error) GetFingerprint(ctx context.Context, key []byte) (string, error) GenerateIdentity(ctx context.Context, name, email, passphrase string) (string, error) } // Crypto is a crypto backend. type Crypto interface { Keyring Encrypt(ctx context.Context, plaintext []byte, recipients []string) ([]byte, error) Decrypt(ctx context.Context, ciphertext []byte) ([]byte, error) RecipientIDs(ctx context.Context, ciphertext []byte) ([]string, error) Name() string Version(context.Context) semver.Version Initialized(ctx context.Context) error Ext() string // filename extension. IDFile() string // recipient IDs. Concurrency() int } // NewCrypto instantiates a new crypto backend. func NewCrypto(ctx context.Context, id CryptoBackend) (Crypto, error) { if be, err := CryptoRegistry.Get(id); err == nil { return be.New(ctx) } return nil, fmt.Errorf("unknown backend %d: %w", id, ErrNotFound) } // DetectCrypto tries to detect the crypto backend used. func DetectCrypto(ctx context.Context, storage Storage) (Crypto, error) { if HasCryptoBackend(ctx) { if be, err := CryptoRegistry.Get(GetCryptoBackend(ctx)); err == nil { return be.New(ctx) } } for _, be := range CryptoRegistry.Prioritized() { debug.Log("Trying %s for %s", be, storage) if err := be.Handles(ctx, storage); err != nil { debug.Log("failed to use crypto %s for %s", be, storage) continue } debug.Log("Using %s for %s", be, storage) return be.New(ctx) } debug.Log("No valid crypto provider found for %s", storage) // TODO: this should return ErrNotSupported, but need to fix some tests for that return nil, nil //nolint:nilnil }