...

Source file src/github.com/opencontainers/go-digest/digest.go

Documentation: github.com/opencontainers/go-digest

     1  // Copyright 2019, 2020 OCI Contributors
     2  // Copyright 2017 Docker, Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     https://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package digest
    17  
    18  import (
    19  	"fmt"
    20  	"hash"
    21  	"io"
    22  	"regexp"
    23  	"strings"
    24  )
    25  
    26  // Digest allows simple protection of hex formatted digest strings, prefixed
    27  // by their algorithm. Strings of type Digest have some guarantee of being in
    28  // the correct format and it provides quick access to the components of a
    29  // digest string.
    30  //
    31  // The following is an example of the contents of Digest types:
    32  //
    33  // 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
    34  //
    35  // This allows to abstract the digest behind this type and work only in those
    36  // terms.
    37  type Digest string
    38  
    39  // NewDigest returns a Digest from alg and a hash.Hash object.
    40  func NewDigest(alg Algorithm, h hash.Hash) Digest {
    41  	return NewDigestFromBytes(alg, h.Sum(nil))
    42  }
    43  
    44  // NewDigestFromBytes returns a new digest from the byte contents of p.
    45  // Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
    46  // functions. This is also useful for rebuilding digests from binary
    47  // serializations.
    48  func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
    49  	return NewDigestFromEncoded(alg, alg.Encode(p))
    50  }
    51  
    52  // NewDigestFromHex is deprecated. Please use NewDigestFromEncoded.
    53  func NewDigestFromHex(alg, hex string) Digest {
    54  	return NewDigestFromEncoded(Algorithm(alg), hex)
    55  }
    56  
    57  // NewDigestFromEncoded returns a Digest from alg and the encoded digest.
    58  func NewDigestFromEncoded(alg Algorithm, encoded string) Digest {
    59  	return Digest(fmt.Sprintf("%s:%s", alg, encoded))
    60  }
    61  
    62  // DigestRegexp matches valid digest types.
    63  var DigestRegexp = regexp.MustCompile(`[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+`)
    64  
    65  // DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
    66  var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)
    67  
    68  var (
    69  	// ErrDigestInvalidFormat returned when digest format invalid.
    70  	ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")
    71  
    72  	// ErrDigestInvalidLength returned when digest has invalid length.
    73  	ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")
    74  
    75  	// ErrDigestUnsupported returned when the digest algorithm is unsupported.
    76  	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
    77  )
    78  
    79  // Parse parses s and returns the validated digest object. An error will
    80  // be returned if the format is invalid.
    81  func Parse(s string) (Digest, error) {
    82  	d := Digest(s)
    83  	return d, d.Validate()
    84  }
    85  
    86  // FromReader consumes the content of rd until io.EOF, returning canonical digest.
    87  func FromReader(rd io.Reader) (Digest, error) {
    88  	return Canonical.FromReader(rd)
    89  }
    90  
    91  // FromBytes digests the input and returns a Digest.
    92  func FromBytes(p []byte) Digest {
    93  	return Canonical.FromBytes(p)
    94  }
    95  
    96  // FromString digests the input and returns a Digest.
    97  func FromString(s string) Digest {
    98  	return Canonical.FromString(s)
    99  }
   100  
   101  // Validate checks that the contents of d is a valid digest, returning an
   102  // error if not.
   103  func (d Digest) Validate() error {
   104  	s := string(d)
   105  	i := strings.Index(s, ":")
   106  	if i <= 0 || i+1 == len(s) {
   107  		return ErrDigestInvalidFormat
   108  	}
   109  	algorithm, encoded := Algorithm(s[:i]), s[i+1:]
   110  	if !algorithm.Available() {
   111  		if !DigestRegexpAnchored.MatchString(s) {
   112  			return ErrDigestInvalidFormat
   113  		}
   114  		return ErrDigestUnsupported
   115  	}
   116  	return algorithm.Validate(encoded)
   117  }
   118  
   119  // Algorithm returns the algorithm portion of the digest. This will panic if
   120  // the underlying digest is not in a valid format.
   121  func (d Digest) Algorithm() Algorithm {
   122  	return Algorithm(d[:d.sepIndex()])
   123  }
   124  
   125  // Verifier returns a writer object that can be used to verify a stream of
   126  // content against the digest. If the digest is invalid, the method will panic.
   127  func (d Digest) Verifier() Verifier {
   128  	return hashVerifier{
   129  		hash:   d.Algorithm().Hash(),
   130  		digest: d,
   131  	}
   132  }
   133  
   134  // Encoded returns the encoded portion of the digest. This will panic if the
   135  // underlying digest is not in a valid format.
   136  func (d Digest) Encoded() string {
   137  	return string(d[d.sepIndex()+1:])
   138  }
   139  
   140  // Hex is deprecated. Please use Digest.Encoded.
   141  func (d Digest) Hex() string {
   142  	return d.Encoded()
   143  }
   144  
   145  func (d Digest) String() string {
   146  	return string(d)
   147  }
   148  
   149  func (d Digest) sepIndex() int {
   150  	i := strings.Index(string(d), ":")
   151  
   152  	if i < 0 {
   153  		panic(fmt.Sprintf("no ':' separator in digest %q", d))
   154  	}
   155  
   156  	return i
   157  }
   158  

View as plain text