mirror of https://github.com/restic/restic.git
Merge 92d1c11c22
into b15d867414
This commit is contained in:
commit
699346ffe1
|
@ -36,6 +36,7 @@ type InitOptions struct {
|
||||||
secondaryRepoOptions
|
secondaryRepoOptions
|
||||||
CopyChunkerParameters bool
|
CopyChunkerParameters bool
|
||||||
RepositoryVersion string
|
RepositoryVersion string
|
||||||
|
AllowEmptyPassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var initOptions InitOptions
|
var initOptions InitOptions
|
||||||
|
@ -47,6 +48,7 @@ func init() {
|
||||||
initSecondaryRepoOptions(f, &initOptions.secondaryRepoOptions, "secondary", "to copy chunker parameters from")
|
initSecondaryRepoOptions(f, &initOptions.secondaryRepoOptions, "secondary", "to copy chunker parameters from")
|
||||||
f.BoolVar(&initOptions.CopyChunkerParameters, "copy-chunker-params", false, "copy chunker parameters from the secondary repository (useful with the copy command)")
|
f.BoolVar(&initOptions.CopyChunkerParameters, "copy-chunker-params", false, "copy chunker parameters from the secondary repository (useful with the copy command)")
|
||||||
f.StringVar(&initOptions.RepositoryVersion, "repository-version", "stable", "repository format version to use, allowed values are a format version, 'latest' and 'stable'")
|
f.StringVar(&initOptions.RepositoryVersion, "repository-version", "stable", "repository format version to use, allowed values are a format version, 'latest' and 'stable'")
|
||||||
|
f.BoolVar(&initOptions.AllowEmptyPassword, "allow-empty-password", false, "allow an empty password (feel beeing warned)")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []string) error {
|
func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []string) error {
|
||||||
|
@ -82,7 +84,8 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
|
||||||
|
|
||||||
gopts.password, err = ReadPasswordTwice(gopts,
|
gopts.password, err = ReadPasswordTwice(gopts,
|
||||||
"enter password for new repository: ",
|
"enter password for new repository: ",
|
||||||
"enter password again: ")
|
"enter password again: ",
|
||||||
|
opts.AllowEmptyPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ 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
|
||||||
|
AllowEmptyPassword bool
|
||||||
Username string
|
Username string
|
||||||
Hostname string
|
Hostname string
|
||||||
}
|
}
|
||||||
|
@ -41,6 +42,7 @@ func init() {
|
||||||
|
|
||||||
flags := cmdKeyAdd.Flags()
|
flags := cmdKeyAdd.Flags()
|
||||||
flags.StringVarP(&keyAddOpts.NewPasswordFile, "new-password-file", "", "", "`file` from which to read the new password")
|
flags.StringVarP(&keyAddOpts.NewPasswordFile, "new-password-file", "", "", "`file` from which to read the new password")
|
||||||
|
flags.BoolVar(&keyAddOpts.AllowEmptyPassword, "allow-empty-password", false, "allow an empty password (feel beeing warned)")
|
||||||
flags.StringVarP(&keyAddOpts.Username, "user", "", "", "the username for new key")
|
flags.StringVarP(&keyAddOpts.Username, "user", "", "", "the username for new key")
|
||||||
flags.StringVarP(&keyAddOpts.Hostname, "host", "", "", "the hostname for new key")
|
flags.StringVarP(&keyAddOpts.Hostname, "host", "", "", "the hostname for new key")
|
||||||
}
|
}
|
||||||
|
@ -60,7 +62,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(gopts, opts.NewPasswordFile)
|
pw, err := getNewPassword(gopts, opts.NewPasswordFile, opts.AllowEmptyPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -83,7 +85,7 @@ 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(gopts GlobalOptions, newPasswordFile string) (string, error) {
|
func getNewPassword(gopts GlobalOptions, newPasswordFile string, allowAllowEmptyPassword bool) (string, error) {
|
||||||
if testKeyNewPassword != "" {
|
if testKeyNewPassword != "" {
|
||||||
return testKeyNewPassword, nil
|
return testKeyNewPassword, nil
|
||||||
}
|
}
|
||||||
|
@ -99,7 +101,8 @@ func getNewPassword(gopts GlobalOptions, newPasswordFile string) (string, error)
|
||||||
|
|
||||||
return ReadPasswordTwice(newopts,
|
return ReadPasswordTwice(newopts,
|
||||||
"enter new password: ",
|
"enter new password: ",
|
||||||
"enter password again: ")
|
"enter password again: ",
|
||||||
|
allowAllowEmptyPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadPasswordFromFile(pwdFile string) (string, error) {
|
func loadPasswordFromFile(pwdFile string) (string, error) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ func init() {
|
||||||
|
|
||||||
flags := cmdKeyPasswd.Flags()
|
flags := cmdKeyPasswd.Flags()
|
||||||
flags.StringVarP(&keyPasswdOpts.NewPasswordFile, "new-password-file", "", "", "`file` from which to read the new password")
|
flags.StringVarP(&keyPasswdOpts.NewPasswordFile, "new-password-file", "", "", "`file` from which to read the new password")
|
||||||
|
flags.BoolVar(&keyPasswdOpts.AllowEmptyPassword, "allow-empty-password", false, "allow an empty password (feel beeing warned)")
|
||||||
flags.StringVarP(&keyPasswdOpts.Username, "user", "", "", "the username for new key")
|
flags.StringVarP(&keyPasswdOpts.Username, "user", "", "", "the username for new key")
|
||||||
flags.StringVarP(&keyPasswdOpts.Hostname, "host", "", "", "the hostname for new key")
|
flags.StringVarP(&keyPasswdOpts.Hostname, "host", "", "", "the hostname for new key")
|
||||||
}
|
}
|
||||||
|
@ -57,7 +58,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(gopts, opts.NewPasswordFile)
|
pw, err := getNewPassword(gopts, opts.NewPasswordFile, opts.AllowEmptyPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,11 @@ func resolvePassword(opts GlobalOptions, envStr string) (string, error) {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return "", errors.Fatalf("%s does not exist", opts.PasswordFile)
|
return "", errors.Fatalf("%s does not exist", opts.PasswordFile)
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(string(s)), errors.Wrap(err, "Readfile")
|
pwd := strings.TrimSpace(string(s))
|
||||||
|
if pwd == "" {
|
||||||
|
pwd = emptyPassword
|
||||||
|
}
|
||||||
|
return pwd, errors.Wrap(err, "Readfile")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pwd := os.Getenv(envStr); pwd != "" {
|
if pwd := os.Getenv(envStr); pwd != "" {
|
||||||
|
@ -348,9 +352,11 @@ func readPasswordTerminal(in *os.File, out io.Writer, prompt string) (password s
|
||||||
return password, nil
|
return password, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emptyPassword = "\xff"
|
||||||
|
|
||||||
// ReadPassword reads the password from a password file, the environment
|
// ReadPassword reads the password from a password file, the environment
|
||||||
// variable RESTIC_PASSWORD or prompts the user.
|
// variable RESTIC_PASSWORD or prompts the user.
|
||||||
func ReadPassword(opts GlobalOptions, prompt string) (string, error) {
|
func ReadPassword(opts GlobalOptions, prompt string, allowAllowEmptyPassword bool) (string, error) {
|
||||||
if opts.password != "" {
|
if opts.password != "" {
|
||||||
return opts.password, nil
|
return opts.password, nil
|
||||||
}
|
}
|
||||||
|
@ -372,21 +378,26 @@ func ReadPassword(opts GlobalOptions, prompt string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(password) == 0 {
|
if len(password) == 0 {
|
||||||
|
if allowAllowEmptyPassword {
|
||||||
|
Warnf("using an empty password is bad security practice\n")
|
||||||
|
return emptyPassword, nil
|
||||||
|
} else {
|
||||||
return "", errors.Fatal("an empty password is not a password")
|
return "", errors.Fatal("an empty password is not a password")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return password, nil
|
return password, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadPasswordTwice calls ReadPassword two times and returns an error when the
|
// ReadPasswordTwice calls ReadPassword two times and returns an error when the
|
||||||
// passwords don't match.
|
// passwords don't match.
|
||||||
func ReadPasswordTwice(gopts GlobalOptions, prompt1, prompt2 string) (string, error) {
|
func ReadPasswordTwice(gopts GlobalOptions, prompt1, prompt2 string, allowAllowEmptyPassword bool) (string, error) {
|
||||||
pw1, err := ReadPassword(gopts, prompt1)
|
pw1, err := ReadPassword(gopts, prompt1, allowAllowEmptyPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if stdinIsTerminal() {
|
if stdinIsTerminal() {
|
||||||
pw2, err := ReadPassword(gopts, prompt2)
|
pw2, err := ReadPassword(gopts, prompt2, allowAllowEmptyPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -469,7 +480,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions) (*repository.Reposi
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; passwordTriesLeft > 0; passwordTriesLeft-- {
|
for ; passwordTriesLeft > 0; passwordTriesLeft-- {
|
||||||
opts.password, err = ReadPassword(opts, "enter password for repository: ")
|
opts.password, err = ReadPassword(opts, "enter password for repository: ", true)
|
||||||
if err != nil && passwordTriesLeft > 1 {
|
if err != nil && passwordTriesLeft > 1 {
|
||||||
opts.password = ""
|
opts.password = ""
|
||||||
fmt.Printf("%s. Try again\n", err)
|
fmt.Printf("%s. Try again\n", err)
|
||||||
|
|
|
@ -109,7 +109,8 @@ func fillSecondaryGlobalOpts(opts secondaryRepoOptions, gopts GlobalOptions, rep
|
||||||
return GlobalOptions{}, false, err
|
return GlobalOptions{}, false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dstGopts.password, err = ReadPassword(dstGopts, "enter password for "+repoPrefix+" repository: ")
|
//FIXME: constant true okay?
|
||||||
|
dstGopts.password, err = ReadPassword(dstGopts, "enter password for "+repoPrefix+" repository: ", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GlobalOptions{}, false, err
|
return GlobalOptions{}, false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1442,6 +1442,7 @@ _restic_init()
|
||||||
two_word_flags+=("--from-password-file")
|
two_word_flags+=("--from-password-file")
|
||||||
local_nonpersistent_flags+=("--from-password-file")
|
local_nonpersistent_flags+=("--from-password-file")
|
||||||
local_nonpersistent_flags+=("--from-password-file=")
|
local_nonpersistent_flags+=("--from-password-file=")
|
||||||
|
flags+=("--allow-empty-password")
|
||||||
flags+=("--from-repo=")
|
flags+=("--from-repo=")
|
||||||
two_word_flags+=("--from-repo")
|
two_word_flags+=("--from-repo")
|
||||||
local_nonpersistent_flags+=("--from-repo")
|
local_nonpersistent_flags+=("--from-repo")
|
||||||
|
@ -1512,6 +1513,10 @@ _restic_key()
|
||||||
command_aliases=()
|
command_aliases=()
|
||||||
|
|
||||||
commands=()
|
commands=()
|
||||||
|
commands+=("add")
|
||||||
|
commands+=("list")
|
||||||
|
commands+=("passwd")
|
||||||
|
commands+=("remove")
|
||||||
|
|
||||||
flags=()
|
flags=()
|
||||||
two_word_flags=()
|
two_word_flags=()
|
||||||
|
@ -1582,6 +1587,74 @@ _restic_key()
|
||||||
noun_aliases=()
|
noun_aliases=()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_restic_key_add()
|
||||||
|
{
|
||||||
|
last_command="restic_key_add"
|
||||||
|
|
||||||
|
command_aliases=()
|
||||||
|
|
||||||
|
commands=()
|
||||||
|
|
||||||
|
flags_with_completion=()
|
||||||
|
flags_completion=()
|
||||||
|
|
||||||
|
flags+=("--allow-empty-password")
|
||||||
|
|
||||||
|
must_have_one_flag=()
|
||||||
|
must_have_one_noun=()
|
||||||
|
noun_aliases=()
|
||||||
|
}
|
||||||
|
|
||||||
|
_restic_key_list()
|
||||||
|
{
|
||||||
|
last_command="restic_key_list"
|
||||||
|
|
||||||
|
command_aliases=()
|
||||||
|
|
||||||
|
commands=()
|
||||||
|
|
||||||
|
flags_with_completion=()
|
||||||
|
flags_completion=()
|
||||||
|
|
||||||
|
must_have_one_flag=()
|
||||||
|
must_have_one_noun=()
|
||||||
|
noun_aliases=()
|
||||||
|
}
|
||||||
|
|
||||||
|
_restic_key_passwd()
|
||||||
|
{
|
||||||
|
last_command="restic_key_passwd"
|
||||||
|
|
||||||
|
command_aliases=()
|
||||||
|
|
||||||
|
commands=()
|
||||||
|
|
||||||
|
flags_with_completion=()
|
||||||
|
flags_completion=()
|
||||||
|
|
||||||
|
flags+=("--allow-empty-password")
|
||||||
|
|
||||||
|
must_have_one_flag=()
|
||||||
|
must_have_one_noun=()
|
||||||
|
noun_aliases=()
|
||||||
|
}
|
||||||
|
|
||||||
|
_restic_key_remove()
|
||||||
|
{
|
||||||
|
last_command="restic_key_remove"
|
||||||
|
|
||||||
|
command_aliases=()
|
||||||
|
|
||||||
|
commands=()
|
||||||
|
|
||||||
|
flags_with_completion=()
|
||||||
|
flags_completion=()
|
||||||
|
|
||||||
|
must_have_one_flag=()
|
||||||
|
must_have_one_noun=()
|
||||||
|
noun_aliases=()
|
||||||
|
}
|
||||||
|
|
||||||
_restic_list()
|
_restic_list()
|
||||||
{
|
{
|
||||||
last_command="restic_list"
|
last_command="restic_list"
|
||||||
|
|
Loading…
Reference in New Issue