Merge pull request #2910 from mtdcr/repository-file

Add new option --repository-file (default: $RESTIC_REPOSITORY_FILE)
This commit is contained in:
MichaelEischer 2020-10-01 01:04:23 +02:00 committed by GitHub
commit f361ed66de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 6 deletions

View file

@ -0,0 +1,10 @@
Enhancement: New option --repository-file
We've added a new command-line option --repository-file as an alternative
to -r. This allows to read the repository URL from a file in order to
prevent certain types of information leaks, especially for URLs containing
credentials.
https://github.com/restic/restic/issues/1458
https://github.com/restic/restic/issues/2900
https://github.com/restic/restic/pull/2910

View file

@ -52,7 +52,12 @@ func runInit(opts InitOptions, gopts GlobalOptions, args []string) error {
return err return err
} }
be, err := create(gopts.Repo, gopts.extended) repo, err := ReadRepo(gopts)
if err != nil {
return err
}
be, err := create(repo, gopts.extended)
if err != nil { if err != nil {
return errors.Fatalf("create repository at %s failed: %v\n", location.StripPassword(gopts.Repo), err) return errors.Fatalf("create repository at %s failed: %v\n", location.StripPassword(gopts.Repo), err)
} }

View file

@ -49,6 +49,7 @@ type backendWrapper func(r restic.Backend) (restic.Backend, error)
// GlobalOptions hold all global options for restic. // GlobalOptions hold all global options for restic.
type GlobalOptions struct { type GlobalOptions struct {
Repo string Repo string
RepositoryFile string
PasswordFile string PasswordFile string
PasswordCommand string PasswordCommand string
KeyHint string KeyHint string
@ -101,6 +102,7 @@ func init() {
f := cmdRoot.PersistentFlags() f := cmdRoot.PersistentFlags()
f.StringVarP(&globalOptions.Repo, "repo", "r", os.Getenv("RESTIC_REPOSITORY"), "`repository` to backup to or restore from (default: $RESTIC_REPOSITORY)") f.StringVarP(&globalOptions.Repo, "repo", "r", os.Getenv("RESTIC_REPOSITORY"), "`repository` to backup to or restore from (default: $RESTIC_REPOSITORY)")
f.StringVarP(&globalOptions.RepositoryFile, "repository-file", "", os.Getenv("RESTIC_REPOSITORY_FILE"), "`file` to read the repository location from (default: $RESTIC_REPOSITORY_FILE)")
f.StringVarP(&globalOptions.PasswordFile, "password-file", "p", os.Getenv("RESTIC_PASSWORD_FILE"), "`file` to read the repository password from (default: $RESTIC_PASSWORD_FILE)") f.StringVarP(&globalOptions.PasswordFile, "password-file", "p", os.Getenv("RESTIC_PASSWORD_FILE"), "`file` to read the repository password from (default: $RESTIC_PASSWORD_FILE)")
f.StringVarP(&globalOptions.KeyHint, "key-hint", "", os.Getenv("RESTIC_KEY_HINT"), "`key` ID of key to try decrypting first (default: $RESTIC_KEY_HINT)") f.StringVarP(&globalOptions.KeyHint, "key-hint", "", os.Getenv("RESTIC_KEY_HINT"), "`key` ID of key to try decrypting first (default: $RESTIC_KEY_HINT)")
f.StringVarP(&globalOptions.PasswordCommand, "password-command", "", os.Getenv("RESTIC_PASSWORD_COMMAND"), "shell `command` to obtain the repository password from (default: $RESTIC_PASSWORD_COMMAND)") f.StringVarP(&globalOptions.PasswordCommand, "password-command", "", os.Getenv("RESTIC_PASSWORD_COMMAND"), "shell `command` to obtain the repository password from (default: $RESTIC_PASSWORD_COMMAND)")
@ -382,15 +384,41 @@ func ReadPasswordTwice(gopts GlobalOptions, prompt1, prompt2 string) (string, er
return pw1, nil return pw1, nil
} }
func ReadRepo(opts GlobalOptions) (string, error) {
if opts.Repo == "" && opts.RepositoryFile == "" {
return "", errors.Fatal("Please specify repository location (-r or --repository-file)")
}
repo := opts.Repo
if opts.RepositoryFile != "" {
if repo != "" {
return "", errors.Fatal("Options -r and --repository-file are mutually exclusive, please specify only one")
}
s, err := textfile.Read(opts.RepositoryFile)
if os.IsNotExist(errors.Cause(err)) {
return "", errors.Fatalf("%s does not exist", opts.RepositoryFile)
}
if err != nil {
return "", err
}
repo = strings.TrimSpace(string(s))
}
return repo, nil
}
const maxKeys = 20 const maxKeys = 20
// OpenRepository reads the password and opens the repository. // OpenRepository reads the password and opens the repository.
func OpenRepository(opts GlobalOptions) (*repository.Repository, error) { func OpenRepository(opts GlobalOptions) (*repository.Repository, error) {
if opts.Repo == "" { repo, err := ReadRepo(opts)
return nil, errors.Fatal("Please specify repository location (-r)") if err != nil {
return nil, err
} }
be, err := open(opts.Repo, opts, opts.extended) be, err := open(repo, opts, opts.extended)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -2,8 +2,11 @@ package main
import ( import (
"bytes" "bytes"
"io/ioutil"
"path/filepath"
"testing" "testing"
"github.com/restic/restic/internal/test"
rtest "github.com/restic/restic/internal/test" rtest "github.com/restic/restic/internal/test"
) )
@ -26,3 +29,33 @@ func Test_PrintFunctionsRespectsGlobalStdout(t *testing.T) {
buf.Reset() buf.Reset()
} }
} }
func TestReadRepo(t *testing.T) {
tempDir, cleanup := test.TempDir(t)
defer cleanup()
// test --repo option
var opts GlobalOptions
opts.Repo = tempDir
repo, err := ReadRepo(opts)
rtest.OK(t, err)
rtest.Equals(t, tempDir, repo)
// test --repository-file option
foo := filepath.Join(tempDir, "foo")
err = ioutil.WriteFile(foo, []byte(tempDir+"\n"), 0666)
rtest.OK(t, err)
var opts2 GlobalOptions
opts2.RepositoryFile = foo
repo, err = ReadRepo(opts2)
rtest.OK(t, err)
rtest.Equals(t, tempDir, repo)
var opts3 GlobalOptions
opts3.RepositoryFile = foo + "-invalid"
repo, err = ReadRepo(opts3)
if err == nil {
t.Fatal("must not read repository path from invalid file path")
}
}

View file

@ -22,8 +22,10 @@ other options. You can skip to the next chapter once you've read the relevant
section here. section here.
For automated backups, restic accepts the repository location in the For automated backups, restic accepts the repository location in the
environment variable ``RESTIC_REPOSITORY``. For the password, several options environment variable ``RESTIC_REPOSITORY``. Restic can also read the repository
exist: location from a file specified via the ``--repository-file`` option or the
environment variable ``RESTIC_REPOSITORY_FILE``. For the password, several
options exist:
* Setting the environment variable ``RESTIC_PASSWORD`` * Setting the environment variable ``RESTIC_PASSWORD``

View file

@ -407,6 +407,7 @@ environment variables. The following lists these environment variables:
.. code-block:: console .. code-block:: console
RESTIC_REPOSITORY_FILE Name of file containing the repository location (replaces --repository-file)
RESTIC_REPOSITORY Location of repository (replaces -r) RESTIC_REPOSITORY Location of repository (replaces -r)
RESTIC_PASSWORD_FILE Location of password file (replaces --password-file) RESTIC_PASSWORD_FILE Location of password file (replaces --password-file)
RESTIC_PASSWORD The actual password for the repository RESTIC_PASSWORD The actual password for the repository

View file

@ -60,6 +60,7 @@ Usage help is available:
-p, --password-file file file to read the repository password from (default: $RESTIC_PASSWORD_FILE) -p, --password-file file file to read the repository password from (default: $RESTIC_PASSWORD_FILE)
-q, --quiet do not output comprehensive progress report -q, --quiet do not output comprehensive progress report
-r, --repo repository repository to backup to or restore from (default: $RESTIC_REPOSITORY) -r, --repo repository repository to backup to or restore from (default: $RESTIC_REPOSITORY)
--repository-file file file to read the repository location from (default: $RESTIC_REPOSITORY_FILE)
--tls-client-cert file path to a file containing PEM encoded TLS client certificate and private key --tls-client-cert file path to a file containing PEM encoded TLS client certificate and private key
-v, --verbose n be verbose (specify --verbose multiple times or level --verbose=n) -v, --verbose n be verbose (specify --verbose multiple times or level --verbose=n)
@ -92,6 +93,7 @@ command:
--exclude-caches excludes cache directories that are marked with a CACHEDIR.TAG file. See https://bford.info/cachedir/ for the Cache Directory Tagging Standard --exclude-caches excludes cache directories that are marked with a CACHEDIR.TAG file. See https://bford.info/cachedir/ for the Cache Directory Tagging Standard
--exclude-file file read exclude patterns from a file (can be specified multiple times) --exclude-file file read exclude patterns from a file (can be specified multiple times)
--exclude-if-present filename[:header] takes filename[:header], exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times) --exclude-if-present filename[:header] takes filename[:header], exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times)
--exclude-larger-than size max size of the files to be backed up (allowed suffixes: k/K, m/M, g/G, t/T)
--files-from file read the files to backup from file (can be combined with file args/can be specified multiple times) --files-from file read the files to backup from file (can be combined with file args/can be specified multiple times)
-f, --force force re-reading the target files/directories (overrides the "parent" flag) -f, --force force re-reading the target files/directories (overrides the "parent" flag)
-h, --help help for backup -h, --help help for backup
@ -122,6 +124,7 @@ command:
-p, --password-file file file to read the repository password from (default: $RESTIC_PASSWORD_FILE) -p, --password-file file file to read the repository password from (default: $RESTIC_PASSWORD_FILE)
-q, --quiet do not output comprehensive progress report -q, --quiet do not output comprehensive progress report
-r, --repo repository repository to backup to or restore from (default: $RESTIC_REPOSITORY) -r, --repo repository repository to backup to or restore from (default: $RESTIC_REPOSITORY)
--repository-file file file to read the repository location from (default: $RESTIC_REPOSITORY_FILE)
--tls-client-cert file path to a file containing PEM encoded TLS client certificate and private key --tls-client-cert file path to a file containing PEM encoded TLS client certificate and private key
-v, --verbose n be verbose (specify --verbose multiple times or level --verbose=n) -v, --verbose n be verbose (specify --verbose multiple times or level --verbose=n)