| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | package server | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	"crypto/rand" | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	"crypto/sha256" | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	"encoding/hex" | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/backend" | 
					
						
							| 
									
										
										
										
											2015-04-06 00:22:19 +02:00
										 |  |  | 	"github.com/restic/restic/chunker" | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	"github.com/restic/restic/debug" | 
					
						
							|  |  |  | 	"github.com/restic/restic/pack" | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | // Config contains the configuration for a repository. | 
					
						
							|  |  |  | type Config struct { | 
					
						
							|  |  |  | 	Version           uint        `json:"version"` | 
					
						
							|  |  |  | 	ID                string      `json:"id"` | 
					
						
							|  |  |  | 	ChunkerPolynomial chunker.Pol `json:"chunker_polynomial"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Server is used to access a repository in a backend. | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | type Server struct { | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	be     backend.Backend | 
					
						
							|  |  |  | 	Config Config | 
					
						
							|  |  |  | 	key    *Key | 
					
						
							|  |  |  | 	idx    *Index | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pm    sync.Mutex | 
					
						
							|  |  |  | 	packs []*pack.Packer | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func NewServer(be backend.Backend) *Server { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return &Server{ | 
					
						
							|  |  |  | 		be:  be, | 
					
						
							|  |  |  | 		idx: NewIndex(), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | // Find loads the list of all blobs of type t and searches for names which start | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | // with prefix. If none is found, nil and ErrNoIDPrefixFound is returned. If | 
					
						
							|  |  |  | // more than one is found, nil and ErrMultipleIDMatches is returned. | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Find(t backend.Type, prefix string) (string, error) { | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 	return backend.Find(s.be, t, prefix) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FindSnapshot takes a string and tries to find a snapshot whose ID matches | 
					
						
							|  |  |  | // the string as closely as possible. | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) FindSnapshot(name string) (string, error) { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	return backend.FindSnapshot(s.be, name) | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // PrefixLength returns the number of bytes required so that all prefixes of | 
					
						
							|  |  |  | // all IDs of type t are unique. | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) PrefixLength(t backend.Type) (int, error) { | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 	return backend.PrefixLength(s.be, t) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | // Load tries to load and decrypt content identified by t and id from the | 
					
						
							|  |  |  | // backend. | 
					
						
							|  |  |  | func (s *Server) Load(t backend.Type, id backend.ID) ([]byte, error) { | 
					
						
							|  |  |  | 	debug.Log("Server.Load", "load %v with id %v", t, id.Str()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// load blob from pack | 
					
						
							|  |  |  | 	rd, err := s.be.Get(t, id.String()) | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		debug.Log("Server.Load", "error loading %v: %v", id.Str(), err) | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf, err := ioutil.ReadAll(rd) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	err = rd.Close() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	// check hash | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	if !backend.Hash(buf).Equal(id) { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 		return nil, errors.New("invalid data returned") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// decrypt | 
					
						
							|  |  |  | 	plain, err := s.Decrypt(buf) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return plain, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LoadBlob tries to load and decrypt content identified by t and id from a | 
					
						
							|  |  |  | // pack from the backend. | 
					
						
							|  |  |  | func (s *Server) LoadBlob(t pack.BlobType, id backend.ID) ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2015-04-29 23:47:50 +02:00
										 |  |  | 	debug.Log("Server.LoadBlob", "load %v with id %v", t, id.Str()) | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// lookup pack | 
					
						
							|  |  |  | 	packID, tpe, offset, length, err := s.idx.Lookup(id) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-29 23:47:50 +02:00
										 |  |  | 		debug.Log("Server.LoadBlob", "id %v not found in index: %v", id.Str(), err) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	if tpe != t { | 
					
						
							| 
									
										
										
										
											2015-04-29 23:47:50 +02:00
										 |  |  | 		debug.Log("Server.LoadBlob", "wrong type returned for %v: wanted %v, got %v", id.Str(), t, tpe) | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, fmt.Errorf("blob has wrong type %v (wanted: %v)", tpe, t) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-29 23:47:50 +02:00
										 |  |  | 	debug.Log("Server.LoadBlob", "id %v found in pack %v at offset %v (length %d)", id.Str(), packID.Str(), offset, length) | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// load blob from pack | 
					
						
							|  |  |  | 	rd, err := s.be.GetReader(backend.Data, packID.String(), offset, length) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-29 23:47:50 +02:00
										 |  |  | 		debug.Log("Server.LoadBlob", "error loading pack %v for %v: %v", packID.Str(), id.Str(), err) | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	buf, err := ioutil.ReadAll(rd) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = rd.Close() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// decrypt | 
					
						
							|  |  |  | 	plain, err := s.Decrypt(buf) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// check hash | 
					
						
							|  |  |  | 	if !backend.Hash(plain).Equal(id) { | 
					
						
							|  |  |  | 		return nil, errors.New("invalid data returned") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return plain, nil | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | // LoadJSONEncrypted decrypts the data and afterwards calls json.Unmarshal on | 
					
						
							|  |  |  | // the item. | 
					
						
							| 
									
										
										
										
											2015-05-03 17:14:12 +02:00
										 |  |  | func (s *Server) LoadJSONUnpacked(t backend.Type, id backend.ID, item interface{}) error { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// load blob from backend | 
					
						
							|  |  |  | 	rd, err := s.be.Get(t, id.String()) | 
					
						
							| 
									
										
										
										
											2015-03-28 15:07:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	defer rd.Close() | 
					
						
							| 
									
										
										
										
											2015-03-28 15:07:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// decrypt | 
					
						
							|  |  |  | 	decryptRd, err := s.key.DecryptFrom(rd) | 
					
						
							|  |  |  | 	defer decryptRd.Close() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// decode | 
					
						
							|  |  |  | 	decoder := json.NewDecoder(decryptRd) | 
					
						
							|  |  |  | 	err = decoder.Decode(item) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | // LoadJSONPack calls LoadBlob() to load a blob from the backend, decrypt the | 
					
						
							|  |  |  | // data and afterwards call json.Unmarshal on the item. | 
					
						
							|  |  |  | func (s *Server) LoadJSONPack(t pack.BlobType, id backend.ID, item interface{}) error { | 
					
						
							|  |  |  | 	// lookup pack | 
					
						
							|  |  |  | 	packID, _, offset, length, err := s.idx.Lookup(id) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// load blob from pack | 
					
						
							|  |  |  | 	rd, err := s.be.GetReader(backend.Data, packID.String(), offset, length) | 
					
						
							| 
									
										
										
										
											2015-02-15 23:48:59 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-22 00:21:56 +01:00
										 |  |  | 	defer rd.Close() | 
					
						
							| 
									
										
										
										
											2015-02-15 23:48:59 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// decrypt | 
					
						
							|  |  |  | 	decryptRd, err := s.key.DecryptFrom(rd) | 
					
						
							| 
									
										
										
										
											2015-02-17 23:37:45 +01:00
										 |  |  | 	defer decryptRd.Close() | 
					
						
							| 
									
										
										
										
											2015-02-15 23:48:59 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// decode | 
					
						
							| 
									
										
										
										
											2015-03-02 09:56:56 +01:00
										 |  |  | 	decoder := json.NewDecoder(decryptRd) | 
					
						
							| 
									
										
										
										
											2015-02-15 23:48:59 +01:00
										 |  |  | 	err = decoder.Decode(item) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-15 23:48:59 +01:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | const minPackSize = 4 * chunker.MiB | 
					
						
							|  |  |  | const maxPackSize = 16 * chunker.MiB | 
					
						
							|  |  |  | const maxPackers = 200 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // findPacker returns a packer for a new blob of size bytes. Either a new one is | 
					
						
							|  |  |  | // created or one is returned that already has some blobs. | 
					
						
							|  |  |  | func (s *Server) findPacker(size uint) (*pack.Packer, error) { | 
					
						
							|  |  |  | 	s.pm.Lock() | 
					
						
							|  |  |  | 	defer s.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// search for a suitable packer | 
					
						
							|  |  |  | 	if len(s.packs) > 0 { | 
					
						
							|  |  |  | 		debug.Log("Server.findPacker", "searching packer for %d bytes\n", size) | 
					
						
							|  |  |  | 		for i, p := range s.packs { | 
					
						
							|  |  |  | 			if p.Size()+size < maxPackSize { | 
					
						
							|  |  |  | 				debug.Log("Server.findPacker", "found packer %v", p) | 
					
						
							|  |  |  | 				// remove from list | 
					
						
							|  |  |  | 				s.packs = append(s.packs[:i], s.packs[i+1:]...) | 
					
						
							|  |  |  | 				return p, nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// no suitable packer found, return new | 
					
						
							|  |  |  | 	blob, err := s.be.Create() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	debug.Log("Server.findPacker", "create new pack %p", blob) | 
					
						
							|  |  |  | 	return pack.NewPacker(s.key.Master(), blob), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // insertPacker appends p to s.packs. | 
					
						
							|  |  |  | func (s *Server) insertPacker(p *pack.Packer) { | 
					
						
							|  |  |  | 	s.pm.Lock() | 
					
						
							|  |  |  | 	defer s.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.packs = append(s.packs, p) | 
					
						
							|  |  |  | 	debug.Log("Server.insertPacker", "%d packers\n", len(s.packs)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // savePacker stores p in the backend. | 
					
						
							|  |  |  | func (s *Server) savePacker(p *pack.Packer) error { | 
					
						
							|  |  |  | 	debug.Log("Server.savePacker", "save packer with %d blobs\n", p.Count()) | 
					
						
							|  |  |  | 	_, err := p.Finalize() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// move file to the final location | 
					
						
							|  |  |  | 	sid := p.ID() | 
					
						
							|  |  |  | 	err = p.Writer().(backend.Blob).Finalize(backend.Data, sid.String()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		debug.Log("Server.savePacker", "blob Finalize() error: %v", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	debug.Log("Server.savePacker", "saved as %v", sid.Str()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// update blobs in the index | 
					
						
							|  |  |  | 	for _, b := range p.Blobs() { | 
					
						
							|  |  |  | 		debug.Log("Server.savePacker", "  updating blob %v to pack %v", b.ID.Str(), sid.Str()) | 
					
						
							|  |  |  | 		s.idx.Store(b.Type, b.ID, sid, b.Offset, uint(b.Length)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // countPacker returns the number of open (unfinished) packers. | 
					
						
							|  |  |  | func (s *Server) countPacker() int { | 
					
						
							|  |  |  | 	s.pm.Lock() | 
					
						
							|  |  |  | 	defer s.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return len(s.packs) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Save encrypts data and stores it to the backend as type t. If data is small | 
					
						
							|  |  |  | // enough, it will be packed together with other small blobs. | 
					
						
							|  |  |  | func (s *Server) Save(t pack.BlobType, data []byte, id backend.ID) (backend.ID, error) { | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if id == nil { | 
					
						
							|  |  |  | 		// compute plaintext hash | 
					
						
							|  |  |  | 		id = backend.Hash(data) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	debug.Log("Server.Save", "save id %v (%v, %d bytes)", id.Str(), t, len(data)) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// get buf from the pool | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | 	ciphertext := getBuf() | 
					
						
							|  |  |  | 	defer freeBuf(ciphertext) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// encrypt blob | 
					
						
							| 
									
										
										
										
											2015-04-12 20:58:41 +02:00
										 |  |  | 	ciphertext, err := s.Encrypt(ciphertext, data) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// find suitable packer and add blob | 
					
						
							|  |  |  | 	packer, err := s.findPacker(uint(len(ciphertext))) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// save ciphertext | 
					
						
							|  |  |  | 	packer.Add(t, id, bytes.NewReader(ciphertext)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// add this id to the index, although we don't know yet in which pack it | 
					
						
							|  |  |  | 	// will be saved, the entry will be updated when the pack is written. | 
					
						
							|  |  |  | 	s.idx.Store(t, id, nil, 0, 0) | 
					
						
							|  |  |  | 	debug.Log("Server.Save", "saving stub for %v (%v) in index", id.Str, t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if the pack is not full enough and there are less than maxPackers | 
					
						
							|  |  |  | 	// packers, put back to the list | 
					
						
							|  |  |  | 	if packer.Size() < minPackSize && s.countPacker() < maxPackers { | 
					
						
							|  |  |  | 		debug.Log("Server.Save", "pack is not full enough (%d bytes)", packer.Size()) | 
					
						
							|  |  |  | 		s.insertPacker(packer) | 
					
						
							|  |  |  | 		return id, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// else write the pack to the backend | 
					
						
							|  |  |  | 	return id, s.savePacker(packer) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SaveFrom encrypts data read from rd and stores it in a pack in the backend as type t. | 
					
						
							|  |  |  | func (s *Server) SaveFrom(t pack.BlobType, id backend.ID, length uint, rd io.Reader) error { | 
					
						
							|  |  |  | 	debug.Log("Server.SaveFrom", "save id %v (%v, %d bytes)", id.Str(), t, length) | 
					
						
							|  |  |  | 	if id == nil { | 
					
						
							|  |  |  | 		return errors.New("id is nil") | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	buf, err := ioutil.ReadAll(rd) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	_, err = s.Save(t, buf, id) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | // SaveJSON serialises item as JSON and encrypts and saves it in a pack in the | 
					
						
							|  |  |  | // backend as type t. | 
					
						
							|  |  |  | func (s *Server) SaveJSON(t pack.BlobType, item interface{}) (backend.ID, error) { | 
					
						
							|  |  |  | 	debug.Log("Server.SaveJSON", "save %v blob", t) | 
					
						
							|  |  |  | 	buf := getBuf()[:0] | 
					
						
							|  |  |  | 	defer freeBuf(buf) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wr := bytes.NewBuffer(buf) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	enc := json.NewEncoder(wr) | 
					
						
							|  |  |  | 	err := enc.Encode(item) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("json.Encode: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	buf = wr.Bytes() | 
					
						
							|  |  |  | 	return s.Save(t, buf, nil) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SaveJSONUnpacked serialises item as JSON and encrypts and saves it in the | 
					
						
							|  |  |  | // backend as type t, without a pack. It returns the storage hash. | 
					
						
							|  |  |  | func (s *Server) SaveJSONUnpacked(t backend.Type, item interface{}) (backend.ID, error) { | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	// create file | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	blob, err := s.be.Create() | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	debug.Log("Server.SaveJSONUnpacked", "create new file %p", blob) | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// hash | 
					
						
							|  |  |  | 	hw := backend.NewHashingWriter(blob, sha256.New()) | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// encrypt blob | 
					
						
							|  |  |  | 	ewr := s.key.EncryptTo(hw) | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	enc := json.NewEncoder(ewr) | 
					
						
							|  |  |  | 	err = enc.Encode(item) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, fmt.Errorf("json.Encode: %v", err) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	err = ewr.Close() | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// finalize blob in the backend | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	sid := backend.ID(hw.Sum(nil)) | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	err = blob.Finalize(t, sid.String()) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-15 17:26:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return sid, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Flush saves all remaining packs. | 
					
						
							|  |  |  | func (s *Server) Flush() error { | 
					
						
							|  |  |  | 	s.pm.Lock() | 
					
						
							|  |  |  | 	defer s.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	debug.Log("Server.Flush", "manually flushing %d packs", len(s.packs)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, p := range s.packs { | 
					
						
							|  |  |  | 		err := s.savePacker(p) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s.packs = s.packs[:0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *Server) Backend() backend.Backend { | 
					
						
							|  |  |  | 	return s.be | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *Server) Index() *Index { | 
					
						
							|  |  |  | 	return s.idx | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetIndex instructs the server to use the given index. | 
					
						
							|  |  |  | func (s *Server) SetIndex(i *Index) { | 
					
						
							|  |  |  | 	s.idx = i | 
					
						
							| 
									
										
										
										
											2015-02-08 22:54:45 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | // SaveIndex saves all new packs in the index in the backend, returned is the | 
					
						
							|  |  |  | // storage ID. | 
					
						
							|  |  |  | func (s *Server) SaveIndex() (backend.ID, error) { | 
					
						
							|  |  |  | 	debug.Log("Server.SaveIndex", "Saving index") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// create blob | 
					
						
							|  |  |  | 	blob, err := s.be.Create() | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	debug.Log("Server.SaveIndex", "create new pack %p", blob) | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// hash | 
					
						
							|  |  |  | 	hw := backend.NewHashingWriter(blob, sha256.New()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// encrypt blob | 
					
						
							|  |  |  | 	ewr := s.key.EncryptTo(hw) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = s.idx.Encode(ewr) | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	err = ewr.Close() | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	// finalize blob in the backend | 
					
						
							|  |  |  | 	sid := backend.ID(hw.Sum(nil)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = blob.Finalize(backend.Index, sid.String()) | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2015-02-16 00:24:58 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	debug.Log("Server.SaveIndex", "Saved index as %v", sid.Str()) | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return sid, nil | 
					
						
							| 
									
										
										
										
											2015-01-10 23:40:10 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | // LoadIndex loads all index files from the backend and merges them with the | 
					
						
							|  |  |  | // current index. | 
					
						
							|  |  |  | func (s *Server) LoadIndex() error { | 
					
						
							|  |  |  | 	debug.Log("Server.LoadIndex", "Loading index") | 
					
						
							|  |  |  | 	done := make(chan struct{}) | 
					
						
							|  |  |  | 	defer close(done) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for id := range s.be.List(backend.Index, done) { | 
					
						
							|  |  |  | 		err := s.loadIndex(id) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // loadIndex loads the index id and merges it with the currently used index. | 
					
						
							|  |  |  | func (s *Server) loadIndex(id string) error { | 
					
						
							|  |  |  | 	debug.Log("Server.loadIndex", "Loading index %v", id[:8]) | 
					
						
							|  |  |  | 	before := len(s.idx.pack) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rd, err := s.be.Get(backend.Index, id) | 
					
						
							|  |  |  | 	defer rd.Close() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// decrypt | 
					
						
							|  |  |  | 	decryptRd, err := s.key.DecryptFrom(rd) | 
					
						
							|  |  |  | 	defer decryptRd.Close() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	idx, err := DecodeIndex(decryptRd) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		debug.Log("Server.loadIndex", "error while decoding index %v: %v", id, err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.idx.Merge(idx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	after := len(s.idx.pack) | 
					
						
							|  |  |  | 	debug.Log("Server.loadIndex", "Loaded index %v, added %v blobs", id[:8], after-before) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | const repositoryIDSize = sha256.Size | 
					
						
							|  |  |  | const RepositoryVersion = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *Server) createConfig() (err error) { | 
					
						
							|  |  |  | 	s.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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.Config.ID = hex.EncodeToString(newID) | 
					
						
							|  |  |  | 	s.Config.Version = RepositoryVersion | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	debug.Log("Server.createConfig", "New config: %#v", s.Config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, err = s.SaveJSONUnpacked(backend.Config, s.Config) | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *Server) loadConfig(cfg *Config) error { | 
					
						
							| 
									
										
										
										
											2015-05-03 17:42:01 +02:00
										 |  |  | 	err := s.LoadJSONUnpacked(backend.Config, nil, cfg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !cfg.ChunkerPolynomial.Irreducible() { | 
					
						
							|  |  |  | 		return errors.New("invalid chunker polynomial") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SearchKey tries to find a key for which the supplied password works, | 
					
						
							|  |  |  | // afterwards the repository config is read and parsed. | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | func (s *Server) SearchKey(password string) error { | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | 	key, err := SearchKey(s, password) | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.key = key | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	return s.loadConfig(&s.Config) | 
					
						
							| 
									
										
										
										
											2015-05-03 16:36:52 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-03 17:17:10 +02:00
										 |  |  | // CreateMasterKey creates a new key with the supplied password, afterwards the | 
					
						
							|  |  |  | // repository config is created. | 
					
						
							|  |  |  | func (s *Server) CreateMasterKey(password string) error { | 
					
						
							| 
									
										
										
										
											2015-05-03 17:46:18 +02:00
										 |  |  | 	has, err := s.Test(backend.Config, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if has { | 
					
						
							|  |  |  | 		return errors.New("repository master key and config already initialized") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	key, err := createMasterKey(s, password) | 
					
						
							| 
									
										
										
										
											2015-05-03 16:36:52 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.key = key | 
					
						
							| 
									
										
										
										
											2015-05-03 17:37:12 +02:00
										 |  |  | 	return s.createConfig() | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Decrypt(ciphertext []byte) ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | 	if s.key == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("key for server not set") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | 	return s.key.Decrypt(nil, ciphertext) | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Encrypt(ciphertext, plaintext []byte) ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | 	if s.key == nil { | 
					
						
							| 
									
										
										
										
											2015-04-12 20:58:41 +02:00
										 |  |  | 		return nil, errors.New("key for server not set") | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.key.Encrypt(ciphertext, plaintext) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Key() *Key { | 
					
						
							| 
									
										
										
										
											2014-12-21 18:10:19 +01:00
										 |  |  | 	return s.key | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | // Count returns the number of blobs of a given type in the backend. | 
					
						
							| 
									
										
										
										
											2015-04-26 17:44:38 +02:00
										 |  |  | func (s *Server) Count(t backend.Type) (n uint) { | 
					
						
							|  |  |  | 	for _ = range s.be.List(t, nil) { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 		n++ | 
					
						
							| 
									
										
										
										
											2015-02-21 15:32:48 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	return | 
					
						
							| 
									
										
										
										
											2015-02-21 15:32:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | // Proxy methods to backend | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Get(t backend.Type, name string) (io.ReadCloser, error) { | 
					
						
							|  |  |  | 	return s.be.Get(t, name) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *Server) List(t backend.Type, done <-chan struct{}) <-chan string { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	return s.be.List(t, done) | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Test(t backend.Type, name string) (bool, error) { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	return s.be.Test(t, name) | 
					
						
							| 
									
										
										
										
											2015-02-15 17:09:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Remove(t backend.Type, name string) error { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	return s.be.Remove(t, name) | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Close() error { | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 	return s.be.Close() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Delete() error { | 
					
						
							| 
									
										
										
										
											2014-12-21 17:02:49 +01:00
										 |  |  | 	if b, ok := s.be.(backend.Deleter); ok { | 
					
						
							|  |  |  | 		return b.Delete() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return errors.New("Delete() called for backend that does not implement this method") | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-14 11:56:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 14:46:15 +02:00
										 |  |  | func (s *Server) Location() string { | 
					
						
							| 
									
										
										
										
											2015-03-28 11:50:23 +01:00
										 |  |  | 	return s.be.Location() | 
					
						
							|  |  |  | } |