1
0
Fork 0
mirror of https://github.com/restic/restic.git synced 2024-12-23 08:16:36 +00:00

Add option to read the password from a file

This commit is contained in:
Alexander Neumann 2016-09-12 14:08:51 +02:00
parent 791f73e0db
commit 65afeba19a
4 changed files with 59 additions and 25 deletions

View file

@ -20,9 +20,12 @@ func (cmd CmdInit) Execute(args []string) error {
}
if cmd.global.password == "" {
cmd.global.password = cmd.global.ReadPasswordTwice(
cmd.global.password, err = cmd.global.ReadPasswordTwice(
"enter password for new backend: ",
"enter password again: ")
if err != nil {
return err
}
}
s := repository.New(be)

View file

@ -56,9 +56,9 @@ func (cmd CmdKey) listKeys(s *repository.Repository) error {
return tab.Write(cmd.global.stdout)
}
func (cmd CmdKey) getNewPassword() string {
func (cmd CmdKey) getNewPassword() (string, error) {
if cmd.newPassword != "" {
return cmd.newPassword
return cmd.newPassword, nil
}
return cmd.global.ReadPasswordTwice(
@ -67,7 +67,12 @@ func (cmd CmdKey) getNewPassword() string {
}
func (cmd CmdKey) addKey(repo *repository.Repository) error {
id, err := repository.AddKey(repo, cmd.getNewPassword(), repo.Key())
pw, err := cmd.getNewPassword()
if err != nil {
return err
}
id, err := repository.AddKey(repo, pw, repo.Key())
if err != nil {
return errors.Fatalf("creating new key failed: %v\n", err)
}
@ -92,7 +97,12 @@ func (cmd CmdKey) deleteKey(repo *repository.Repository, name string) error {
}
func (cmd CmdKey) changePassword(repo *repository.Repository) error {
id, err := repository.AddKey(repo, cmd.getNewPassword(), repo.Key())
pw, err := cmd.getNewPassword()
if err != nil {
return err
}
id, err := repository.AddKey(repo, pw, repo.Key())
if err != nil {
return errors.Fatalf("creating new key failed: %v\n", err)
}

View file

@ -3,6 +3,7 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"restic"
"runtime"
@ -28,11 +29,12 @@ var compiledAt = "unknown time"
// GlobalOptions holds all those options that can be set for every command.
type GlobalOptions struct {
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restore from"`
CacheDir string ` long:"cache-dir" description:"Directory to use as a local cache"`
Quiet bool `short:"q" long:"quiet" default:"false" description:"Do not output comprehensive progress report"`
NoLock bool ` long:"no-lock" default:"false" description:"Do not lock the repo, this allows some operations on read-only repos."`
Options []string `short:"o" long:"option" description:"Specify options in the form 'foo.key=value'"`
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restore from"`
PasswordFile string `short:"p" long:"password-file" description:"Read the repository password from a file"`
CacheDir string ` long:"cache-dir" description:"Directory to use as a local cache"`
Quiet bool `short:"q" long:"quiet" default:"false" description:"Do not output comprehensive progress report"`
NoLock bool ` long:"no-lock" default:"false" description:"Do not lock the repo, this allows some operations on read-only repos."`
Options []string `short:"o" long:"option" description:"Specify options in the form 'foo.key=value'"`
password string
stdout io.Writer
@ -185,7 +187,7 @@ func readPassword(in io.Reader) (password string, err error) {
buf = buf[:n]
if err != nil && errors.Cause(err) != io.ErrUnexpectedEOF {
return "", err
return "", errors.Wrap(err, "ReadFull")
}
return strings.TrimRight(string(buf), "\r\n"), nil
@ -199,15 +201,25 @@ func readPasswordTerminal(in *os.File, out io.Writer, prompt string) (password s
buf, err := terminal.ReadPassword(int(in.Fd()))
fmt.Fprintln(out)
if err != nil {
return "", err
return "", errors.Wrap(err, "ReadPassword")
}
password = string(buf)
return password, nil
}
// ReadPassword reads the password from stdin.
func (o GlobalOptions) ReadPassword(prompt string) string {
// ReadPassword reads the password from a password file, the environment
// variable RESTIC_PASSWORD or prompts the user.
func (o GlobalOptions) ReadPassword(prompt string) (string, error) {
if o.PasswordFile != "" {
s, err := ioutil.ReadFile(o.PasswordFile)
return strings.TrimSpace(string(s)), errors.Wrap(err, "Readfile")
}
if pwd := os.Getenv("RESTIC_PASSWORD"); pwd != "" {
return pwd, nil
}
var (
password string
err error
@ -220,26 +232,33 @@ func (o GlobalOptions) ReadPassword(prompt string) string {
}
if err != nil {
o.Exitf(2, "unable to read password: %v", err)
return "", errors.Wrap(err, "unable to read password")
}
if len(password) == 0 {
o.Exitf(1, "an empty password is not a password")
return "", errors.Fatal("an empty password is not a password")
}
return password
return password, nil
}
// ReadPasswordTwice calls ReadPassword two times and returns an error when the
// passwords don't match.
func (o GlobalOptions) ReadPasswordTwice(prompt1, prompt2 string) string {
pw1 := o.ReadPassword(prompt1)
pw2 := o.ReadPassword(prompt2)
if pw1 != pw2 {
o.Exitf(1, "passwords do not match")
func (o GlobalOptions) ReadPasswordTwice(prompt1, prompt2 string) (string, error) {
pw1, err := o.ReadPassword(prompt1)
if err != nil {
return "", err
}
pw2, err := o.ReadPassword(prompt2)
if err != nil {
return "", err
}
return pw1
if pw1 != pw2 {
return "", errors.Fatal("passwords do not match")
}
return pw1, nil
}
const maxKeys = 20
@ -258,7 +277,10 @@ func (o GlobalOptions) OpenRepository() (*repository.Repository, error) {
s := repository.New(be)
if o.password == "" {
o.password = o.ReadPassword("enter password for repository: ")
o.password, err = o.ReadPassword("enter password for repository: ")
if err != nil {
return nil, err
}
}
err = s.SearchKey(o.password, maxKeys)

View file

@ -28,7 +28,6 @@ func main() {
// defer profile.Start(profile.MemProfileRate(100000), profile.ProfilePath(".")).Stop()
// defer profile.Start(profile.CPUProfile, profile.ProfilePath(".")).Stop()
globalOpts.Repo = os.Getenv("RESTIC_REPOSITORY")
globalOpts.password = os.Getenv("RESTIC_PASSWORD")
debug.Log("restic", "main %#v", os.Args)