mirror of
https://github.com/octoleo/restic.git
synced 2024-11-29 16:23:59 +00:00
Merge pull request #2318 from classmarkets/2175-named-keys
Allow specifying user and host when adding keys
This commit is contained in:
commit
2580eef2aa
9
changelog/unreleased/issue-2175
Normal file
9
changelog/unreleased/issue-2175
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Enhancement: Allow specifying user and host when creating keys
|
||||||
|
|
||||||
|
When adding a new key to the repository, the username and hostname for the new
|
||||||
|
key can be specified on the command line. This allows overriding the defaults,
|
||||||
|
for example if you would prefer to use the FQDN to identify the host or if you
|
||||||
|
want to add keys for several different hosts without having to run the key add
|
||||||
|
command on those hosts.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/2175
|
@ -32,13 +32,19 @@ Exit status is 0 if the command was successful, and non-zero if there was any er
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var newPasswordFile string
|
var (
|
||||||
|
newPasswordFile string
|
||||||
|
keyUsername string
|
||||||
|
keyHostname string
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmdRoot.AddCommand(cmdKey)
|
cmdRoot.AddCommand(cmdKey)
|
||||||
|
|
||||||
flags := cmdKey.Flags()
|
flags := cmdKey.Flags()
|
||||||
flags.StringVarP(&newPasswordFile, "new-password-file", "", "", "the file from which to load a new password")
|
flags.StringVarP(&newPasswordFile, "new-password-file", "", "", "the file from which to load a new password")
|
||||||
|
flags.StringVarP(&keyUsername, "user", "", "", "the username for new keys")
|
||||||
|
flags.StringVarP(&keyHostname, "host", "", "", "the hostname for new keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions) error {
|
func listKeys(ctx context.Context, s *repository.Repository, gopts GlobalOptions) error {
|
||||||
@ -120,7 +126,7 @@ func addKey(gopts GlobalOptions, repo *repository.Repository) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := repository.AddKey(gopts.ctx, repo, pw, repo.Key())
|
id, err := repository.AddKey(gopts.ctx, repo, pw, keyUsername, keyHostname, repo.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Fatalf("creating new key failed: %v\n", err)
|
return errors.Fatalf("creating new key failed: %v\n", err)
|
||||||
}
|
}
|
||||||
@ -151,7 +157,7 @@ func changePassword(gopts GlobalOptions, repo *repository.Repository) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := repository.AddKey(gopts.ctx, repo, pw, repo.Key())
|
id, err := repository.AddKey(gopts.ctx, repo, pw, "", "", repo.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Fatalf("creating new key failed: %v\n", err)
|
return errors.Fatalf("creating new key failed: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -724,6 +724,28 @@ func testRunKeyAddNewKey(t testing.TB, newPassword string, gopts GlobalOptions)
|
|||||||
rtest.OK(t, runKey(gopts, []string{"add"}))
|
rtest.OK(t, runKey(gopts, []string{"add"}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testRunKeyAddNewKeyUserHost(t testing.TB, gopts GlobalOptions) {
|
||||||
|
testKeyNewPassword = "john's geheimnis"
|
||||||
|
defer func() {
|
||||||
|
testKeyNewPassword = ""
|
||||||
|
keyUsername = ""
|
||||||
|
keyHostname = ""
|
||||||
|
}()
|
||||||
|
|
||||||
|
cmdKey.Flags().Parse([]string{"--user=john", "--host=example.com"})
|
||||||
|
|
||||||
|
t.Log("adding key for john@example.com")
|
||||||
|
rtest.OK(t, runKey(gopts, []string{"add"}))
|
||||||
|
|
||||||
|
repo, err := OpenRepository(gopts)
|
||||||
|
rtest.OK(t, err)
|
||||||
|
key, err := repository.SearchKey(gopts.ctx, repo, testKeyNewPassword, 1, "")
|
||||||
|
rtest.OK(t, err)
|
||||||
|
|
||||||
|
rtest.Equals(t, "john", key.Username)
|
||||||
|
rtest.Equals(t, "example.com", key.Hostname)
|
||||||
|
}
|
||||||
|
|
||||||
func testRunKeyPasswd(t testing.TB, newPassword string, gopts GlobalOptions) {
|
func testRunKeyPasswd(t testing.TB, newPassword string, gopts GlobalOptions) {
|
||||||
testKeyNewPassword = newPassword
|
testKeyNewPassword = newPassword
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -766,6 +788,8 @@ func TestKeyAddRemove(t *testing.T) {
|
|||||||
t.Logf("testing access with last password %q\n", env.gopts.password)
|
t.Logf("testing access with last password %q\n", env.gopts.password)
|
||||||
rtest.OK(t, runKey(env.gopts, []string{"list"}))
|
rtest.OK(t, runKey(env.gopts, []string{"list"}))
|
||||||
testRunCheck(t, env.gopts)
|
testRunCheck(t, env.gopts)
|
||||||
|
|
||||||
|
testRunKeyAddNewKeyUserHost(t, env.gopts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFileSize(filename string, size int64) error {
|
func testFileSize(filename string, size int64) error {
|
||||||
|
@ -58,7 +58,7 @@ var (
|
|||||||
// createMasterKey creates a new master key in the given backend and encrypts
|
// createMasterKey creates a new master key in the given backend and encrypts
|
||||||
// it with the password.
|
// it with the password.
|
||||||
func createMasterKey(s *Repository, password string) (*Key, error) {
|
func createMasterKey(s *Repository, password string) (*Key, error) {
|
||||||
return AddKey(context.TODO(), s, password, nil)
|
return AddKey(context.TODO(), s, password, "", "", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenKey tries do decrypt the key specified by name with the given password.
|
// OpenKey tries do decrypt the key specified by name with the given password.
|
||||||
@ -199,7 +199,7 @@ func LoadKey(ctx context.Context, s *Repository, name string) (k *Key, err error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddKey adds a new key to an already existing repository.
|
// AddKey adds a new key to an already existing repository.
|
||||||
func AddKey(ctx context.Context, s *Repository, password string, template *crypto.Key) (*Key, error) {
|
func AddKey(ctx context.Context, s *Repository, password, username, hostname string, template *crypto.Key) (*Key, error) {
|
||||||
// make sure we have valid KDF parameters
|
// make sure we have valid KDF parameters
|
||||||
if Params == nil {
|
if Params == nil {
|
||||||
p, err := crypto.Calibrate(KDFTimeout, KDFMemory)
|
p, err := crypto.Calibrate(KDFTimeout, KDFMemory)
|
||||||
@ -214,23 +214,28 @@ func AddKey(ctx context.Context, s *Repository, password string, template *crypt
|
|||||||
// fill meta data about key
|
// fill meta data about key
|
||||||
newkey := &Key{
|
newkey := &Key{
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
|
Username: username,
|
||||||
|
Hostname: hostname,
|
||||||
|
|
||||||
KDF: "scrypt",
|
KDF: "scrypt",
|
||||||
N: Params.N,
|
N: Params.N,
|
||||||
R: Params.R,
|
R: Params.R,
|
||||||
P: Params.P,
|
P: Params.P,
|
||||||
}
|
}
|
||||||
|
|
||||||
hn, err := os.Hostname()
|
if newkey.Hostname == "" {
|
||||||
if err == nil {
|
newkey.Hostname, _ = os.Hostname()
|
||||||
newkey.Hostname = hn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if newkey.Username == "" {
|
||||||
usr, err := user.Current()
|
usr, err := user.Current()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
newkey.Username = usr.Username
|
newkey.Username = usr.Username
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// generate random salt
|
// generate random salt
|
||||||
|
var err error
|
||||||
newkey.Salt, err = crypto.NewSalt()
|
newkey.Salt, err = crypto.NewSalt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("unable to read enough random bytes for salt: " + err.Error())
|
panic("unable to read enough random bytes for salt: " + err.Error())
|
||||||
|
Loading…
Reference in New Issue
Block a user