diff --git a/docs/content/docs.md b/docs/content/docs.md index e3a15ab6d..5e72b4bf0 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -880,6 +880,14 @@ Rclone will do its best to transfer the best file it has so in practice this should not cause a problem. Think of `--order-by` as being more of a best efforts flag rather than a perfect ordering. +### --password-command=STRING ### + +This flag supplies a program which should supply the config password +when run. This is an alternative to rclone prompting for the password +or setting the `RCLONE_CONFIG_PASS` variable. + +See the [Configuration Encryption](#configuration-encryption) for more info. + ### -P, --progress ### This flag makes rclone update the stats in a static block in the @@ -1361,13 +1369,13 @@ which will retrieve the password and print on standard output. This script should have a fully specified path name and not rely on any environment variables. The script is supplied either via `--password-command="..."` command line argument or via the -`RCLONE_CONFIG_PASS_COMMAND` environment variable. +`RCLONE_PASSWORD_COMMAND` environment variable. One useful example of this is using the `passwordstore` application to retrieve the password: ``` -export RCLONE_CONFIG_PASS_COMMAND="pass rclone/config" +export RCLONE_PASSWORD_COMMAND="pass rclone/config" ``` If the `passwordstore` password manager holds the password for the @@ -1381,11 +1389,11 @@ script method of supplying the password enhances the security of the config password considerably. If you are running rclone inside a script, unless you are using the -`RCLONE_CONFIG_PASS_COMMAND` method, you might want to disable +`--password-command` method, you might want to disable password prompts. To do that, pass the parameter `--ask-password=false` to rclone. This will make rclone fail instead of asking for a password if `RCLONE_CONFIG_PASS` doesn't contain -a valid password, and `RCLONE_CONFIG_PASS_COMMAND` has not been supplied. +a valid password, and `--password-command` has not been supplied. Developer options diff --git a/fs/config/config.go b/fs/config/config.go index 97c34f166..d1bb40a94 100644 --- a/fs/config/config.go +++ b/fs/config/config.go @@ -275,10 +275,6 @@ func loadConfigFile() (*goconfig.ConfigFile, error) { if len(configKey) == 0 { pwc := fs.Config.PasswordCommand - - if pwc == "" { - pwc = os.Getenv("RCLONE_CONFIG_PASS_COMMAND") - } if pwc != "" { var stdout bytes.Buffer var stderr bytes.Buffer @@ -291,7 +287,7 @@ func loadConfigFile() (*goconfig.ConfigFile, error) { if err := cmd.Run(); err != nil { // One does not always get the stderr returned in the wrapped error. - fs.Errorf(nil, "Using RCLONE_CONFIG_PASS_COMMAND returned: %v", err) + fs.Errorf(nil, "Using --password-command returned: %v", err) if ers := strings.TrimSpace(stderr.String()); ers != "" { fs.Errorf(nil, "--password-command stderr: %s", ers) } @@ -357,7 +353,7 @@ func loadConfigFile() (*goconfig.ConfigFile, error) { } else { if len(configKey) == 0 { if usingPasswordCommand { - return nil, errors.New("using password command derived password, unable to decrypt configuration") + return nil, errors.New("using --password-command derived password, unable to decrypt configuration") } if !fs.Config.AskPassword { return nil, errors.New("unable to decrypt configuration and not allowed to ask for password - set RCLONE_CONFIG_PASS to your configuration password") diff --git a/fs/config/config_test.go b/fs/config/config_test.go index 23642d1e4..f064b0d51 100644 --- a/fs/config/config_test.go +++ b/fs/config/config_test.go @@ -270,15 +270,24 @@ func TestConfigLoadEncrypted(t *testing.T) { assert.Equal(t, expect, keys) } -func expectConfigValid(t *testing.T) { - var err error +func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) { + oldConfigPath := ConfigPath + oldConfig := fs.Config + ConfigPath = "./testdata/encrypted.conf" + // using fs.Config.PasswordCommand, correct password + fs.Config.PasswordCommand = "echo asdf" + defer func() { + ConfigPath = oldConfigPath + configKey = nil // reset password + fs.Config = oldConfig + fs.Config.PasswordCommand = "" + }() configKey = nil // reset password c, err := loadConfigFile() require.NoError(t, err) - // Not sure why there is no "RCLONE_ENCRYPT_V0" here... sections := c.GetSectionList() var expect = []string{"nounc", "unc"} assert.Equal(t, expect, sections) @@ -288,64 +297,24 @@ func expectConfigValid(t *testing.T) { assert.Equal(t, expect, keys) } -func expectConfigInvalid(t *testing.T) { - var err error - - configKey = nil // reset password - - _, err = loadConfigFile() - require.Error(t, err) -} - -func TestConfigLoadEncryptedWithValidPassCommand(t *testing.T) { - oldConfigPath := ConfigPath - oldConfig := fs.Config - ConfigPath = "./testdata/encrypted.conf" - defer func() { - ConfigPath = oldConfigPath - configKey = nil // reset password - fs.Config = oldConfig - }() - - // using fs.Config.PasswordCommand, correct password - fs.Config.PasswordCommand = "echo asdf" - expectConfigValid(t) - - var err error - - // using "RCLONE_CONFIG_PASS_COMMAND" - - err = os.Setenv("RCLONE_CONFIG_PASS_COMMAND", "echo asdf") - require.NoError(t, err) - expectConfigValid(t) - - err = os.Unsetenv("RCLONE_CONFIG_PASS_COMMAND") - require.NoError(t, err) -} - func TestConfigLoadEncryptedWithInvalidPassCommand(t *testing.T) { oldConfigPath := ConfigPath oldConfig := fs.Config ConfigPath = "./testdata/encrypted.conf" + // using fs.Config.PasswordCommand, incorrect password + fs.Config.PasswordCommand = "echo asdf-blurfl" defer func() { ConfigPath = oldConfigPath configKey = nil // reset password fs.Config = oldConfig + fs.Config.PasswordCommand = "" }() - // using fs.Config.PasswordCommand, incorrect password - fs.Config.PasswordCommand = "echo asdf-blurfl" - expectConfigInvalid(t) - fs.Config.PasswordCommand = "" + configKey = nil // reset password - var err error - - err = os.Setenv("RCLONE_CONFIG_PASS_COMMAND", "echo asdf-blurfl") - require.NoError(t, err) - expectConfigInvalid(t) - - err = os.Unsetenv("RCLONE_CONFIG_PASS_COMMAND") - require.NoError(t, err) + _, err := loadConfigFile() + require.Error(t, err) + assert.Contains(t, err.Error(), "using --password-command derived password") } func TestConfigLoadEncryptedFailures(t *testing.T) {