diff --git a/archiver.go b/archiver.go index aba53cbcb..594b56673 100644 --- a/archiver.go +++ b/archiver.go @@ -22,9 +22,8 @@ const ( ) type Archiver struct { - s Server - key *Key - ch *ContentHandler + s Server + ch *ContentHandler bl *BlobList // blobs used for the current snapshot parentBl *BlobList // blobs from the parent snapshot @@ -58,11 +57,10 @@ func (s *Stats) Add(other Stats) { s.Other += other.Other } -func NewArchiver(s Server, key *Key) (*Archiver, error) { +func NewArchiver(s Server) (*Archiver, error) { var err error arch := &Archiver{ s: s, - key: key, fileToken: make(chan struct{}, maxConcurrentFiles), blobToken: make(chan struct{}, maxConcurrentBlobs), } @@ -82,7 +80,7 @@ func NewArchiver(s Server, key *Key) (*Archiver, error) { arch.Filter = func(string, os.FileInfo) bool { return true } arch.bl = NewBlobList() - arch.ch, err = NewContentHandler(s, key) + arch.ch, err = NewContentHandler(s) if err != nil { return nil, err } diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 24f2bb7c8..03365635a 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -72,7 +72,7 @@ func (cmd CmdBackup) Execute(args []string) error { return fmt.Errorf("wrong number of parameters, Usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } @@ -81,7 +81,7 @@ func (cmd CmdBackup) Execute(args []string) error { target := args[0] if len(args) > 1 { - parentSnapshotID, err = backend.FindSnapshot(be, args[1]) + parentSnapshotID, err = s.FindSnapshot(args[1]) if err != nil { return fmt.Errorf("invalid id %q: %v", args[1], err) } @@ -89,7 +89,7 @@ func (cmd CmdBackup) Execute(args []string) error { fmt.Printf("found parent snapshot %v\n", parentSnapshotID) } - arch, err := restic.NewArchiver(be, key) + arch, err := restic.NewArchiver(s) if err != nil { fmt.Fprintf(os.Stderr, "err: %v\n", err) } @@ -183,7 +183,7 @@ func (cmd CmdBackup) Execute(args []string) error { close(arch.ScannerStats) } - plen, err := backend.PrefixLength(be, backend.Snapshot) + plen, err := s.PrefixLength(backend.Snapshot) if err != nil { return err } diff --git a/cmd/restic/cmd_cat.go b/cmd/restic/cmd_cat.go index 6af0a476a..2ee657bc3 100644 --- a/cmd/restic/cmd_cat.go +++ b/cmd/restic/cmd_cat.go @@ -31,7 +31,7 @@ func (cmd CmdCat) Execute(args []string) error { return fmt.Errorf("type or ID not specified, Usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } @@ -47,13 +47,13 @@ func (cmd CmdCat) Execute(args []string) error { } // find snapshot id with prefix - id, err = backend.Find(be, backend.Snapshot, args[1]) + id, err = s.FindSnapshot(args[1]) if err != nil { return err } } - ch, err := restic.NewContentHandler(be, key) + ch, err := restic.NewContentHandler(s) if err != nil { return err } @@ -73,13 +73,13 @@ func (cmd CmdCat) Execute(args []string) error { } // try storage id - buf, err := be.Get(backend.Data, id) + buf, err := s.Get(backend.Data, id) if err != nil { return err } // decrypt - buf, err = key.Decrypt(buf) + buf, err = s.Decrypt(buf) if err != nil { return err } @@ -98,13 +98,13 @@ func (cmd CmdCat) Execute(args []string) error { err := ch.LoadJSON(backend.Tree, id, &tree) if err != nil { // try storage id - buf, err := be.Get(backend.Tree, id) + buf, err := s.Get(backend.Tree, id) if err != nil { return err } // decrypt - buf, err = key.Decrypt(buf) + buf, err = s.Decrypt(buf) if err != nil { return err } @@ -156,7 +156,7 @@ func (cmd CmdCat) Execute(args []string) error { return nil case "key": - data, err := be.Get(backend.Key, id) + data, err := s.Get(backend.Key, id) if err != nil { return err } diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 585e60339..55cec11be 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -110,10 +110,10 @@ func (c CmdFind) findInTree(ch *restic.ContentHandler, id backend.ID, path strin return results, nil } -func (c CmdFind) findInSnapshot(be restic.Server, key *restic.Key, id backend.ID) error { +func (c CmdFind) findInSnapshot(s restic.Server, id backend.ID) error { debug("searching in snapshot %s\n for entries within [%s %s]", id, c.oldest, c.newest) - ch, err := restic.NewContentHandler(be, key) + ch, err := restic.NewContentHandler(s) if err != nil { return err } @@ -166,7 +166,7 @@ func (c CmdFind) Execute(args []string) error { } } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } @@ -174,21 +174,21 @@ func (c CmdFind) Execute(args []string) error { c.pattern = args[0] if c.Snapshot != "" { - snapshotID, err := backend.FindSnapshot(be, c.Snapshot) + snapshotID, err := backend.FindSnapshot(s, c.Snapshot) if err != nil { return fmt.Errorf("invalid id %q: %v", args[1], err) } - return c.findInSnapshot(be, key, snapshotID) + return c.findInSnapshot(s, snapshotID) } - list, err := be.List(backend.Snapshot) + list, err := s.List(backend.Snapshot) if err != nil { return err } for _, snapshotID := range list { - err := c.findInSnapshot(be, key, snapshotID) + err := c.findInSnapshot(s, snapshotID) if err != nil { return err diff --git a/cmd/restic/cmd_fsck.go b/cmd/restic/cmd_fsck.go index fcb1c6329..ae80f0f2a 100644 --- a/cmd/restic/cmd_fsck.go +++ b/cmd/restic/cmd_fsck.go @@ -75,10 +75,10 @@ func fsckTree(ch *restic.ContentHandler, id backend.ID) error { return nil } -func fsck_snapshot(be restic.Server, key *restic.Key, id backend.ID) error { +func fsck_snapshot(s restic.Server, id backend.ID) error { debug("checking snapshot %v\n", id) - ch, err := restic.NewContentHandler(be, key) + ch, err := restic.NewContentHandler(s) if err != nil { return err } @@ -108,27 +108,27 @@ func (cmd CmdFsck) Execute(args []string) error { return fmt.Errorf("type or ID not specified, Usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } if len(args) == 1 && args[0] != "all" { - snapshotID, err := backend.FindSnapshot(be, args[0]) + snapshotID, err := s.FindSnapshot(args[0]) if err != nil { return fmt.Errorf("invalid id %q: %v", args[0], err) } - return fsck_snapshot(be, key, snapshotID) + return fsck_snapshot(s, snapshotID) } - list, err := be.List(backend.Snapshot) + list, err := s.List(backend.Snapshot) if err != nil { return err } for _, snapshotID := range list { - err := fsck_snapshot(be, key, snapshotID) + err := fsck_snapshot(s, snapshotID) if err != nil { return err diff --git a/cmd/restic/cmd_key.go b/cmd/restic/cmd_key.go index 9332ebb8c..c502fc3db 100644 --- a/cmd/restic/cmd_key.go +++ b/cmd/restic/cmd_key.go @@ -22,17 +22,17 @@ func init() { } } -func list_keys(be restic.Server, key *restic.Key) error { +func list_keys(s restic.Server) error { tab := NewTable() tab.Header = fmt.Sprintf(" %-10s %-10s %-10s %s", "ID", "User", "Host", "Created") tab.RowFormat = "%s%-10s %-10s %-10s %s" - plen, err := backend.PrefixLength(be, backend.Key) + plen, err := s.PrefixLength(backend.Key) if err != nil { return err } - backend.Each(be, backend.Key, func(id backend.ID, data []byte, err error) { + s.Each(backend.Key, func(id backend.ID, data []byte, err error) { k := restic.Key{} err = json.Unmarshal(data, &k) if err != nil { @@ -40,7 +40,7 @@ func list_keys(be restic.Server, key *restic.Key) error { } var current string - if id.Equal(key.ID()) { + if id.Equal(s.Key().ID()) { current = "*" } else { current = " " @@ -54,7 +54,7 @@ func list_keys(be restic.Server, key *restic.Key) error { return nil } -func add_key(be restic.Server, key *restic.Key) error { +func add_key(s restic.Server) error { pw := readPassword("RESTIC_NEWPASSWORD", "enter password for new key: ") pw2 := readPassword("RESTIC_NEWPASSWORD", "enter password again: ") @@ -62,7 +62,7 @@ func add_key(be restic.Server, key *restic.Key) error { return errors.New("passwords do not match") } - id, err := key.AddKey(be, pw) + id, err := s.Key().AddKey(s, pw) if err != nil { return fmt.Errorf("creating new key failed: %v\n", err) } @@ -72,12 +72,12 @@ func add_key(be restic.Server, key *restic.Key) error { return nil } -func delete_key(be restic.Server, key *restic.Key, id backend.ID) error { - if id.Equal(key.ID()) { +func delete_key(s restic.Server, id backend.ID) error { + if id.Equal(s.Key().ID()) { return errors.New("refusing to remove key currently used to access repository") } - err := be.Remove(backend.Key, id) + err := s.Remove(backend.Key, id) if err != nil { return err } @@ -86,7 +86,7 @@ func delete_key(be restic.Server, key *restic.Key, id backend.ID) error { return nil } -func change_password(be restic.Server, key *restic.Key) error { +func change_password(s restic.Server) error { pw := readPassword("RESTIC_NEWPASSWORD", "enter password for new key: ") pw2 := readPassword("RESTIC_NEWPASSWORD", "enter password again: ") @@ -95,13 +95,13 @@ func change_password(be restic.Server, key *restic.Key) error { } // add new key - id, err := key.AddKey(be, pw) + id, err := s.Key().AddKey(s, pw) if err != nil { return fmt.Errorf("creating new key failed: %v\n", err) } // remove old key - err = be.Remove(backend.Key, key.ID()) + err = s.Remove(backend.Key, s.Key().ID()) if err != nil { return err } @@ -120,25 +120,25 @@ func (cmd CmdKey) Execute(args []string) error { return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } switch args[0] { case "list": - return list_keys(be, key) + return list_keys(s) case "add": - return add_key(be, key) + return add_key(s) case "rm": - id, err := backend.Find(be, backend.Key, args[1]) + id, err := backend.Find(s, backend.Key, args[1]) if err != nil { return err } - return delete_key(be, key, id) + return delete_key(s, id) case "change": - return change_password(be, key) + return change_password(s) } return nil diff --git a/cmd/restic/cmd_list.go b/cmd/restic/cmd_list.go index b85b9f010..5d43d8eed 100644 --- a/cmd/restic/cmd_list.go +++ b/cmd/restic/cmd_list.go @@ -28,22 +28,22 @@ func (cmd CmdList) Execute(args []string) error { return fmt.Errorf("type not specified, Usage: %s", cmd.Usage()) } - be, _, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } var ( t backend.Type - each func(backend.Type, func(backend.ID, []byte, error)) error = be.Each + each func(backend.Type, func(backend.ID, []byte, error)) error = s.Each ) switch args[0] { case "data": t = backend.Data - each = be.EachDecrypted + each = s.EachDecrypted case "trees": t = backend.Tree - each = be.EachDecrypted + each = s.EachDecrypted case "snapshots": t = backend.Snapshot case "maps": diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index b64454a43..94d2b04bb 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -63,22 +63,22 @@ func (cmd CmdLs) Usage() string { return "ls snapshot-ID [DIR]" } -func (cmd CmdLs) Execute(be restic.Server, key *restic.Key, args []string) error { +func (cmd CmdLs) Execute(s restic.Server, key *restic.Key, args []string) error { if len(args) < 1 || len(args) > 2 { return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } - id, err := backend.FindSnapshot(be, args[0]) + id, err := backend.FindSnapshot(s, args[0]) if err != nil { return err } - ch, err := restic.NewContentHandler(be, key) + ch, err := restic.NewContentHandler(s) if err != nil { return err } diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index 2dbe9ea74..b165f2805 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -29,12 +29,12 @@ func (cmd CmdRestore) Execute(args []string) error { return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } - id, err := backend.FindSnapshot(be, args[0]) + id, err := backend.FindSnapshot(s, args[0]) if err != nil { errx(1, "invalid id %q: %v", args[0], err) } @@ -42,7 +42,7 @@ func (cmd CmdRestore) Execute(args []string) error { target := args[1] // create restorer - res, err := restic.NewRestorer(be, key, id) + res, err := restic.NewRestorer(s, id) if err != nil { fmt.Fprintf(os.Stderr, "creating restorer failed: %v\n", err) os.Exit(2) diff --git a/cmd/restic/cmd_snapshots.go b/cmd/restic/cmd_snapshots.go index c431607e3..036ca49b9 100644 --- a/cmd/restic/cmd_snapshots.go +++ b/cmd/restic/cmd_snapshots.go @@ -92,12 +92,12 @@ func (cmd CmdSnapshots) Execute(args []string) error { return fmt.Errorf("wrong number of arguments, usage: %s", cmd.Usage()) } - be, key, err := OpenRepo() + s, err := OpenRepo() if err != nil { return err } - ch, err := restic.NewContentHandler(be, key) + ch, err := restic.NewContentHandler(s) if err != nil { return err } @@ -107,7 +107,7 @@ func (cmd CmdSnapshots) Execute(args []string) error { tab.RowFormat = "%-8s %-19s %-10s %s" list := []*restic.Snapshot{} - backend.EachID(be, backend.Snapshot, func(id backend.ID) { + s.EachID(backend.Snapshot, func(id backend.ID) { sn, err := restic.LoadSnapshot(ch, id) if err != nil { fmt.Fprintf(os.Stderr, "error loading snapshot %s: %v\n", id, err) @@ -127,7 +127,7 @@ func (cmd CmdSnapshots) Execute(args []string) error { } }) - plen, err := backend.PrefixLength(be, backend.Snapshot) + plen, err := s.PrefixLength(backend.Snapshot) if err != nil { return err } diff --git a/cmd/restic/main.go b/cmd/restic/main.go index ee2f835bf..5fec20030 100644 --- a/cmd/restic/main.go +++ b/cmd/restic/main.go @@ -129,20 +129,20 @@ func create(u string) (backend.Backend, error) { return backend.CreateSFTP(url.Path[1:], "ssh", args...) } -func OpenRepo() (restic.Server, *restic.Key, error) { +func OpenRepo() (restic.Server, error) { be, err := open(opts.Repo) if err != nil { - return restic.Server{}, nil, err + return restic.Server{}, err } s := restic.NewServer(be) - key, err := restic.SearchKey(s, readPassword("RESTIC_PASSWORD", "Enter Password for Repository: ")) + err = s.SearchKey(readPassword("RESTIC_PASSWORD", "Enter Password for Repository: ")) if err != nil { - return restic.Server{}, nil, fmt.Errorf("unable to open repo: %v", err) + return restic.Server{}, fmt.Errorf("unable to open repo: %v", err) } - return s, key, nil + return s, nil } func init() { @@ -171,59 +171,5 @@ func main() { os.Exit(1) } - // fmt.Printf("parser: %#v\n", parser) - // fmt.Printf("%#v\n", parser.Active.Name) - - // if opts.Repo == "" { - // fmt.Fprintf(os.Stderr, "no repository specified, use -r or RESTIC_REPOSITORY variable\n") - // os.Exit(1) - // } - - // if len(args) == 0 { - // cmds := []string{"init"} - // for k := range commands { - // cmds = append(cmds, k) - // } - // sort.Strings(cmds) - // fmt.Printf("nothing to do, available commands: [%v]\n", strings.Join(cmds, "|")) - // os.Exit(0) - // } - - // cmd := args[0] - - // switch cmd { - // case "init": - // err = commandInit(opts.Repo) - // if err != nil { - // errx(1, "error executing command %q: %v", cmd, err) - // } - // return - - // case "version": - // fmt.Printf("%v\n", version) - // return - // } - - // f, ok := commands[cmd] - // if !ok { - // errx(1, "unknown command: %q\n", cmd) - // } - - // // read_password("enter password: ") - // repo, err := open(opts.Repo) - // if err != nil { - // errx(1, "unable to open repo: %v", err) - // } - - // key, err := restic.SearchKey(repo, readPassword("RESTIC_PASSWORD", "Enter Password for Repository: ")) - // if err != nil { - // errx(2, "unable to open repo: %v", err) - // } - - // err = f(repo, key, args[1:]) - // if err != nil { - // errx(1, "error executing command %q: %v", cmd, err) - // } - // restic.PoolAlloc() } diff --git a/contenthandler.go b/contenthandler.go index 3beed5f09..16fd7a2ab 100644 --- a/contenthandler.go +++ b/contenthandler.go @@ -11,18 +11,16 @@ import ( var ErrWrongData = errors.New("wrong data decrypt, checksum does not match") type ContentHandler struct { - s Server - key *Key + s Server bl *BlobList } // NewContentHandler creates a new content handler. -func NewContentHandler(s Server, key *Key) (*ContentHandler, error) { +func NewContentHandler(s Server) (*ContentHandler, error) { ch := &ContentHandler{ - s: s, - key: key, - bl: NewBlobList(), + s: s, + bl: NewBlobList(), } return ch, nil @@ -95,7 +93,7 @@ func (ch *ContentHandler) Save(t backend.Type, data []byte) (Blob, error) { } // encrypt blob - n, err := ch.key.Encrypt(ciphertext, data) + n, err := ch.s.Encrypt(ciphertext, data) if err != nil { return Blob{}, err } @@ -139,7 +137,7 @@ func (ch *ContentHandler) Load(t backend.Type, id backend.ID) ([]byte, error) { } // decrypt - buf, err = ch.key.Decrypt(buf) + buf, err = ch.s.Decrypt(buf) if err != nil { return nil, err } @@ -165,7 +163,7 @@ func (ch *ContentHandler) Load(t backend.Type, id backend.ID) ([]byte, error) { } // decrypt - buf, err = ch.key.Decrypt(buf) + buf, err = ch.s.Decrypt(buf) if err != nil { return nil, err } @@ -207,7 +205,7 @@ func (ch *ContentHandler) LoadJSONRaw(t backend.Type, id backend.ID, item interf } // decrypt - buf, err = ch.key.Decrypt(buf) + buf, err = ch.s.Decrypt(buf) if err != nil { return err } diff --git a/restorer.go b/restorer.go index 7650e60b8..f26b30354 100644 --- a/restorer.go +++ b/restorer.go @@ -11,24 +11,20 @@ import ( ) type Restorer struct { - s Server - key *Key - ch *ContentHandler - sn *Snapshot + s Server + ch *ContentHandler + sn *Snapshot Error func(dir string, node *Node, err error) error Filter func(item string, node *Node) bool } // NewRestorer creates a restorer preloaded with the content from the snapshot snid. -func NewRestorer(s Server, key *Key, snid backend.ID) (*Restorer, error) { - r := &Restorer{ - s: s, - key: key, - } +func NewRestorer(s Server, snid backend.ID) (*Restorer, error) { + r := &Restorer{s: s} var err error - r.ch, err = NewContentHandler(s, key) + r.ch, err = NewContentHandler(s) if err != nil { return nil, arrar.Annotate(err, "create contenthandler for restorer") } diff --git a/server.go b/server.go index dec529b31..563971ffb 100644 --- a/server.go +++ b/server.go @@ -55,6 +55,37 @@ func (s Server) Backend() backend.Backend { return s.be } +func (s *Server) SearchKey(password string) error { + key, err := SearchKey(*s, password) + if err != nil { + return err + } + + s.key = key + + return nil +} + +func (s Server) Decrypt(ciphertext []byte) ([]byte, error) { + if s.key == nil { + return nil, errors.New("key for server not set") + } + + return s.key.Decrypt(ciphertext) +} + +func (s Server) Encrypt(ciphertext, plaintext []byte) (int, error) { + if s.key == nil { + return 0, errors.New("key for server not set") + } + + return s.key.Encrypt(ciphertext, plaintext) +} + +func (s Server) Key() *Key { + return s.key +} + // Each calls Each() with the given parameters, Decrypt() on the ciphertext // and, on successful decryption, f with the plaintext. func (s Server) EachDecrypted(t backend.Type, f func(backend.ID, []byte, error)) error {