integrity: Add support for sha384
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 5 Apr 2019 09:40:02 +0000 (11:40 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 5 Apr 2019 14:35:07 +0000 (16:35 +0200)
Fixes #5815

docs/content/en/hugo-pipes/fingerprint.md
resources/resource_transformers/integrity/integrity.go
resources/resource_transformers/integrity/integrity_test.go [new file with mode: 0644]

index 96aa7f556b93337f0248497d70f51f8ade25f524..7aa3f100aab3641acd222b16637c912c3c488857 100755 (executable)
@@ -18,7 +18,7 @@ draft: false
 
 Fingerprinting and [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) can be applied to any asset file using `resources.Fingerpint` which takes two arguments, the resource object and a [hash function](https://en.wikipedia.org/wiki/Cryptographic_hash_function). 
 
-The default hash function is `sha256`. Other available functions are `sha512` and `md5`.
+The default hash function is `sha256`. Other available functions are `sha384` (from Hugo `0.55`), `sha512` and `md5`.
 
 Any so processed asset will bear a `.Data.Integrity` property containing an integrity string, which is made up of the name of the hash function, one hyphen and the base64-encoded hash sum.
 
index 90afafb88123396fcb8268418f6abdfc18e13266..95065603d0ff6d37548eff2c08451616e0830a5a 100644 (file)
@@ -19,11 +19,12 @@ import (
        "crypto/sha512"
        "encoding/base64"
        "encoding/hex"
-       "fmt"
        "hash"
        "html/template"
        "io"
 
+       "github.com/pkg/errors"
+
        "github.com/gohugoio/hugo/resources"
        "github.com/gohugoio/hugo/resources/resource"
 )
@@ -52,19 +53,10 @@ func (t *fingerprintTransformation) Key() resources.ResourceTransformationKey {
 // Transform creates a MD5 hash of the Resource content and inserts that hash before
 // the extension in the filename.
 func (t *fingerprintTransformation) Transform(ctx *resources.ResourceTransformationCtx) error {
-       algo := t.algo
-
-       var h hash.Hash
 
-       switch algo {
-       case "md5":
-               h = md5.New()
-       case "sha256":
-               h = sha256.New()
-       case "sha512":
-               h = sha512.New()
-       default:
-               return fmt.Errorf("unsupported crypto algo: %q, use either md5, sha256 or sha512", algo)
+       h, err := newHash(t.algo)
+       if err != nil {
+               return err
        }
 
        io.Copy(io.MultiWriter(h, ctx.To), ctx.From)
@@ -73,11 +65,26 @@ func (t *fingerprintTransformation) Transform(ctx *resources.ResourceTransformat
                return err
        }
 
-       ctx.Data["Integrity"] = integrity(algo, d)
+       ctx.Data["Integrity"] = integrity(t.algo, d)
        ctx.AddOutPathIdentifier("." + hex.EncodeToString(d[:]))
        return nil
 }
 
+func newHash(algo string) (hash.Hash, error) {
+       switch algo {
+       case "md5":
+               return md5.New(), nil
+       case "sha256":
+               return sha256.New(), nil
+       case "sha384":
+               return sha512.New384(), nil
+       case "sha512":
+               return sha512.New(), nil
+       default:
+               return nil, errors.Errorf("unsupported crypto algo: %q, use either md5, sha256, sha384 or sha512", algo)
+       }
+}
+
 // Fingerprint applies fingerprinting of the given resource and hash algorithm.
 // It defaults to sha256 if none given, and the options are md5, sha256 or sha512.
 // The same algo is used for both the fingerprinting part (aka cache busting) and
diff --git a/resources/resource_transformers/integrity/integrity_test.go b/resources/resource_transformers/integrity/integrity_test.go
new file mode 100644 (file)
index 0000000..7e32e32
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2019 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package integrity
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/require"
+)
+
+func TestHashFromAlgo(t *testing.T) {
+
+       for _, algo := range []struct {
+               name string
+               bits int
+       }{
+               {"md5", 128},
+               {"sha256", 256},
+               {"sha384", 384},
+               {"sha512", 512},
+               {"shaman", -1},
+       } {
+
+               t.Run(algo.name, func(t *testing.T) {
+                       assert := require.New(t)
+                       h, err := newHash(algo.name)
+                       if algo.bits > 0 {
+                               assert.NoError(err)
+                               assert.Equal(algo.bits/8, h.Size())
+                       } else {
+                               assert.Error(err)
+                               assert.Contains(err.Error(), "use either md5, sha256, sha384 or sha512")
+                       }
+
+               })
+       }
+}