2015-01-02 22:21:29 +01:00
|
|
|
package manifest
|
2014-11-22 04:29:08 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
|
2014-12-24 01:01:38 +01:00
|
|
|
"github.com/docker/distribution/digest"
|
2015-01-28 23:54:09 +01:00
|
|
|
"github.com/docker/libtrust"
|
2014-11-22 04:29:08 +01:00
|
|
|
)
|
|
|
|
|
2015-02-20 01:47:13 +01:00
|
|
|
// TODO(stevvooe): When we rev the manifest format, the contents of this
|
2015-06-04 17:35:14 +02:00
|
|
|
// package should be moved to manifest/v1.
|
2015-02-20 01:47:13 +01:00
|
|
|
|
|
|
|
const (
|
|
|
|
// ManifestMediaType specifies the mediaType for the current version. Note
|
|
|
|
// that for schema version 1, the the media is optionally
|
|
|
|
// "application/json".
|
|
|
|
ManifestMediaType = "application/vnd.docker.distribution.manifest.v1+json"
|
|
|
|
)
|
|
|
|
|
2014-11-22 04:29:08 +01:00
|
|
|
// 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
|
2015-01-03 02:54:01 +01:00
|
|
|
History []History `json:"history"`
|
2014-11-22 04:29:08 +01:00
|
|
|
}
|
|
|
|
|
2014-11-26 21:52:52 +01:00
|
|
|
// SignedManifest provides an envelope for a signed image manifest, including
|
|
|
|
// the format sensitive raw bytes. It contains fields to
|
2014-11-22 04:29:08 +01:00
|
|
|
type SignedManifest struct {
|
|
|
|
Manifest
|
|
|
|
|
|
|
|
// Raw is the byte representation of the ImageManifest, used for signature
|
2014-12-02 02:10:33 +01:00
|
|
|
// verification. The value of Raw must be used directly during
|
|
|
|
// serialization, or the signature check will fail. The manifest byte
|
|
|
|
// representation cannot change or it will have to be re-signed.
|
2014-11-22 04:29:08 +01:00
|
|
|
Raw []byte `json:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON populates a new ImageManifest struct from JSON data.
|
2014-11-26 21:52:52 +01:00
|
|
|
func (sm *SignedManifest) UnmarshalJSON(b []byte) error {
|
2014-11-22 04:29:08 +01:00
|
|
|
var manifest Manifest
|
|
|
|
if err := json.Unmarshal(b, &manifest); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-11-26 21:52:52 +01:00
|
|
|
sm.Manifest = manifest
|
2014-12-02 00:57:05 +01:00
|
|
|
sm.Raw = make([]byte, len(b), len(b))
|
|
|
|
copy(sm.Raw, b)
|
2014-11-22 04:29:08 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-01-28 23:54:09 +01:00
|
|
|
// Payload returns the raw, signed content of the signed manifest. The
|
|
|
|
// contents can be used to calculate the content identifier.
|
|
|
|
func (sm *SignedManifest) Payload() ([]byte, error) {
|
|
|
|
jsig, err := libtrust.ParsePrettySignature(sm.Raw, "signatures")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve the payload in the manifest.
|
|
|
|
return jsig.Payload()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signatures returns the signatures as provided by
|
|
|
|
// (*libtrust.JSONSignature).Signatures. The byte slices are opaque jws
|
|
|
|
// signatures.
|
|
|
|
func (sm *SignedManifest) Signatures() ([][]byte, error) {
|
|
|
|
jsig, err := libtrust.ParsePrettySignature(sm.Raw, "signatures")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve the payload in the manifest.
|
|
|
|
return jsig.Signatures()
|
|
|
|
}
|
|
|
|
|
2014-11-22 04:29:08 +01:00
|
|
|
// MarshalJSON returns the contents of raw. If Raw is nil, marshals the inner
|
2014-12-02 02:10:33 +01:00
|
|
|
// contents. Applications requiring a marshaled signed manifest should simply
|
2015-01-02 22:21:29 +01:00
|
|
|
// use Raw directly, since the the content produced by json.Marshal will be
|
2014-12-02 02:10:33 +01:00
|
|
|
// compacted and will fail signature checks.
|
2014-11-26 21:52:52 +01:00
|
|
|
func (sm *SignedManifest) MarshalJSON() ([]byte, error) {
|
|
|
|
if len(sm.Raw) > 0 {
|
|
|
|
return sm.Raw, nil
|
2014-11-22 04:29:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the raw data is not available, just dump the inner content.
|
2014-11-26 21:52:52 +01:00
|
|
|
return json.Marshal(&sm.Manifest)
|
2014-11-22 04:29:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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"`
|
|
|
|
}
|
|
|
|
|
2015-01-03 02:54:01 +01:00
|
|
|
// History stores unstructured v1 compatibility information
|
|
|
|
type History struct {
|
2014-11-22 04:29:08 +01:00
|
|
|
// V1Compatibility is the raw v1 compatibility information
|
|
|
|
V1Compatibility string `json:"v1Compatibility"`
|
|
|
|
}
|