config encryption: set, remove and check to manage config file encryption #7859

This commit is contained in:
Nick Craig-Wood
2024-09-06 10:34:29 +01:00
parent ffb2e2a6de
commit 2d1c2b1f76
6 changed files with 194 additions and 10 deletions
+29
View File
@@ -41,6 +41,11 @@ var (
PassConfigKeyForDaemonization = false
)
// IsEncrypted returns true if the config file is encrypted
func IsEncrypted() bool {
return len(configKey) > 0
}
// Decrypt will automatically decrypt a reader
func Decrypt(b io.ReadSeeker) (io.Reader, error) {
ctx := context.Background()
@@ -313,6 +318,11 @@ func ClearConfigPassword() {
//
// This will use --password-command if configured to read the password.
func changeConfigPassword() {
// Set RCLONE_PASSWORD_CHANGE to "1" when calling the --password-command tool
_ = os.Setenv("RCLONE_PASSWORD_CHANGE", "1")
defer func() {
_ = os.Unsetenv("RCLONE_PASSWORD_CHANGE")
}()
pass, err := GetPasswordCommand(context.Background())
if err != nil {
fmt.Printf("Failed to read new password with --password-command: %v\n", err)
@@ -329,3 +339,22 @@ func changeConfigPassword() {
return
}
}
// ChangeConfigPasswordAndSave will query the user twice
// for a password. If the same password is entered
// twice the key is updated.
//
// This will use --password-command if configured to read the password.
//
// It will then save the config
func ChangeConfigPasswordAndSave() {
changeConfigPassword()
SaveConfig()
}
// RemoveConfigPasswordAndSave will clear the config password and save
// the unencrypted config file.
func RemoveConfigPasswordAndSave() {
configKey = nil
SaveConfig()
}
+29 -2
View File
@@ -2,6 +2,8 @@ package config
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/rclone/rclone/fs"
@@ -64,8 +66,33 @@ func TestChangeConfigPassword(t *testing.T) {
// Get rid of any config password
ClearConfigPassword()
// Set correct password using --password command
ci.PasswordCommand = fs.SpaceSepList{"echo", "asdf"}
// Return the password, checking the state of the environment variable
checkCode := `
package main
import (
"fmt"
"os"
"log"
)
func main() {
v := os.Getenv("RCLONE_PASSWORD_CHANGE")
if v == "" {
log.Fatal("Env var not found")
} else if v != "1" {
log.Fatal("Env var wrong value")
} else {
fmt.Println("asdf")
}
}
`
dir := t.TempDir()
code := filepath.Join(dir, "file.go")
require.NoError(t, os.WriteFile(code, []byte(checkCode), 0777))
// Set correct password using --password-command
ci.PasswordCommand = fs.SpaceSepList{"go", "run", code}
changeConfigPassword()
err = Data().Load()
require.NoError(t, err)
+31
View File
@@ -6,6 +6,8 @@ package config_test
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/rclone/rclone/fs"
@@ -24,8 +26,10 @@ func TestConfigLoadEncrypted(t *testing.T) {
}()
// Set correct password
assert.False(t, config.IsEncrypted())
err = config.SetConfigPassword("asdf")
require.NoError(t, err)
assert.True(t, config.IsEncrypted())
err = config.Data().Load()
require.NoError(t, err)
sections := config.Data().GetSectionList()
@@ -138,4 +142,31 @@ func TestGetPasswordCommand(t *testing.T) {
ci.PasswordCommand = fs.SpaceSepList{"XXX non-existent command XXX", ""}
_, err = config.GetPasswordCommand(ctx)
assert.ErrorContains(t, err, "not found")
// Check the state of the environment variable in --password-command
checkCode := `
package main
import (
"fmt"
"os"
)
func main() {
if _, found := os.LookupEnv("RCLONE_PASSWORD_CHANGE"); found {
fmt.Println("Env var set")
} else {
fmt.Println("OK")
}
}
`
dir := t.TempDir()
code := filepath.Join(dir, "file.go")
require.NoError(t, os.WriteFile(code, []byte(checkCode), 0777))
// Check the environment variable unset when called directly
ci.PasswordCommand = fs.SpaceSepList{"go", "run", code}
pass, err = config.GetPasswordCommand(ctx)
require.NoError(t, err)
assert.Equal(t, "OK", pass)
}
+3 -6
View File
@@ -797,13 +797,11 @@ func SetPassword() {
what := []string{"cChange Password", "uUnencrypt configuration", "qQuit to main menu"}
switch i := Command(what); i {
case 'c':
changeConfigPassword()
SaveConfig()
ChangeConfigPasswordAndSave()
fmt.Println("Password changed")
continue
case 'u':
configKey = nil
SaveConfig()
RemoveConfigPasswordAndSave()
continue
case 'q':
return
@@ -815,8 +813,7 @@ func SetPassword() {
what := []string{"aAdd Password", "qQuit to main menu"}
switch i := Command(what); i {
case 'a':
changeConfigPassword()
SaveConfig()
ChangeConfigPasswordAndSave()
fmt.Println("Password set")
continue
case 'q':