mirror of https://github.com/docker/docs.git
151 lines
3.7 KiB
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)
|
|
}
|