diff --git a/datamodel/low/v2/examples.go b/datamodel/low/v2/examples.go index ee90e30..b8bfa68 100644 --- a/datamodel/low/v2/examples.go +++ b/datamodel/low/v2/examples.go @@ -4,9 +4,12 @@ package v2 import ( + "crypto/sha256" + "fmt" "github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/index" "gopkg.in/yaml.v3" + "strings" ) // Examples represents a low-level Swagger / OpenAPI 2 Example object. @@ -70,3 +73,12 @@ func (e *Examples) Build(root *yaml.Node, _ *index.SpecIndex) error { } return nil } + +// Hash will return a consistent SHA256 Hash of the Examples object +func (e *Examples) Hash() [32]byte { + var f []string + for k := range e.Values { + f = append(f, fmt.Sprint(e.Values[k].Value)) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/datamodel/low/v2/response.go b/datamodel/low/v2/response.go index 6de361a..77e4af4 100644 --- a/datamodel/low/v2/response.go +++ b/datamodel/low/v2/response.go @@ -4,10 +4,13 @@ package v2 import ( + "crypto/sha256" + "fmt" "github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/index" "gopkg.in/yaml.v3" + "strings" ) // Response is a representation of a high-level Swagger / OpenAPI 2 Response object, backed by a low-level one. @@ -62,6 +65,24 @@ func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error { ValueNode: kN, } } - return nil } + +// Hash will return a consistent SHA256 Hash of the Response object +func (r *Response) Hash() [32]byte { + var f []string + if r.Description.Value != "" { + f = append(f, r.Description.Value) + } + if !r.Schema.IsEmpty() { + f = append(f, low.GenerateHashString(r.Schema.Value.Schema())) + } + for k := range r.Examples.Value.Values { + f = append(f, low.GenerateHashString(r.Examples.Value.Values[k].Value)) + } + for k := range r.Extensions { + f = append(f, fmt.Sprintf("%s-%x", k.Value, + sha256.Sum256([]byte(fmt.Sprint(r.Extensions[k].Value))))) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/datamodel/low/v3/link.go b/datamodel/low/v3/link.go index af01057..54f03fa 100644 --- a/datamodel/low/v3/link.go +++ b/datamodel/low/v3/link.go @@ -4,9 +4,12 @@ package v3 import ( + "crypto/sha256" + "fmt" "github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/index" "gopkg.in/yaml.v3" + "strings" ) // Link represents a low-level OpenAPI 3+ Link object. @@ -53,3 +56,31 @@ func (l *Link) Build(root *yaml.Node, idx *index.SpecIndex) error { l.Server = ser return nil } + +// Hash will return a consistent SHA256 Hash of the Link object +func (l *Link) Hash() [32]byte { + var f []string + if l.Description.Value != "" { + f = append(f, l.Description.Value) + } + if l.OperationRef.Value != "" { + f = append(f, l.OperationRef.Value) + } + if l.OperationId.Value != "" { + f = append(f, l.OperationId.Value) + } + if l.RequestBody.Value != "" { + f = append(f, l.RequestBody.Value) + } + if l.Server.Value != nil { + f = append(f, low.GenerateHashString(l.Server.Value)) + } + for k := range l.Parameters.Value { + f = append(f, fmt.Sprintf("%s-%s", k.Value, l.Parameters.Value[k].Value)) + } + for k := range l.Extensions { + f = append(f, fmt.Sprintf("%s-%x", k.Value, + sha256.Sum256([]byte(fmt.Sprint(l.Extensions[k].Value))))) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/datamodel/low/v3/response.go b/datamodel/low/v3/response.go index 3c004b0..5c56a7f 100644 --- a/datamodel/low/v3/response.go +++ b/datamodel/low/v3/response.go @@ -4,11 +4,13 @@ package v3 import ( + "crypto/sha256" "fmt" "github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/utils" "gopkg.in/yaml.v3" + "strings" ) // Responses represents a low-level OpenAPI 3+ Responses object. @@ -134,6 +136,27 @@ func (r *Response) Build(root *yaml.Node, idx *index.SpecIndex) error { ValueNode: linkValue, } } - return nil } + +// Hash will return a consistent SHA256 Hash of the Response object +func (r *Response) Hash() [32]byte { + var f []string + if r.Description.Value != "" { + f = append(f, r.Description.Value) + } + for k := range r.Headers.Value { + f = append(f, low.GenerateHashString(r.Headers.Value[k])) + } + for k := range r.Content.Value { + f = append(f, low.GenerateHashString(r.Content.Value[k])) + } + for k := range r.Links.Value { + f = append(f, low.GenerateHashString(r.Links.Value[k])) + } + for k := range r.Extensions { + f = append(f, fmt.Sprintf("%s-%x", k.Value, + sha256.Sum256([]byte(fmt.Sprint(r.Extensions[k].Value))))) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/datamodel/low/v3/server.go b/datamodel/low/v3/server.go index af428d3..74776c1 100644 --- a/datamodel/low/v3/server.go +++ b/datamodel/low/v3/server.go @@ -4,10 +4,12 @@ package v3 import ( + "crypto/sha256" "github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/utils" "gopkg.in/yaml.v3" + "strings" ) // Server represents a low-level OpenAPI 3+ Server object. @@ -57,3 +59,18 @@ func (s *Server) Build(root *yaml.Node, idx *index.SpecIndex) error { } return nil } + +// Hash will return a consistent SHA256 Hash of the Server object +func (s *Server) Hash() [32]byte { + var f []string + for k := range s.Variables.Value { + f = append(f, low.GenerateHashString(s.Variables.Value[k].Value)) + } + if !s.URL.IsEmpty() { + f = append(f, s.URL.Value) + } + if !s.Description.IsEmpty() { + f = append(f, s.Description.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/datamodel/low/v3/server_variable.go b/datamodel/low/v3/server_variable.go index 889a97d..18795e9 100644 --- a/datamodel/low/v3/server_variable.go +++ b/datamodel/low/v3/server_variable.go @@ -1,7 +1,9 @@ package v3 import ( + "crypto/sha256" "github.com/pb33f/libopenapi/datamodel/low" + "strings" ) // ServerVariable represents a low-level OpenAPI 3+ ServerVariable object. @@ -16,3 +18,18 @@ type ServerVariable struct { Default low.NodeReference[string] Description low.NodeReference[string] } + +// Hash will return a consistent SHA256 Hash of the ServerVariable object +func (s *ServerVariable) Hash() [32]byte { + var f []string + for k := range s.Enum { + f = append(f, s.Enum[k].Value) + } + if !s.Default.IsEmpty() { + f = append(f, s.Default.Value) + } + if !s.Description.IsEmpty() { + f = append(f, s.Description.Value) + } + return sha256.Sum256([]byte(strings.Join(f, "|"))) +} diff --git a/what-changed/model/response.go b/what-changed/model/response.go new file mode 100644 index 0000000..e6c99af --- /dev/null +++ b/what-changed/model/response.go @@ -0,0 +1,4 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model diff --git a/what-changed/model/server_variable.go b/what-changed/model/server_variable.go new file mode 100644 index 0000000..e6c99af --- /dev/null +++ b/what-changed/model/server_variable.go @@ -0,0 +1,4 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package model