diff --git a/config/options.go b/config/options.go index d66ee2ff9..2411f6991 100644 --- a/config/options.go +++ b/config/options.go @@ -15,8 +15,6 @@ import ( "sync/atomic" "time" - "github.com/cespare/xxhash/v2" - "github.com/mitchellh/hashstructure" "github.com/spf13/viper" "gopkg.in/yaml.v2" @@ -26,6 +24,7 @@ import ( "github.com/pomerium/pomerium/internal/directory/google" "github.com/pomerium/pomerium/internal/directory/okta" "github.com/pomerium/pomerium/internal/directory/onelogin" + "github.com/pomerium/pomerium/internal/hashutil" "github.com/pomerium/pomerium/internal/identity/oauth" "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/telemetry" @@ -740,12 +739,7 @@ func (o *Options) GetOauthOptions() oauth.Options { // Checksum returns the checksum of the current options struct func (o *Options) Checksum() uint64 { - hash, err := hashstructure.Hash(o, &hashstructure.HashOptions{Hasher: xxhash.New()}) - if err != nil { - log.Warn().Err(err).Msg("config: checksum failure") - return 0 - } - return hash + return hashutil.MustHash(o) } // ApplySettings modifies the config options using the given protobuf settings. diff --git a/config/policy.go b/config/policy.go index a42c49d1f..c5467b978 100644 --- a/config/policy.go +++ b/config/policy.go @@ -12,10 +12,9 @@ import ( "strings" "time" - "github.com/cespare/xxhash/v2" "github.com/golang/protobuf/ptypes" - "github.com/mitchellh/hashstructure" + "github.com/pomerium/pomerium/internal/hashutil" "github.com/pomerium/pomerium/internal/identity" "github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/pkg/cryptutil" @@ -330,10 +329,7 @@ func (p *Policy) Validate() error { // Checksum returns the xxhash hash for the policy. func (p *Policy) Checksum() uint64 { - cs, _ := hashstructure.Hash(p, &hashstructure.HashOptions{ - Hasher: xxhash.New(), - }) - return cs + return hashutil.MustHash(p) } // RouteID returns a unique identifier for a route @@ -346,10 +342,7 @@ func (p *Policy) RouteID() uint64 { Regex: p.Regex, } - cs, _ := hashstructure.Hash(id, &hashstructure.HashOptions{ - Hasher: xxhash.New(), - }) - return cs + return hashutil.MustHash(id) } func (p *Policy) String() string { diff --git a/go.mod b/go.mod index 0a7612f72..01600368e 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/lithammer/shortuuid/v3 v3.0.4 - github.com/mitchellh/hashstructure v1.0.0 + github.com/mitchellh/hashstructure/v2 v2.0.1 github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09 github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce github.com/onsi/ginkgo v1.11.0 // indirect diff --git a/go.sum b/go.sum index 4d29ee947..60448ba4b 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,8 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= -github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/hashstructure/v2 v2.0.1 h1:L60q1+q7cXE4JeEJJKMnh2brFIe3rZxCihYAB61ypAY= +github.com/mitchellh/hashstructure/v2 v2.0.1/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= diff --git a/internal/databroker/config_source.go b/internal/databroker/config_source.go index 0a232fcb0..d9a754300 100644 --- a/internal/databroker/config_source.go +++ b/internal/databroker/config_source.go @@ -9,9 +9,9 @@ import ( "github.com/cenkalti/backoff/v4" "github.com/golang/protobuf/ptypes" - "github.com/mitchellh/hashstructure" "github.com/pomerium/pomerium/config" + "github.com/pomerium/pomerium/internal/hashutil" "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/telemetry/trace" "github.com/pomerium/pomerium/pkg/grpc" @@ -151,7 +151,7 @@ func (src *ConfigSource) runUpdater(cfg *config.Config) { ServiceName: cfg.Options.Services, SignedJWTKey: sharedKey, } - h, err := hashstructure.Hash(connectionOptions, nil) + h, err := hashutil.Hash(connectionOptions) if err != nil { log.Fatal().Err(err).Send() } diff --git a/internal/hashutil/hashutil.go b/internal/hashutil/hashutil.go index 8b2882cd4..15d0de0c5 100644 --- a/internal/hashutil/hashutil.go +++ b/internal/hashutil/hashutil.go @@ -1,22 +1,29 @@ -// Package hashutil provides NON-CRYPTOGRAPHIC utility functions for hashing +// Package hashutil provides NON-CRYPTOGRAPHIC utility functions for hashing. +// +// http://cyan4973.github.io/xxHash/ package hashutil import ( "github.com/cespare/xxhash/v2" - "github.com/mitchellh/hashstructure" + "github.com/mitchellh/hashstructure/v2" ) -// Hash returns the xxhash value of an arbitrary value or struct. Returns 0 -// on error. NOT SUITABLE FOR CRYTOGRAPHIC HASHING. -// -// http://cyan4973.github.io/xxHash/ -func Hash(v interface{}) uint64 { - opts := &hashstructure.HashOptions{ - Hasher: xxhash.New(), - } - hash, err := hashstructure.Hash(v, opts) +// MustHash returns the xxhash of an arbitrary value or struct. Returns 0 +// on error. +// NOT SUITABLE FOR CRYTOGRAPHIC HASHING. +func MustHash(v interface{}) uint64 { + hash, err := Hash(v) if err != nil { hash = 0 } return hash } + +// Hash returns the xxhash of an arbitrary value or struct. +// NOT SUITABLE FOR CRYTOGRAPHIC HASHING. +func Hash(v interface{}) (uint64, error) { + opts := &hashstructure.HashOptions{ + Hasher: xxhash.New(), + } + return hashstructure.Hash(v, hashstructure.FormatV2, opts) +} diff --git a/internal/hashutil/hashutil_test.go b/internal/hashutil/hashutil_test.go index 245ca3853..6b2d6c707 100644 --- a/internal/hashutil/hashutil_test.go +++ b/internal/hashutil/hashutil_test.go @@ -1,17 +1,22 @@ // Package hashutil provides NON-CRYPTOGRAPHIC utility functions for hashing package hashutil -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestHash(t *testing.T) { t.Parallel() tests := []struct { - name string - v interface{} - want uint64 + name string + v interface{} + want uint64 + wantErr bool }{ - {"string", "string", 6134271061086542852}, - {"num", 7, 609900476111905877}, + {"string", "string", 6134271061086542852, false}, + {"num", 7, 609900476111905877, false}, {"compound struct", struct { NESCarts []string numberOfCarts int @@ -19,17 +24,26 @@ func TestHash(t *testing.T) { []string{"Battletoads", "Mega Man 1", "Clash at Demonhead"}, 12, }, - 9061978360207659575}, + 1349584765528830812, false}, {"compound struct with embedded func (errors!)", struct { AnswerToEverythingFn func() int }{ func() int { return 42 }, }, - 0}, + 0, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := Hash(tt.v); got != tt.want { + if got := MustHash(tt.v); got != tt.want { + t.Errorf("MustHash() = %v, want %v", got, tt.want) + } + got, err := Hash(tt.v) + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + if got != tt.want { t.Errorf("Hash() = %v, want %v", got, tt.want) } })