From c9c283533ce1d16e90b5d2717585b9af377d2b86 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 23 Jul 2024 12:36:04 +0100 Subject: [PATCH] config: factor --password-command code into its own function #7859 --- fs/config/crypt.go | 70 +++++++++++++++++++++++++---------------- fs/config/crypt_test.go | 26 +++++++++++++++ 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/fs/config/crypt.go b/fs/config/crypt.go index 8fc476f82..ad42640b0 100644 --- a/fs/config/crypt.go +++ b/fs/config/crypt.go @@ -78,37 +78,19 @@ func Decrypt(b io.ReadSeeker) (io.Reader, error) { } if len(configKey) == 0 { - if len(ci.PasswordCommand) != 0 { - var stdout bytes.Buffer - var stderr bytes.Buffer - - cmd := exec.Command(ci.PasswordCommand[0], ci.PasswordCommand[1:]...) - - cmd.Stdout = &stdout - cmd.Stderr = &stderr - cmd.Stdin = os.Stdin - - if err := cmd.Run(); err != nil { - // One does not always get the stderr returned in the wrapped error. - fs.Errorf(nil, "Using --password-command returned: %v", err) - if ers := strings.TrimSpace(stderr.String()); ers != "" { - fs.Errorf(nil, "--password-command stderr: %s", ers) - } - return nil, fmt.Errorf("password command failed: %w", err) + pass, err := GetPasswordCommand(ctx) + if err != nil { + return nil, err + } + if pass != "" { + usingPasswordCommand = true + err = SetConfigPassword(pass) + if err != nil { + return nil, fmt.Errorf("incorrect password: %w", err) } - if pass := strings.Trim(stdout.String(), "\r\n"); pass != "" { - err := SetConfigPassword(pass) - if err != nil { - return nil, fmt.Errorf("incorrect password: %w", err) - } - } else { - return nil, errors.New("password-command returned empty string") - } - if len(configKey) == 0 { return nil, errors.New("unable to decrypt configuration: incorrect password") } - usingPasswordCommand = true } else { usingPasswordCommand = false @@ -183,6 +165,40 @@ func Decrypt(b io.ReadSeeker) (io.Reader, error) { return bytes.NewReader(out), nil } +// GetPasswordCommand gets the password using the --password-command setting +// +// If the the --password-command flag was not in use it returns "", nil +func GetPasswordCommand(ctx context.Context) (pass string, err error) { + ci := fs.GetConfig(ctx) + if len(ci.PasswordCommand) == 0 { + return "", nil + } + + var stdout bytes.Buffer + var stderr bytes.Buffer + + cmd := exec.Command(ci.PasswordCommand[0], ci.PasswordCommand[1:]...) + + cmd.Stdout = &stdout + cmd.Stderr = &stderr + cmd.Stdin = os.Stdin + + err = cmd.Run() + if err != nil { + // One does not always get the stderr returned in the wrapped error. + fs.Errorf(nil, "Using --password-command returned: %v", err) + if ers := strings.TrimSpace(stderr.String()); ers != "" { + fs.Errorf(nil, "--password-command stderr: %s", ers) + } + return pass, fmt.Errorf("password command failed: %w", err) + } + pass = strings.Trim(stdout.String(), "\r\n") + if pass == "" { + return pass, errors.New("--password-command returned empty string") + } + return pass, nil +} + // Encrypt the config file func Encrypt(src io.Reader, dst io.Writer) error { if len(configKey) == 0 { diff --git a/fs/config/crypt_test.go b/fs/config/crypt_test.go index 04f54864d..5cb3fa016 100644 --- a/fs/config/crypt_test.go +++ b/fs/config/crypt_test.go @@ -113,3 +113,29 @@ func TestConfigLoadEncryptedFailures(t *testing.T) { err = config.Data().Load() assert.Equal(t, config.ErrorConfigFileNotFound, err) } + +func TestGetPasswordCommand(t *testing.T) { + ctx, ci := fs.AddConfig(context.Background()) + + // Not configured + ci.PasswordCommand = fs.SpaceSepList{} + pass, err := config.GetPasswordCommand(ctx) + require.NoError(t, err) + assert.Equal(t, "", pass) + + // With password - happy path + ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf"} + pass, err = config.GetPasswordCommand(ctx) + require.NoError(t, err) + assert.Equal(t, "asdf", pass) + + // Empty password returned + ci.PasswordCommand = fs.SpaceSepList{"echo", ""} + _, err = config.GetPasswordCommand(ctx) + assert.ErrorContains(t, err, "returned empty string") + + // Error when running command + ci.PasswordCommand = fs.SpaceSepList{"XXX non-existent command XXX", ""} + _, err = config.GetPasswordCommand(ctx) + assert.ErrorContains(t, err, "not found") +}