-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-
394
-
395
-
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
-
423
-
424
-
425
-
426
-
427
-
428
-
429
-
430
-
431
-
432
-
433
-
434
-
435
-
436
-
437
-
438
-
439
-
440
-
441
-
442
-
443
-
444
-
445
-
446
-
447
-
448
-
449
-
450
-
451
-
452
-
453
-
454
-
455
-
456
-
457
-
458
-
459
-
460
-
461
-
462
-
463
-
464
-
465
-
466
-
467
-
468
-
469
-
470
-
471
-
472
-
473
-
474
-
475
-
476
-
477
-
478
-
479
-
480
-
481
-
482
-
483
-
484
-
485
-
486
-
487
-
488
-
489
-
490
-
491
-
492
-
493
-
494
-
495
-
496
-
497
-
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
-
506
-
507
-
508
-
509
-
510
-
511
-
512
-
513
-
514
-
515
-
516
-
517
-
518
-
519
-
520
-
521
-
522
-
523
-
524
-
525
-
526
-
527
-
528
-
529
-
530
-
531
-
532
-
533
-
534
-
535
-
536
-
537
-
538
-
539
-
540
-
541
-
542
-
543
-
544
-
545
-
546
-
547
-
548
-
549
-
550
-
551
-
552
-
553
-
554
-
555
-
556
-
557
-
558
-
559
-
560
-
561
-
562
-
563
-
564
-
565
-
566
-
567
-
568
-
569
-
570
-
571
-
572
-
573
-
574
-
575
-
576
-
577
-
578
-
579
-
580
-
581
-
582
-
583
-
584
-
585
-
586
-
587
-
588
-
589
-
590
-
591
-
592
-
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
-
623
-
624
-
625
-
626
-
627
-
628
-
629
-
630
-
631
-
632
-
633
-
634
-
635
-
636
-
637
-
638
-
639
-
640
-
641
-
642
-
643
-
644
-
645
// Copyright 2015 go-swagger maintainers
//
// 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 validate
import (
"fmt"
"reflect"
"github.com/go-openapi/errors"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
)
// An EntityValidator is an interface for things that can validate entities
type EntityValidator interface {
Validate(interface{}) *Result
}
type valueValidator interface {
SetPath(path string)
Applies(interface{}, reflect.Kind) bool
Validate(interface{}) *Result
}
type itemsValidator struct {
items *spec.Items
root interface{}
path string
in string
validators []valueValidator
KnownFormats strfmt.Registry
}
func newItemsValidator(path, in string, items *spec.Items, root interface{}, formats strfmt.Registry) *itemsValidator {
iv := &itemsValidator{path: path, in: in, items: items, root: root, KnownFormats: formats}
iv.validators = []valueValidator{
&typeValidator{
Type: spec.StringOrArray([]string{items.Type}),
Nullable: items.Nullable,
Format: items.Format,
In: in,
Path: path,
},
iv.stringValidator(),
iv.formatValidator(),
iv.numberValidator(),
iv.sliceValidator(),
iv.commonValidator(),
}
return iv
}
func (i *itemsValidator) Validate(index int, data interface{}) *Result {
tpe := reflect.TypeOf(data)
kind := tpe.Kind()
mainResult := new(Result)
path := fmt.Sprintf("%s.%d", i.path, index)
for _, validator := range i.validators {
validator.SetPath(path)
if validator.Applies(i.root, kind) {
result := validator.Validate(data)
mainResult.Merge(result)
mainResult.Inc()
if result != nil && result.HasErrors() {
return mainResult
}
}
}
return mainResult
}
func (i *itemsValidator) commonValidator() valueValidator {
return &basicCommonValidator{
In: i.in,
Default: i.items.Default,
Enum: i.items.Enum,
}
}
func (i *itemsValidator) sliceValidator() valueValidator {
return &basicSliceValidator{
In: i.in,
Default: i.items.Default,
MaxItems: i.items.MaxItems,
MinItems: i.items.MinItems,
UniqueItems: i.items.UniqueItems,
Source: i.root,
Items: i.items.Items,
KnownFormats: i.KnownFormats,
}
}
func (i *itemsValidator) numberValidator() valueValidator {
return &numberValidator{
In: i.in,
Default: i.items.Default,
MultipleOf: i.items.MultipleOf,
Maximum: i.items.Maximum,
ExclusiveMaximum: i.items.ExclusiveMaximum,
Minimum: i.items.Minimum,
ExclusiveMinimum: i.items.ExclusiveMinimum,
Type: i.items.Type,
Format: i.items.Format,
}
}
func (i *itemsValidator) stringValidator() valueValidator {
return &stringValidator{
In: i.in,
Default: i.items.Default,
MaxLength: i.items.MaxLength,
MinLength: i.items.MinLength,
Pattern: i.items.Pattern,
AllowEmptyValue: false,
}
}
func (i *itemsValidator) formatValidator() valueValidator {
return &formatValidator{
In: i.in,
//Default: i.items.Default,
Format: i.items.Format,
KnownFormats: i.KnownFormats,
}
}
type basicCommonValidator struct {
Path string
In string
Default interface{}
Enum []interface{}
}
func (b *basicCommonValidator) SetPath(path string) {
b.Path = path
}
func (b *basicCommonValidator) Applies(source interface{}, kind reflect.Kind) bool {
switch source.(type) {
case *spec.Parameter, *spec.Schema, *spec.Header:
return true
}
return false
}
func (b *basicCommonValidator) Validate(data interface{}) (res *Result) {
if len(b.Enum) > 0 {
for _, enumValue := range b.Enum {
actualType := reflect.TypeOf(enumValue)
if actualType != nil { // Safeguard
expectedValue := reflect.ValueOf(data)
if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) {
return nil
}
}
}
}
return errorHelp.sErr(errors.EnumFail(b.Path, b.In, data, b.Enum))
}
return nil
}
// A HeaderValidator has very limited subset of validations to apply
type HeaderValidator struct {
name string
header *spec.Header
validators []valueValidator
KnownFormats strfmt.Registry
}
// NewHeaderValidator creates a new header validator object
func NewHeaderValidator(name string, header *spec.Header, formats strfmt.Registry) *HeaderValidator {
p := &HeaderValidator{name: name, header: header, KnownFormats: formats}
p.validators = []valueValidator{
&typeValidator{
Type: spec.StringOrArray([]string{header.Type}),
Nullable: header.Nullable,
Format: header.Format,
In: "header",
Path: name,
},
p.stringValidator(),
p.formatValidator(),
p.numberValidator(),
p.sliceValidator(),
p.commonValidator(),
}
return p
}
// Validate the value of the header against its schema
func (p *HeaderValidator) Validate(data interface{}) *Result {
result := new(Result)
tpe := reflect.TypeOf(data)
kind := tpe.Kind()
for _, validator := range p.validators {
if validator.Applies(p.header, kind) {
if err := validator.Validate(data); err != nil {
result.Merge(err)
if err.HasErrors() {
return result
}
}
}
}
return nil
}
func (p *HeaderValidator) commonValidator() valueValidator {
return &basicCommonValidator{
Path: p.name,
In: "response",
Default: p.header.Default,
Enum: p.header.Enum,
}
}
func (p *HeaderValidator) sliceValidator() valueValidator {
return &basicSliceValidator{
Path: p.name,
In: "response",
Default: p.header.Default,
MaxItems: p.header.MaxItems,
MinItems: p.header.MinItems,
UniqueItems: p.header.UniqueItems,
Items: p.header.Items,
Source: p.header,
KnownFormats: p.KnownFormats,
}
}
func (p *HeaderValidator) numberValidator() valueValidator {
return &numberValidator{
Path: p.name,
In: "response",
Default: p.header.Default,
MultipleOf: p.header.MultipleOf,
Maximum: p.header.Maximum,
ExclusiveMaximum: p.header.ExclusiveMaximum,
Minimum: p.header.Minimum,
ExclusiveMinimum: p.header.ExclusiveMinimum,
Type: p.header.Type,
Format: p.header.Format,
}
}
func (p *HeaderValidator) stringValidator() valueValidator {
return &stringValidator{
Path: p.name,
In: "response",
Default: p.header.Default,
Required: true,
MaxLength: p.header.MaxLength,
MinLength: p.header.MinLength,
Pattern: p.header.Pattern,
AllowEmptyValue: false,
}
}
func (p *HeaderValidator) formatValidator() valueValidator {
return &formatValidator{
Path: p.name,
In: "response",
//Default: p.header.Default,
Format: p.header.Format,
KnownFormats: p.KnownFormats,
}
}
// A ParamValidator has very limited subset of validations to apply
type ParamValidator struct {
param *spec.Parameter
validators []valueValidator
KnownFormats strfmt.Registry
}
// NewParamValidator creates a new param validator object
func NewParamValidator(param *spec.Parameter, formats strfmt.Registry) *ParamValidator {
p := &ParamValidator{param: param, KnownFormats: formats}
p.validators = []valueValidator{
&typeValidator{
Type: spec.StringOrArray([]string{param.Type}),
Nullable: param.Nullable,
Format: param.Format,
In: param.In,
Path: param.Name,
},
p.stringValidator(),
p.formatValidator(),
p.numberValidator(),
p.sliceValidator(),
p.commonValidator(),
}
return p
}
// Validate the data against the description of the parameter
func (p *ParamValidator) Validate(data interface{}) *Result {
result := new(Result)
tpe := reflect.TypeOf(data)
kind := tpe.Kind()
// TODO: validate type
for _, validator := range p.validators {
if validator.Applies(p.param, kind) {
if err := validator.Validate(data); err != nil {
result.Merge(err)
if err.HasErrors() {
return result
}
}
}
}
return nil
}
func (p *ParamValidator) commonValidator() valueValidator {
return &basicCommonValidator{
Path: p.param.Name,
In: p.param.In,
Default: p.param.Default,
Enum: p.param.Enum,
}
}
func (p *ParamValidator) sliceValidator() valueValidator {
return &basicSliceValidator{
Path: p.param.Name,
In: p.param.In,
Default: p.param.Default,
MaxItems: p.param.MaxItems,
MinItems: p.param.MinItems,
UniqueItems: p.param.UniqueItems,
Items: p.param.Items,
Source: p.param,
KnownFormats: p.KnownFormats,
}
}
func (p *ParamValidator) numberValidator() valueValidator {
return &numberValidator{
Path: p.param.Name,
In: p.param.In,
Default: p.param.Default,
MultipleOf: p.param.MultipleOf,
Maximum: p.param.Maximum,
ExclusiveMaximum: p.param.ExclusiveMaximum,
Minimum: p.param.Minimum,
ExclusiveMinimum: p.param.ExclusiveMinimum,
Type: p.param.Type,
Format: p.param.Format,
}
}
func (p *ParamValidator) stringValidator() valueValidator {
return &stringValidator{
Path: p.param.Name,
In: p.param.In,
Default: p.param.Default,
AllowEmptyValue: p.param.AllowEmptyValue,
Required: p.param.Required,
MaxLength: p.param.MaxLength,
MinLength: p.param.MinLength,
Pattern: p.param.Pattern,
}
}
func (p *ParamValidator) formatValidator() valueValidator {
return &formatValidator{
Path: p.param.Name,
In: p.param.In,
//Default: p.param.Default,
Format: p.param.Format,
KnownFormats: p.KnownFormats,
}
}
type basicSliceValidator struct {
Path string
In string
Default interface{}
MaxItems *int64
MinItems *int64
UniqueItems bool
Items *spec.Items
Source interface{}
itemsValidator *itemsValidator
KnownFormats strfmt.Registry
}
func (s *basicSliceValidator) SetPath(path string) {
s.Path = path
}
func (s *basicSliceValidator) Applies(source interface{}, kind reflect.Kind) bool {
switch source.(type) {
case *spec.Parameter, *spec.Items, *spec.Header:
return kind == reflect.Slice
}
return false
}
func (s *basicSliceValidator) Validate(data interface{}) *Result {
val := reflect.ValueOf(data)
size := int64(val.Len())
if s.MinItems != nil {
if err := MinItems(s.Path, s.In, size, *s.MinItems); err != nil {
return errorHelp.sErr(err)
}
}
if s.MaxItems != nil {
if err := MaxItems(s.Path, s.In, size, *s.MaxItems); err != nil {
return errorHelp.sErr(err)
}
}
if s.UniqueItems {
if err := UniqueItems(s.Path, s.In, data); err != nil {
return errorHelp.sErr(err)
}
}
if s.itemsValidator == nil && s.Items != nil {
s.itemsValidator = newItemsValidator(s.Path, s.In, s.Items, s.Source, s.KnownFormats)
}
if s.itemsValidator != nil {
for i := 0; i < int(size); i++ {
ele := val.Index(i)
if err := s.itemsValidator.Validate(i, ele.Interface()); err != nil && err.HasErrors() {
return err
}
}
}
return nil
}
/* unused
func (s *basicSliceValidator) hasDuplicates(value reflect.Value, size int) bool {
dict := make(map[interface{}]struct{})
for i := 0; i < size; i++ {
ele := value.Index(i)
if _, ok := dict[ele.Interface()]; ok {
return true
}
dict[ele.Interface()] = struct{}{}
}
return false
}
*/
type numberValidator struct {
Path string
In string
Default interface{}
MultipleOf *float64
Maximum *float64
ExclusiveMaximum bool
Minimum *float64
ExclusiveMinimum bool
// Allows for more accurate behavior regarding integers
Type string
Format string
}
func (n *numberValidator) SetPath(path string) {
n.Path = path
}
func (n *numberValidator) Applies(source interface{}, kind reflect.Kind) bool {
switch source.(type) {
case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header:
isInt := kind >= reflect.Int && kind <= reflect.Uint64
isFloat := kind == reflect.Float32 || kind == reflect.Float64
r := isInt || isFloat
debugLog("schema props validator for %q applies %t for %T (kind: %v) isInt=%t, isFloat=%t\n", n.Path, r, source, kind, isInt, isFloat)
return r
}
debugLog("schema props validator for %q applies %t for %T (kind: %v)\n", n.Path, false, source, kind)
return false
}
// Validate provides a validator for generic JSON numbers,
//
// By default, numbers are internally represented as float64.
// Formats float, or float32 may alter this behavior by mapping to float32.
// A special validation process is followed for integers, with optional "format":
// this is an attempt to provide a validation with native types.
//
// NOTE: since the constraint specified (boundary, multipleOf) is unmarshalled
// as float64, loss of information remains possible (e.g. on very large integers).
//
// Since this value directly comes from the unmarshalling, it is not possible
// at this stage of processing to check further and guarantee the correctness of such values.
//
// Normally, the JSON Number.MAX_SAFE_INTEGER (resp. Number.MIN_SAFE_INTEGER)
// would check we do not get such a loss.
//
// If this is the case, replace AddErrors() by AddWarnings() and IsValid() by !HasWarnings().
//
// TODO: consider replacing boundary check errors by simple warnings.
//
// TODO: default boundaries with MAX_SAFE_INTEGER are not checked (specific to json.Number?)
func (n *numberValidator) Validate(val interface{}) *Result {
res := new(Result)
resMultiple := new(Result)
resMinimum := new(Result)
resMaximum := new(Result)
// Used only to attempt to validate constraint on value,
// even though value or constraint specified do not match type and format
data := valueHelp.asFloat64(val)
// Is the provided value within the range of the specified numeric type and format?
res.AddErrors(IsValueValidAgainstRange(val, n.Type, n.Format, "Checked", n.Path))
if n.MultipleOf != nil {
// Is the constraint specifier within the range of the specific numeric type and format?
resMultiple.AddErrors(IsValueValidAgainstRange(*n.MultipleOf, n.Type, n.Format, "MultipleOf", n.Path))
if resMultiple.IsValid() {
// Constraint validated with compatible types
if err := MultipleOfNativeType(n.Path, n.In, val, *n.MultipleOf); err != nil {
resMultiple.Merge(errorHelp.sErr(err))
}
} else {
// Constraint nevertheless validated, converted as general number
if err := MultipleOf(n.Path, n.In, data, *n.MultipleOf); err != nil {
resMultiple.Merge(errorHelp.sErr(err))
}
}
}
// nolint: dupl
if n.Maximum != nil {
// Is the constraint specifier within the range of the specific numeric type and format?
resMaximum.AddErrors(IsValueValidAgainstRange(*n.Maximum, n.Type, n.Format, "Maximum boundary", n.Path))
if resMaximum.IsValid() {
// Constraint validated with compatible types
if err := MaximumNativeType(n.Path, n.In, val, *n.Maximum, n.ExclusiveMaximum); err != nil {
resMaximum.Merge(errorHelp.sErr(err))
}
} else {
// Constraint nevertheless validated, converted as general number
if err := Maximum(n.Path, n.In, data, *n.Maximum, n.ExclusiveMaximum); err != nil {
resMaximum.Merge(errorHelp.sErr(err))
}
}
}
// nolint: dupl
if n.Minimum != nil {
// Is the constraint specifier within the range of the specific numeric type and format?
resMinimum.AddErrors(IsValueValidAgainstRange(*n.Minimum, n.Type, n.Format, "Minimum boundary", n.Path))
if resMinimum.IsValid() {
// Constraint validated with compatible types
if err := MinimumNativeType(n.Path, n.In, val, *n.Minimum, n.ExclusiveMinimum); err != nil {
resMinimum.Merge(errorHelp.sErr(err))
}
} else {
// Constraint nevertheless validated, converted as general number
if err := Minimum(n.Path, n.In, data, *n.Minimum, n.ExclusiveMinimum); err != nil {
resMinimum.Merge(errorHelp.sErr(err))
}
}
}
res.Merge(resMultiple, resMinimum, resMaximum)
res.Inc()
return res
}
type stringValidator struct {
Default interface{}
Required bool
AllowEmptyValue bool
MaxLength *int64
MinLength *int64
Pattern string
Path string
In string
}
func (s *stringValidator) SetPath(path string) {
s.Path = path
}
func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool {
switch source.(type) {
case *spec.Parameter, *spec.Schema, *spec.Items, *spec.Header:
r := kind == reflect.String
debugLog("string validator for %q applies %t for %T (kind: %v)\n", s.Path, r, source, kind)
return r
}
debugLog("string validator for %q applies %t for %T (kind: %v)\n", s.Path, false, source, kind)
return false
}
func (s *stringValidator) Validate(val interface{}) *Result {
data, ok := val.(string)
if !ok {
return errorHelp.sErr(errors.InvalidType(s.Path, s.In, stringType, val))
}
if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") {
if err := RequiredString(s.Path, s.In, data); err != nil {
return errorHelp.sErr(err)
}
}
if s.MaxLength != nil {
if err := MaxLength(s.Path, s.In, data, *s.MaxLength); err != nil {
return errorHelp.sErr(err)
}
}
if s.MinLength != nil {
if err := MinLength(s.Path, s.In, data, *s.MinLength); err != nil {
return errorHelp.sErr(err)
}
}
if s.Pattern != "" {
if err := Pattern(s.Path, s.In, data, s.Pattern); err != nil {
return errorHelp.sErr(err)
}
}
return nil
}