diff --git a/go.mod b/go.mod index 0f989045b..015b11409 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/gobuffalo/flect v1.0.2 github.com/google/gofuzz v1.2.0 github.com/google/uuid v1.6.0 - github.com/gorilla/schema v1.3.0 + github.com/gorilla/schema v1.4.1 github.com/graphql-go/graphql v0.8.1 github.com/graphql-go/handler v0.2.4 github.com/open-policy-agent/gatekeeper/v3 v3.0.0-00010101000000-000000000000 diff --git a/go.sum b/go.sum index 4ec34aa9b..379a368f9 100644 --- a/go.sum +++ b/go.sum @@ -280,8 +280,8 @@ github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/schema v1.3.0 h1:rbciOzXAx3IB8stEFnfTwO3sYa6EWlQk79XdyustPDA= -github.com/gorilla/schema v1.3.0/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= +github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= +github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= diff --git a/vendor/github.com/gorilla/schema/decoder.go b/vendor/github.com/gorilla/schema/decoder.go index 98f072e41..54c88ecb3 100644 --- a/vendor/github.com/gorilla/schema/decoder.go +++ b/vendor/github.com/gorilla/schema/decoder.go @@ -12,9 +12,13 @@ import ( "strings" ) +const ( + defaultMaxSize = 16000 +) + // NewDecoder returns a new Decoder. func NewDecoder() *Decoder { - return &Decoder{cache: newCache()} + return &Decoder{cache: newCache(), maxSize: defaultMaxSize} } // Decoder decodes values from a map[string][]string to a struct. @@ -22,6 +26,7 @@ type Decoder struct { cache *cache zeroEmpty bool ignoreUnknownKeys bool + maxSize int } // SetAliasTag changes the tag used to locate custom field aliases. @@ -54,6 +59,13 @@ func (d *Decoder) IgnoreUnknownKeys(i bool) { d.ignoreUnknownKeys = i } +// MaxSize limits the size of slices for URL nested arrays or object arrays. +// Choose MaxSize carefully; large values may create many zero-value slice elements. +// Example: "items.100000=apple" would create a slice with 100,000 empty strings. +func (d *Decoder) MaxSize(size int) { + d.maxSize = size +} + // RegisterConverter registers a converter function for a custom type. func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter) { d.cache.registerConverter(value, converterFunc) @@ -92,9 +104,9 @@ func (d *Decoder) Decode(dst interface{}, src map[string][]string) error { return nil } -//setDefaults sets the default values when the `default` tag is specified, -//default is supported on basic/primitive types and their pointers, -//nested structs can also have default tags +// setDefaults sets the default values when the `default` tag is specified, +// default is supported on basic/primitive types and their pointers, +// nested structs can also have default tags func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError { struc := d.cache.get(t) if struc == nil { @@ -104,6 +116,15 @@ func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError { errs := MultiError{} + if v.Type().Kind() == reflect.Struct { + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + if field.Type().Kind() == reflect.Ptr && field.IsNil() && v.Type().Field(i).Anonymous { + field.Set(reflect.New(field.Type().Elem())) + } + } + } + for _, f := range struc.fields { vCurrent := v.FieldByName(f.name) @@ -121,7 +142,7 @@ func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError { } else if f.typ.Kind() == reflect.Slice { vals := strings.Split(f.defaultValue, "|") - //check if slice has one of the supported types for defaults + // check if slice has one of the supported types for defaults if _, ok := builtinConverters[f.typ.Elem().Kind()]; !ok { errs.merge(MultiError{"default-" + f.name: errors.New("default option is supported only on: bool, float variants, string, unit variants types or their corresponding pointers or slices")}) continue @@ -129,10 +150,13 @@ func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError { defaultSlice := reflect.MakeSlice(f.typ, 0, cap(vals)) for _, val := range vals { - //this check is to handle if the wrong value is provided - if convertedVal := builtinConverters[f.typ.Elem().Kind()](val); convertedVal.IsValid() { - defaultSlice = reflect.Append(defaultSlice, convertedVal) + // this check is to handle if the wrong value is provided + convertedVal := builtinConverters[f.typ.Elem().Kind()](val) + if !convertedVal.IsValid() { + errs.merge(MultiError{"default-" + f.name: fmt.Errorf("failed setting default: %s is not compatible with field %s type", val, f.name)}) + break } + defaultSlice = reflect.Append(defaultSlice, convertedVal) } vCurrent.Set(defaultSlice) } else if f.typ.Kind() == reflect.Ptr { @@ -142,12 +166,12 @@ func (d *Decoder) setDefaults(t reflect.Type, v reflect.Value) MultiError { errs.merge(MultiError{"default-" + f.name: errors.New("default option is supported only on: bool, float variants, string, unit variants types or their corresponding pointers or slices")}) } - //this check is to handle if the wrong value is provided + // this check is to handle if the wrong value is provided if convertedVal := convertPointer(t1.Kind(), f.defaultValue); convertedVal.IsValid() { vCurrent.Set(convertedVal) } } else { - //this check is to handle if the wrong value is provided + // this check is to handle if the wrong value is provided if convertedVal := builtinConverters[f.typ.Kind()](f.defaultValue); convertedVal.IsValid() { vCurrent.Set(builtinConverters[f.typ.Kind()](f.defaultValue)) } @@ -290,6 +314,10 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values // Slice of structs. Let's go recursive. if len(parts) > 1 { idx := parts[0].index + // a defensive check to avoid creating a large slice based on user input index + if idx > d.maxSize { + return fmt.Errorf("%v index %d is larger than the configured maxSize %d", v.Kind(), idx, d.maxSize) + } if v.IsNil() || v.Len() < idx+1 { value := reflect.MakeSlice(t, idx+1, idx+1) if v.Len() < idx+1 { diff --git a/vendor/modules.txt b/vendor/modules.txt index fa54eea9e..bfd17bc38 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -371,7 +371,7 @@ github.com/googleapis/gax-go/v2/internal # github.com/gorilla/mux v1.8.1 ## explicit; go 1.20 github.com/gorilla/mux -# github.com/gorilla/schema v1.3.0 +# github.com/gorilla/schema v1.4.1 ## explicit; go 1.20 github.com/gorilla/schema # github.com/graphql-go/graphql v0.8.1