mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 20:47:49 +00:00
Added hashing functions to all v2 and v3 models that handle security, thats the next target.
246 lines
8.4 KiB
Go
246 lines
8.4 KiB
Go
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package model
|
|
|
|
import (
|
|
"github.com/pb33f/libopenapi/datamodel/low"
|
|
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
|
"reflect"
|
|
)
|
|
|
|
type HeaderChanges struct {
|
|
PropertyChanges
|
|
SchemaChanges *SchemaChanges
|
|
ExamplesChanges map[string]*ExampleChanges
|
|
ContentChanges map[string]*MediaTypeChanges
|
|
ExtensionChanges *ExtensionChanges
|
|
|
|
// V2 changes
|
|
ItemsChanges *ItemsChanges
|
|
}
|
|
|
|
func (h *HeaderChanges) TotalChanges() int {
|
|
c := h.PropertyChanges.TotalChanges()
|
|
for k := range h.ExamplesChanges {
|
|
c += h.ExamplesChanges[k].TotalChanges()
|
|
}
|
|
for k := range h.ContentChanges {
|
|
c += h.ContentChanges[k].TotalChanges()
|
|
}
|
|
if h.ExtensionChanges != nil {
|
|
c += h.ExtensionChanges.TotalChanges()
|
|
}
|
|
if h.SchemaChanges != nil {
|
|
c += h.SchemaChanges.TotalChanges()
|
|
}
|
|
if h.ItemsChanges != nil {
|
|
c += h.ItemsChanges.TotalChanges()
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (h *HeaderChanges) TotalBreakingChanges() int {
|
|
c := h.PropertyChanges.TotalBreakingChanges()
|
|
for k := range h.ContentChanges {
|
|
c += h.ContentChanges[k].TotalBreakingChanges()
|
|
}
|
|
if h.ItemsChanges != nil {
|
|
c += h.ItemsChanges.TotalBreakingChanges()
|
|
}
|
|
if h.SchemaChanges != nil {
|
|
c += h.SchemaChanges.TotalBreakingChanges()
|
|
}
|
|
return c
|
|
}
|
|
|
|
func addOpenAPIHeaderProperties(left, right low.IsHeader, changes *[]*Change) []*PropertyCheck {
|
|
var props []*PropertyCheck
|
|
|
|
// style
|
|
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
|
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
|
|
|
// allow reserved
|
|
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
|
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, false)
|
|
|
|
// allow empty value
|
|
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
|
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
|
|
|
// explode
|
|
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
|
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
|
|
|
// example
|
|
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
|
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
|
|
|
// deprecated
|
|
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
|
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
|
|
|
// required
|
|
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
|
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
|
|
|
return props
|
|
}
|
|
|
|
func addSwaggerHeaderProperties(left, right low.IsHeader, changes *[]*Change) []*PropertyCheck {
|
|
var props []*PropertyCheck
|
|
|
|
// type
|
|
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
|
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
|
|
|
// format
|
|
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
|
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
|
|
|
// collection format
|
|
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
|
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
|
|
|
// maximum
|
|
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
|
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
|
|
|
// minimum
|
|
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
|
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
|
|
|
// exclusive maximum
|
|
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
|
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
|
|
|
// exclusive minimum
|
|
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
|
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
|
|
|
// max length
|
|
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
|
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
|
|
|
// min length
|
|
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
|
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
|
|
|
// pattern
|
|
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
|
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
|
|
|
// max items
|
|
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
|
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
|
|
|
// min items
|
|
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
|
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
|
|
|
// unique items
|
|
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
|
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
|
|
|
// multiple of
|
|
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
|
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
|
|
|
return props
|
|
}
|
|
|
|
func addCommonHeaderProperties(left, right low.IsHeader, changes *[]*Change) []*PropertyCheck {
|
|
var props []*PropertyCheck
|
|
|
|
// description
|
|
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
|
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
|
|
|
return props
|
|
}
|
|
|
|
func CompareHeadersV2(l, r *v2.Header) *HeaderChanges {
|
|
return CompareHeaders(l, r)
|
|
}
|
|
|
|
func CompareHeadersV3(l, r *v3.Header) *HeaderChanges {
|
|
return CompareHeaders(l, r)
|
|
}
|
|
|
|
func CompareHeaders(l, r any) *HeaderChanges {
|
|
|
|
var changes []*Change
|
|
var props []*PropertyCheck
|
|
hc := new(HeaderChanges)
|
|
|
|
// handle swagger.
|
|
if reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(r) {
|
|
lHeader := l.(*v2.Header)
|
|
rHeader := r.(*v2.Header)
|
|
|
|
// perform hash check to avoid further processing
|
|
if low.AreEqual(lHeader, rHeader) {
|
|
return nil
|
|
}
|
|
|
|
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
|
props = append(props, addSwaggerHeaderProperties(lHeader, rHeader, &changes)...)
|
|
|
|
// enum
|
|
if len(lHeader.Enum.Value) > 0 || len(rHeader.Enum.Value) > 0 {
|
|
ExtractStringValueSliceChanges(lHeader.Enum.Value, rHeader.Enum.Value, &changes, v3.EnumLabel)
|
|
}
|
|
|
|
// items
|
|
if !lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
|
if !low.AreEqual(lHeader.Items.Value, rHeader.Items.Value) {
|
|
hc.ItemsChanges = CompareItems(lHeader.Items.Value, rHeader.Items.Value)
|
|
}
|
|
}
|
|
if lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
|
CreateChange(&changes, ObjectAdded, v3.ItemsLabel, nil,
|
|
rHeader.Items.ValueNode, true, nil, rHeader.Items.Value)
|
|
}
|
|
if !lHeader.Items.IsEmpty() && rHeader.Items.IsEmpty() {
|
|
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, lHeader.Items.ValueNode,
|
|
nil, true, lHeader.Items.Value, nil)
|
|
}
|
|
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
|
}
|
|
|
|
// handle OpenAPI
|
|
if reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(r) {
|
|
lHeader := l.(*v3.Header)
|
|
rHeader := r.(*v3.Header)
|
|
|
|
// perform hash check to avoid further processing
|
|
if low.AreEqual(lHeader, rHeader) {
|
|
return nil
|
|
}
|
|
|
|
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
|
props = append(props, addOpenAPIHeaderProperties(lHeader, rHeader, &changes)...)
|
|
|
|
// header
|
|
if !lHeader.Schema.IsEmpty() || !rHeader.Schema.IsEmpty() {
|
|
hc.SchemaChanges = CompareSchemas(lHeader.Schema.Value, rHeader.Schema.Value)
|
|
}
|
|
|
|
// examples
|
|
hc.ExamplesChanges = CheckMapForChanges(lHeader.Examples.Value, rHeader.Examples.Value,
|
|
&changes, v3.ExamplesLabel, CompareExamples)
|
|
|
|
// content
|
|
hc.ContentChanges = CheckMapForChanges(lHeader.Content.Value, rHeader.Content.Value,
|
|
&changes, v3.ContentLabel, CompareMediaTypes)
|
|
|
|
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
|
|
|
}
|
|
CheckProperties(props)
|
|
hc.Changes = changes
|
|
return hc
|
|
}
|