From fea2464d4d6d5dde7323bc81a76716987c82cdf6 Mon Sep 17 00:00:00 2001 From: Gary Kim Date: Wed, 12 Jun 2019 18:40:05 +0800 Subject: [PATCH] Allow multiple retries for interactive password input Restic used to quit if the repository password was typed incorrectly once. Restic will now ask the user again for the repository password if typed incorrectly. The user will now get three tries to input the correct password before restic quits. --- changelog/unreleased/issue-2306 | 7 +++++++ cmd/restic/global.go | 30 ++++++++++++++++++++++++------ internal/repository/key.go | 2 +- 3 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 changelog/unreleased/issue-2306 diff --git a/changelog/unreleased/issue-2306 b/changelog/unreleased/issue-2306 new file mode 100644 index 000000000..78d29d600 --- /dev/null +++ b/changelog/unreleased/issue-2306 @@ -0,0 +1,7 @@ +Enhancement: Allow multiple retries for interactive password input + +Restic used to quit if the repository password was typed incorrectly once. +Restic will now ask the user again for the repository password if typed incorrectly. +The user will now get three tries to input the correct password before restic quits. + +https://github.com/restic/restic/issues/2306 diff --git a/cmd/restic/global.go b/cmd/restic/global.go index 69987cf80..864feaa70 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -319,7 +319,7 @@ func ReadPassword(opts GlobalOptions, prompt string) (string, error) { } if len(password) == 0 { - return "", errors.Fatal("an empty password is not a password") + return "", errors.New("an empty password is not a password") } return password, nil @@ -365,14 +365,32 @@ func OpenRepository(opts GlobalOptions) (*repository.Repository, error) { s := repository.New(be) - opts.password, err = ReadPassword(opts, "enter password for repository: ") - if err != nil { - return nil, err + passwordTriesLeft := 1 + if stdinIsTerminal() && opts.password == "" { + passwordTriesLeft = 3 } - err = s.SearchKey(opts.ctx, opts.password, maxKeys, opts.KeyHint) + for ; passwordTriesLeft > 0; passwordTriesLeft-- { + opts.password, err = ReadPassword(opts, "enter password for repository: ") + if err != nil && passwordTriesLeft > 1 { + opts.password = "" + fmt.Printf("%s. Try again\n", err) + } + if err != nil { + continue + } + + err = s.SearchKey(opts.ctx, opts.password, maxKeys, opts.KeyHint) + if err != nil && passwordTriesLeft > 1 { + opts.password = "" + fmt.Printf("%s. Try again\n", err) + } + } if err != nil { - return nil, err + if errors.IsFatal(err) { + return nil, err + } + return nil, errors.Fatalf("%s", err) } if stdoutIsTerminal() && !opts.JSON { diff --git a/internal/repository/key.go b/internal/repository/key.go index 62558c0b3..6705ceb28 100644 --- a/internal/repository/key.go +++ b/internal/repository/key.go @@ -18,7 +18,7 @@ import ( var ( // ErrNoKeyFound is returned when no key for the repository could be decrypted. - ErrNoKeyFound = errors.Fatal("wrong password or no key found") + ErrNoKeyFound = errors.New("wrong password or no key found") // ErrMaxKeysReached is returned when the maximum number of keys was checked and no key could be found. ErrMaxKeysReached = errors.Fatal("maximum number of keys reached")