forked from TrueCloudLab/restic
Add --insecure-no-password option
This also includes two derived options `--from-insecure-no-password` used for commands that require specifying a source repository. And `--new-insecure-no-password` for the `key add` and `key passwd` commands. Specifying `--insecure-no-password` disabled the password prompt and immediately uses an empty password. Passing a password via CLI option or environment variable at the same time is an error.
This commit is contained in:
parent
d4b0d21199
commit
1d2277b4c3
9 changed files with 150 additions and 31 deletions
|
@ -257,7 +257,7 @@ func readFilenamesRaw(r io.Reader) (names []string, err error) {
|
||||||
|
|
||||||
// Check returns an error when an invalid combination of options was set.
|
// Check returns an error when an invalid combination of options was set.
|
||||||
func (opts BackupOptions) Check(gopts GlobalOptions, args []string) error {
|
func (opts BackupOptions) Check(gopts GlobalOptions, args []string) error {
|
||||||
if gopts.password == "" {
|
if gopts.password == "" && !gopts.InsecureNoPassword {
|
||||||
if opts.Stdin {
|
if opts.Stdin {
|
||||||
return errors.Fatal("cannot read both password and data from stdin")
|
return errors.Fatal("cannot read both password and data from stdin")
|
||||||
}
|
}
|
||||||
|
|
|
@ -627,3 +627,17 @@ func TestStdinFromCommandFailNoOutputAndExitCode(t *testing.T) {
|
||||||
|
|
||||||
testRunCheck(t, env.gopts)
|
testRunCheck(t, env.gopts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBackupEmptyPassword(t *testing.T) {
|
||||||
|
// basic sanity test that empty passwords work
|
||||||
|
env, cleanup := withTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
env.gopts.password = ""
|
||||||
|
env.gopts.InsecureNoPassword = true
|
||||||
|
|
||||||
|
testSetupBackupData(t, env)
|
||||||
|
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, BackupOptions{}, env.gopts)
|
||||||
|
testListSnapshots(t, env.gopts, 1)
|
||||||
|
testRunCheck(t, env.gopts)
|
||||||
|
}
|
||||||
|
|
|
@ -13,10 +13,12 @@ func testRunCopy(t testing.TB, srcGopts GlobalOptions, dstGopts GlobalOptions) {
|
||||||
gopts := srcGopts
|
gopts := srcGopts
|
||||||
gopts.Repo = dstGopts.Repo
|
gopts.Repo = dstGopts.Repo
|
||||||
gopts.password = dstGopts.password
|
gopts.password = dstGopts.password
|
||||||
|
gopts.InsecureNoPassword = dstGopts.InsecureNoPassword
|
||||||
copyOpts := CopyOptions{
|
copyOpts := CopyOptions{
|
||||||
secondaryRepoOptions: secondaryRepoOptions{
|
secondaryRepoOptions: secondaryRepoOptions{
|
||||||
Repo: srcGopts.Repo,
|
Repo: srcGopts.Repo,
|
||||||
password: srcGopts.password,
|
password: srcGopts.password,
|
||||||
|
InsecureNoPassword: srcGopts.InsecureNoPassword,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,3 +136,22 @@ func TestCopyUnstableJSON(t *testing.T) {
|
||||||
testRunCheck(t, env2.gopts)
|
testRunCheck(t, env2.gopts)
|
||||||
testListSnapshots(t, env2.gopts, 1)
|
testListSnapshots(t, env2.gopts, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCopyToEmptyPassword(t *testing.T) {
|
||||||
|
env, cleanup := withTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
env2, cleanup2 := withTestEnvironment(t)
|
||||||
|
defer cleanup2()
|
||||||
|
env2.gopts.password = ""
|
||||||
|
env2.gopts.InsecureNoPassword = true
|
||||||
|
|
||||||
|
testSetupBackupData(t, env)
|
||||||
|
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, BackupOptions{}, env.gopts)
|
||||||
|
|
||||||
|
testRunInit(t, env2.gopts)
|
||||||
|
testRunCopy(t, env.gopts, env2.gopts)
|
||||||
|
|
||||||
|
testListSnapshots(t, env.gopts, 1)
|
||||||
|
testListSnapshots(t, env2.gopts, 1)
|
||||||
|
testRunCheck(t, env2.gopts)
|
||||||
|
}
|
||||||
|
|
|
@ -28,12 +28,14 @@ Exit status is 0 if the command is successful, and non-zero if there was any err
|
||||||
|
|
||||||
type KeyAddOptions struct {
|
type KeyAddOptions struct {
|
||||||
NewPasswordFile string
|
NewPasswordFile string
|
||||||
|
InsecureNoPassword bool
|
||||||
Username string
|
Username string
|
||||||
Hostname string
|
Hostname string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts *KeyAddOptions) Add(flags *pflag.FlagSet) {
|
func (opts *KeyAddOptions) Add(flags *pflag.FlagSet) {
|
||||||
flags.StringVarP(&opts.NewPasswordFile, "new-password-file", "", "", "`file` from which to read the new password")
|
flags.StringVarP(&opts.NewPasswordFile, "new-password-file", "", "", "`file` from which to read the new password")
|
||||||
|
flags.BoolVar(&opts.InsecureNoPassword, "new-insecure-no-password", false, "add an empty password for the repository (insecure)")
|
||||||
flags.StringVarP(&opts.Username, "user", "", "", "the username for new key")
|
flags.StringVarP(&opts.Username, "user", "", "", "the username for new key")
|
||||||
flags.StringVarP(&opts.Hostname, "host", "", "", "the hostname for new key")
|
flags.StringVarP(&opts.Hostname, "host", "", "", "the hostname for new key")
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,7 @@ func runKeyAdd(ctx context.Context, gopts GlobalOptions, opts KeyAddOptions, arg
|
||||||
}
|
}
|
||||||
|
|
||||||
func addKey(ctx context.Context, repo *repository.Repository, gopts GlobalOptions, opts KeyAddOptions) error {
|
func addKey(ctx context.Context, repo *repository.Repository, gopts GlobalOptions, opts KeyAddOptions) error {
|
||||||
pw, err := getNewPassword(ctx, gopts, opts.NewPasswordFile)
|
pw, err := getNewPassword(ctx, gopts, opts.NewPasswordFile, opts.InsecureNoPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -86,19 +88,35 @@ func addKey(ctx context.Context, repo *repository.Repository, gopts GlobalOption
|
||||||
// testKeyNewPassword is used to set a new password during integration testing.
|
// testKeyNewPassword is used to set a new password during integration testing.
|
||||||
var testKeyNewPassword string
|
var testKeyNewPassword string
|
||||||
|
|
||||||
func getNewPassword(ctx context.Context, gopts GlobalOptions, newPasswordFile string) (string, error) {
|
func getNewPassword(ctx context.Context, gopts GlobalOptions, newPasswordFile string, insecureNoPassword bool) (string, error) {
|
||||||
if testKeyNewPassword != "" {
|
if testKeyNewPassword != "" {
|
||||||
return testKeyNewPassword, nil
|
return testKeyNewPassword, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if insecureNoPassword {
|
||||||
|
if newPasswordFile != "" {
|
||||||
|
return "", fmt.Errorf("only either --new-password-file or --new-insecure-no-password may be specified")
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
if newPasswordFile != "" {
|
if newPasswordFile != "" {
|
||||||
return loadPasswordFromFile(newPasswordFile)
|
password, err := loadPasswordFromFile(newPasswordFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if password == "" {
|
||||||
|
return "", fmt.Errorf("an empty password is not allowed by default. Pass the flag `--new-insecure-no-password` to restic to disable this check")
|
||||||
|
}
|
||||||
|
return password, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we already have an open repository, temporary remove the password
|
// Since we already have an open repository, temporary remove the password
|
||||||
// to prompt the user for the passwd.
|
// to prompt the user for the passwd.
|
||||||
newopts := gopts
|
newopts := gopts
|
||||||
newopts.password = ""
|
newopts.password = ""
|
||||||
|
// empty passwords are already handled above
|
||||||
|
newopts.InsecureNoPassword = false
|
||||||
|
|
||||||
return ReadPasswordTwice(ctx, newopts,
|
return ReadPasswordTwice(ctx, newopts,
|
||||||
"enter new password: ",
|
"enter new password: ",
|
||||||
|
|
|
@ -3,6 +3,8 @@ package main
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -109,6 +111,43 @@ func TestKeyAddRemove(t *testing.T) {
|
||||||
testRunKeyAddNewKeyUserHost(t, env.gopts)
|
testRunKeyAddNewKeyUserHost(t, env.gopts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKeyAddInvalid(t *testing.T) {
|
||||||
|
env, cleanup := withTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
testRunInit(t, env.gopts)
|
||||||
|
|
||||||
|
err := runKeyAdd(context.TODO(), env.gopts, KeyAddOptions{
|
||||||
|
NewPasswordFile: "some-file",
|
||||||
|
InsecureNoPassword: true,
|
||||||
|
}, []string{})
|
||||||
|
rtest.Assert(t, strings.Contains(err.Error(), "only either"), "unexpected error message, got %q", err)
|
||||||
|
|
||||||
|
pwfile := filepath.Join(t.TempDir(), "pwfile")
|
||||||
|
rtest.OK(t, os.WriteFile(pwfile, []byte{}, 0o666))
|
||||||
|
|
||||||
|
err = runKeyAdd(context.TODO(), env.gopts, KeyAddOptions{
|
||||||
|
NewPasswordFile: pwfile,
|
||||||
|
}, []string{})
|
||||||
|
rtest.Assert(t, strings.Contains(err.Error(), "an empty password is not allowed by default"), "unexpected error message, got %q", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyAddEmpty(t *testing.T) {
|
||||||
|
env, cleanup := withTestEnvironment(t)
|
||||||
|
// must list keys more than once
|
||||||
|
env.gopts.backendTestHook = nil
|
||||||
|
defer cleanup()
|
||||||
|
testRunInit(t, env.gopts)
|
||||||
|
|
||||||
|
rtest.OK(t, runKeyAdd(context.TODO(), env.gopts, KeyAddOptions{
|
||||||
|
InsecureNoPassword: true,
|
||||||
|
}, []string{}))
|
||||||
|
|
||||||
|
env.gopts.password = ""
|
||||||
|
env.gopts.InsecureNoPassword = true
|
||||||
|
|
||||||
|
testRunCheck(t, env.gopts)
|
||||||
|
}
|
||||||
|
|
||||||
type emptySaveBackend struct {
|
type emptySaveBackend struct {
|
||||||
backend.Backend
|
backend.Backend
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ func runKeyPasswd(ctx context.Context, gopts GlobalOptions, opts KeyPasswdOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func changePassword(ctx context.Context, repo *repository.Repository, gopts GlobalOptions, opts KeyPasswdOptions) error {
|
func changePassword(ctx context.Context, repo *repository.Repository, gopts GlobalOptions, opts KeyPasswdOptions) error {
|
||||||
pw, err := getNewPassword(ctx, gopts, opts.NewPasswordFile)
|
pw, err := getNewPassword(ctx, gopts, opts.NewPasswordFile, opts.InsecureNoPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,22 +52,23 @@ type backendWrapper func(r backend.Backend) (backend.Backend, error)
|
||||||
|
|
||||||
// GlobalOptions hold all global options for restic.
|
// GlobalOptions hold all global options for restic.
|
||||||
type GlobalOptions struct {
|
type GlobalOptions struct {
|
||||||
Repo string
|
Repo string
|
||||||
RepositoryFile string
|
RepositoryFile string
|
||||||
PasswordFile string
|
PasswordFile string
|
||||||
PasswordCommand string
|
PasswordCommand string
|
||||||
KeyHint string
|
KeyHint string
|
||||||
Quiet bool
|
Quiet bool
|
||||||
Verbose int
|
Verbose int
|
||||||
NoLock bool
|
NoLock bool
|
||||||
RetryLock time.Duration
|
RetryLock time.Duration
|
||||||
JSON bool
|
JSON bool
|
||||||
CacheDir string
|
CacheDir string
|
||||||
NoCache bool
|
NoCache bool
|
||||||
CleanupCache bool
|
CleanupCache bool
|
||||||
Compression repository.CompressionMode
|
Compression repository.CompressionMode
|
||||||
PackSize uint
|
PackSize uint
|
||||||
NoExtraVerify bool
|
NoExtraVerify bool
|
||||||
|
InsecureNoPassword bool
|
||||||
|
|
||||||
backend.TransportOptions
|
backend.TransportOptions
|
||||||
limiter.Limits
|
limiter.Limits
|
||||||
|
@ -125,6 +126,7 @@ func init() {
|
||||||
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
|
f.BoolVar(&globalOptions.NoCache, "no-cache", false, "do not use a local cache")
|
||||||
f.StringSliceVar(&globalOptions.RootCertFilenames, "cacert", nil, "`file` to load root certificates from (default: use system certificates or $RESTIC_CACERT)")
|
f.StringSliceVar(&globalOptions.RootCertFilenames, "cacert", nil, "`file` to load root certificates from (default: use system certificates or $RESTIC_CACERT)")
|
||||||
f.StringVar(&globalOptions.TLSClientCertKeyFilename, "tls-client-cert", "", "path to a `file` containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT)")
|
f.StringVar(&globalOptions.TLSClientCertKeyFilename, "tls-client-cert", "", "path to a `file` containing PEM encoded TLS client certificate and private key (default: $RESTIC_TLS_CLIENT_CERT)")
|
||||||
|
f.BoolVar(&globalOptions.InsecureNoPassword, "insecure-no-password", false, "use an empty password for the repository, must be passed to every restic command (insecure)")
|
||||||
f.BoolVar(&globalOptions.InsecureTLS, "insecure-tls", false, "skip TLS certificate verification when connecting to the repository (insecure)")
|
f.BoolVar(&globalOptions.InsecureTLS, "insecure-tls", false, "skip TLS certificate verification when connecting to the repository (insecure)")
|
||||||
f.BoolVar(&globalOptions.CleanupCache, "cleanup-cache", false, "auto remove old cache directories")
|
f.BoolVar(&globalOptions.CleanupCache, "cleanup-cache", false, "auto remove old cache directories")
|
||||||
f.Var(&globalOptions.Compression, "compression", "compression mode (only available for repository format version 2), one of (auto|off|max) (default: $RESTIC_COMPRESSION)")
|
f.Var(&globalOptions.Compression, "compression", "compression mode (only available for repository format version 2), one of (auto|off|max) (default: $RESTIC_COMPRESSION)")
|
||||||
|
@ -327,6 +329,13 @@ func readPasswordTerminal(ctx context.Context, in *os.File, out *os.File, prompt
|
||||||
// variable RESTIC_PASSWORD or prompts the user. If the context is canceled,
|
// variable RESTIC_PASSWORD or prompts the user. If the context is canceled,
|
||||||
// the function leaks the password reading goroutine.
|
// the function leaks the password reading goroutine.
|
||||||
func ReadPassword(ctx context.Context, opts GlobalOptions, prompt string) (string, error) {
|
func ReadPassword(ctx context.Context, opts GlobalOptions, prompt string) (string, error) {
|
||||||
|
if opts.InsecureNoPassword {
|
||||||
|
if opts.password != "" {
|
||||||
|
return "", errors.Fatal("--insecure-no-password must not be specified together with providing a password via a cli option or environment variable")
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
if opts.password != "" {
|
if opts.password != "" {
|
||||||
return opts.password, nil
|
return opts.password, nil
|
||||||
}
|
}
|
||||||
|
@ -348,7 +357,7 @@ func ReadPassword(ctx context.Context, opts GlobalOptions, prompt string) (strin
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(password) == 0 {
|
if len(password) == 0 {
|
||||||
return "", errors.Fatal("an empty password is not a password")
|
return "", errors.Fatal("an empty password is not allowed by default. Pass the flag `--insecure-no-password` to restic to disable this check")
|
||||||
}
|
}
|
||||||
|
|
||||||
return password, nil
|
return password, nil
|
||||||
|
@ -445,7 +454,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordTriesLeft := 1
|
passwordTriesLeft := 1
|
||||||
if stdinIsTerminal() && opts.password == "" {
|
if stdinIsTerminal() && opts.password == "" && !opts.InsecureNoPassword {
|
||||||
passwordTriesLeft = 3
|
passwordTriesLeft = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
|
@ -50,3 +52,14 @@ func TestReadRepo(t *testing.T) {
|
||||||
t.Fatal("must not read repository path from invalid file path")
|
t.Fatal("must not read repository path from invalid file path")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadEmptyPassword(t *testing.T) {
|
||||||
|
opts := GlobalOptions{InsecureNoPassword: true}
|
||||||
|
password, err := ReadPassword(context.TODO(), opts, "test")
|
||||||
|
rtest.OK(t, err)
|
||||||
|
rtest.Equals(t, "", password, "got unexpected password")
|
||||||
|
|
||||||
|
opts.password = "invalid"
|
||||||
|
_, err = ReadPassword(context.TODO(), opts, "test")
|
||||||
|
rtest.Assert(t, strings.Contains(err.Error(), "must not be specified together with providing a password via a cli option or environment variable"), "unexpected error message, got %v", err)
|
||||||
|
}
|
||||||
|
|
|
@ -11,11 +11,12 @@ import (
|
||||||
type secondaryRepoOptions struct {
|
type secondaryRepoOptions struct {
|
||||||
password string
|
password string
|
||||||
// from-repo options
|
// from-repo options
|
||||||
Repo string
|
Repo string
|
||||||
RepositoryFile string
|
RepositoryFile string
|
||||||
PasswordFile string
|
PasswordFile string
|
||||||
PasswordCommand string
|
PasswordCommand string
|
||||||
KeyHint string
|
KeyHint string
|
||||||
|
InsecureNoPassword bool
|
||||||
// repo2 options
|
// repo2 options
|
||||||
LegacyRepo string
|
LegacyRepo string
|
||||||
LegacyRepositoryFile string
|
LegacyRepositoryFile string
|
||||||
|
@ -49,6 +50,7 @@ func initSecondaryRepoOptions(f *pflag.FlagSet, opts *secondaryRepoOptions, repo
|
||||||
f.StringVarP(&opts.PasswordFile, "from-password-file", "", "", "`file` to read the source repository password from (default: $RESTIC_FROM_PASSWORD_FILE)")
|
f.StringVarP(&opts.PasswordFile, "from-password-file", "", "", "`file` to read the source repository password from (default: $RESTIC_FROM_PASSWORD_FILE)")
|
||||||
f.StringVarP(&opts.KeyHint, "from-key-hint", "", "", "key ID of key to try decrypting the source repository first (default: $RESTIC_FROM_KEY_HINT)")
|
f.StringVarP(&opts.KeyHint, "from-key-hint", "", "", "key ID of key to try decrypting the source repository first (default: $RESTIC_FROM_KEY_HINT)")
|
||||||
f.StringVarP(&opts.PasswordCommand, "from-password-command", "", "", "shell `command` to obtain the source repository password from (default: $RESTIC_FROM_PASSWORD_COMMAND)")
|
f.StringVarP(&opts.PasswordCommand, "from-password-command", "", "", "shell `command` to obtain the source repository password from (default: $RESTIC_FROM_PASSWORD_COMMAND)")
|
||||||
|
f.BoolVar(&opts.InsecureNoPassword, "from-insecure-no-password", false, "use an empty password for the source repository, must be passed to every restic command (insecure)")
|
||||||
|
|
||||||
opts.Repo = os.Getenv("RESTIC_FROM_REPOSITORY")
|
opts.Repo = os.Getenv("RESTIC_FROM_REPOSITORY")
|
||||||
opts.RepositoryFile = os.Getenv("RESTIC_FROM_REPOSITORY_FILE")
|
opts.RepositoryFile = os.Getenv("RESTIC_FROM_REPOSITORY_FILE")
|
||||||
|
@ -63,7 +65,7 @@ func fillSecondaryGlobalOpts(ctx context.Context, opts secondaryRepoOptions, gop
|
||||||
}
|
}
|
||||||
|
|
||||||
hasFromRepo := opts.Repo != "" || opts.RepositoryFile != "" || opts.PasswordFile != "" ||
|
hasFromRepo := opts.Repo != "" || opts.RepositoryFile != "" || opts.PasswordFile != "" ||
|
||||||
opts.KeyHint != "" || opts.PasswordCommand != ""
|
opts.KeyHint != "" || opts.PasswordCommand != "" || opts.InsecureNoPassword
|
||||||
hasRepo2 := opts.LegacyRepo != "" || opts.LegacyRepositoryFile != "" || opts.LegacyPasswordFile != "" ||
|
hasRepo2 := opts.LegacyRepo != "" || opts.LegacyRepositoryFile != "" || opts.LegacyPasswordFile != "" ||
|
||||||
opts.LegacyKeyHint != "" || opts.LegacyPasswordCommand != ""
|
opts.LegacyKeyHint != "" || opts.LegacyPasswordCommand != ""
|
||||||
|
|
||||||
|
@ -85,6 +87,7 @@ func fillSecondaryGlobalOpts(ctx context.Context, opts secondaryRepoOptions, gop
|
||||||
dstGopts.PasswordFile = opts.PasswordFile
|
dstGopts.PasswordFile = opts.PasswordFile
|
||||||
dstGopts.PasswordCommand = opts.PasswordCommand
|
dstGopts.PasswordCommand = opts.PasswordCommand
|
||||||
dstGopts.KeyHint = opts.KeyHint
|
dstGopts.KeyHint = opts.KeyHint
|
||||||
|
dstGopts.InsecureNoPassword = opts.InsecureNoPassword
|
||||||
|
|
||||||
pwdEnv = "RESTIC_FROM_PASSWORD"
|
pwdEnv = "RESTIC_FROM_PASSWORD"
|
||||||
repoPrefix = "source"
|
repoPrefix = "source"
|
||||||
|
@ -98,6 +101,8 @@ func fillSecondaryGlobalOpts(ctx context.Context, opts secondaryRepoOptions, gop
|
||||||
dstGopts.PasswordFile = opts.LegacyPasswordFile
|
dstGopts.PasswordFile = opts.LegacyPasswordFile
|
||||||
dstGopts.PasswordCommand = opts.LegacyPasswordCommand
|
dstGopts.PasswordCommand = opts.LegacyPasswordCommand
|
||||||
dstGopts.KeyHint = opts.LegacyKeyHint
|
dstGopts.KeyHint = opts.LegacyKeyHint
|
||||||
|
// keep existing bevhaior for legacy options
|
||||||
|
dstGopts.InsecureNoPassword = false
|
||||||
|
|
||||||
pwdEnv = "RESTIC_PASSWORD2"
|
pwdEnv = "RESTIC_PASSWORD2"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue