repository: Refactor Config

This commit is contained in:
Alexander Neumann 2015-07-02 22:36:31 +02:00
parent 867f6c8e24
commit c553a57e0d
3 changed files with 146 additions and 54 deletions

87
repository/config.go Normal file
View File

@ -0,0 +1,87 @@
package repository
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
"io"
"github.com/restic/restic/backend"
"github.com/restic/restic/chunker"
"github.com/restic/restic/debug"
)
// Config contains the configuration for a repository.
type Config struct {
Version uint `json:"version"`
ID string `json:"id"`
ChunkerPolynomial chunker.Pol `json:"chunker_polynomial"`
}
// repositoryIDSize is the length of the ID chosen at random for a new repository.
const repositoryIDSize = sha256.Size
// RepoVersion is the version that is written to the config when a repository
// is newly created with Init().
const RepoVersion = 1
// JSONUnpackedSaver saves unpacked JSON.
type JSONUnpackedSaver interface {
SaveJSONUnpacked(backend.Type, interface{}) (backend.ID, error)
}
// JSONUnpackedLoader loads unpacked JSON.
type JSONUnpackedLoader interface {
LoadJSONUnpacked(backend.Type, backend.ID, interface{}) error
}
// CreateConfig creates a config file with a randomly selected polynomial and
// ID and saves the config in the repository.
func CreateConfig(r JSONUnpackedSaver) (Config, error) {
var (
err error
cfg Config
)
cfg.ChunkerPolynomial, err = chunker.RandomPolynomial()
if err != nil {
return Config{}, err
}
newID := make([]byte, repositoryIDSize)
_, err = io.ReadFull(rand.Reader, newID)
if err != nil {
return Config{}, err
}
cfg.ID = hex.EncodeToString(newID)
cfg.Version = RepoVersion
debug.Log("Repo.CreateConfig", "New config: %#v", cfg)
_, err = r.SaveJSONUnpacked(backend.Config, cfg)
return cfg, err
}
// LoadConfig returns loads, checks and returns the config for a repository.
func LoadConfig(r JSONUnpackedLoader) (Config, error) {
var (
cfg Config
)
err := r.LoadJSONUnpacked(backend.Config, nil, &cfg)
if err != nil {
return Config{}, err
}
if cfg.Version != RepoVersion {
return Config{}, errors.New("unsupported repository version")
}
if !cfg.ChunkerPolynomial.Irreducible() {
return Config{}, errors.New("invalid chunker polynomial")
}
return cfg, nil
}

53
repository/config_test.go Normal file
View File

@ -0,0 +1,53 @@
package repository_test
import (
"testing"
"github.com/restic/restic/backend"
"github.com/restic/restic/repository"
. "github.com/restic/restic/test"
)
type saver func(backend.Type, interface{}) (backend.ID, error)
func (s saver) SaveJSONUnpacked(t backend.Type, arg interface{}) (backend.ID, error) {
return s(t, arg)
}
type loader func(backend.Type, backend.ID, interface{}) error
func (l loader) LoadJSONUnpacked(t backend.Type, id backend.ID, arg interface{}) error {
return l(t, id, arg)
}
func TestConfig(t *testing.T) {
resultConfig := repository.Config{}
save := func(tpe backend.Type, arg interface{}) (backend.ID, error) {
Assert(t, tpe == backend.Config,
"wrong backend type: got %v, wanted %v",
tpe, backend.Config)
cfg := arg.(repository.Config)
resultConfig = cfg
return backend.ID{}, nil
}
cfg1, err := repository.CreateConfig(saver(save))
OK(t, err)
load := func(tpe backend.Type, id backend.ID, arg interface{}) error {
Assert(t, tpe == backend.Config,
"wrong backend type: got %v, wanted %v",
tpe, backend.Config)
cfg := arg.(*repository.Config)
*cfg = resultConfig
return nil
}
cfg2, err := repository.LoadConfig(loader(load))
OK(t, err)
Assert(t, cfg1 == cfg2,
"configs aren't equal: %v != %v", cfg1, cfg2)
}

View File

@ -2,9 +2,7 @@ package repository
import ( import (
"bytes" "bytes"
"crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -19,13 +17,6 @@ import (
"github.com/restic/restic/pack" "github.com/restic/restic/pack"
) )
// Config contains the configuration for a repository.
type Config struct {
Version uint `json:"version"`
ID string `json:"id"`
ChunkerPolynomial chunker.Pol `json:"chunker_polynomial"`
}
// Repository is used to access a repository in a backend. // Repository is used to access a repository in a backend.
type Repository struct { type Repository struct {
be backend.Backend be backend.Backend
@ -526,47 +517,6 @@ func (r *Repository) loadIndex(id string) error {
return nil return nil
} }
const repositoryIDSize = sha256.Size
const RepoVersion = 1
func createConfig(r *Repository) (err error) {
r.Config.ChunkerPolynomial, err = chunker.RandomPolynomial()
if err != nil {
return err
}
newID := make([]byte, repositoryIDSize)
_, err = io.ReadFull(rand.Reader, newID)
if err != nil {
return err
}
r.Config.ID = hex.EncodeToString(newID)
r.Config.Version = RepoVersion
debug.Log("Repo.createConfig", "New config: %#v", r.Config)
_, err = r.SaveJSONUnpacked(backend.Config, r.Config)
return err
}
func (r *Repository) loadConfig(cfg *Config) error {
err := r.LoadJSONUnpacked(backend.Config, nil, cfg)
if err != nil {
return err
}
if cfg.Version != RepoVersion {
return errors.New("unsupported repository version")
}
if !cfg.ChunkerPolynomial.Irreducible() {
return errors.New("invalid chunker polynomial")
}
return nil
}
// SearchKey finds a key with the supplied password, afterwards the config is // SearchKey finds a key with the supplied password, afterwards the config is
// read and parsed. // read and parsed.
func (r *Repository) SearchKey(password string) error { func (r *Repository) SearchKey(password string) error {
@ -577,11 +527,12 @@ func (r *Repository) SearchKey(password string) error {
r.key = key.master r.key = key.master
r.keyName = key.Name() r.keyName = key.Name()
return r.loadConfig(&r.Config) r.Config, err = LoadConfig(r)
return err
} }
// Init creates a new master key with the supplied password and initializes the // Init creates a new master key with the supplied password, initializes and
// repository config. // saves the repository config.
func (r *Repository) Init(password string) error { func (r *Repository) Init(password string) error {
has, err := r.be.Test(backend.Config, "") has, err := r.be.Test(backend.Config, "")
if err != nil { if err != nil {
@ -598,7 +549,8 @@ func (r *Repository) Init(password string) error {
r.key = key.master r.key = key.master
r.keyName = key.Name() r.keyName = key.Name()
return createConfig(r) r.Config, err = CreateConfig(r)
return err
} }
func (r *Repository) Decrypt(ciphertext []byte) ([]byte, error) { func (r *Repository) Decrypt(ciphertext []byte) ([]byte, error) {