docs/server/storage/memory.go

151 lines
3.7 KiB
Go

package storage
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"sync"
"time"
)
type key struct {
algorithm string
public []byte
}
type ver struct {
version int
data []byte
createupdate time.Time
}
// MemStorage is really just designed for dev and testing. It is very
// inefficient in many scenarios
type MemStorage struct {
lock sync.Mutex
tufMeta map[string][]*ver
keys map[string]map[string]*key
checksums map[string]map[string]ver
}
// NewMemStorage instantiates a memStorage instance
func NewMemStorage() *MemStorage {
return &MemStorage{
tufMeta: make(map[string][]*ver),
keys: make(map[string]map[string]*key),
checksums: make(map[string]map[string]ver),
}
}
// UpdateCurrent updates the meta data for a specific role
func (st *MemStorage) UpdateCurrent(gun string, update MetaUpdate) error {
id := entryKey(gun, update.Role)
st.lock.Lock()
defer st.lock.Unlock()
if space, ok := st.tufMeta[id]; ok {
for _, v := range space {
if v.version >= update.Version {
return &ErrOldVersion{}
}
}
}
version := ver{version: update.Version, data: update.Data, createupdate: time.Now()}
st.tufMeta[id] = append(st.tufMeta[id], &version)
checksumBytes := sha256.Sum256(update.Data)
checksum := hex.EncodeToString(checksumBytes[:])
_, ok := st.checksums[gun]
if !ok {
st.checksums[gun] = make(map[string]ver)
}
st.checksums[gun][checksum] = version
return nil
}
// UpdateMany updates multiple TUF records
func (st *MemStorage) UpdateMany(gun string, updates []MetaUpdate) error {
for _, u := range updates {
if err := st.UpdateCurrent(gun, u); err != nil {
return err
}
}
return nil
}
// GetCurrent returns the createupdate date metadata for a given role, under a GUN.
func (st *MemStorage) GetCurrent(gun, role string) (*time.Time, []byte, error) {
id := entryKey(gun, role)
st.lock.Lock()
defer st.lock.Unlock()
space, ok := st.tufMeta[id]
if !ok || len(space) == 0 {
return nil, nil, ErrNotFound{}
}
return &(space[len(space)-1].createupdate), space[len(space)-1].data, nil
}
// GetChecksum returns the createupdate date and metadata for a given role, under a GUN.
func (st *MemStorage) GetChecksum(gun, role, checksum string) (*time.Time, []byte, error) {
st.lock.Lock()
defer st.lock.Unlock()
space, ok := st.checksums[gun][checksum]
if !ok || len(space.data) == 0 {
return nil, nil, ErrNotFound{}
}
return &(space.createupdate), space.data, nil
}
// Delete deletes all the metadata for a given GUN
func (st *MemStorage) Delete(gun string) error {
st.lock.Lock()
defer st.lock.Unlock()
for k := range st.tufMeta {
if strings.HasPrefix(k, gun) {
delete(st.tufMeta, k)
}
}
delete(st.checksums, gun)
return nil
}
// GetKey returns the public key material of the timestamp key of a given gun
func (st *MemStorage) GetKey(gun, role string) (algorithm string, public []byte, err error) {
// no need for lock. It's ok to return nil if an update
// wasn't observed
g, ok := st.keys[gun]
if !ok {
return "", nil, &ErrNoKey{gun: gun}
}
k, ok := g[role]
if !ok {
return "", nil, &ErrNoKey{gun: gun}
}
return k.algorithm, k.public, nil
}
// SetKey sets a key under a gun and role
func (st *MemStorage) SetKey(gun, role, algorithm string, public []byte) error {
k := &key{algorithm: algorithm, public: public}
st.lock.Lock()
defer st.lock.Unlock()
// we hold the lock so nothing will be able to race to write a key
// between checking and setting
_, _, err := st.GetKey(gun, role)
if _, ok := err.(*ErrNoKey); !ok {
return &ErrKeyExists{gun: gun, role: role}
}
_, ok := st.keys[gun]
if !ok {
st.keys[gun] = make(map[string]*key)
}
st.keys[gun][role] = k
return nil
}
func entryKey(gun, role string) string {
return fmt.Sprintf("%s.%s", gun, role)
}