chore: vendor

This commit is contained in:
2024-08-04 11:06:58 +02:00
parent 2a5985e44e
commit 04aec8232f
3557 changed files with 981078 additions and 1 deletions

View File

@ -0,0 +1,22 @@
package storage
import (
"errors"
"fmt"
)
var (
// ErrPathOutsideStore indicates that the returned path would be
// outside the store
ErrPathOutsideStore = errors.New("path outside file store")
)
// ErrMetaNotFound indicates we did not find a particular piece
// of metadata in the store
type ErrMetaNotFound struct {
Resource string
}
func (err ErrMetaNotFound) Error() string {
return fmt.Sprintf("%s trust data unavailable. Has a notary repository been initialized?", err.Resource)
}

View File

@ -0,0 +1,278 @@
package storage
import (
"bytes"
"encoding/pem"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/sirupsen/logrus"
"github.com/theupdateframework/notary"
)
// NewFileStore creates a fully configurable file store
func NewFileStore(baseDir, fileExt string) (*FilesystemStore, error) {
baseDir = filepath.Clean(baseDir)
if err := createDirectory(baseDir, notary.PrivExecPerms); err != nil {
return nil, err
}
if !strings.HasPrefix(fileExt, ".") {
fileExt = "." + fileExt
}
return &FilesystemStore{
baseDir: baseDir,
ext: fileExt,
}, nil
}
// NewPrivateKeyFileStorage initializes a new filestore for private keys, appending
// the notary.PrivDir to the baseDir.
func NewPrivateKeyFileStorage(baseDir, fileExt string) (*FilesystemStore, error) {
baseDir = filepath.Join(baseDir, notary.PrivDir)
myStore, err := NewFileStore(baseDir, fileExt)
myStore.migrateTo0Dot4()
return myStore, err
}
// NewPrivateSimpleFileStore is a wrapper to create an owner readable/writeable
// _only_ filestore
func NewPrivateSimpleFileStore(baseDir, fileExt string) (*FilesystemStore, error) {
return NewFileStore(baseDir, fileExt)
}
// FilesystemStore is a store in a locally accessible directory
type FilesystemStore struct {
baseDir string
ext string
}
func (f *FilesystemStore) moveKeyTo0Dot4Location(file string) {
keyID := filepath.Base(file)
fileDir := filepath.Dir(file)
d, _ := f.Get(file)
block, _ := pem.Decode(d)
if block == nil {
logrus.Warn("Key data for", file, "could not be decoded as a valid PEM block. The key will not been migrated and may not be available")
return
}
fileDir = strings.TrimPrefix(fileDir, notary.RootKeysSubdir)
fileDir = strings.TrimPrefix(fileDir, notary.NonRootKeysSubdir)
if fileDir != "" {
block.Headers["gun"] = filepath.ToSlash(fileDir[1:])
}
if strings.Contains(keyID, "_") {
role := strings.Split(keyID, "_")[1]
keyID = strings.TrimSuffix(keyID, "_"+role)
block.Headers["role"] = role
}
var keyPEM bytes.Buffer
// since block came from decoding the PEM bytes in the first place, and all we're doing is adding some headers we ignore the possibility of an error while encoding the block
pem.Encode(&keyPEM, block)
f.Set(keyID, keyPEM.Bytes())
}
func (f *FilesystemStore) migrateTo0Dot4() {
rootKeysSubDir := filepath.Clean(filepath.Join(f.Location(), notary.RootKeysSubdir))
nonRootKeysSubDir := filepath.Clean(filepath.Join(f.Location(), notary.NonRootKeysSubdir))
if _, err := os.Stat(rootKeysSubDir); !os.IsNotExist(err) && f.Location() != rootKeysSubDir {
if rootKeysSubDir == "" || rootKeysSubDir == "/" {
// making sure we don't remove a user's homedir
logrus.Warn("The directory for root keys is an unsafe value, we are not going to delete the directory. Please delete it manually")
} else {
// root_keys exists, migrate things from it
listOnlyRootKeysDirStore, _ := NewFileStore(rootKeysSubDir, f.ext)
for _, file := range listOnlyRootKeysDirStore.ListFiles() {
f.moveKeyTo0Dot4Location(filepath.Join(notary.RootKeysSubdir, file))
}
// delete the old directory
os.RemoveAll(rootKeysSubDir)
}
}
if _, err := os.Stat(nonRootKeysSubDir); !os.IsNotExist(err) && f.Location() != nonRootKeysSubDir {
if nonRootKeysSubDir == "" || nonRootKeysSubDir == "/" {
// making sure we don't remove a user's homedir
logrus.Warn("The directory for non root keys is an unsafe value, we are not going to delete the directory. Please delete it manually")
} else {
// tuf_keys exists, migrate things from it
listOnlyNonRootKeysDirStore, _ := NewFileStore(nonRootKeysSubDir, f.ext)
for _, file := range listOnlyNonRootKeysDirStore.ListFiles() {
f.moveKeyTo0Dot4Location(filepath.Join(notary.NonRootKeysSubdir, file))
}
// delete the old directory
os.RemoveAll(nonRootKeysSubDir)
}
}
// if we have a trusted_certificates folder, let's delete for a complete migration since it is unused by new clients
certsSubDir := filepath.Join(f.Location(), "trusted_certificates")
if certsSubDir == "" || certsSubDir == "/" {
logrus.Warn("The directory for trusted certificate is an unsafe value, we are not going to delete the directory. Please delete it manually")
} else {
os.RemoveAll(certsSubDir)
}
}
func (f *FilesystemStore) getPath(name string) (string, error) {
fileName := fmt.Sprintf("%s%s", name, f.ext)
fullPath := filepath.Join(f.baseDir, fileName)
if !strings.HasPrefix(fullPath, f.baseDir) {
return "", ErrPathOutsideStore
}
return fullPath, nil
}
// GetSized returns the meta for the given name (a role) up to size bytes
// If size is "NoSizeLimit", this corresponds to "infinite," but we cut off at a
// predefined threshold "notary.MaxDownloadSize". If the file is larger than size
// we return ErrMaliciousServer for consistency with the HTTPStore
func (f *FilesystemStore) GetSized(name string, size int64) ([]byte, error) {
p, err := f.getPath(name)
if err != nil {
return nil, err
}
file, err := os.Open(p)
if err != nil {
if os.IsNotExist(err) {
err = ErrMetaNotFound{Resource: name}
}
return nil, err
}
defer func() {
_ = file.Close()
}()
if size == NoSizeLimit {
size = notary.MaxDownloadSize
}
stat, err := file.Stat()
if err != nil {
return nil, err
}
if stat.Size() > size {
return nil, ErrMaliciousServer{}
}
l := io.LimitReader(file, size)
return ioutil.ReadAll(l)
}
// Get returns the meta for the given name.
func (f *FilesystemStore) Get(name string) ([]byte, error) {
p, err := f.getPath(name)
if err != nil {
return nil, err
}
meta, err := ioutil.ReadFile(p)
if err != nil {
if os.IsNotExist(err) {
err = ErrMetaNotFound{Resource: name}
}
return nil, err
}
return meta, nil
}
// SetMulti sets the metadata for multiple roles in one operation
func (f *FilesystemStore) SetMulti(metas map[string][]byte) error {
for role, blob := range metas {
err := f.Set(role, blob)
if err != nil {
return err
}
}
return nil
}
// Set sets the meta for a single role
func (f *FilesystemStore) Set(name string, meta []byte) error {
fp, err := f.getPath(name)
if err != nil {
return err
}
// Ensures the parent directories of the file we are about to write exist
err = os.MkdirAll(filepath.Dir(fp), notary.PrivExecPerms)
if err != nil {
return err
}
// if something already exists, just delete it and re-write it
os.RemoveAll(fp)
// Write the file to disk
return ioutil.WriteFile(fp, meta, notary.PrivNoExecPerms)
}
// RemoveAll clears the existing filestore by removing its base directory
func (f *FilesystemStore) RemoveAll() error {
return os.RemoveAll(f.baseDir)
}
// Remove removes the metadata for a single role - if the metadata doesn't
// exist, no error is returned
func (f *FilesystemStore) Remove(name string) error {
p, err := f.getPath(name)
if err != nil {
return err
}
return os.RemoveAll(p) // RemoveAll succeeds if path doesn't exist
}
// Location returns a human readable name for the storage location
func (f FilesystemStore) Location() string {
return f.baseDir
}
// ListFiles returns a list of all the filenames that can be used with Get*
// to retrieve content from this filestore
func (f FilesystemStore) ListFiles() []string {
files := make([]string, 0, 0)
filepath.Walk(f.baseDir, func(fp string, fi os.FileInfo, err error) error {
// If there are errors, ignore this particular file
if err != nil {
return nil
}
// Ignore if it is a directory
if fi.IsDir() {
return nil
}
// If this is a symlink, ignore it
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
return nil
}
// Only allow matches that end with our certificate extension (e.g. *.crt)
matched, _ := filepath.Match("*"+f.ext, fi.Name())
if matched {
// Find the relative path for this file relative to the base path.
fp, err = filepath.Rel(f.baseDir, fp)
if err != nil {
return err
}
trimmed := strings.TrimSuffix(fp, f.ext)
files = append(files, trimmed)
}
return nil
})
return files
}
// createDirectory receives a string of the path to a directory.
// It does not support passing files, so the caller has to remove
// the filename by doing filepath.Dir(full_path_to_file)
func createDirectory(dir string, perms os.FileMode) error {
// This prevents someone passing /path/to/dir and 'dir' not being created
// If two '//' exist, MkdirAll deals it with correctly
dir = dir + "/"
return os.MkdirAll(dir, perms)
}

View File

@ -0,0 +1,379 @@
// A Store that can fetch and set metadata on a remote server.
// Some API constraints:
// - Response bodies for error codes should be unmarshallable as:
// {"errors": [{..., "detail": <serialized validation error>}]}
// else validation error details, etc. will be unparsable. The errors
// should have a github.com/theupdateframework/notary/tuf/validation/SerializableError
// in the Details field.
// If writing your own server, please have a look at
// github.com/docker/distribution/registry/api/errcode
package storage
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"path"
"github.com/sirupsen/logrus"
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/tuf/data"
"github.com/theupdateframework/notary/tuf/validation"
)
const (
// MaxErrorResponseSize is the maximum size for an error message - 1KiB
MaxErrorResponseSize int64 = 1 << 10
// MaxKeySize is the maximum size for a stored TUF key - 256KiB
MaxKeySize = 256 << 10
)
// ErrServerUnavailable indicates an error from the server. code allows us to
// populate the http error we received
type ErrServerUnavailable struct {
code int
}
// NetworkError represents any kind of network error when attempting to make a request
type NetworkError struct {
Wrapped error
}
func (n NetworkError) Error() string {
if _, ok := n.Wrapped.(*url.Error); ok {
// QueryUnescape does the inverse transformation of QueryEscape,
// converting %AB into the byte 0xAB and '+' into ' ' (space).
// It returns an error if any % is not followed by two hexadecimal digits.
//
// If this happens, we log out the QueryUnescape error and return the
// original error to client.
res, err := url.QueryUnescape(n.Wrapped.Error())
if err != nil {
logrus.Errorf("unescape network error message failed: %s", err)
return n.Wrapped.Error()
}
return res
}
return n.Wrapped.Error()
}
func (err ErrServerUnavailable) Error() string {
if err.code == 401 {
return fmt.Sprintf("you are not authorized to perform this operation: server returned 401.")
}
return fmt.Sprintf("unable to reach trust server at this time: %d.", err.code)
}
// ErrMaliciousServer indicates the server returned a response that is highly suspected
// of being malicious. i.e. it attempted to send us more data than the known size of a
// particular role metadata.
type ErrMaliciousServer struct{}
func (err ErrMaliciousServer) Error() string {
return "trust server returned a bad response."
}
// ErrInvalidOperation indicates that the server returned a 400 response and
// propagate any body we received.
type ErrInvalidOperation struct {
msg string
}
func (err ErrInvalidOperation) Error() string {
if err.msg != "" {
return fmt.Sprintf("trust server rejected operation: %s", err.msg)
}
return "trust server rejected operation."
}
// HTTPStore manages pulling and pushing metadata from and to a remote
// service over HTTP. It assumes the URL structure of the remote service
// maps identically to the structure of the TUF repo:
// <baseURL>/<metaPrefix>/(root|targets|snapshot|timestamp).json
// <baseURL>/<targetsPrefix>/foo.sh
//
// If consistent snapshots are disabled, it is advised that caching is not
// enabled. Simple set a cachePath (and ensure it's writeable) to enable
// caching.
type HTTPStore struct {
baseURL url.URL
metaPrefix string
metaExtension string
keyExtension string
roundTrip http.RoundTripper
}
// NewNotaryServerStore returns a new HTTPStore against a URL which should represent a notary
// server
func NewNotaryServerStore(serverURL string, gun data.GUN, roundTrip http.RoundTripper) (RemoteStore, error) {
return NewHTTPStore(
serverURL+"/v2/"+gun.String()+"/_trust/tuf/",
"",
"json",
"key",
roundTrip,
)
}
// NewHTTPStore initializes a new store against a URL and a number of configuration options.
//
// In case of a nil `roundTrip`, a default offline store is used instead.
func NewHTTPStore(baseURL, metaPrefix, metaExtension, keyExtension string, roundTrip http.RoundTripper) (RemoteStore, error) {
base, err := url.Parse(baseURL)
if err != nil {
return nil, err
}
if !base.IsAbs() {
return nil, errors.New("HTTPStore requires an absolute baseURL")
}
if roundTrip == nil {
return &OfflineStore{}, nil
}
return &HTTPStore{
baseURL: *base,
metaPrefix: metaPrefix,
metaExtension: metaExtension,
keyExtension: keyExtension,
roundTrip: roundTrip,
}, nil
}
func tryUnmarshalError(resp *http.Response, defaultError error) error {
b := io.LimitReader(resp.Body, MaxErrorResponseSize)
bodyBytes, err := ioutil.ReadAll(b)
if err != nil {
return defaultError
}
var parsedErrors struct {
Errors []struct {
Detail validation.SerializableError `json:"detail"`
} `json:"errors"`
}
if err := json.Unmarshal(bodyBytes, &parsedErrors); err != nil {
return defaultError
}
if len(parsedErrors.Errors) != 1 {
return defaultError
}
err = parsedErrors.Errors[0].Detail.Error
if err == nil {
return defaultError
}
return err
}
func translateStatusToError(resp *http.Response, resource string) error {
switch resp.StatusCode {
case http.StatusOK:
return nil
case http.StatusNotFound:
return ErrMetaNotFound{Resource: resource}
case http.StatusBadRequest:
return tryUnmarshalError(resp, ErrInvalidOperation{})
default:
return ErrServerUnavailable{code: resp.StatusCode}
}
}
// GetSized downloads the named meta file with the given size. A short body
// is acceptable because in the case of timestamp.json, the size is a cap,
// not an exact length.
// If size is "NoSizeLimit", this corresponds to "infinite," but we cut off at a
// predefined threshold "notary.MaxDownloadSize".
func (s HTTPStore) GetSized(name string, size int64) ([]byte, error) {
url, err := s.buildMetaURL(name)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
return nil, err
}
resp, err := s.roundTrip.RoundTrip(req)
if err != nil {
return nil, NetworkError{Wrapped: err}
}
defer resp.Body.Close()
if err := translateStatusToError(resp, name); err != nil {
logrus.Debugf("received HTTP status %d when requesting %s.", resp.StatusCode, name)
return nil, err
}
if size == NoSizeLimit {
size = notary.MaxDownloadSize
}
if resp.ContentLength > size {
return nil, ErrMaliciousServer{}
}
logrus.Debugf("%d when retrieving metadata for %s", resp.StatusCode, name)
b := io.LimitReader(resp.Body, size)
body, err := ioutil.ReadAll(b)
if err != nil {
return nil, err
}
return body, nil
}
// Set sends a single piece of metadata to the TUF server
func (s HTTPStore) Set(name string, blob []byte) error {
return s.SetMulti(map[string][]byte{name: blob})
}
// Remove always fails, because we should never be able to delete metadata
// remotely
func (s HTTPStore) Remove(name string) error {
return ErrInvalidOperation{msg: "cannot delete individual metadata files"}
}
// NewMultiPartMetaRequest builds a request with the provided metadata updates
// in multipart form
func NewMultiPartMetaRequest(url string, metas map[string][]byte) (*http.Request, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
for role, blob := range metas {
part, err := writer.CreateFormFile("files", role)
if err != nil {
return nil, err
}
_, err = io.Copy(part, bytes.NewBuffer(blob))
if err != nil {
return nil, err
}
}
err := writer.Close()
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", writer.FormDataContentType())
return req, nil
}
// SetMulti does a single batch upload of multiple pieces of TUF metadata.
// This should be preferred for updating a remote server as it enable the server
// to remain consistent, either accepting or rejecting the complete update.
func (s HTTPStore) SetMulti(metas map[string][]byte) error {
url, err := s.buildMetaURL("")
if err != nil {
return err
}
req, err := NewMultiPartMetaRequest(url.String(), metas)
if err != nil {
return err
}
resp, err := s.roundTrip.RoundTrip(req)
if err != nil {
return NetworkError{Wrapped: err}
}
defer resp.Body.Close()
// if this 404's something is pretty wrong
return translateStatusToError(resp, "POST metadata endpoint")
}
// RemoveAll will attempt to delete all TUF metadata for a GUN
func (s HTTPStore) RemoveAll() error {
url, err := s.buildMetaURL("")
if err != nil {
return err
}
req, err := http.NewRequest("DELETE", url.String(), nil)
if err != nil {
return err
}
resp, err := s.roundTrip.RoundTrip(req)
if err != nil {
return NetworkError{Wrapped: err}
}
defer resp.Body.Close()
return translateStatusToError(resp, "DELETE metadata for GUN endpoint")
}
func (s HTTPStore) buildMetaURL(name string) (*url.URL, error) {
var filename string
if name != "" {
filename = fmt.Sprintf("%s.%s", name, s.metaExtension)
}
uri := path.Join(s.metaPrefix, filename)
return s.buildURL(uri)
}
func (s HTTPStore) buildKeyURL(name data.RoleName) (*url.URL, error) {
filename := fmt.Sprintf("%s.%s", name.String(), s.keyExtension)
uri := path.Join(s.metaPrefix, filename)
return s.buildURL(uri)
}
func (s HTTPStore) buildURL(uri string) (*url.URL, error) {
sub, err := url.Parse(uri)
if err != nil {
return nil, err
}
return s.baseURL.ResolveReference(sub), nil
}
// GetKey retrieves a public key from the remote server
func (s HTTPStore) GetKey(role data.RoleName) ([]byte, error) {
url, err := s.buildKeyURL(role)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
return nil, err
}
resp, err := s.roundTrip.RoundTrip(req)
if err != nil {
return nil, NetworkError{Wrapped: err}
}
defer resp.Body.Close()
if err := translateStatusToError(resp, role.String()+" key"); err != nil {
return nil, err
}
b := io.LimitReader(resp.Body, MaxKeySize)
body, err := ioutil.ReadAll(b)
if err != nil {
return nil, err
}
return body, nil
}
// RotateKey rotates a private key and returns the public component from the remote server
func (s HTTPStore) RotateKey(role data.RoleName) ([]byte, error) {
url, err := s.buildKeyURL(role)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url.String(), nil)
if err != nil {
return nil, err
}
resp, err := s.roundTrip.RoundTrip(req)
if err != nil {
return nil, NetworkError{Wrapped: err}
}
defer resp.Body.Close()
if err := translateStatusToError(resp, role.String()+" key"); err != nil {
return nil, err
}
b := io.LimitReader(resp.Body, MaxKeySize)
body, err := ioutil.ReadAll(b)
if err != nil {
return nil, err
}
return body, nil
}
// Location returns a human readable name for the storage location
func (s HTTPStore) Location() string {
return s.baseURL.Host
}

View File

@ -0,0 +1,39 @@
package storage
import (
"github.com/theupdateframework/notary/tuf/data"
)
// NoSizeLimit is represented as -1 for arguments to GetMeta
const NoSizeLimit int64 = -1
// MetadataStore must be implemented by anything that intends to interact
// with a store of TUF files
type MetadataStore interface {
GetSized(name string, size int64) ([]byte, error)
Set(name string, blob []byte) error
SetMulti(map[string][]byte) error
RemoveAll() error
Remove(name string) error
Location() string
}
// PublicKeyStore must be implemented by a key service
type PublicKeyStore interface {
GetKey(role data.RoleName) ([]byte, error)
RotateKey(role data.RoleName) ([]byte, error)
}
// RemoteStore is similar to LocalStore with the added expectation that it should
// provide a way to download targets once located
type RemoteStore interface {
MetadataStore
PublicKeyStore
}
// Bootstrapper is a thing that can set itself up
type Bootstrapper interface {
// Bootstrap instructs a configured Bootstrapper to perform
// its setup operations.
Bootstrap() error
}

View File

@ -0,0 +1,137 @@
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
}

View File

@ -0,0 +1,58 @@
package storage
import (
"github.com/theupdateframework/notary/tuf/data"
)
// ErrOffline is used to indicate we are operating offline
type ErrOffline struct{}
func (e ErrOffline) Error() string {
return "client is offline"
}
var err = ErrOffline{}
// OfflineStore is to be used as a placeholder for a nil store. It simply
// returns ErrOffline for every operation
type OfflineStore struct{}
// GetSized returns ErrOffline
func (es OfflineStore) GetSized(name string, size int64) ([]byte, error) {
return nil, err
}
// Set returns ErrOffline
func (es OfflineStore) Set(name string, blob []byte) error {
return err
}
// SetMulti returns ErrOffline
func (es OfflineStore) SetMulti(map[string][]byte) error {
return err
}
// Remove returns ErrOffline
func (es OfflineStore) Remove(name string) error {
return err
}
// GetKey returns ErrOffline
func (es OfflineStore) GetKey(role data.RoleName) ([]byte, error) {
return nil, err
}
// RotateKey returns ErrOffline
func (es OfflineStore) RotateKey(role data.RoleName) ([]byte, error) {
return nil, err
}
// RemoveAll return ErrOffline
func (es OfflineStore) RemoveAll() error {
return err
}
// Location returns a human readable name for the storage location
func (es OfflineStore) Location() string {
return "offline"
}