Merge pull request #2910 from mtdcr/repository-file
Add new option --repository-file (default: $RESTIC_REPOSITORY_FILE)
This commit is contained in:
commit
f361ed66de
7 changed files with 88 additions and 6 deletions
10
changelog/unreleased/pull-2910
Normal file
10
changelog/unreleased/pull-2910
Normal 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
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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``
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue