github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/manifest/schema1/manifest.go (about) 1 package schema1 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "github.com/docker/distribution" 8 "github.com/docker/distribution/digest" 9 "github.com/docker/distribution/manifest" 10 "github.com/docker/libtrust" 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: MediaTypeManifest, 43 } 44 return sm, desc, err 45 } 46 err := distribution.RegisterManifestSchema(MediaTypeManifest, 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; charset=utf-8", 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 retuend 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), 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), 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 returnes 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 MediaTypeManifest, 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 }