2
2
mirror of https://github.com/octoleo/restic.git synced 2024-06-01 08:30:49 +00:00

Fix reading password from stdin

Reading the password from non-terminal stdin used io.ReadFull with a
byte slice of length 1000.

We are now using a Scanner to read one line of input, independent of its
length.

Additionally, if stdin is not a terminal, the password is read only
once instead of twice (in an effort to detect typos).

Fixes #2203

Signed-off-by: Peter Schultz <peter.schultz@classmarkets.com>
This commit is contained in:
Peter Schultz 2019-03-26 16:14:40 +01:00
parent 870e7583a1
commit 5715517e29
2 changed files with 18 additions and 14 deletions

View File

@ -0,0 +1,6 @@
Bugfix: Fix reading passwords from stdin
Passwords for the `init`, `key add`, and `key passwd` commands can now be read from
non-terminal stdin.
https://github.com/restic/restic/issues/2203

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bufio"
"context" "context"
"fmt" "fmt"
"io" "io"
@ -273,15 +274,10 @@ func resolvePassword(opts GlobalOptions) (string, error) {
// readPassword reads the password from the given reader directly. // readPassword reads the password from the given reader directly.
func readPassword(in io.Reader) (password string, err error) { func readPassword(in io.Reader) (password string, err error) {
buf := make([]byte, 1000) sc := bufio.NewScanner(in)
n, err := io.ReadFull(in, buf) sc.Scan()
buf = buf[:n]
if err != nil && errors.Cause(err) != io.ErrUnexpectedEOF { return sc.Text(), errors.Wrap(err, "Scan")
return "", errors.Wrap(err, "ReadFull")
}
return strings.TrimRight(string(buf), "\r\n"), nil
} }
// readPasswordTerminal reads the password from the given reader which must be a // readPasswordTerminal reads the password from the given reader which must be a
@ -336,13 +332,15 @@ func ReadPasswordTwice(gopts GlobalOptions, prompt1, prompt2 string) (string, er
if err != nil { if err != nil {
return "", err return "", err
} }
pw2, err := ReadPassword(gopts, prompt2) if stdinIsTerminal() {
if err != nil { pw2, err := ReadPassword(gopts, prompt2)
return "", err if err != nil {
} return "", err
}
if pw1 != pw2 { if pw1 != pw2 {
return "", errors.Fatal("passwords do not match") return "", errors.Fatal("passwords do not match")
}
} }
return pw1, nil return pw1, nil