config encryption: set, remove and check to manage config file encryption #7859
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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':
|
||||
|
||||
Reference in New Issue
Block a user