1package storage 2 3import ( 4 "crypto/sha256" 5 "encoding/json" 6 "fmt" 7 8 "github.com/theupdateframework/notary" 9 "github.com/theupdateframework/notary/tuf/data" 10 "github.com/theupdateframework/notary/tuf/utils" 11) 12 13// NewMemoryStore returns a MetadataStore that operates entirely in memory. 14// Very useful for testing 15func NewMemoryStore(seed map[data.RoleName][]byte) *MemoryStore { 16 var ( 17 consistent = make(map[string][]byte) 18 initial = make(map[string][]byte) 19 ) 20 // add all seed meta to consistent 21 for name, d := range seed { 22 checksum := sha256.Sum256(d) 23 path := utils.ConsistentName(name.String(), checksum[:]) 24 initial[name.String()] = d 25 consistent[path] = d 26 } 27 28 return &MemoryStore{ 29 data: initial, 30 consistent: consistent, 31 } 32} 33 34// MemoryStore implements a mock RemoteStore entirely in memory. 35// For testing purposes only. 36type MemoryStore struct { 37 data map[string][]byte 38 consistent map[string][]byte 39} 40 41// GetSized returns up to size bytes of data references by name. 42// If size is "NoSizeLimit", this corresponds to "infinite," but we cut off at a 43// predefined threshold "notary.MaxDownloadSize", as we will always know the 44// size for everything but a timestamp and sometimes a root, 45// neither of which should be exceptionally large 46func (m MemoryStore) GetSized(name string, size int64) ([]byte, error) { 47 d, ok := m.data[name] 48 if ok { 49 if size == NoSizeLimit { 50 size = notary.MaxDownloadSize 51 } 52 if int64(len(d)) < size { 53 return d, nil 54 } 55 return d[:size], nil 56 } 57 d, ok = m.consistent[name] 58 if ok { 59 if int64(len(d)) < size { 60 return d, nil 61 } 62 return d[:size], nil 63 } 64 return nil, ErrMetaNotFound{Resource: name} 65} 66 67// Get returns the data associated with name 68func (m MemoryStore) Get(name string) ([]byte, error) { 69 if d, ok := m.data[name]; ok { 70 return d, nil 71 } 72 if d, ok := m.consistent[name]; ok { 73 return d, nil 74 } 75 return nil, ErrMetaNotFound{Resource: name} 76} 77 78// Set sets the metadata value for the given name 79func (m *MemoryStore) Set(name string, meta []byte) error { 80 m.data[name] = meta 81 82 parsedMeta := &data.SignedMeta{} 83 err := json.Unmarshal(meta, parsedMeta) 84 if err == nil { 85 // no parse error means this is metadata and not a key, so store by version 86 version := parsedMeta.Signed.Version 87 versionedName := fmt.Sprintf("%d.%s", version, name) 88 m.data[versionedName] = meta 89 } 90 91 checksum := sha256.Sum256(meta) 92 path := utils.ConsistentName(name, checksum[:]) 93 m.consistent[path] = meta 94 return nil 95} 96 97// SetMulti sets multiple pieces of metadata for multiple names 98// in a single operation. 99func (m *MemoryStore) SetMulti(metas map[string][]byte) error { 100 for role, blob := range metas { 101 m.Set(role, blob) 102 } 103 return nil 104} 105 106// Remove removes the metadata for a single role - if the metadata doesn't 107// exist, no error is returned 108func (m *MemoryStore) Remove(name string) error { 109 if meta, ok := m.data[name]; ok { 110 checksum := sha256.Sum256(meta) 111 path := utils.ConsistentName(name, checksum[:]) 112 delete(m.data, name) 113 delete(m.consistent, path) 114 } 115 return nil 116} 117 118// RemoveAll clears the existing memory store by setting this store as new empty one 119func (m *MemoryStore) RemoveAll() error { 120 *m = *NewMemoryStore(nil) 121 return nil 122} 123 124// Location provides a human readable name for the storage location 125func (m MemoryStore) Location() string { 126 return "memory" 127} 128 129// ListFiles returns a list of all files. The names returned should be 130// usable with Get directly, with no modification. 131func (m *MemoryStore) ListFiles() []string { 132 names := make([]string, 0, len(m.data)) 133 for n := range m.data { 134 names = append(names, n) 135 } 136 return names 137} 138