podman

Форк
0
450 строк · 14.5 Кб
1
// Copyright 2015 go-swagger maintainers
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package validate
16

17
import (
18
	"context"
19
	"fmt"
20
	"reflect"
21
	"strings"
22
	"unicode/utf8"
23

24
	"github.com/go-openapi/errors"
25
	"github.com/go-openapi/strfmt"
26
	"github.com/go-openapi/swag"
27
)
28

29
// Enum validates if the data is a member of the enum
30
func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
31
	return EnumCase(path, in, data, enum, true)
32
}
33

34
// EnumCase validates if the data is a member of the enum and may respect case-sensitivity for strings
35
func EnumCase(path, in string, data interface{}, enum interface{}, caseSensitive bool) *errors.Validation {
36
	val := reflect.ValueOf(enum)
37
	if val.Kind() != reflect.Slice {
38
		return nil
39
	}
40

41
	dataString := convertEnumCaseStringKind(data, caseSensitive)
42
	var values []interface{}
43
	for i := 0; i < val.Len(); i++ {
44
		ele := val.Index(i)
45
		enumValue := ele.Interface()
46
		if data != nil {
47
			if reflect.DeepEqual(data, enumValue) {
48
				return nil
49
			}
50
			enumString := convertEnumCaseStringKind(enumValue, caseSensitive)
51
			if dataString != nil && enumString != nil && strings.EqualFold(*dataString, *enumString) {
52
				return nil
53
			}
54
			actualType := reflect.TypeOf(enumValue)
55
			if actualType == nil { // Safeguard. Frankly, I don't know how we may get a nil
56
				continue
57
			}
58
			expectedValue := reflect.ValueOf(data)
59
			if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
60
				// Attempt comparison after type conversion
61
				if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) {
62
					return nil
63
				}
64
			}
65
		}
66
		values = append(values, enumValue)
67
	}
68
	return errors.EnumFail(path, in, data, values)
69
}
70

71
// convertEnumCaseStringKind converts interface if it is kind of string and case insensitivity is set
72
func convertEnumCaseStringKind(value interface{}, caseSensitive bool) *string {
73
	if caseSensitive {
74
		return nil
75
	}
76

77
	val := reflect.ValueOf(value)
78
	if val.Kind() != reflect.String {
79
		return nil
80
	}
81

82
	str := fmt.Sprintf("%v", value)
83
	return &str
84
}
85

86
// MinItems validates that there are at least n items in a slice
87
func MinItems(path, in string, size, min int64) *errors.Validation {
88
	if size < min {
89
		return errors.TooFewItems(path, in, min, size)
90
	}
91
	return nil
92
}
93

94
// MaxItems validates that there are at most n items in a slice
95
func MaxItems(path, in string, size, max int64) *errors.Validation {
96
	if size > max {
97
		return errors.TooManyItems(path, in, max, size)
98
	}
99
	return nil
100
}
101

102
// UniqueItems validates that the provided slice has unique elements
103
func UniqueItems(path, in string, data interface{}) *errors.Validation {
104
	val := reflect.ValueOf(data)
105
	if val.Kind() != reflect.Slice {
106
		return nil
107
	}
108
	var unique []interface{}
109
	for i := 0; i < val.Len(); i++ {
110
		v := val.Index(i).Interface()
111
		for _, u := range unique {
112
			if reflect.DeepEqual(v, u) {
113
				return errors.DuplicateItems(path, in)
114
			}
115
		}
116
		unique = append(unique, v)
117
	}
118
	return nil
119
}
120

121
// MinLength validates a string for minimum length
122
func MinLength(path, in, data string, minLength int64) *errors.Validation {
123
	strLen := int64(utf8.RuneCount([]byte(data)))
124
	if strLen < minLength {
125
		return errors.TooShort(path, in, minLength, data)
126
	}
127
	return nil
128
}
129

130
// MaxLength validates a string for maximum length
131
func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
132
	strLen := int64(utf8.RuneCount([]byte(data)))
133
	if strLen > maxLength {
134
		return errors.TooLong(path, in, maxLength, data)
135
	}
136
	return nil
137
}
138

139
// ReadOnly validates an interface for readonly
140
func ReadOnly(ctx context.Context, path, in string, data interface{}) *errors.Validation {
141

142
	// read only is only validated when operationType is request
143
	if op := extractOperationType(ctx); op != request {
144
		return nil
145
	}
146

147
	// data must be of zero value of its type
148
	val := reflect.ValueOf(data)
149
	if val.IsValid() {
150
		if reflect.DeepEqual(reflect.Zero(val.Type()).Interface(), val.Interface()) {
151
			return nil
152
		}
153
	} else {
154
		return nil
155
	}
156

157
	return errors.ReadOnly(path, in, data)
158
}
159

160
// Required validates an interface for requiredness
161
func Required(path, in string, data interface{}) *errors.Validation {
162
	val := reflect.ValueOf(data)
163
	if val.IsValid() {
164
		if reflect.DeepEqual(reflect.Zero(val.Type()).Interface(), val.Interface()) {
165
			return errors.Required(path, in, data)
166
		}
167
		return nil
168
	}
169
	return errors.Required(path, in, data)
170
}
171

172
// RequiredString validates a string for requiredness
173
func RequiredString(path, in, data string) *errors.Validation {
174
	if data == "" {
175
		return errors.Required(path, in, data)
176
	}
177
	return nil
178
}
179

180
// RequiredNumber validates a number for requiredness
181
func RequiredNumber(path, in string, data float64) *errors.Validation {
182
	if data == 0 {
183
		return errors.Required(path, in, data)
184
	}
185
	return nil
186
}
187

188
// Pattern validates a string against a regular expression
189
func Pattern(path, in, data, pattern string) *errors.Validation {
190
	re, err := compileRegexp(pattern)
191
	if err != nil {
192
		return errors.FailedPattern(path, in, fmt.Sprintf("%s, but pattern is invalid: %s", pattern, err.Error()), data)
193
	}
194
	if !re.MatchString(data) {
195
		return errors.FailedPattern(path, in, pattern, data)
196
	}
197
	return nil
198
}
199

200
// MaximumInt validates if a number is smaller than a given maximum
201
func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
202
	if (!exclusive && data > max) || (exclusive && data >= max) {
203
		return errors.ExceedsMaximumInt(path, in, max, exclusive, data)
204
	}
205
	return nil
206
}
207

208
// MaximumUint validates if a number is smaller than a given maximum
209
func MaximumUint(path, in string, data, max uint64, exclusive bool) *errors.Validation {
210
	if (!exclusive && data > max) || (exclusive && data >= max) {
211
		return errors.ExceedsMaximumUint(path, in, max, exclusive, data)
212
	}
213
	return nil
214
}
215

216
// Maximum validates if a number is smaller than a given maximum
217
func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
218
	if (!exclusive && data > max) || (exclusive && data >= max) {
219
		return errors.ExceedsMaximum(path, in, max, exclusive, data)
220
	}
221
	return nil
222
}
223

224
// Minimum validates if a number is smaller than a given minimum
225
func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
226
	if (!exclusive && data < min) || (exclusive && data <= min) {
227
		return errors.ExceedsMinimum(path, in, min, exclusive, data)
228
	}
229
	return nil
230
}
231

232
// MinimumInt validates if a number is smaller than a given minimum
233
func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
234
	if (!exclusive && data < min) || (exclusive && data <= min) {
235
		return errors.ExceedsMinimumInt(path, in, min, exclusive, data)
236
	}
237
	return nil
238
}
239

240
// MinimumUint validates if a number is smaller than a given minimum
241
func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
242
	if (!exclusive && data < min) || (exclusive && data <= min) {
243
		return errors.ExceedsMinimumUint(path, in, min, exclusive, data)
244
	}
245
	return nil
246
}
247

248
// MultipleOf validates if the provided number is a multiple of the factor
249
func MultipleOf(path, in string, data, factor float64) *errors.Validation {
250
	// multipleOf factor must be positive
251
	if factor <= 0 {
252
		return errors.MultipleOfMustBePositive(path, in, factor)
253
	}
254
	var mult float64
255
	if factor < 1 {
256
		mult = 1 / factor * data
257
	} else {
258
		mult = data / factor
259
	}
260
	if !swag.IsFloat64AJSONInteger(mult) {
261
		return errors.NotMultipleOf(path, in, factor, data)
262
	}
263
	return nil
264
}
265

266
// MultipleOfInt validates if the provided integer is a multiple of the factor
267
func MultipleOfInt(path, in string, data int64, factor int64) *errors.Validation {
268
	// multipleOf factor must be positive
269
	if factor <= 0 {
270
		return errors.MultipleOfMustBePositive(path, in, factor)
271
	}
272
	mult := data / factor
273
	if mult*factor != data {
274
		return errors.NotMultipleOf(path, in, factor, data)
275
	}
276
	return nil
277
}
278

279
// MultipleOfUint validates if the provided unsigned integer is a multiple of the factor
280
func MultipleOfUint(path, in string, data, factor uint64) *errors.Validation {
281
	// multipleOf factor must be positive
282
	if factor == 0 {
283
		return errors.MultipleOfMustBePositive(path, in, factor)
284
	}
285
	mult := data / factor
286
	if mult*factor != data {
287
		return errors.NotMultipleOf(path, in, factor, data)
288
	}
289
	return nil
290
}
291

292
// FormatOf validates if a string matches a format in the format registry
293
func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
294
	if registry == nil {
295
		registry = strfmt.Default
296
	}
297
	if ok := registry.ContainsName(format); !ok {
298
		return errors.InvalidTypeName(format)
299
	}
300
	if ok := registry.Validates(format, data); !ok {
301
		return errors.InvalidType(path, in, format, data)
302
	}
303
	return nil
304
}
305

306
// MaximumNativeType provides native type constraint validation as a facade
307
// to various numeric types versions of Maximum constraint check.
308
//
309
// Assumes that any possible loss conversion during conversion has been
310
// checked beforehand.
311
//
312
// NOTE: currently, the max value is marshalled as a float64, no matter what,
313
// which means there may be a loss during conversions (e.g. for very large integers)
314
//
315
// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free
316
func MaximumNativeType(path, in string, val interface{}, max float64, exclusive bool) *errors.Validation {
317
	kind := reflect.ValueOf(val).Type().Kind()
318
	switch kind {
319
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
320
		value := valueHelp.asInt64(val)
321
		return MaximumInt(path, in, value, int64(max), exclusive)
322
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
323
		value := valueHelp.asUint64(val)
324
		if max < 0 {
325
			return errors.ExceedsMaximum(path, in, max, exclusive, val)
326
		}
327
		return MaximumUint(path, in, value, uint64(max), exclusive)
328
	case reflect.Float32, reflect.Float64:
329
		fallthrough
330
	default:
331
		value := valueHelp.asFloat64(val)
332
		return Maximum(path, in, value, max, exclusive)
333
	}
334
}
335

336
// MinimumNativeType provides native type constraint validation as a facade
337
// to various numeric types versions of Minimum constraint check.
338
//
339
// Assumes that any possible loss conversion during conversion has been
340
// checked beforehand.
341
//
342
// NOTE: currently, the min value is marshalled as a float64, no matter what,
343
// which means there may be a loss during conversions (e.g. for very large integers)
344
//
345
// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free
346
func MinimumNativeType(path, in string, val interface{}, min float64, exclusive bool) *errors.Validation {
347
	kind := reflect.ValueOf(val).Type().Kind()
348
	switch kind {
349
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
350
		value := valueHelp.asInt64(val)
351
		return MinimumInt(path, in, value, int64(min), exclusive)
352
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
353
		value := valueHelp.asUint64(val)
354
		if min < 0 {
355
			return nil
356
		}
357
		return MinimumUint(path, in, value, uint64(min), exclusive)
358
	case reflect.Float32, reflect.Float64:
359
		fallthrough
360
	default:
361
		value := valueHelp.asFloat64(val)
362
		return Minimum(path, in, value, min, exclusive)
363
	}
364
}
365

366
// MultipleOfNativeType provides native type constraint validation as a facade
367
// to various numeric types version of MultipleOf constraint check.
368
//
369
// Assumes that any possible loss conversion during conversion has been
370
// checked beforehand.
371
//
372
// NOTE: currently, the multipleOf factor is marshalled as a float64, no matter what,
373
// which means there may be a loss during conversions (e.g. for very large integers)
374
//
375
// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free
376
func MultipleOfNativeType(path, in string, val interface{}, multipleOf float64) *errors.Validation {
377
	kind := reflect.ValueOf(val).Type().Kind()
378
	switch kind {
379
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
380
		value := valueHelp.asInt64(val)
381
		return MultipleOfInt(path, in, value, int64(multipleOf))
382
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
383
		value := valueHelp.asUint64(val)
384
		return MultipleOfUint(path, in, value, uint64(multipleOf))
385
	case reflect.Float32, reflect.Float64:
386
		fallthrough
387
	default:
388
		value := valueHelp.asFloat64(val)
389
		return MultipleOf(path, in, value, multipleOf)
390
	}
391
}
392

393
// IsValueValidAgainstRange checks that a numeric value is compatible with
394
// the range defined by Type and Format, that is, may be converted without loss.
395
//
396
// NOTE: this check is about type capacity and not formal verification such as: 1.0 != 1L
397
func IsValueValidAgainstRange(val interface{}, typeName, format, prefix, path string) error {
398
	kind := reflect.ValueOf(val).Type().Kind()
399

400
	// What is the string representation of val
401
	var stringRep string
402
	switch kind {
403
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
404
		stringRep = swag.FormatUint64(valueHelp.asUint64(val))
405
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
406
		stringRep = swag.FormatInt64(valueHelp.asInt64(val))
407
	case reflect.Float32, reflect.Float64:
408
		stringRep = swag.FormatFloat64(valueHelp.asFloat64(val))
409
	default:
410
		return fmt.Errorf("%s value number range checking called with invalid (non numeric) val type in %s", prefix, path)
411
	}
412

413
	var errVal error
414

415
	switch typeName {
416
	case integerType:
417
		switch format {
418
		case integerFormatInt32:
419
			_, errVal = swag.ConvertInt32(stringRep)
420
		case integerFormatUInt32:
421
			_, errVal = swag.ConvertUint32(stringRep)
422
		case integerFormatUInt64:
423
			_, errVal = swag.ConvertUint64(stringRep)
424
		case integerFormatInt64:
425
			fallthrough
426
		default:
427
			_, errVal = swag.ConvertInt64(stringRep)
428
		}
429
	case numberType:
430
		fallthrough
431
	default:
432
		switch format {
433
		case numberFormatFloat, numberFormatFloat32:
434
			_, errVal = swag.ConvertFloat32(stringRep)
435
		case numberFormatDouble, numberFormatFloat64:
436
			fallthrough
437
		default:
438
			// No check can be performed here since
439
			// no number beyond float64 is supported
440
		}
441
	}
442
	if errVal != nil { // We don't report the actual errVal from strconv
443
		if format != "" {
444
			errVal = fmt.Errorf("%s value must be of type %s with format %s in %s", prefix, typeName, format, path)
445
		} else {
446
			errVal = fmt.Errorf("%s value must be of type %s (default format) in %s", prefix, typeName, path)
447
		}
448
	}
449
	return errVal
450
}
451

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.