mirror of
https://github.com/containers/skopeo.git
synced 2025-10-22 19:50:00 +00:00
The Docker Registry manifest upload should supply a Content-Type, and guessing from the contents is the easiest we can do right now. Also eliminate dockerutils.manifestMIMEType, it is making it too difficult to use the returned value to be worth the extra safety.
65 lines
2.2 KiB
Go
65 lines
2.2 KiB
Go
package dockerutils
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
|
|
"github.com/docker/libtrust"
|
|
)
|
|
|
|
// FIXME: Should we just use docker/distribution and docker/docker implementations directly?
|
|
|
|
const (
|
|
// DockerV2Schema1MIMEType MIME type represents Docker manifest schema 1
|
|
DockerV2Schema1MIMEType = "application/vnd.docker.distribution.manifest.v1+json"
|
|
// DockerV2Schema2MIMEType MIME type represents Docker manifest schema 2
|
|
DockerV2Schema2MIMEType = "application/vnd.docker.distribution.manifest.v2+json"
|
|
)
|
|
|
|
// GuessManifestMIMEType guesses MIME type of a manifest and returns it _if it is recognized_, or "" if unknown or unrecognized.
|
|
// FIXME? We should, in general, prefer out-of-band MIME type instead of blindly parsing the manifest,
|
|
// but we may not have such metadata available (e.g. when the manifest is a local file).
|
|
func GuessManifestMIMEType(manifest []byte) string {
|
|
// A subset of manifest fields; the rest is silently ignored by json.Unmarshal.
|
|
// Also docker/distribution/manifest.Versioned.
|
|
meta := struct {
|
|
MediaType string `json:"mediaType"`
|
|
SchemaVersion int `json:"schemaVersion"`
|
|
}{}
|
|
if err := json.Unmarshal(manifest, &meta); err != nil {
|
|
return ""
|
|
}
|
|
|
|
switch meta.MediaType {
|
|
case DockerV2Schema2MIMEType: // A recognized type.
|
|
return meta.MediaType
|
|
}
|
|
switch meta.SchemaVersion {
|
|
case 1:
|
|
return DockerV2Schema1MIMEType
|
|
case 2: // Really should not happen, meta.MediaType should have been set. But given the data, this is our best guess.
|
|
return DockerV2Schema2MIMEType
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ManifestDigest returns the a digest of a docker manifest, with any necessary implied transformations like stripping v1s1 signatures.
|
|
func ManifestDigest(manifest []byte) (string, error) {
|
|
if GuessManifestMIMEType(manifest) == DockerV2Schema1MIMEType {
|
|
sig, err := libtrust.ParsePrettySignature(manifest, "signatures")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
manifest, err = sig.Payload()
|
|
if err != nil {
|
|
// Coverage: This should never happen, libtrust's Payload() can fail only if joseBase64UrlDecode() fails, on a string
|
|
// that libtrust itself has josebase64UrlEncode()d
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
hash := sha256.Sum256(manifest)
|
|
return "sha256:" + hex.EncodeToString(hash[:]), nil
|
|
}
|