126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
|
package storage
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/docker/libtrust"
|
||
|
|
||
|
"github.com/docker/docker-registry/digest"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
// ErrManifestUnknown is returned if the manifest is not known by the
|
||
|
// registry.
|
||
|
ErrManifestUnknown = fmt.Errorf("unknown manifest")
|
||
|
|
||
|
// ErrManifestUnverified is returned when the registry is unable to verify
|
||
|
// the manifest.
|
||
|
ErrManifestUnverified = fmt.Errorf("unverified manifest")
|
||
|
)
|
||
|
|
||
|
// Versioned provides a struct with just the manifest schemaVersion. Incoming
|
||
|
// content with unknown schema version can be decoded against this struct to
|
||
|
// check the version.
|
||
|
type Versioned struct {
|
||
|
// SchemaVersion is the image manifest schema that this image follows
|
||
|
SchemaVersion int `json:"schemaVersion"`
|
||
|
}
|
||
|
|
||
|
// Manifest provides the base accessible fields for working with V2 image
|
||
|
// format in the registry.
|
||
|
type Manifest struct {
|
||
|
Versioned
|
||
|
|
||
|
// Name is the name of the image's repository
|
||
|
Name string `json:"name"`
|
||
|
|
||
|
// Tag is the tag of the image specified by this manifest
|
||
|
Tag string `json:"tag"`
|
||
|
|
||
|
// Architecture is the host architecture on which this image is intended to
|
||
|
// run
|
||
|
Architecture string `json:"architecture"`
|
||
|
|
||
|
// FSLayers is a list of filesystem layer blobSums contained in this image
|
||
|
FSLayers []FSLayer `json:"fsLayers"`
|
||
|
|
||
|
// History is a list of unstructured historical data for v1 compatibility
|
||
|
History []ManifestHistory `json:"history"`
|
||
|
}
|
||
|
|
||
|
// Sign signs the manifest with the provided private key, returning a
|
||
|
// SignedManifest. This typically won't be used within the registry, except
|
||
|
// for testing.
|
||
|
func (m *Manifest) Sign(pk libtrust.PrivateKey) (*SignedManifest, error) {
|
||
|
p, err := json.Marshal(m)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
js, err := libtrust.NewJSONSignature(p)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if err := js.Sign(pk); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
pretty, err := js.PrettySignature("signatures")
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &SignedManifest{
|
||
|
Manifest: *m,
|
||
|
Raw: pretty,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// SignedManifest provides an envelope for
|
||
|
type SignedManifest struct {
|
||
|
Manifest
|
||
|
|
||
|
// Raw is the byte representation of the ImageManifest, used for signature
|
||
|
// verification. The manifest byte representation cannot change or it will
|
||
|
// have to be re-signed.
|
||
|
Raw []byte `json:"-"`
|
||
|
}
|
||
|
|
||
|
// UnmarshalJSON populates a new ImageManifest struct from JSON data.
|
||
|
func (m *SignedManifest) UnmarshalJSON(b []byte) error {
|
||
|
var manifest Manifest
|
||
|
if err := json.Unmarshal(b, &manifest); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
m.Manifest = manifest
|
||
|
m.Raw = b
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// MarshalJSON returns the contents of raw. If Raw is nil, marshals the inner
|
||
|
// contents.
|
||
|
func (m *SignedManifest) MarshalJSON() ([]byte, error) {
|
||
|
if len(m.Raw) > 0 {
|
||
|
return m.Raw, nil
|
||
|
}
|
||
|
|
||
|
// If the raw data is not available, just dump the inner content.
|
||
|
return json.Marshal(&m.Manifest)
|
||
|
}
|
||
|
|
||
|
// FSLayer is a container struct for BlobSums defined in an image manifest
|
||
|
type FSLayer struct {
|
||
|
// BlobSum is the tarsum of the referenced filesystem image layer
|
||
|
BlobSum digest.Digest `json:"blobSum"`
|
||
|
}
|
||
|
|
||
|
// ManifestHistory stores unstructured v1 compatibility information
|
||
|
type ManifestHistory struct {
|
||
|
// V1Compatibility is the raw v1 compatibility information
|
||
|
V1Compatibility string `json:"v1Compatibility"`
|
||
|
}
|