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 be069f4eb..e0d94814b 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -320,7 +320,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 @@ -366,14 +366,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")