138 lines
3.6 KiB
Go
138 lines
3.6 KiB
Go
package storage
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/theupdateframework/notary"
|
|
"github.com/theupdateframework/notary/tuf/data"
|
|
"github.com/theupdateframework/notary/tuf/utils"
|
|
)
|
|
|
|
// NewMemoryStore returns a MetadataStore that operates entirely in memory.
|
|
// Very useful for testing
|
|
func NewMemoryStore(seed map[data.RoleName][]byte) *MemoryStore {
|
|
var (
|
|
consistent = make(map[string][]byte)
|
|
initial = make(map[string][]byte)
|
|
)
|
|
// add all seed meta to consistent
|
|
for name, d := range seed {
|
|
checksum := sha256.Sum256(d)
|
|
path := utils.ConsistentName(name.String(), checksum[:])
|
|
initial[name.String()] = d
|
|
consistent[path] = d
|
|
}
|
|
|
|
return &MemoryStore{
|
|
data: initial,
|
|
consistent: consistent,
|
|
}
|
|
}
|
|
|
|
// MemoryStore implements a mock RemoteStore entirely in memory.
|
|
// For testing purposes only.
|
|
type MemoryStore struct {
|
|
data map[string][]byte
|
|
consistent map[string][]byte
|
|
}
|
|
|
|
// GetSized returns up to size bytes of data references by name.
|
|
// If size is "NoSizeLimit", this corresponds to "infinite," but we cut off at a
|
|
// predefined threshold "notary.MaxDownloadSize", as we will always know the
|
|
// size for everything but a timestamp and sometimes a root,
|
|
// neither of which should be exceptionally large
|
|
func (m MemoryStore) GetSized(name string, size int64) ([]byte, error) {
|
|
d, ok := m.data[name]
|
|
if ok {
|
|
if size == NoSizeLimit {
|
|
size = notary.MaxDownloadSize
|
|
}
|
|
if int64(len(d)) < size {
|
|
return d, nil
|
|
}
|
|
return d[:size], nil
|
|
}
|
|
d, ok = m.consistent[name]
|
|
if ok {
|
|
if int64(len(d)) < size {
|
|
return d, nil
|
|
}
|
|
return d[:size], nil
|
|
}
|
|
return nil, ErrMetaNotFound{Resource: name}
|
|
}
|
|
|
|
// Get returns the data associated with name
|
|
func (m MemoryStore) Get(name string) ([]byte, error) {
|
|
if d, ok := m.data[name]; ok {
|
|
return d, nil
|
|
}
|
|
if d, ok := m.consistent[name]; ok {
|
|
return d, nil
|
|
}
|
|
return nil, ErrMetaNotFound{Resource: name}
|
|
}
|
|
|
|
// Set sets the metadata value for the given name
|
|
func (m *MemoryStore) Set(name string, meta []byte) error {
|
|
m.data[name] = meta
|
|
|
|
parsedMeta := &data.SignedMeta{}
|
|
err := json.Unmarshal(meta, parsedMeta)
|
|
if err == nil {
|
|
// no parse error means this is metadata and not a key, so store by version
|
|
version := parsedMeta.Signed.Version
|
|
versionedName := fmt.Sprintf("%d.%s", version, name)
|
|
m.data[versionedName] = meta
|
|
}
|
|
|
|
checksum := sha256.Sum256(meta)
|
|
path := utils.ConsistentName(name, checksum[:])
|
|
m.consistent[path] = meta
|
|
return nil
|
|
}
|
|
|
|
// SetMulti sets multiple pieces of metadata for multiple names
|
|
// in a single operation.
|
|
func (m *MemoryStore) SetMulti(metas map[string][]byte) error {
|
|
for role, blob := range metas {
|
|
m.Set(role, blob)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Remove removes the metadata for a single role - if the metadata doesn't
|
|
// exist, no error is returned
|
|
func (m *MemoryStore) Remove(name string) error {
|
|
if meta, ok := m.data[name]; ok {
|
|
checksum := sha256.Sum256(meta)
|
|
path := utils.ConsistentName(name, checksum[:])
|
|
delete(m.data, name)
|
|
delete(m.consistent, path)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RemoveAll clears the existing memory store by setting this store as new empty one
|
|
func (m *MemoryStore) RemoveAll() error {
|
|
*m = *NewMemoryStore(nil)
|
|
return nil
|
|
}
|
|
|
|
// Location provides a human readable name for the storage location
|
|
func (m MemoryStore) Location() string {
|
|
return "memory"
|
|
}
|
|
|
|
// ListFiles returns a list of all files. The names returned should be
|
|
// usable with Get directly, with no modification.
|
|
func (m *MemoryStore) ListFiles() []string {
|
|
names := make([]string, 0, len(m.data))
|
|
for n := range m.data {
|
|
names = append(names, n)
|
|
}
|
|
return names
|
|
}
|