...

Source file src/github.com/docker/distribution/manifest/schema1/manifest.go

Documentation: github.com/docker/distribution/manifest/schema1

     1  package schema1
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/docker/distribution"
     8  	"github.com/docker/distribution/manifest"
     9  	"github.com/docker/libtrust"
    10  	"github.com/opencontainers/go-digest"
    11  )
    12  
    13  const (
    14  	// MediaTypeManifest specifies the mediaType for the current version. Note
    15  	// that for schema version 1, the the media is optionally "application/json".
    16  	MediaTypeManifest = "application/vnd.docker.distribution.manifest.v1+json"
    17  	// MediaTypeSignedManifest specifies the mediatype for current SignedManifest version
    18  	MediaTypeSignedManifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
    19  	// MediaTypeManifestLayer specifies the media type for manifest layers
    20  	MediaTypeManifestLayer = "application/vnd.docker.container.image.rootfs.diff+x-gtar"
    21  )
    22  
    23  var (
    24  	// SchemaVersion provides a pre-initialized version structure for this
    25  	// packages version of the manifest.
    26  	SchemaVersion = manifest.Versioned{
    27  		SchemaVersion: 1,
    28  	}
    29  )
    30  
    31  func init() {
    32  	schema1Func := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
    33  		sm := new(SignedManifest)
    34  		err := sm.UnmarshalJSON(b)
    35  		if err != nil {
    36  			return nil, distribution.Descriptor{}, err
    37  		}
    38  
    39  		desc := distribution.Descriptor{
    40  			Digest:    digest.FromBytes(sm.Canonical),
    41  			Size:      int64(len(sm.Canonical)),
    42  			MediaType: MediaTypeSignedManifest,
    43  		}
    44  		return sm, desc, err
    45  	}
    46  	err := distribution.RegisterManifestSchema(MediaTypeSignedManifest, schema1Func)
    47  	if err != nil {
    48  		panic(fmt.Sprintf("Unable to register manifest: %s", err))
    49  	}
    50  	err = distribution.RegisterManifestSchema("", schema1Func)
    51  	if err != nil {
    52  		panic(fmt.Sprintf("Unable to register manifest: %s", err))
    53  	}
    54  	err = distribution.RegisterManifestSchema("application/json", schema1Func)
    55  	if err != nil {
    56  		panic(fmt.Sprintf("Unable to register manifest: %s", err))
    57  	}
    58  }
    59  
    60  // FSLayer is a container struct for BlobSums defined in an image manifest
    61  type FSLayer struct {
    62  	// BlobSum is the tarsum of the referenced filesystem image layer
    63  	BlobSum digest.Digest `json:"blobSum"`
    64  }
    65  
    66  // History stores unstructured v1 compatibility information
    67  type History struct {
    68  	// V1Compatibility is the raw v1 compatibility information
    69  	V1Compatibility string `json:"v1Compatibility"`
    70  }
    71  
    72  // Manifest provides the base accessible fields for working with V2 image
    73  // format in the registry.
    74  type Manifest struct {
    75  	manifest.Versioned
    76  
    77  	// Name is the name of the image's repository
    78  	Name string `json:"name"`
    79  
    80  	// Tag is the tag of the image specified by this manifest
    81  	Tag string `json:"tag"`
    82  
    83  	// Architecture is the host architecture on which this image is intended to
    84  	// run
    85  	Architecture string `json:"architecture"`
    86  
    87  	// FSLayers is a list of filesystem layer blobSums contained in this image
    88  	FSLayers []FSLayer `json:"fsLayers"`
    89  
    90  	// History is a list of unstructured historical data for v1 compatibility
    91  	History []History `json:"history"`
    92  }
    93  
    94  // SignedManifest provides an envelope for a signed image manifest, including
    95  // the format sensitive raw bytes.
    96  type SignedManifest struct {
    97  	Manifest
    98  
    99  	// Canonical is the canonical byte representation of the ImageManifest,
   100  	// without any attached signatures. The manifest byte
   101  	// representation cannot change or it will have to be re-signed.
   102  	Canonical []byte `json:"-"`
   103  
   104  	// all contains the byte representation of the Manifest including signatures
   105  	// and is returned by Payload()
   106  	all []byte
   107  }
   108  
   109  // UnmarshalJSON populates a new SignedManifest struct from JSON data.
   110  func (sm *SignedManifest) UnmarshalJSON(b []byte) error {
   111  	sm.all = make([]byte, len(b))
   112  	// store manifest and signatures in all
   113  	copy(sm.all, b)
   114  
   115  	jsig, err := libtrust.ParsePrettySignature(b, "signatures")
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	// Resolve the payload in the manifest.
   121  	bytes, err := jsig.Payload()
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	// sm.Canonical stores the canonical manifest JSON
   127  	sm.Canonical = make([]byte, len(bytes))
   128  	copy(sm.Canonical, bytes)
   129  
   130  	// Unmarshal canonical JSON into Manifest object
   131  	var manifest Manifest
   132  	if err := json.Unmarshal(sm.Canonical, &manifest); err != nil {
   133  		return err
   134  	}
   135  
   136  	sm.Manifest = manifest
   137  
   138  	return nil
   139  }
   140  
   141  // References returns the descriptors of this manifests references
   142  func (sm SignedManifest) References() []distribution.Descriptor {
   143  	dependencies := make([]distribution.Descriptor, len(sm.FSLayers))
   144  	for i, fsLayer := range sm.FSLayers {
   145  		dependencies[i] = distribution.Descriptor{
   146  			MediaType: "application/vnd.docker.container.image.rootfs.diff+x-gtar",
   147  			Digest:    fsLayer.BlobSum,
   148  		}
   149  	}
   150  
   151  	return dependencies
   152  
   153  }
   154  
   155  // MarshalJSON returns the contents of raw. If Raw is nil, marshals the inner
   156  // contents. Applications requiring a marshaled signed manifest should simply
   157  // use Raw directly, since the the content produced by json.Marshal will be
   158  // compacted and will fail signature checks.
   159  func (sm *SignedManifest) MarshalJSON() ([]byte, error) {
   160  	if len(sm.all) > 0 {
   161  		return sm.all, nil
   162  	}
   163  
   164  	// If the raw data is not available, just dump the inner content.
   165  	return json.Marshal(&sm.Manifest)
   166  }
   167  
   168  // Payload returns the signed content of the signed manifest.
   169  func (sm SignedManifest) Payload() (string, []byte, error) {
   170  	return MediaTypeSignedManifest, sm.all, nil
   171  }
   172  
   173  // Signatures returns the signatures as provided by
   174  // (*libtrust.JSONSignature).Signatures. The byte slices are opaque jws
   175  // signatures.
   176  func (sm *SignedManifest) Signatures() ([][]byte, error) {
   177  	jsig, err := libtrust.ParsePrettySignature(sm.all, "signatures")
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  
   182  	// Resolve the payload in the manifest.
   183  	return jsig.Signatures()
   184  }
   185  

View as plain text