1
0
mirror of https://github.com/rclone/rclone.git synced 2025-12-16 00:04:40 +00:00

config: add --obscure and --no-obscure flags to config create/update

Before this change there was some ambiguity about whether passwords
were obscured on not passing them into config create or config update.

This change adds the --obscure and --no-obscure flags to make the
intent clear.

It also updates the remote control and the tests.

Fixes #3728
This commit is contained in:
Nick Craig-Wood
2020-05-12 14:24:53 +01:00
parent c4bc249b66
commit 98c34e413d
5 changed files with 107 additions and 53 deletions

View File

@@ -1030,7 +1030,10 @@ func suppressConfirm() func() {
// UpdateRemote adds the keyValues passed in to the remote of name.
// keyValues should be key, value pairs.
func UpdateRemote(name string, keyValues rc.Params) error {
func UpdateRemote(name string, keyValues rc.Params, doObscure, noObscure bool) error {
if doObscure && noObscure {
return errors.New("can't use --obscure and --no-obscure together")
}
err := fspath.CheckConfigName(name)
if err != nil {
return err
@@ -1039,18 +1042,20 @@ func UpdateRemote(name string, keyValues rc.Params) error {
// Work out which options need to be obscured
needsObscure := map[string]struct{}{}
if fsType := FileGet(name, "type"); fsType != "" {
if ri, err := fs.Find(fsType); err != nil {
fs.Debugf(nil, "Couldn't find fs for type %q", fsType)
} else {
for _, opt := range ri.Options {
if opt.IsPassword {
needsObscure[opt.Name] = struct{}{}
if !noObscure {
if fsType := FileGet(name, "type"); fsType != "" {
if ri, err := fs.Find(fsType); err != nil {
fs.Debugf(nil, "Couldn't find fs for type %q", fsType)
} else {
for _, opt := range ri.Options {
if opt.IsPassword {
needsObscure[opt.Name] = struct{}{}
}
}
}
} else {
fs.Debugf(nil, "UpdateRemote: Couldn't find fs type")
}
} else {
fs.Debugf(nil, "UpdateRemote: Couldn't find fs type")
}
// Set the config
@@ -1059,8 +1064,9 @@ func UpdateRemote(name string, keyValues rc.Params) error {
// Obscure parameter if necessary
if _, ok := needsObscure[k]; ok {
_, err := obscure.Reveal(vStr)
if err != nil {
if err != nil || doObscure {
// If error => not already obscured, so obscure it
// or we are forced to obscure
vStr, err = obscure.Obscure(vStr)
if err != nil {
return errors.Wrap(err, "UpdateRemote: obscure failed")
@@ -1077,7 +1083,7 @@ func UpdateRemote(name string, keyValues rc.Params) error {
// CreateRemote creates a new remote with name, provider and a list of
// parameters which are key, value pairs. If update is set then it
// adds the new keys rather than replacing all of them.
func CreateRemote(name string, provider string, keyValues rc.Params) error {
func CreateRemote(name string, provider string, keyValues rc.Params, doObscure, noObscure bool) error {
err := fspath.CheckConfigName(name)
if err != nil {
return err
@@ -1087,7 +1093,7 @@ func CreateRemote(name string, provider string, keyValues rc.Params) error {
// Set the type
getConfigData().SetValue(name, "type", provider)
// Set the remaining values
return UpdateRemote(name, keyValues)
return UpdateRemote(name, keyValues, doObscure, noObscure)
}
// PasswordRemote adds the keyValues passed in to the remote of name.
@@ -1101,7 +1107,7 @@ func PasswordRemote(name string, keyValues rc.Params) error {
for k, v := range keyValues {
keyValues[k] = obscure.MustObscure(fmt.Sprint(v))
}
return UpdateRemote(name, keyValues)
return UpdateRemote(name, keyValues, false, true)
}
// JSONListProviders prints all the providers and options in JSON format

View File

@@ -180,35 +180,54 @@ func TestNewRemoteName(t *testing.T) {
func TestCreateUpatePasswordRemote(t *testing.T) {
defer testConfigFile(t, "update.conf")()
require.NoError(t, CreateRemote("test2", "config_test_remote", rc.Params{
"bool": true,
"pass": "potato",
}))
for _, doObscure := range []bool{false, true} {
for _, noObscure := range []bool{false, true} {
if doObscure && noObscure {
break
}
t.Run(fmt.Sprintf("doObscure=%v,noObscure=%v", doObscure, noObscure), func(t *testing.T) {
require.NoError(t, CreateRemote("test2", "config_test_remote", rc.Params{
"bool": true,
"pass": "potato",
}, doObscure, noObscure))
assert.Equal(t, []string{"test2"}, configFile.GetSectionList())
assert.Equal(t, "config_test_remote", FileGet("test2", "type"))
assert.Equal(t, "true", FileGet("test2", "bool"))
assert.Equal(t, "potato", obscure.MustReveal(FileGet("test2", "pass")))
assert.Equal(t, []string{"test2"}, configFile.GetSectionList())
assert.Equal(t, "config_test_remote", FileGet("test2", "type"))
assert.Equal(t, "true", FileGet("test2", "bool"))
gotPw := FileGet("test2", "pass")
if !noObscure {
gotPw = obscure.MustReveal(gotPw)
}
assert.Equal(t, "potato", gotPw)
require.NoError(t, UpdateRemote("test2", rc.Params{
"bool": false,
"pass": obscure.MustObscure("potato2"),
"spare": "spare",
}))
wantPw := obscure.MustObscure("potato2")
require.NoError(t, UpdateRemote("test2", rc.Params{
"bool": false,
"pass": wantPw,
"spare": "spare",
}, doObscure, noObscure))
assert.Equal(t, []string{"test2"}, configFile.GetSectionList())
assert.Equal(t, "config_test_remote", FileGet("test2", "type"))
assert.Equal(t, "false", FileGet("test2", "bool"))
assert.Equal(t, "potato2", obscure.MustReveal(FileGet("test2", "pass")))
assert.Equal(t, []string{"test2"}, configFile.GetSectionList())
assert.Equal(t, "config_test_remote", FileGet("test2", "type"))
assert.Equal(t, "false", FileGet("test2", "bool"))
gotPw = FileGet("test2", "pass")
if doObscure {
gotPw = obscure.MustReveal(gotPw)
}
assert.Equal(t, wantPw, gotPw)
require.NoError(t, PasswordRemote("test2", rc.Params{
"pass": "potato3",
}))
require.NoError(t, PasswordRemote("test2", rc.Params{
"pass": "potato3",
}))
assert.Equal(t, []string{"test2"}, configFile.GetSectionList())
assert.Equal(t, "config_test_remote", FileGet("test2", "type"))
assert.Equal(t, "false", FileGet("test2", "bool"))
assert.Equal(t, "potato3", obscure.MustReveal(FileGet("test2", "pass")))
})
}
}
assert.Equal(t, []string{"test2"}, configFile.GetSectionList())
assert.Equal(t, "config_test_remote", FileGet("test2", "type"))
assert.Equal(t, "false", FileGet("test2", "bool"))
assert.Equal(t, "potato3", obscure.MustReveal(FileGet("test2", "pass")))
}
// Test some error cases
@@ -409,7 +428,7 @@ func TestFileRefresh(t *testing.T) {
defer testConfigFile(t, "refresh.conf")()
require.NoError(t, CreateRemote("refresh_test", "config_test_remote", rc.Params{
"bool": true,
}))
}, false, false))
b, err := ioutil.ReadFile(ConfigPath)
assert.NoError(t, err)

View File

@@ -111,6 +111,10 @@ func init() {
if name == "create" {
extraHelp = "- type - type of the new remote\n"
}
if name == "create" || name == "update" {
extraHelp += "- obscure - optional bool - forces obscuring of passwords\n"
extraHelp += "- noObscure - optional bool - forces passwords not to be obscured\n"
}
rc.Add(rc.Call{
Path: "config/" + name,
AuthRequired: true,
@@ -140,15 +144,17 @@ func rcConfig(ctx context.Context, in rc.Params, what string) (out rc.Params, er
if err != nil {
return nil, err
}
doObscure, _ := in.GetBool("obscure")
noObscure, _ := in.GetBool("noObscure")
switch what {
case "create":
remoteType, err := in.GetString("type")
if err != nil {
return nil, err
}
return nil, CreateRemote(name, remoteType, parameters)
return nil, CreateRemote(name, remoteType, parameters, doObscure, noObscure)
case "update":
return nil, UpdateRemote(name, parameters)
return nil, UpdateRemote(name, parameters, doObscure, noObscure)
case "password":
return nil, PasswordRemote(name, parameters)
}

View File

@@ -101,11 +101,12 @@ func TestRc(t *testing.T) {
t.Run("Password", func(t *testing.T) {
call := rc.Calls.Get("config/password")
assert.NotNil(t, call)
pw2 := obscure.MustObscure("password")
in := rc.Params{
"name": testName,
"parameters": rc.Params{
"test_key": "rutabaga",
"test_key2": "cabbage",
"test_key2": pw2, // check we encode an already encoded password
},
}
out, err := call.Fn(context.Background(), in)
@@ -114,7 +115,7 @@ func TestRc(t *testing.T) {
assert.Equal(t, "local", config.FileGet(testName, "type"))
assert.Equal(t, "rutabaga", obscure.MustReveal(config.FileGet(testName, "test_key")))
assert.Equal(t, "cabbage", obscure.MustReveal(config.FileGet(testName, "test_key2")))
assert.Equal(t, pw2, obscure.MustReveal(config.FileGet(testName, "test_key2")))
})
// Delete the test remote