1 package validator
2 3 import (
4 "bytes"
5 "context"
6 "crypto/sha256"
7 "encoding/hex"
8 "encoding/json"
9 "fmt"
10 "io/fs"
11 "net"
12 "net/url"
13 "os"
14 "reflect"
15 "strconv"
16 "strings"
17 "sync"
18 "syscall"
19 "time"
20 "unicode/utf8"
21 22 "golang.org/x/crypto/sha3"
23 "golang.org/x/text/language"
24 25 "github.com/gabriel-vasile/mimetype"
26 urn "github.com/leodido/go-urn"
27 )
28 29 // Func accepts a FieldLevel interface for all validation needs. The return
30 // value should be true when validation succeeds.
31 type Func func(fl FieldLevel) bool
32 33 // FuncCtx accepts a context.Context and FieldLevel interface for all
34 // validation needs. The return value should be true when validation succeeds.
35 type FuncCtx func(ctx context.Context, fl FieldLevel) bool
36 37 // wrapFunc wraps normal Func makes it compatible with FuncCtx
38 func wrapFunc(fn Func) FuncCtx {
39 if fn == nil {
40 return nil // be sure not to wrap a bad function.
41 }
42 return func(ctx context.Context, fl FieldLevel) bool {
43 return fn(fl)
44 }
45 }
46 47 var (
48 restrictedTags = map[string]struct{}{
49 diveTag: {},
50 keysTag: {},
51 endKeysTag: {},
52 structOnlyTag: {},
53 omitempty: {},
54 omitnil: {},
55 skipValidationTag: {},
56 utf8HexComma: {},
57 utf8Pipe: {},
58 noStructLevelTag: {},
59 requiredTag: {},
60 isdefault: {},
61 }
62 63 // bakedInAliases is a default mapping of a single validation tag that
64 // defines a common or complex set of validation(s) to simplify
65 // adding validation to structs.
66 bakedInAliases = map[string]string{
67 "iscolor": "hexcolor|rgb|rgba|hsl|hsla",
68 "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric",
69 "eu_country_code": "iso3166_1_alpha2_eu|iso3166_1_alpha3_eu|iso3166_1_alpha_numeric_eu",
70 }
71 72 // bakedInValidators is the default map of ValidationFunc
73 // you can add, remove or even replace items to suite your needs,
74 // or even disregard and use your own map if so desired.
75 bakedInValidators = map[string]Func{
76 "required": hasValue,
77 "required_if": requiredIf,
78 "required_unless": requiredUnless,
79 "skip_unless": skipUnless,
80 "required_with": requiredWith,
81 "required_with_all": requiredWithAll,
82 "required_without": requiredWithout,
83 "required_without_all": requiredWithoutAll,
84 "excluded_if": excludedIf,
85 "excluded_unless": excludedUnless,
86 "excluded_with": excludedWith,
87 "excluded_with_all": excludedWithAll,
88 "excluded_without": excludedWithout,
89 "excluded_without_all": excludedWithoutAll,
90 "isdefault": isDefault,
91 "len": hasLengthOf,
92 "min": hasMinOf,
93 "max": hasMaxOf,
94 "eq": isEq,
95 "eq_ignore_case": isEqIgnoreCase,
96 "ne": isNe,
97 "ne_ignore_case": isNeIgnoreCase,
98 "lt": isLt,
99 "lte": isLte,
100 "gt": isGt,
101 "gte": isGte,
102 "eqfield": isEqField,
103 "eqcsfield": isEqCrossStructField,
104 "necsfield": isNeCrossStructField,
105 "gtcsfield": isGtCrossStructField,
106 "gtecsfield": isGteCrossStructField,
107 "ltcsfield": isLtCrossStructField,
108 "ltecsfield": isLteCrossStructField,
109 "nefield": isNeField,
110 "gtefield": isGteField,
111 "gtfield": isGtField,
112 "ltefield": isLteField,
113 "ltfield": isLtField,
114 "fieldcontains": fieldContains,
115 "fieldexcludes": fieldExcludes,
116 "alpha": isAlpha,
117 "alphanum": isAlphanum,
118 "alphaunicode": isAlphaUnicode,
119 "alphanumunicode": isAlphanumUnicode,
120 "boolean": isBoolean,
121 "numeric": isNumeric,
122 "number": isNumber,
123 "hexadecimal": isHexadecimal,
124 "hexcolor": isHEXColor,
125 "rgb": isRGB,
126 "rgba": isRGBA,
127 "hsl": isHSL,
128 "hsla": isHSLA,
129 "e164": isE164,
130 "email": isEmail,
131 "url": isURL,
132 "http_url": isHttpURL,
133 "uri": isURI,
134 "urn_rfc2141": isUrnRFC2141, // RFC 2141
135 "file": isFile,
136 "filepath": isFilePath,
137 "base32": isBase32,
138 "base64": isBase64,
139 "base64url": isBase64URL,
140 "base64rawurl": isBase64RawURL,
141 "contains": contains,
142 "containsany": containsAny,
143 "containsrune": containsRune,
144 "excludes": excludes,
145 "excludesall": excludesAll,
146 "excludesrune": excludesRune,
147 "startswith": startsWith,
148 "endswith": endsWith,
149 "startsnotwith": startsNotWith,
150 "endsnotwith": endsNotWith,
151 "image": isImage,
152 "isbn": isISBN,
153 "isbn10": isISBN10,
154 "isbn13": isISBN13,
155 "issn": isISSN,
156 "eth_addr": isEthereumAddress,
157 "eth_addr_checksum": isEthereumAddressChecksum,
158 "btc_addr": isBitcoinAddress,
159 "btc_addr_bech32": isBitcoinBech32Address,
160 "uuid": isUUID,
161 "uuid3": isUUID3,
162 "uuid4": isUUID4,
163 "uuid5": isUUID5,
164 "uuid_rfc4122": isUUIDRFC4122,
165 "uuid3_rfc4122": isUUID3RFC4122,
166 "uuid4_rfc4122": isUUID4RFC4122,
167 "uuid5_rfc4122": isUUID5RFC4122,
168 "ulid": isULID,
169 "md4": isMD4,
170 "md5": isMD5,
171 "sha256": isSHA256,
172 "sha384": isSHA384,
173 "sha512": isSHA512,
174 "ripemd128": isRIPEMD128,
175 "ripemd160": isRIPEMD160,
176 "tiger128": isTIGER128,
177 "tiger160": isTIGER160,
178 "tiger192": isTIGER192,
179 "ascii": isASCII,
180 "printascii": isPrintableASCII,
181 "multibyte": hasMultiByteCharacter,
182 "datauri": isDataURI,
183 "latitude": isLatitude,
184 "longitude": isLongitude,
185 "ssn": isSSN,
186 "ipv4": isIPv4,
187 "ipv6": isIPv6,
188 "ip": isIP,
189 "cidrv4": isCIDRv4,
190 "cidrv6": isCIDRv6,
191 "cidr": isCIDR,
192 "tcp4_addr": isTCP4AddrResolvable,
193 "tcp6_addr": isTCP6AddrResolvable,
194 "tcp_addr": isTCPAddrResolvable,
195 "udp4_addr": isUDP4AddrResolvable,
196 "udp6_addr": isUDP6AddrResolvable,
197 "udp_addr": isUDPAddrResolvable,
198 "ip4_addr": isIP4AddrResolvable,
199 "ip6_addr": isIP6AddrResolvable,
200 "ip_addr": isIPAddrResolvable,
201 "unix_addr": isUnixAddrResolvable,
202 "mac": isMAC,
203 "hostname": isHostnameRFC952, // RFC 952
204 "hostname_rfc1123": isHostnameRFC1123, // RFC 1123
205 "fqdn": isFQDN,
206 "unique": isUnique,
207 "oneof": isOneOf,
208 "oneofci": isOneOfCI,
209 "html": isHTML,
210 "html_encoded": isHTMLEncoded,
211 "url_encoded": isURLEncoded,
212 "dir": isDir,
213 "dirpath": isDirPath,
214 "json": isJSON,
215 "jwt": isJWT,
216 "hostname_port": isHostnamePort,
217 "port": isPort,
218 "lowercase": isLowercase,
219 "uppercase": isUppercase,
220 "datetime": isDatetime,
221 "timezone": isTimeZone,
222 "iso3166_1_alpha2": isIso3166Alpha2,
223 "iso3166_1_alpha2_eu": isIso3166Alpha2EU,
224 "iso3166_1_alpha3": isIso3166Alpha3,
225 "iso3166_1_alpha3_eu": isIso3166Alpha3EU,
226 "iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
227 "iso3166_1_alpha_numeric_eu": isIso3166AlphaNumericEU,
228 "iso3166_2": isIso31662,
229 "iso4217": isIso4217,
230 "iso4217_numeric": isIso4217Numeric,
231 "bcp47_language_tag": isBCP47LanguageTag,
232 "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2,
233 "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
234 "bic": isIsoBicFormat,
235 "semver": isSemverFormat,
236 "dns_rfc1035_label": isDnsRFC1035LabelFormat,
237 "credit_card": isCreditCard,
238 "cve": isCveFormat,
239 "luhn_checksum": hasLuhnChecksum,
240 "mongodb": isMongoDBObjectId,
241 "mongodb_connection_string": isMongoDBConnectionString,
242 "cron": isCron,
243 "spicedb": isSpiceDB,
244 }
245 )
246 247 var (
248 oneofValsCache = map[string][]string{}
249 oneofValsCacheRWLock = sync.RWMutex{}
250 )
251 252 func parseOneOfParam2(s string) []string {
253 oneofValsCacheRWLock.RLock()
254 vals, ok := oneofValsCache[s]
255 oneofValsCacheRWLock.RUnlock()
256 if !ok {
257 oneofValsCacheRWLock.Lock()
258 vals = splitParamsRegex().FindAllString(s, -1)
259 for i := 0; i < len(vals); i++ {
260 vals[i] = strings.Replace(vals[i], "'", "", -1)
261 }
262 oneofValsCache[s] = vals
263 oneofValsCacheRWLock.Unlock()
264 }
265 return vals
266 }
267 268 func isURLEncoded(fl FieldLevel) bool {
269 return uRLEncodedRegex().MatchString(fl.Field().String())
270 }
271 272 func isHTMLEncoded(fl FieldLevel) bool {
273 return hTMLEncodedRegex().MatchString(fl.Field().String())
274 }
275 276 func isHTML(fl FieldLevel) bool {
277 return hTMLRegex().MatchString(fl.Field().String())
278 }
279 280 func isOneOf(fl FieldLevel) bool {
281 vals := parseOneOfParam2(fl.Param())
282 283 field := fl.Field()
284 285 var v string
286 switch field.Kind() {
287 case reflect.String:
288 v = field.String()
289 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
290 v = strconv.FormatInt(field.Int(), 10)
291 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
292 v = strconv.FormatUint(field.Uint(), 10)
293 default:
294 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
295 }
296 for i := 0; i < len(vals); i++ {
297 if vals[i] == v {
298 return true
299 }
300 }
301 return false
302 }
303 304 // isOneOfCI is the validation function for validating if the current field's value is one of the provided string values (case insensitive).
305 func isOneOfCI(fl FieldLevel) bool {
306 vals := parseOneOfParam2(fl.Param())
307 field := fl.Field()
308 309 if field.Kind() != reflect.String {
310 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
311 }
312 v := field.String()
313 for _, val := range vals {
314 if strings.EqualFold(val, v) {
315 return true
316 }
317 }
318 return false
319 }
320 321 // isUnique is the validation function for validating if each array|slice|map value is unique
322 func isUnique(fl FieldLevel) bool {
323 field := fl.Field()
324 param := fl.Param()
325 v := reflect.ValueOf(struct{}{})
326 327 switch field.Kind() {
328 case reflect.Slice, reflect.Array:
329 elem := field.Type().Elem()
330 if elem.Kind() == reflect.Ptr {
331 elem = elem.Elem()
332 }
333 334 if param == "" {
335 m := reflect.MakeMap(reflect.MapOf(elem, v.Type()))
336 337 for i := 0; i < field.Len(); i++ {
338 m.SetMapIndex(reflect.Indirect(field.Index(i)), v)
339 }
340 return field.Len() == m.Len()
341 }
342 343 sf, ok := elem.FieldByName(param)
344 if !ok {
345 panic(fmt.Sprintf("Bad field name %s", param))
346 }
347 348 sfTyp := sf.Type
349 if sfTyp.Kind() == reflect.Ptr {
350 sfTyp = sfTyp.Elem()
351 }
352 353 m := reflect.MakeMap(reflect.MapOf(sfTyp, v.Type()))
354 var fieldlen int
355 for i := 0; i < field.Len(); i++ {
356 key := reflect.Indirect(reflect.Indirect(field.Index(i)).FieldByName(param))
357 if key.IsValid() {
358 fieldlen++
359 m.SetMapIndex(key, v)
360 }
361 }
362 return fieldlen == m.Len()
363 case reflect.Map:
364 var m reflect.Value
365 if field.Type().Elem().Kind() == reflect.Ptr {
366 m = reflect.MakeMap(reflect.MapOf(field.Type().Elem().Elem(), v.Type()))
367 } else {
368 m = reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
369 }
370 371 for _, k := range field.MapKeys() {
372 m.SetMapIndex(reflect.Indirect(field.MapIndex(k)), v)
373 }
374 375 return field.Len() == m.Len()
376 default:
377 if parent := fl.Parent(); parent.Kind() == reflect.Struct {
378 uniqueField := parent.FieldByName(param)
379 if uniqueField == reflect.ValueOf(nil) {
380 panic(fmt.Sprintf("Bad field name provided %s", param))
381 }
382 383 if uniqueField.Kind() != field.Kind() {
384 panic(fmt.Sprintf("Bad field type %T:%T", field.Interface(), uniqueField.Interface()))
385 }
386 387 return field.Interface() != uniqueField.Interface()
388 }
389 390 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
391 }
392 }
393 394 // isMAC is the validation function for validating if the field's value is a valid MAC address.
395 func isMAC(fl FieldLevel) bool {
396 _, err := net.ParseMAC(fl.Field().String())
397 398 return err == nil
399 }
400 401 // isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
402 func isCIDRv4(fl FieldLevel) bool {
403 ip, net, err := net.ParseCIDR(fl.Field().String())
404 405 return err == nil && ip.To4() != nil && net.IP.Equal(ip)
406 }
407 408 // isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
409 func isCIDRv6(fl FieldLevel) bool {
410 ip, _, err := net.ParseCIDR(fl.Field().String())
411 412 return err == nil && ip.To4() == nil
413 }
414 415 // isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
416 func isCIDR(fl FieldLevel) bool {
417 _, _, err := net.ParseCIDR(fl.Field().String())
418 419 return err == nil
420 }
421 422 // isIPv4 is the validation function for validating if a value is a valid v4 IP address.
423 func isIPv4(fl FieldLevel) bool {
424 ip := net.ParseIP(fl.Field().String())
425 426 return ip != nil && ip.To4() != nil
427 }
428 429 // isIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
430 func isIPv6(fl FieldLevel) bool {
431 ip := net.ParseIP(fl.Field().String())
432 433 return ip != nil && ip.To4() == nil
434 }
435 436 // isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
437 func isIP(fl FieldLevel) bool {
438 ip := net.ParseIP(fl.Field().String())
439 440 return ip != nil
441 }
442 443 // isSSN is the validation function for validating if the field's value is a valid SSN.
444 func isSSN(fl FieldLevel) bool {
445 field := fl.Field()
446 447 if field.Len() != 11 {
448 return false
449 }
450 451 return sSNRegex().MatchString(field.String())
452 }
453 454 // isLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
455 func isLongitude(fl FieldLevel) bool {
456 field := fl.Field()
457 458 var v string
459 switch field.Kind() {
460 case reflect.String:
461 v = field.String()
462 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
463 v = strconv.FormatInt(field.Int(), 10)
464 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
465 v = strconv.FormatUint(field.Uint(), 10)
466 case reflect.Float32:
467 v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
468 case reflect.Float64:
469 v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
470 default:
471 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
472 }
473 474 return longitudeRegex().MatchString(v)
475 }
476 477 // isLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
478 func isLatitude(fl FieldLevel) bool {
479 field := fl.Field()
480 481 var v string
482 switch field.Kind() {
483 case reflect.String:
484 v = field.String()
485 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
486 v = strconv.FormatInt(field.Int(), 10)
487 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
488 v = strconv.FormatUint(field.Uint(), 10)
489 case reflect.Float32:
490 v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
491 case reflect.Float64:
492 v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
493 default:
494 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
495 }
496 497 return latitudeRegex().MatchString(v)
498 }
499 500 // isDataURI is the validation function for validating if the field's value is a valid data URI.
501 func isDataURI(fl FieldLevel) bool {
502 uri := strings.SplitN(fl.Field().String(), ",", 2)
503 504 if len(uri) != 2 {
505 return false
506 }
507 508 if !dataURIRegex().MatchString(uri[0]) {
509 return false
510 }
511 512 return base64Regex().MatchString(uri[1])
513 }
514 515 // hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
516 func hasMultiByteCharacter(fl FieldLevel) bool {
517 field := fl.Field()
518 519 if field.Len() == 0 {
520 return true
521 }
522 523 return multibyteRegex().MatchString(field.String())
524 }
525 526 // isPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
527 func isPrintableASCII(fl FieldLevel) bool {
528 return printableASCIIRegex().MatchString(fl.Field().String())
529 }
530 531 // isASCII is the validation function for validating if the field's value is a valid ASCII character.
532 func isASCII(fl FieldLevel) bool {
533 return aSCIIRegex().MatchString(fl.Field().String())
534 }
535 536 // isUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
537 func isUUID5(fl FieldLevel) bool {
538 return fieldMatchesRegexByStringerValOrString(uUID5Regex, fl)
539 }
540 541 // isUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
542 func isUUID4(fl FieldLevel) bool {
543 return fieldMatchesRegexByStringerValOrString(uUID4Regex, fl)
544 }
545 546 // isUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
547 func isUUID3(fl FieldLevel) bool {
548 return fieldMatchesRegexByStringerValOrString(uUID3Regex, fl)
549 }
550 551 // isUUID is the validation function for validating if the field's value is a valid UUID of any version.
552 func isUUID(fl FieldLevel) bool {
553 return fieldMatchesRegexByStringerValOrString(uUIDRegex, fl)
554 }
555 556 // isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID.
557 func isUUID5RFC4122(fl FieldLevel) bool {
558 return fieldMatchesRegexByStringerValOrString(uUID5RFC4122Regex, fl)
559 }
560 561 // isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID.
562 func isUUID4RFC4122(fl FieldLevel) bool {
563 return fieldMatchesRegexByStringerValOrString(uUID4RFC4122Regex, fl)
564 }
565 566 // isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID.
567 func isUUID3RFC4122(fl FieldLevel) bool {
568 return fieldMatchesRegexByStringerValOrString(uUID3RFC4122Regex, fl)
569 }
570 571 // isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version.
572 func isUUIDRFC4122(fl FieldLevel) bool {
573 return fieldMatchesRegexByStringerValOrString(uUIDRFC4122Regex, fl)
574 }
575 576 // isULID is the validation function for validating if the field's value is a valid ULID.
577 func isULID(fl FieldLevel) bool {
578 return fieldMatchesRegexByStringerValOrString(uLIDRegex, fl)
579 }
580 581 // isMD4 is the validation function for validating if the field's value is a valid MD4.
582 func isMD4(fl FieldLevel) bool {
583 return md4Regex().MatchString(fl.Field().String())
584 }
585 586 // isMD5 is the validation function for validating if the field's value is a valid MD5.
587 func isMD5(fl FieldLevel) bool {
588 return md5Regex().MatchString(fl.Field().String())
589 }
590 591 // isSHA256 is the validation function for validating if the field's value is a valid SHA256.
592 func isSHA256(fl FieldLevel) bool {
593 return sha256Regex().MatchString(fl.Field().String())
594 }
595 596 // isSHA384 is the validation function for validating if the field's value is a valid SHA384.
597 func isSHA384(fl FieldLevel) bool {
598 return sha384Regex().MatchString(fl.Field().String())
599 }
600 601 // isSHA512 is the validation function for validating if the field's value is a valid SHA512.
602 func isSHA512(fl FieldLevel) bool {
603 return sha512Regex().MatchString(fl.Field().String())
604 }
605 606 // isRIPEMD128 is the validation function for validating if the field's value is a valid PIPEMD128.
607 func isRIPEMD128(fl FieldLevel) bool {
608 return ripemd128Regex().MatchString(fl.Field().String())
609 }
610 611 // isRIPEMD160 is the validation function for validating if the field's value is a valid PIPEMD160.
612 func isRIPEMD160(fl FieldLevel) bool {
613 return ripemd160Regex().MatchString(fl.Field().String())
614 }
615 616 // isTIGER128 is the validation function for validating if the field's value is a valid TIGER128.
617 func isTIGER128(fl FieldLevel) bool {
618 return tiger128Regex().MatchString(fl.Field().String())
619 }
620 621 // isTIGER160 is the validation function for validating if the field's value is a valid TIGER160.
622 func isTIGER160(fl FieldLevel) bool {
623 return tiger160Regex().MatchString(fl.Field().String())
624 }
625 626 // isTIGER192 is the validation function for validating if the field's value is a valid isTIGER192.
627 func isTIGER192(fl FieldLevel) bool {
628 return tiger192Regex().MatchString(fl.Field().String())
629 }
630 631 // isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
632 func isISBN(fl FieldLevel) bool {
633 return isISBN10(fl) || isISBN13(fl)
634 }
635 636 // isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
637 func isISBN13(fl FieldLevel) bool {
638 s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
639 640 if !iSBN13Regex().MatchString(s) {
641 return false
642 }
643 644 var checksum int32
645 var i int32
646 647 factor := []int32{1, 3}
648 649 for i = 0; i < 12; i++ {
650 checksum += factor[i%2] * int32(s[i]-'0')
651 }
652 653 return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
654 }
655 656 // isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
657 func isISBN10(fl FieldLevel) bool {
658 s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
659 660 if !iSBN10Regex().MatchString(s) {
661 return false
662 }
663 664 var checksum int32
665 var i int32
666 667 for i = 0; i < 9; i++ {
668 checksum += (i + 1) * int32(s[i]-'0')
669 }
670 671 if s[9] == 'X' {
672 checksum += 10 * 10
673 } else {
674 checksum += 10 * int32(s[9]-'0')
675 }
676 677 return checksum%11 == 0
678 }
679 680 // isISSN is the validation function for validating if the field's value is a valid ISSN.
681 func isISSN(fl FieldLevel) bool {
682 s := fl.Field().String()
683 684 if !iSSNRegex().MatchString(s) {
685 return false
686 }
687 s = strings.ReplaceAll(s, "-", "")
688 689 pos := 8
690 checksum := 0
691 692 for i := 0; i < 7; i++ {
693 checksum += pos * int(s[i]-'0')
694 pos--
695 }
696 697 if s[7] == 'X' {
698 checksum += 10
699 } else {
700 checksum += int(s[7] - '0')
701 }
702 703 return checksum%11 == 0
704 }
705 706 // isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address.
707 func isEthereumAddress(fl FieldLevel) bool {
708 address := fl.Field().String()
709 710 return ethAddressRegex().MatchString(address)
711 }
712 713 // isEthereumAddressChecksum is the validation function for validating if the field's value is a valid checksummed Ethereum address.
714 func isEthereumAddressChecksum(fl FieldLevel) bool {
715 address := fl.Field().String()
716 717 if !ethAddressRegex().MatchString(address) {
718 return false
719 }
720 // Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
721 address = address[2:] // Skip "0x" prefix.
722 h := sha3.NewLegacyKeccak256()
723 // hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash
724 _, _ = h.Write([]byte(strings.ToLower(address)))
725 hash := hex.EncodeToString(h.Sum(nil))
726 727 for i := 0; i < len(address); i++ {
728 if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case.
729 continue
730 }
731 if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' {
732 return false
733 }
734 }
735 736 return true
737 }
738 739 // isBitcoinAddress is the validation function for validating if the field's value is a valid btc address
740 func isBitcoinAddress(fl FieldLevel) bool {
741 address := fl.Field().String()
742 743 if !btcAddressRegex().MatchString(address) {
744 return false
745 }
746 747 alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
748 749 decode := [25]byte{}
750 751 for _, n := range []byte(address) {
752 d := bytes.IndexByte(alphabet, n)
753 754 for i := 24; i >= 0; i-- {
755 d += 58 * int(decode[i])
756 decode[i] = byte(d % 256)
757 d /= 256
758 }
759 }
760 761 h := sha256.New()
762 _, _ = h.Write(decode[:21])
763 d := h.Sum([]byte{})
764 h = sha256.New()
765 _, _ = h.Write(d)
766 767 validchecksum := [4]byte{}
768 computedchecksum := [4]byte{}
769 770 copy(computedchecksum[:], h.Sum(d[:0]))
771 copy(validchecksum[:], decode[21:])
772 773 return validchecksum == computedchecksum
774 }
775 776 // isBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address
777 func isBitcoinBech32Address(fl FieldLevel) bool {
778 address := fl.Field().String()
779 780 if !btcLowerAddressRegexBech32().MatchString(address) && !btcUpperAddressRegexBech32().MatchString(address) {
781 return false
782 }
783 784 am := len(address) % 8
785 786 if am == 0 || am == 3 || am == 5 {
787 return false
788 }
789 790 address = strings.ToLower(address)
791 792 alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
793 794 hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc
795 addr := address[3:]
796 dp := make([]int, 0, len(addr))
797 798 for _, c := range addr {
799 dp = append(dp, strings.IndexRune(alphabet, c))
800 }
801 802 ver := dp[0]
803 804 if ver < 0 || ver > 16 {
805 return false
806 }
807 808 if ver == 0 {
809 if len(address) != 42 && len(address) != 62 {
810 return false
811 }
812 }
813 814 values := append(hr, dp...)
815 816 GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
817 818 p := 1
819 820 for _, v := range values {
821 b := p >> 25
822 p = (p&0x1ffffff)<<5 ^ v
823 824 for i := 0; i < 5; i++ {
825 if (b>>uint(i))&1 == 1 {
826 p ^= GEN[i]
827 }
828 }
829 }
830 831 if p != 1 {
832 return false
833 }
834 835 b := uint(0)
836 acc := 0
837 mv := (1 << 5) - 1
838 var sw []int
839 840 for _, v := range dp[1 : len(dp)-6] {
841 acc = (acc << 5) | v
842 b += 5
843 for b >= 8 {
844 b -= 8
845 sw = append(sw, (acc>>b)&mv)
846 }
847 }
848 849 if len(sw) < 2 || len(sw) > 40 {
850 return false
851 }
852 853 return true
854 }
855 856 // excludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
857 func excludesRune(fl FieldLevel) bool {
858 return !containsRune(fl)
859 }
860 861 // excludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
862 func excludesAll(fl FieldLevel) bool {
863 return !containsAny(fl)
864 }
865 866 // excludes is the validation function for validating that the field's value does not contain the text specified within the param.
867 func excludes(fl FieldLevel) bool {
868 return !contains(fl)
869 }
870 871 // containsRune is the validation function for validating that the field's value contains the rune specified within the param.
872 func containsRune(fl FieldLevel) bool {
873 r, _ := utf8.DecodeRuneInString(fl.Param())
874 875 return strings.ContainsRune(fl.Field().String(), r)
876 }
877 878 // containsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
879 func containsAny(fl FieldLevel) bool {
880 return strings.ContainsAny(fl.Field().String(), fl.Param())
881 }
882 883 // contains is the validation function for validating that the field's value contains the text specified within the param.
884 func contains(fl FieldLevel) bool {
885 return strings.Contains(fl.Field().String(), fl.Param())
886 }
887 888 // startsWith is the validation function for validating that the field's value starts with the text specified within the param.
889 func startsWith(fl FieldLevel) bool {
890 return strings.HasPrefix(fl.Field().String(), fl.Param())
891 }
892 893 // endsWith is the validation function for validating that the field's value ends with the text specified within the param.
894 func endsWith(fl FieldLevel) bool {
895 return strings.HasSuffix(fl.Field().String(), fl.Param())
896 }
897 898 // startsNotWith is the validation function for validating that the field's value does not start with the text specified within the param.
899 func startsNotWith(fl FieldLevel) bool {
900 return !startsWith(fl)
901 }
902 903 // endsNotWith is the validation function for validating that the field's value does not end with the text specified within the param.
904 func endsNotWith(fl FieldLevel) bool {
905 return !endsWith(fl)
906 }
907 908 // fieldContains is the validation function for validating if the current field's value contains the field specified by the param's value.
909 func fieldContains(fl FieldLevel) bool {
910 field := fl.Field()
911 912 currentField, _, ok := fl.GetStructFieldOK()
913 914 if !ok {
915 return false
916 }
917 918 return strings.Contains(field.String(), currentField.String())
919 }
920 921 // fieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value.
922 func fieldExcludes(fl FieldLevel) bool {
923 field := fl.Field()
924 925 currentField, _, ok := fl.GetStructFieldOK()
926 if !ok {
927 return true
928 }
929 930 return !strings.Contains(field.String(), currentField.String())
931 }
932 933 // isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
934 func isNeField(fl FieldLevel) bool {
935 field := fl.Field()
936 kind := field.Kind()
937 938 currentField, currentKind, ok := fl.GetStructFieldOK()
939 940 if !ok || currentKind != kind {
941 return true
942 }
943 944 switch kind {
945 946 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
947 return field.Int() != currentField.Int()
948 949 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
950 return field.Uint() != currentField.Uint()
951 952 case reflect.Float32, reflect.Float64:
953 return field.Float() != currentField.Float()
954 955 case reflect.Slice, reflect.Map, reflect.Array:
956 return int64(field.Len()) != int64(currentField.Len())
957 958 case reflect.Bool:
959 return field.Bool() != currentField.Bool()
960 961 case reflect.Struct:
962 963 fieldType := field.Type()
964 965 if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
966 967 t := currentField.Interface().(time.Time)
968 fieldTime := field.Interface().(time.Time)
969 970 return !fieldTime.Equal(t)
971 }
972 973 // Not Same underlying type i.e. struct and time
974 if fieldType != currentField.Type() {
975 return true
976 }
977 }
978 979 // default reflect.String:
980 return field.String() != currentField.String()
981 }
982 983 // isNe is the validation function for validating that the field's value does not equal the provided param value.
984 func isNe(fl FieldLevel) bool {
985 return !isEq(fl)
986 }
987 988 // isNeIgnoreCase is the validation function for validating that the field's string value does not equal the
989 // provided param value. The comparison is case-insensitive
990 func isNeIgnoreCase(fl FieldLevel) bool {
991 return !isEqIgnoreCase(fl)
992 }
993 994 // isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
995 func isLteCrossStructField(fl FieldLevel) bool {
996 field := fl.Field()
997 kind := field.Kind()
998 999 topField, topKind, ok := fl.GetStructFieldOK()
1000 if !ok || topKind != kind {
1001 return false
1002 }
1003 1004 switch kind {
1005 1006 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1007 return field.Int() <= topField.Int()
1008 1009 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1010 return field.Uint() <= topField.Uint()
1011 1012 case reflect.Float32, reflect.Float64:
1013 return field.Float() <= topField.Float()
1014 1015 case reflect.Slice, reflect.Map, reflect.Array:
1016 return int64(field.Len()) <= int64(topField.Len())
1017 1018 case reflect.Struct:
1019 1020 fieldType := field.Type()
1021 1022 if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
1023 1024 fieldTime := field.Convert(timeType).Interface().(time.Time)
1025 topTime := topField.Convert(timeType).Interface().(time.Time)
1026 1027 return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
1028 }
1029 1030 // Not Same underlying type i.e. struct and time
1031 if fieldType != topField.Type() {
1032 return false
1033 }
1034 }
1035 1036 // default reflect.String:
1037 return field.String() <= topField.String()
1038 }
1039 1040 // isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
1041 // NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
1042 func isLtCrossStructField(fl FieldLevel) bool {
1043 field := fl.Field()
1044 kind := field.Kind()
1045 1046 topField, topKind, ok := fl.GetStructFieldOK()
1047 if !ok || topKind != kind {
1048 return false
1049 }
1050 1051 switch kind {
1052 1053 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1054 return field.Int() < topField.Int()
1055 1056 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1057 return field.Uint() < topField.Uint()
1058 1059 case reflect.Float32, reflect.Float64:
1060 return field.Float() < topField.Float()
1061 1062 case reflect.Slice, reflect.Map, reflect.Array:
1063 return int64(field.Len()) < int64(topField.Len())
1064 1065 case reflect.Struct:
1066 1067 fieldType := field.Type()
1068 1069 if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
1070 1071 fieldTime := field.Convert(timeType).Interface().(time.Time)
1072 topTime := topField.Convert(timeType).Interface().(time.Time)
1073 1074 return fieldTime.Before(topTime)
1075 }
1076 1077 // Not Same underlying type i.e. struct and time
1078 if fieldType != topField.Type() {
1079 return false
1080 }
1081 }
1082 1083 // default reflect.String:
1084 return field.String() < topField.String()
1085 }
1086 1087 // isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
1088 func isGteCrossStructField(fl FieldLevel) bool {
1089 field := fl.Field()
1090 kind := field.Kind()
1091 1092 topField, topKind, ok := fl.GetStructFieldOK()
1093 if !ok || topKind != kind {
1094 return false
1095 }
1096 1097 switch kind {
1098 1099 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1100 return field.Int() >= topField.Int()
1101 1102 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1103 return field.Uint() >= topField.Uint()
1104 1105 case reflect.Float32, reflect.Float64:
1106 return field.Float() >= topField.Float()
1107 1108 case reflect.Slice, reflect.Map, reflect.Array:
1109 return int64(field.Len()) >= int64(topField.Len())
1110 1111 case reflect.Struct:
1112 1113 fieldType := field.Type()
1114 1115 if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
1116 1117 fieldTime := field.Convert(timeType).Interface().(time.Time)
1118 topTime := topField.Convert(timeType).Interface().(time.Time)
1119 1120 return fieldTime.After(topTime) || fieldTime.Equal(topTime)
1121 }
1122 1123 // Not Same underlying type i.e. struct and time
1124 if fieldType != topField.Type() {
1125 return false
1126 }
1127 }
1128 1129 // default reflect.String:
1130 return field.String() >= topField.String()
1131 }
1132 1133 // isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
1134 func isGtCrossStructField(fl FieldLevel) bool {
1135 field := fl.Field()
1136 kind := field.Kind()
1137 1138 topField, topKind, ok := fl.GetStructFieldOK()
1139 if !ok || topKind != kind {
1140 return false
1141 }
1142 1143 switch kind {
1144 1145 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1146 return field.Int() > topField.Int()
1147 1148 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1149 return field.Uint() > topField.Uint()
1150 1151 case reflect.Float32, reflect.Float64:
1152 return field.Float() > topField.Float()
1153 1154 case reflect.Slice, reflect.Map, reflect.Array:
1155 return int64(field.Len()) > int64(topField.Len())
1156 1157 case reflect.Struct:
1158 1159 fieldType := field.Type()
1160 1161 if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
1162 1163 fieldTime := field.Convert(timeType).Interface().(time.Time)
1164 topTime := topField.Convert(timeType).Interface().(time.Time)
1165 1166 return fieldTime.After(topTime)
1167 }
1168 1169 // Not Same underlying type i.e. struct and time
1170 if fieldType != topField.Type() {
1171 return false
1172 }
1173 }
1174 1175 // default reflect.String:
1176 return field.String() > topField.String()
1177 }
1178 1179 // isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
1180 func isNeCrossStructField(fl FieldLevel) bool {
1181 field := fl.Field()
1182 kind := field.Kind()
1183 1184 topField, currentKind, ok := fl.GetStructFieldOK()
1185 if !ok || currentKind != kind {
1186 return true
1187 }
1188 1189 switch kind {
1190 1191 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1192 return topField.Int() != field.Int()
1193 1194 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1195 return topField.Uint() != field.Uint()
1196 1197 case reflect.Float32, reflect.Float64:
1198 return topField.Float() != field.Float()
1199 1200 case reflect.Slice, reflect.Map, reflect.Array:
1201 return int64(topField.Len()) != int64(field.Len())
1202 1203 case reflect.Bool:
1204 return topField.Bool() != field.Bool()
1205 1206 case reflect.Struct:
1207 1208 fieldType := field.Type()
1209 1210 if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
1211 1212 t := field.Convert(timeType).Interface().(time.Time)
1213 fieldTime := topField.Convert(timeType).Interface().(time.Time)
1214 1215 return !fieldTime.Equal(t)
1216 }
1217 1218 // Not Same underlying type i.e. struct and time
1219 if fieldType != topField.Type() {
1220 return true
1221 }
1222 }
1223 1224 // default reflect.String:
1225 return topField.String() != field.String()
1226 }
1227 1228 // isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
1229 func isEqCrossStructField(fl FieldLevel) bool {
1230 field := fl.Field()
1231 kind := field.Kind()
1232 1233 topField, topKind, ok := fl.GetStructFieldOK()
1234 if !ok || topKind != kind {
1235 return false
1236 }
1237 1238 switch kind {
1239 1240 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1241 return topField.Int() == field.Int()
1242 1243 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1244 return topField.Uint() == field.Uint()
1245 1246 case reflect.Float32, reflect.Float64:
1247 return topField.Float() == field.Float()
1248 1249 case reflect.Slice, reflect.Map, reflect.Array:
1250 return int64(topField.Len()) == int64(field.Len())
1251 1252 case reflect.Bool:
1253 return topField.Bool() == field.Bool()
1254 1255 case reflect.Struct:
1256 1257 fieldType := field.Type()
1258 1259 if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
1260 1261 t := field.Convert(timeType).Interface().(time.Time)
1262 fieldTime := topField.Convert(timeType).Interface().(time.Time)
1263 1264 return fieldTime.Equal(t)
1265 }
1266 1267 // Not Same underlying type i.e. struct and time
1268 if fieldType != topField.Type() {
1269 return false
1270 }
1271 }
1272 1273 // default reflect.String:
1274 return topField.String() == field.String()
1275 }
1276 1277 // isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
1278 func isEqField(fl FieldLevel) bool {
1279 field := fl.Field()
1280 kind := field.Kind()
1281 1282 currentField, currentKind, ok := fl.GetStructFieldOK()
1283 if !ok || currentKind != kind {
1284 return false
1285 }
1286 1287 switch kind {
1288 1289 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1290 return field.Int() == currentField.Int()
1291 1292 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1293 return field.Uint() == currentField.Uint()
1294 1295 case reflect.Float32, reflect.Float64:
1296 return field.Float() == currentField.Float()
1297 1298 case reflect.Slice, reflect.Map, reflect.Array:
1299 return int64(field.Len()) == int64(currentField.Len())
1300 1301 case reflect.Bool:
1302 return field.Bool() == currentField.Bool()
1303 1304 case reflect.Struct:
1305 1306 fieldType := field.Type()
1307 1308 if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
1309 1310 t := currentField.Convert(timeType).Interface().(time.Time)
1311 fieldTime := field.Convert(timeType).Interface().(time.Time)
1312 1313 return fieldTime.Equal(t)
1314 }
1315 1316 // Not Same underlying type i.e. struct and time
1317 if fieldType != currentField.Type() {
1318 return false
1319 }
1320 }
1321 1322 // default reflect.String:
1323 return field.String() == currentField.String()
1324 }
1325 1326 // isEq is the validation function for validating if the current field's value is equal to the param's value.
1327 func isEq(fl FieldLevel) bool {
1328 field := fl.Field()
1329 param := fl.Param()
1330 1331 switch field.Kind() {
1332 1333 case reflect.String:
1334 return field.String() == param
1335 1336 case reflect.Slice, reflect.Map, reflect.Array:
1337 p := asInt(param)
1338 1339 return int64(field.Len()) == p
1340 1341 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1342 p := asIntFromType(field.Type(), param)
1343 1344 return field.Int() == p
1345 1346 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1347 p := asUint(param)
1348 1349 return field.Uint() == p
1350 1351 case reflect.Float32:
1352 p := asFloat32(param)
1353 1354 return field.Float() == p
1355 1356 case reflect.Float64:
1357 p := asFloat64(param)
1358 1359 return field.Float() == p
1360 1361 case reflect.Bool:
1362 p := asBool(param)
1363 1364 return field.Bool() == p
1365 }
1366 1367 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1368 }
1369 1370 // isEqIgnoreCase is the validation function for validating if the current field's string value is
1371 // equal to the param's value.
1372 // The comparison is case-insensitive.
1373 func isEqIgnoreCase(fl FieldLevel) bool {
1374 field := fl.Field()
1375 param := fl.Param()
1376 1377 switch field.Kind() {
1378 1379 case reflect.String:
1380 return strings.EqualFold(field.String(), param)
1381 }
1382 1383 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1384 }
1385 1386 // isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2
1387 // example: `postcode_iso3166_alpha2=US`
1388 func isPostcodeByIso3166Alpha2(fl FieldLevel) bool {
1389 field := fl.Field()
1390 param := fl.Param()
1391 1392 postcodeRegexInit.Do(initPostcodes)
1393 reg, found := postCodeRegexDict[param]
1394 if !found {
1395 return false
1396 }
1397 1398 return reg.MatchString(field.String())
1399 }
1400 1401 // isPostcodeByIso3166Alpha2Field validates by field which represents for a value of country code in iso 3166 alpha 2
1402 // example: `postcode_iso3166_alpha2_field=CountryCode`
1403 func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
1404 field := fl.Field()
1405 params := parseOneOfParam2(fl.Param())
1406 1407 if len(params) != 1 {
1408 return false
1409 }
1410 1411 currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0])
1412 if !found {
1413 return false
1414 }
1415 1416 if kind != reflect.String {
1417 panic(fmt.Sprintf("Bad field type %T", currentField.Interface()))
1418 }
1419 1420 reg, found := postCodeRegexDict[currentField.String()]
1421 if !found {
1422 return false
1423 }
1424 1425 return reg.MatchString(field.String())
1426 }
1427 1428 // isBase32 is the validation function for validating if the current field's value is a valid base 32.
1429 func isBase32(fl FieldLevel) bool {
1430 return base32Regex().MatchString(fl.Field().String())
1431 }
1432 1433 // isBase64 is the validation function for validating if the current field's value is a valid base 64.
1434 func isBase64(fl FieldLevel) bool {
1435 return base64Regex().MatchString(fl.Field().String())
1436 }
1437 1438 // isBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string.
1439 func isBase64URL(fl FieldLevel) bool {
1440 return base64URLRegex().MatchString(fl.Field().String())
1441 }
1442 1443 // isBase64RawURL is the validation function for validating if the current field's value is a valid base64 URL safe string without '=' padding.
1444 func isBase64RawURL(fl FieldLevel) bool {
1445 return base64RawURLRegex().MatchString(fl.Field().String())
1446 }
1447 1448 // isURI is the validation function for validating if the current field's value is a valid URI.
1449 func isURI(fl FieldLevel) bool {
1450 field := fl.Field()
1451 1452 switch field.Kind() {
1453 case reflect.String:
1454 1455 s := field.String()
1456 1457 // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
1458 // emulate browser and strip the '#' suffix prior to validation. see issue-#237
1459 if i := strings.Index(s, "#"); i > -1 {
1460 s = s[:i]
1461 }
1462 1463 if len(s) == 0 {
1464 return false
1465 }
1466 1467 _, err := url.ParseRequestURI(s)
1468 1469 return err == nil
1470 }
1471 1472 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1473 }
1474 1475 // isFileURL is the helper function for validating if the `path` valid file URL as per RFC8089
1476 func isFileURL(path string) bool {
1477 if !strings.HasPrefix(path, "file:/") {
1478 return false
1479 }
1480 _, err := url.ParseRequestURI(path)
1481 return err == nil
1482 }
1483 1484 // isURL is the validation function for validating if the current field's value is a valid URL.
1485 func isURL(fl FieldLevel) bool {
1486 field := fl.Field()
1487 1488 switch field.Kind() {
1489 case reflect.String:
1490 1491 s := strings.ToLower(field.String())
1492 1493 if len(s) == 0 {
1494 return false
1495 }
1496 1497 if isFileURL(s) {
1498 return true
1499 }
1500 1501 url, err := url.Parse(s)
1502 if err != nil || url.Scheme == "" {
1503 return false
1504 }
1505 1506 if url.Host == "" && url.Fragment == "" && url.Opaque == "" {
1507 return false
1508 }
1509 1510 return true
1511 }
1512 1513 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1514 }
1515 1516 // isHttpURL is the validation function for validating if the current field's value is a valid HTTP(s) URL.
1517 func isHttpURL(fl FieldLevel) bool {
1518 if !isURL(fl) {
1519 return false
1520 }
1521 1522 field := fl.Field()
1523 switch field.Kind() {
1524 case reflect.String:
1525 1526 s := strings.ToLower(field.String())
1527 1528 url, err := url.Parse(s)
1529 if err != nil || url.Host == "" {
1530 return false
1531 }
1532 1533 return url.Scheme == "http" || url.Scheme == "https"
1534 }
1535 1536 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1537 }
1538 1539 // isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
1540 func isUrnRFC2141(fl FieldLevel) bool {
1541 field := fl.Field()
1542 1543 switch field.Kind() {
1544 case reflect.String:
1545 1546 str := field.String()
1547 1548 _, match := urn.Parse([]byte(str))
1549 1550 return match
1551 }
1552 1553 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1554 }
1555 1556 // isFile is the validation function for validating if the current field's value is a valid existing file path.
1557 func isFile(fl FieldLevel) bool {
1558 field := fl.Field()
1559 1560 switch field.Kind() {
1561 case reflect.String:
1562 fileInfo, err := os.Stat(field.String())
1563 if err != nil {
1564 return false
1565 }
1566 1567 return !fileInfo.IsDir()
1568 }
1569 1570 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1571 }
1572 1573 // isImage is the validation function for validating if the current field's value contains the path to a valid image file
1574 func isImage(fl FieldLevel) bool {
1575 mimetypes := map[string]bool{
1576 "image/bmp": true,
1577 "image/cis-cod": true,
1578 "image/gif": true,
1579 "image/ief": true,
1580 "image/jpeg": true,
1581 "image/jp2": true,
1582 "image/jpx": true,
1583 "image/jpm": true,
1584 "image/pipeg": true,
1585 "image/png": true,
1586 "image/svg+xml": true,
1587 "image/tiff": true,
1588 "image/webp": true,
1589 "image/x-cmu-raster": true,
1590 "image/x-cmx": true,
1591 "image/x-icon": true,
1592 "image/x-portable-anymap": true,
1593 "image/x-portable-bitmap": true,
1594 "image/x-portable-graymap": true,
1595 "image/x-portable-pixmap": true,
1596 "image/x-rgb": true,
1597 "image/x-xbitmap": true,
1598 "image/x-xpixmap": true,
1599 "image/x-xwindowdump": true,
1600 }
1601 field := fl.Field()
1602 1603 switch field.Kind() {
1604 case reflect.String:
1605 filePath := field.String()
1606 fileInfo, err := os.Stat(filePath)
1607 1608 if err != nil {
1609 return false
1610 }
1611 1612 if fileInfo.IsDir() {
1613 return false
1614 }
1615 1616 file, err := os.Open(filePath)
1617 if err != nil {
1618 return false
1619 }
1620 defer file.Close()
1621 1622 mime, err := mimetype.DetectReader(file)
1623 if err != nil {
1624 return false
1625 }
1626 1627 if _, ok := mimetypes[mime.String()]; ok {
1628 return true
1629 }
1630 }
1631 return false
1632 }
1633 1634 // isFilePath is the validation function for validating if the current field's value is a valid file path.
1635 func isFilePath(fl FieldLevel) bool {
1636 1637 var exists bool
1638 var err error
1639 1640 field := fl.Field()
1641 1642 // Not valid if it is a directory.
1643 if isDir(fl) {
1644 return false
1645 }
1646 // If it exists, it obviously is valid.
1647 // This is done first to avoid code duplication and unnecessary additional logic.
1648 if exists = isFile(fl); exists {
1649 return true
1650 }
1651 1652 // It does not exist but may still be a valid filepath.
1653 switch field.Kind() {
1654 case reflect.String:
1655 // Every OS allows for whitespace, but none
1656 // let you use a file with no filename (to my knowledge).
1657 // Unless you're dealing with raw inodes, but I digress.
1658 if strings.TrimSpace(field.String()) == "" {
1659 return false
1660 }
1661 // We make sure it isn't a directory.
1662 if strings.HasSuffix(field.String(), string(os.PathSeparator)) {
1663 return false
1664 }
1665 if _, err = os.Stat(field.String()); err != nil {
1666 switch t := err.(type) {
1667 case *fs.PathError:
1668 if t.Err == syscall.EINVAL {
1669 // It's definitely an invalid character in the filepath.
1670 return false
1671 }
1672 // It could be a permission error, a does-not-exist error, etc.
1673 // Out-of-scope for this validation, though.
1674 return true
1675 default:
1676 // Something went *seriously* wrong.
1677 /*
1678 Per https://pkg.go.dev/os#Stat:
1679 "If there is an error, it will be of type *PathError."
1680 */
1681 panic(err)
1682 }
1683 }
1684 }
1685 1686 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
1687 }
1688 1689 // isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number.
1690 func isE164(fl FieldLevel) bool {
1691 return e164Regex().MatchString(fl.Field().String())
1692 }
1693 1694 // isEmail is the validation function for validating if the current field's value is a valid email address.
1695 func isEmail(fl FieldLevel) bool {
1696 return emailRegex().MatchString(fl.Field().String())
1697 }
1698 1699 // isHSLA is the validation function for validating if the current field's value is a valid HSLA color.
1700 func isHSLA(fl FieldLevel) bool {
1701 return hslaRegex().MatchString(fl.Field().String())
1702 }
1703 1704 // isHSL is the validation function for validating if the current field's value is a valid HSL color.
1705 func isHSL(fl FieldLevel) bool {
1706 return hslRegex().MatchString(fl.Field().String())
1707 }
1708 1709 // isRGBA is the validation function for validating if the current field's value is a valid RGBA color.
1710 func isRGBA(fl FieldLevel) bool {
1711 return rgbaRegex().MatchString(fl.Field().String())
1712 }
1713 1714 // isRGB is the validation function for validating if the current field's value is a valid RGB color.
1715 func isRGB(fl FieldLevel) bool {
1716 return rgbRegex().MatchString(fl.Field().String())
1717 }
1718 1719 // isHEXColor is the validation function for validating if the current field's value is a valid HEX color.
1720 func isHEXColor(fl FieldLevel) bool {
1721 return hexColorRegex().MatchString(fl.Field().String())
1722 }
1723 1724 // isHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
1725 func isHexadecimal(fl FieldLevel) bool {
1726 return hexadecimalRegex().MatchString(fl.Field().String())
1727 }
1728 1729 // isNumber is the validation function for validating if the current field's value is a valid number.
1730 func isNumber(fl FieldLevel) bool {
1731 switch fl.Field().Kind() {
1732 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
1733 return true
1734 default:
1735 return numberRegex().MatchString(fl.Field().String())
1736 }
1737 }
1738 1739 // isNumeric is the validation function for validating if the current field's value is a valid numeric value.
1740 func isNumeric(fl FieldLevel) bool {
1741 switch fl.Field().Kind() {
1742 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
1743 return true
1744 default:
1745 return numericRegex().MatchString(fl.Field().String())
1746 }
1747 }
1748 1749 // isAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
1750 func isAlphanum(fl FieldLevel) bool {
1751 return alphaNumericRegex().MatchString(fl.Field().String())
1752 }
1753 1754 // isAlpha is the validation function for validating if the current field's value is a valid alpha value.
1755 func isAlpha(fl FieldLevel) bool {
1756 return alphaRegex().MatchString(fl.Field().String())
1757 }
1758 1759 // isAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
1760 func isAlphanumUnicode(fl FieldLevel) bool {
1761 return alphaUnicodeNumericRegex().MatchString(fl.Field().String())
1762 }
1763 1764 // isAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
1765 func isAlphaUnicode(fl FieldLevel) bool {
1766 return alphaUnicodeRegex().MatchString(fl.Field().String())
1767 }
1768 1769 // isBoolean is the validation function for validating if the current field's value is a valid boolean value or can be safely converted to a boolean value.
1770 func isBoolean(fl FieldLevel) bool {
1771 switch fl.Field().Kind() {
1772 case reflect.Bool:
1773 return true
1774 default:
1775 _, err := strconv.ParseBool(fl.Field().String())
1776 return err == nil
1777 }
1778 }
1779 1780 // isDefault is the opposite of required aka hasValue
1781 func isDefault(fl FieldLevel) bool {
1782 return !hasValue(fl)
1783 }
1784 1785 // hasValue is the validation function for validating if the current field's value is not the default static value.
1786 func hasValue(fl FieldLevel) bool {
1787 field := fl.Field()
1788 switch field.Kind() {
1789 case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
1790 return !field.IsNil()
1791 default:
1792 if fl.(*validate).fldIsPointer && field.Interface() != nil {
1793 return true
1794 }
1795 return field.IsValid() && !field.IsZero()
1796 }
1797 }
1798 1799 // requireCheckFieldKind is a func for check field kind
1800 func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
1801 field := fl.Field()
1802 kind := field.Kind()
1803 var nullable, found bool
1804 if len(param) > 0 {
1805 field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
1806 if !found {
1807 return defaultNotFoundValue
1808 }
1809 }
1810 switch kind {
1811 case reflect.Invalid:
1812 return defaultNotFoundValue
1813 case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
1814 return field.IsNil()
1815 default:
1816 if nullable && field.Interface() != nil {
1817 return false
1818 }
1819 return field.IsValid() && field.IsZero()
1820 }
1821 }
1822 1823 // requireCheckFieldValue is a func for check field value
1824 func requireCheckFieldValue(
1825 fl FieldLevel, param string, value string, defaultNotFoundValue bool,
1826 ) bool {
1827 field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
1828 if !found {
1829 return defaultNotFoundValue
1830 }
1831 1832 switch kind {
1833 1834 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1835 return field.Int() == asInt(value)
1836 1837 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1838 return field.Uint() == asUint(value)
1839 1840 case reflect.Float32:
1841 return field.Float() == asFloat32(value)
1842 1843 case reflect.Float64:
1844 return field.Float() == asFloat64(value)
1845 1846 case reflect.Slice, reflect.Map, reflect.Array:
1847 return int64(field.Len()) == asInt(value)
1848 1849 case reflect.Bool:
1850 return field.Bool() == (value == "true")
1851 1852 case reflect.Ptr:
1853 if field.IsNil() {
1854 return value == "nil"
1855 }
1856 // Handle non-nil pointers
1857 return requireCheckFieldValue(fl, param, value, defaultNotFoundValue)
1858 }
1859 1860 // default reflect.String:
1861 return field.String() == value
1862 }
1863 1864 // requiredIf is the validation function
1865 // The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field.
1866 func requiredIf(fl FieldLevel) bool {
1867 params := parseOneOfParam2(fl.Param())
1868 if len(params)%2 != 0 {
1869 panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName()))
1870 }
1871 for i := 0; i < len(params); i += 2 {
1872 if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
1873 return true
1874 }
1875 }
1876 return hasValue(fl)
1877 }
1878 1879 // excludedIf is the validation function
1880 // The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field.
1881 func excludedIf(fl FieldLevel) bool {
1882 params := parseOneOfParam2(fl.Param())
1883 if len(params)%2 != 0 {
1884 panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName()))
1885 }
1886 1887 for i := 0; i < len(params); i += 2 {
1888 if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
1889 return true
1890 }
1891 }
1892 return !hasValue(fl)
1893 }
1894 1895 // requiredUnless is the validation function
1896 // The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
1897 func requiredUnless(fl FieldLevel) bool {
1898 params := parseOneOfParam2(fl.Param())
1899 if len(params)%2 != 0 {
1900 panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName()))
1901 }
1902 1903 for i := 0; i < len(params); i += 2 {
1904 if requireCheckFieldValue(fl, params[i], params[i+1], false) {
1905 return true
1906 }
1907 }
1908 return hasValue(fl)
1909 }
1910 1911 // skipUnless is the validation function
1912 // The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
1913 func skipUnless(fl FieldLevel) bool {
1914 params := parseOneOfParam2(fl.Param())
1915 if len(params)%2 != 0 {
1916 panic(fmt.Sprintf("Bad param number for skip_unless %s", fl.FieldName()))
1917 }
1918 for i := 0; i < len(params); i += 2 {
1919 if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
1920 return true
1921 }
1922 }
1923 return hasValue(fl)
1924 }
1925 1926 // excludedUnless is the validation function
1927 // The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field.
1928 func excludedUnless(fl FieldLevel) bool {
1929 params := parseOneOfParam2(fl.Param())
1930 if len(params)%2 != 0 {
1931 panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName()))
1932 }
1933 for i := 0; i < len(params); i += 2 {
1934 if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
1935 return !hasValue(fl)
1936 }
1937 }
1938 return true
1939 }
1940 1941 // excludedWith is the validation function
1942 // The field under validation must not be present or is empty if any of the other specified fields are present.
1943 func excludedWith(fl FieldLevel) bool {
1944 params := parseOneOfParam2(fl.Param())
1945 for _, param := range params {
1946 if !requireCheckFieldKind(fl, param, true) {
1947 return !hasValue(fl)
1948 }
1949 }
1950 return true
1951 }
1952 1953 // requiredWith is the validation function
1954 // The field under validation must be present and not empty only if any of the other specified fields are present.
1955 func requiredWith(fl FieldLevel) bool {
1956 params := parseOneOfParam2(fl.Param())
1957 for _, param := range params {
1958 if !requireCheckFieldKind(fl, param, true) {
1959 return hasValue(fl)
1960 }
1961 }
1962 return true
1963 }
1964 1965 // excludedWithAll is the validation function
1966 // The field under validation must not be present or is empty if all of the other specified fields are present.
1967 func excludedWithAll(fl FieldLevel) bool {
1968 params := parseOneOfParam2(fl.Param())
1969 for _, param := range params {
1970 if requireCheckFieldKind(fl, param, true) {
1971 return true
1972 }
1973 }
1974 return !hasValue(fl)
1975 }
1976 1977 // requiredWithAll is the validation function
1978 // The field under validation must be present and not empty only if all of the other specified fields are present.
1979 func requiredWithAll(fl FieldLevel) bool {
1980 params := parseOneOfParam2(fl.Param())
1981 for _, param := range params {
1982 if requireCheckFieldKind(fl, param, true) {
1983 return true
1984 }
1985 }
1986 return hasValue(fl)
1987 }
1988 1989 // excludedWithout is the validation function
1990 // The field under validation must not be present or is empty when any of the other specified fields are not present.
1991 func excludedWithout(fl FieldLevel) bool {
1992 if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
1993 return !hasValue(fl)
1994 }
1995 return true
1996 }
1997 1998 // requiredWithout is the validation function
1999 // The field under validation must be present and not empty only when any of the other specified fields are not present.
2000 func requiredWithout(fl FieldLevel) bool {
2001 if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
2002 return hasValue(fl)
2003 }
2004 return true
2005 }
2006 2007 // excludedWithoutAll is the validation function
2008 // The field under validation must not be present or is empty when all of the other specified fields are not present.
2009 func excludedWithoutAll(fl FieldLevel) bool {
2010 params := parseOneOfParam2(fl.Param())
2011 for _, param := range params {
2012 if !requireCheckFieldKind(fl, param, true) {
2013 return true
2014 }
2015 }
2016 return !hasValue(fl)
2017 }
2018 2019 // requiredWithoutAll is the validation function
2020 // The field under validation must be present and not empty only when all of the other specified fields are not present.
2021 func requiredWithoutAll(fl FieldLevel) bool {
2022 params := parseOneOfParam2(fl.Param())
2023 for _, param := range params {
2024 if !requireCheckFieldKind(fl, param, true) {
2025 return true
2026 }
2027 }
2028 return hasValue(fl)
2029 }
2030 2031 // isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
2032 func isGteField(fl FieldLevel) bool {
2033 field := fl.Field()
2034 kind := field.Kind()
2035 2036 currentField, currentKind, ok := fl.GetStructFieldOK()
2037 if !ok || currentKind != kind {
2038 return false
2039 }
2040 2041 switch kind {
2042 2043 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2044 2045 return field.Int() >= currentField.Int()
2046 2047 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2048 2049 return field.Uint() >= currentField.Uint()
2050 2051 case reflect.Float32, reflect.Float64:
2052 2053 return field.Float() >= currentField.Float()
2054 2055 case reflect.Struct:
2056 2057 fieldType := field.Type()
2058 2059 if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
2060 2061 t := currentField.Convert(timeType).Interface().(time.Time)
2062 fieldTime := field.Convert(timeType).Interface().(time.Time)
2063 2064 return fieldTime.After(t) || fieldTime.Equal(t)
2065 }
2066 2067 // Not Same underlying type i.e. struct and time
2068 if fieldType != currentField.Type() {
2069 return false
2070 }
2071 }
2072 2073 // default reflect.String
2074 return len(field.String()) >= len(currentField.String())
2075 }
2076 2077 // isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
2078 func isGtField(fl FieldLevel) bool {
2079 field := fl.Field()
2080 kind := field.Kind()
2081 2082 currentField, currentKind, ok := fl.GetStructFieldOK()
2083 if !ok || currentKind != kind {
2084 return false
2085 }
2086 2087 switch kind {
2088 2089 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2090 2091 return field.Int() > currentField.Int()
2092 2093 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2094 2095 return field.Uint() > currentField.Uint()
2096 2097 case reflect.Float32, reflect.Float64:
2098 2099 return field.Float() > currentField.Float()
2100 2101 case reflect.Struct:
2102 2103 fieldType := field.Type()
2104 2105 if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
2106 2107 t := currentField.Convert(timeType).Interface().(time.Time)
2108 fieldTime := field.Convert(timeType).Interface().(time.Time)
2109 2110 return fieldTime.After(t)
2111 }
2112 2113 // Not Same underlying type i.e. struct and time
2114 if fieldType != currentField.Type() {
2115 return false
2116 }
2117 }
2118 2119 // default reflect.String
2120 return len(field.String()) > len(currentField.String())
2121 }
2122 2123 // isGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
2124 func isGte(fl FieldLevel) bool {
2125 field := fl.Field()
2126 param := fl.Param()
2127 2128 switch field.Kind() {
2129 2130 case reflect.String:
2131 p := asInt(param)
2132 2133 return int64(utf8.RuneCountInString(field.String())) >= p
2134 2135 case reflect.Slice, reflect.Map, reflect.Array:
2136 p := asInt(param)
2137 2138 return int64(field.Len()) >= p
2139 2140 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2141 p := asIntFromType(field.Type(), param)
2142 2143 return field.Int() >= p
2144 2145 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2146 p := asUint(param)
2147 2148 return field.Uint() >= p
2149 2150 case reflect.Float32:
2151 p := asFloat32(param)
2152 2153 return field.Float() >= p
2154 2155 case reflect.Float64:
2156 p := asFloat64(param)
2157 2158 return field.Float() >= p
2159 2160 case reflect.Struct:
2161 2162 if field.Type().ConvertibleTo(timeType) {
2163 2164 now := time.Now().UTC()
2165 t := field.Convert(timeType).Interface().(time.Time)
2166 2167 return t.After(now) || t.Equal(now)
2168 }
2169 }
2170 2171 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2172 }
2173 2174 // isGt is the validation function for validating if the current field's value is greater than the param's value.
2175 func isGt(fl FieldLevel) bool {
2176 field := fl.Field()
2177 param := fl.Param()
2178 2179 switch field.Kind() {
2180 2181 case reflect.String:
2182 p := asInt(param)
2183 2184 return int64(utf8.RuneCountInString(field.String())) > p
2185 2186 case reflect.Slice, reflect.Map, reflect.Array:
2187 p := asInt(param)
2188 2189 return int64(field.Len()) > p
2190 2191 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2192 p := asIntFromType(field.Type(), param)
2193 2194 return field.Int() > p
2195 2196 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2197 p := asUint(param)
2198 2199 return field.Uint() > p
2200 2201 case reflect.Float32:
2202 p := asFloat32(param)
2203 2204 return field.Float() > p
2205 2206 case reflect.Float64:
2207 p := asFloat64(param)
2208 2209 return field.Float() > p
2210 2211 case reflect.Struct:
2212 2213 if field.Type().ConvertibleTo(timeType) {
2214 2215 return field.Convert(timeType).Interface().(time.Time).After(time.Now().UTC())
2216 }
2217 }
2218 2219 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2220 }
2221 2222 // hasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
2223 func hasLengthOf(fl FieldLevel) bool {
2224 field := fl.Field()
2225 param := fl.Param()
2226 2227 switch field.Kind() {
2228 2229 case reflect.String:
2230 p := asInt(param)
2231 2232 return int64(utf8.RuneCountInString(field.String())) == p
2233 2234 case reflect.Slice, reflect.Map, reflect.Array:
2235 p := asInt(param)
2236 2237 return int64(field.Len()) == p
2238 2239 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2240 p := asIntFromType(field.Type(), param)
2241 2242 return field.Int() == p
2243 2244 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2245 p := asUint(param)
2246 2247 return field.Uint() == p
2248 2249 case reflect.Float32:
2250 p := asFloat32(param)
2251 2252 return field.Float() == p
2253 2254 case reflect.Float64:
2255 p := asFloat64(param)
2256 2257 return field.Float() == p
2258 }
2259 2260 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2261 }
2262 2263 // hasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
2264 func hasMinOf(fl FieldLevel) bool {
2265 return isGte(fl)
2266 }
2267 2268 // isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
2269 func isLteField(fl FieldLevel) bool {
2270 field := fl.Field()
2271 kind := field.Kind()
2272 2273 currentField, currentKind, ok := fl.GetStructFieldOK()
2274 if !ok || currentKind != kind {
2275 return false
2276 }
2277 2278 switch kind {
2279 2280 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2281 2282 return field.Int() <= currentField.Int()
2283 2284 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2285 2286 return field.Uint() <= currentField.Uint()
2287 2288 case reflect.Float32, reflect.Float64:
2289 2290 return field.Float() <= currentField.Float()
2291 2292 case reflect.Struct:
2293 2294 fieldType := field.Type()
2295 2296 if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
2297 2298 t := currentField.Convert(timeType).Interface().(time.Time)
2299 fieldTime := field.Convert(timeType).Interface().(time.Time)
2300 2301 return fieldTime.Before(t) || fieldTime.Equal(t)
2302 }
2303 2304 // Not Same underlying type i.e. struct and time
2305 if fieldType != currentField.Type() {
2306 return false
2307 }
2308 }
2309 2310 // default reflect.String
2311 return len(field.String()) <= len(currentField.String())
2312 }
2313 2314 // isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
2315 func isLtField(fl FieldLevel) bool {
2316 field := fl.Field()
2317 kind := field.Kind()
2318 2319 currentField, currentKind, ok := fl.GetStructFieldOK()
2320 if !ok || currentKind != kind {
2321 return false
2322 }
2323 2324 switch kind {
2325 2326 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2327 2328 return field.Int() < currentField.Int()
2329 2330 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2331 2332 return field.Uint() < currentField.Uint()
2333 2334 case reflect.Float32, reflect.Float64:
2335 2336 return field.Float() < currentField.Float()
2337 2338 case reflect.Struct:
2339 2340 fieldType := field.Type()
2341 2342 if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
2343 2344 t := currentField.Convert(timeType).Interface().(time.Time)
2345 fieldTime := field.Convert(timeType).Interface().(time.Time)
2346 2347 return fieldTime.Before(t)
2348 }
2349 2350 // Not Same underlying type i.e. struct and time
2351 if fieldType != currentField.Type() {
2352 return false
2353 }
2354 }
2355 2356 // default reflect.String
2357 return len(field.String()) < len(currentField.String())
2358 }
2359 2360 // isLte is the validation function for validating if the current field's value is less than or equal to the param's value.
2361 func isLte(fl FieldLevel) bool {
2362 field := fl.Field()
2363 param := fl.Param()
2364 2365 switch field.Kind() {
2366 2367 case reflect.String:
2368 p := asInt(param)
2369 2370 return int64(utf8.RuneCountInString(field.String())) <= p
2371 2372 case reflect.Slice, reflect.Map, reflect.Array:
2373 p := asInt(param)
2374 2375 return int64(field.Len()) <= p
2376 2377 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2378 p := asIntFromType(field.Type(), param)
2379 2380 return field.Int() <= p
2381 2382 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2383 p := asUint(param)
2384 2385 return field.Uint() <= p
2386 2387 case reflect.Float32:
2388 p := asFloat32(param)
2389 2390 return field.Float() <= p
2391 2392 case reflect.Float64:
2393 p := asFloat64(param)
2394 2395 return field.Float() <= p
2396 2397 case reflect.Struct:
2398 2399 if field.Type().ConvertibleTo(timeType) {
2400 2401 now := time.Now().UTC()
2402 t := field.Convert(timeType).Interface().(time.Time)
2403 2404 return t.Before(now) || t.Equal(now)
2405 }
2406 }
2407 2408 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2409 }
2410 2411 // isLt is the validation function for validating if the current field's value is less than the param's value.
2412 func isLt(fl FieldLevel) bool {
2413 field := fl.Field()
2414 param := fl.Param()
2415 2416 switch field.Kind() {
2417 2418 case reflect.String:
2419 p := asInt(param)
2420 2421 return int64(utf8.RuneCountInString(field.String())) < p
2422 2423 case reflect.Slice, reflect.Map, reflect.Array:
2424 p := asInt(param)
2425 2426 return int64(field.Len()) < p
2427 2428 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2429 p := asIntFromType(field.Type(), param)
2430 2431 return field.Int() < p
2432 2433 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
2434 p := asUint(param)
2435 2436 return field.Uint() < p
2437 2438 case reflect.Float32:
2439 p := asFloat32(param)
2440 2441 return field.Float() < p
2442 2443 case reflect.Float64:
2444 p := asFloat64(param)
2445 2446 return field.Float() < p
2447 2448 case reflect.Struct:
2449 2450 if field.Type().ConvertibleTo(timeType) {
2451 2452 return field.Convert(timeType).Interface().(time.Time).Before(time.Now().UTC())
2453 }
2454 }
2455 2456 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2457 }
2458 2459 // hasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
2460 func hasMaxOf(fl FieldLevel) bool {
2461 return isLte(fl)
2462 }
2463 2464 // isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
2465 func isTCP4AddrResolvable(fl FieldLevel) bool {
2466 if !isIP4Addr(fl) {
2467 return false
2468 }
2469 2470 _, err := net.ResolveTCPAddr("tcp4", fl.Field().String())
2471 return err == nil
2472 }
2473 2474 // isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
2475 func isTCP6AddrResolvable(fl FieldLevel) bool {
2476 if !isIP6Addr(fl) {
2477 return false
2478 }
2479 2480 _, err := net.ResolveTCPAddr("tcp6", fl.Field().String())
2481 2482 return err == nil
2483 }
2484 2485 // isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
2486 func isTCPAddrResolvable(fl FieldLevel) bool {
2487 if !isIP4Addr(fl) && !isIP6Addr(fl) {
2488 return false
2489 }
2490 2491 _, err := net.ResolveTCPAddr("tcp", fl.Field().String())
2492 2493 return err == nil
2494 }
2495 2496 // isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
2497 func isUDP4AddrResolvable(fl FieldLevel) bool {
2498 if !isIP4Addr(fl) {
2499 return false
2500 }
2501 2502 _, err := net.ResolveUDPAddr("udp4", fl.Field().String())
2503 2504 return err == nil
2505 }
2506 2507 // isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
2508 func isUDP6AddrResolvable(fl FieldLevel) bool {
2509 if !isIP6Addr(fl) {
2510 return false
2511 }
2512 2513 _, err := net.ResolveUDPAddr("udp6", fl.Field().String())
2514 2515 return err == nil
2516 }
2517 2518 // isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
2519 func isUDPAddrResolvable(fl FieldLevel) bool {
2520 if !isIP4Addr(fl) && !isIP6Addr(fl) {
2521 return false
2522 }
2523 2524 _, err := net.ResolveUDPAddr("udp", fl.Field().String())
2525 2526 return err == nil
2527 }
2528 2529 // isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
2530 func isIP4AddrResolvable(fl FieldLevel) bool {
2531 if !isIPv4(fl) {
2532 return false
2533 }
2534 2535 _, err := net.ResolveIPAddr("ip4", fl.Field().String())
2536 2537 return err == nil
2538 }
2539 2540 // isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
2541 func isIP6AddrResolvable(fl FieldLevel) bool {
2542 if !isIPv6(fl) {
2543 return false
2544 }
2545 2546 _, err := net.ResolveIPAddr("ip6", fl.Field().String())
2547 2548 return err == nil
2549 }
2550 2551 // isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
2552 func isIPAddrResolvable(fl FieldLevel) bool {
2553 if !isIP(fl) {
2554 return false
2555 }
2556 2557 _, err := net.ResolveIPAddr("ip", fl.Field().String())
2558 2559 return err == nil
2560 }
2561 2562 // isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
2563 func isUnixAddrResolvable(fl FieldLevel) bool {
2564 _, err := net.ResolveUnixAddr("unix", fl.Field().String())
2565 2566 return err == nil
2567 }
2568 2569 func isIP4Addr(fl FieldLevel) bool {
2570 val := fl.Field().String()
2571 2572 if idx := strings.LastIndex(val, ":"); idx != -1 {
2573 val = val[0:idx]
2574 }
2575 2576 ip := net.ParseIP(val)
2577 2578 return ip != nil && ip.To4() != nil
2579 }
2580 2581 func isIP6Addr(fl FieldLevel) bool {
2582 val := fl.Field().String()
2583 2584 if idx := strings.LastIndex(val, ":"); idx != -1 {
2585 if idx != 0 && val[idx-1:idx] == "]" {
2586 val = val[1 : idx-1]
2587 }
2588 }
2589 2590 ip := net.ParseIP(val)
2591 2592 return ip != nil && ip.To4() == nil
2593 }
2594 2595 func isHostnameRFC952(fl FieldLevel) bool {
2596 return hostnameRegexRFC952().MatchString(fl.Field().String())
2597 }
2598 2599 func isHostnameRFC1123(fl FieldLevel) bool {
2600 return hostnameRegexRFC1123().MatchString(fl.Field().String())
2601 }
2602 2603 func isFQDN(fl FieldLevel) bool {
2604 val := fl.Field().String()
2605 2606 if val == "" {
2607 return false
2608 }
2609 2610 return fqdnRegexRFC1123().MatchString(val)
2611 }
2612 2613 // isDir is the validation function for validating if the current field's value is a valid existing directory.
2614 func isDir(fl FieldLevel) bool {
2615 field := fl.Field()
2616 2617 if field.Kind() == reflect.String {
2618 fileInfo, err := os.Stat(field.String())
2619 if err != nil {
2620 return false
2621 }
2622 2623 return fileInfo.IsDir()
2624 }
2625 2626 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2627 }
2628 2629 // isDirPath is the validation function for validating if the current field's value is a valid directory.
2630 func isDirPath(fl FieldLevel) bool {
2631 2632 var exists bool
2633 var err error
2634 2635 field := fl.Field()
2636 2637 // If it exists, it obviously is valid.
2638 // This is done first to avoid code duplication and unnecessary additional logic.
2639 if exists = isDir(fl); exists {
2640 return true
2641 }
2642 2643 // It does not exist but may still be a valid path.
2644 switch field.Kind() {
2645 case reflect.String:
2646 // Every OS allows for whitespace, but none
2647 // let you use a dir with no name (to my knowledge).
2648 // Unless you're dealing with raw inodes, but I digress.
2649 if strings.TrimSpace(field.String()) == "" {
2650 return false
2651 }
2652 if _, err = os.Stat(field.String()); err != nil {
2653 switch t := err.(type) {
2654 case *fs.PathError:
2655 if t.Err == syscall.EINVAL {
2656 // It's definitely an invalid character in the path.
2657 return false
2658 }
2659 // It could be a permission error, a does-not-exist error, etc.
2660 // Out-of-scope for this validation, though.
2661 // Lastly, we make sure it is a directory.
2662 if strings.HasSuffix(field.String(), string(os.PathSeparator)) {
2663 return true
2664 } else {
2665 return false
2666 }
2667 default:
2668 // Something went *seriously* wrong.
2669 /*
2670 Per https://pkg.go.dev/os#Stat:
2671 "If there is an error, it will be of type *PathError."
2672 */
2673 panic(err)
2674 }
2675 }
2676 // We repeat the check here to make sure it is an explicit directory in case the above os.Stat didn't trigger an error.
2677 if strings.HasSuffix(field.String(), string(os.PathSeparator)) {
2678 return true
2679 } else {
2680 return false
2681 }
2682 }
2683 2684 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2685 }
2686 2687 // isJSON is the validation function for validating if the current field's value is a valid json string.
2688 func isJSON(fl FieldLevel) bool {
2689 field := fl.Field()
2690 2691 switch field.Kind() {
2692 case reflect.String:
2693 val := field.String()
2694 return json.Valid([]byte(val))
2695 case reflect.Slice:
2696 fieldType := field.Type()
2697 2698 if fieldType.ConvertibleTo(byteSliceType) {
2699 b := field.Convert(byteSliceType).Interface().([]byte)
2700 return json.Valid(b)
2701 }
2702 }
2703 2704 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2705 }
2706 2707 // isJWT is the validation function for validating if the current field's value is a valid JWT string.
2708 func isJWT(fl FieldLevel) bool {
2709 return jWTRegex().MatchString(fl.Field().String())
2710 }
2711 2712 // isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address.
2713 func isHostnamePort(fl FieldLevel) bool {
2714 val := fl.Field().String()
2715 host, port, err := net.SplitHostPort(val)
2716 if err != nil {
2717 return false
2718 }
2719 // Port must be a iny <= 65535.
2720 if portNum, err := strconv.ParseInt(
2721 port, 10, 32,
2722 ); err != nil || portNum > 65535 || portNum < 1 {
2723 return false
2724 }
2725 2726 // If host is specified, it should match a DNS name
2727 if host != "" {
2728 return hostnameRegexRFC1123().MatchString(host)
2729 }
2730 return true
2731 }
2732 2733 // IsPort validates if the current field's value represents a valid port
2734 func isPort(fl FieldLevel) bool {
2735 val := fl.Field().Uint()
2736 2737 return val >= 1 && val <= 65535
2738 }
2739 2740 // isLowercase is the validation function for validating if the current field's value is a lowercase string.
2741 func isLowercase(fl FieldLevel) bool {
2742 field := fl.Field()
2743 2744 if field.Kind() == reflect.String {
2745 if field.String() == "" {
2746 return false
2747 }
2748 return field.String() == strings.ToLower(field.String())
2749 }
2750 2751 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2752 }
2753 2754 // isUppercase is the validation function for validating if the current field's value is an uppercase string.
2755 func isUppercase(fl FieldLevel) bool {
2756 field := fl.Field()
2757 2758 if field.Kind() == reflect.String {
2759 if field.String() == "" {
2760 return false
2761 }
2762 return field.String() == strings.ToUpper(field.String())
2763 }
2764 2765 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2766 }
2767 2768 // isDatetime is the validation function for validating if the current field's value is a valid datetime string.
2769 func isDatetime(fl FieldLevel) bool {
2770 field := fl.Field()
2771 param := fl.Param()
2772 2773 if field.Kind() == reflect.String {
2774 _, err := time.Parse(param, field.String())
2775 2776 return err == nil
2777 }
2778 2779 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2780 }
2781 2782 // isTimeZone is the validation function for validating if the current field's value is a valid time zone string.
2783 func isTimeZone(fl FieldLevel) bool {
2784 field := fl.Field()
2785 2786 if field.Kind() == reflect.String {
2787 // empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name
2788 if field.String() == "" {
2789 return false
2790 }
2791 2792 // Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name
2793 if strings.ToLower(field.String()) == "local" {
2794 return false
2795 }
2796 2797 _, err := time.LoadLocation(field.String())
2798 return err == nil
2799 }
2800 2801 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2802 }
2803 2804 // isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code.
2805 func isIso3166Alpha2(fl FieldLevel) bool {
2806 _, ok := iso3166_1_alpha2[fl.Field().String()]
2807 return ok
2808 }
2809 2810 // isIso3166Alpha2EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 European Union country code.
2811 func isIso3166Alpha2EU(fl FieldLevel) bool {
2812 _, ok := iso3166_1_alpha2_eu[fl.Field().String()]
2813 return ok
2814 }
2815 2816 // isIso3166Alpha3 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code.
2817 func isIso3166Alpha3(fl FieldLevel) bool {
2818 _, ok := iso3166_1_alpha3[fl.Field().String()]
2819 return ok
2820 }
2821 2822 // isIso3166Alpha3EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 European Union country code.
2823 func isIso3166Alpha3EU(fl FieldLevel) bool {
2824 _, ok := iso3166_1_alpha3_eu[fl.Field().String()]
2825 return ok
2826 }
2827 2828 // isIso3166AlphaNumeric is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code.
2829 func isIso3166AlphaNumeric(fl FieldLevel) bool {
2830 field := fl.Field()
2831 2832 var code int
2833 switch field.Kind() {
2834 case reflect.String:
2835 i, err := strconv.Atoi(field.String())
2836 if err != nil {
2837 return false
2838 }
2839 code = i % 1000
2840 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2841 code = int(field.Int() % 1000)
2842 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
2843 code = int(field.Uint() % 1000)
2844 default:
2845 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2846 }
2847 2848 _, ok := iso3166_1_alpha_numeric[code]
2849 return ok
2850 }
2851 2852 // isIso3166AlphaNumericEU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric European Union country code.
2853 func isIso3166AlphaNumericEU(fl FieldLevel) bool {
2854 field := fl.Field()
2855 2856 var code int
2857 switch field.Kind() {
2858 case reflect.String:
2859 i, err := strconv.Atoi(field.String())
2860 if err != nil {
2861 return false
2862 }
2863 code = i % 1000
2864 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2865 code = int(field.Int() % 1000)
2866 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
2867 code = int(field.Uint() % 1000)
2868 default:
2869 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2870 }
2871 2872 _, ok := iso3166_1_alpha_numeric_eu[code]
2873 return ok
2874 }
2875 2876 // isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code.
2877 func isIso31662(fl FieldLevel) bool {
2878 _, ok := iso3166_2[fl.Field().String()]
2879 return ok
2880 }
2881 2882 // isIso4217 is the validation function for validating if the current field's value is a valid iso4217 currency code.
2883 func isIso4217(fl FieldLevel) bool {
2884 _, ok := iso4217[fl.Field().String()]
2885 return ok
2886 }
2887 2888 // isIso4217Numeric is the validation function for validating if the current field's value is a valid iso4217 numeric currency code.
2889 func isIso4217Numeric(fl FieldLevel) bool {
2890 field := fl.Field()
2891 2892 var code int
2893 switch field.Kind() {
2894 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
2895 code = int(field.Int())
2896 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
2897 code = int(field.Uint())
2898 default:
2899 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2900 }
2901 2902 _, ok := iso4217_numeric[code]
2903 return ok
2904 }
2905 2906 // isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse
2907 func isBCP47LanguageTag(fl FieldLevel) bool {
2908 field := fl.Field()
2909 2910 if field.Kind() == reflect.String {
2911 _, err := language.Parse(field.String())
2912 return err == nil
2913 }
2914 2915 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
2916 }
2917 2918 // isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362
2919 func isIsoBicFormat(fl FieldLevel) bool {
2920 bicString := fl.Field().String()
2921 2922 return bicRegex().MatchString(bicString)
2923 }
2924 2925 // isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0
2926 func isSemverFormat(fl FieldLevel) bool {
2927 semverString := fl.Field().String()
2928 2929 return semverRegex().MatchString(semverString)
2930 }
2931 2932 // isCveFormat is the validation function for validating if the current field's value is a valid cve id, defined in CVE mitre org
2933 func isCveFormat(fl FieldLevel) bool {
2934 cveString := fl.Field().String()
2935 2936 return cveRegex().MatchString(cveString)
2937 }
2938 2939 // isDnsRFC1035LabelFormat is the validation function
2940 // for validating if the current field's value is
2941 // a valid dns RFC 1035 label, defined in RFC 1035.
2942 func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
2943 val := fl.Field().String()
2944 return dnsRegexRFC1035Label().MatchString(val)
2945 }
2946 2947 // digitsHaveLuhnChecksum returns true if and only if the last element of the given digits slice is the Luhn checksum of the previous elements
2948 func digitsHaveLuhnChecksum(digits []string) bool {
2949 size := len(digits)
2950 sum := 0
2951 for i, digit := range digits {
2952 value, err := strconv.Atoi(digit)
2953 if err != nil {
2954 return false
2955 }
2956 if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 {
2957 v := value * 2
2958 if v >= 10 {
2959 sum += 1 + (v % 10)
2960 } else {
2961 sum += v
2962 }
2963 } else {
2964 sum += value
2965 }
2966 }
2967 return (sum % 10) == 0
2968 }
2969 2970 // isMongoDBObjectId is the validation function for validating if the current field's value is valid MongoDB ObjectID
2971 func isMongoDBObjectId(fl FieldLevel) bool {
2972 val := fl.Field().String()
2973 return mongodbIdRegex().MatchString(val)
2974 }
2975 2976 // isMongoDBConnectionString is the validation function for validating if the current field's value is valid MongoDB Connection String
2977 func isMongoDBConnectionString(fl FieldLevel) bool {
2978 val := fl.Field().String()
2979 return mongodbConnectionRegex().MatchString(val)
2980 }
2981 2982 // isSpiceDB is the validation function for validating if the current field's value is valid for use with Authzed SpiceDB in the indicated way
2983 func isSpiceDB(fl FieldLevel) bool {
2984 val := fl.Field().String()
2985 param := fl.Param()
2986 2987 switch param {
2988 case "permission":
2989 return spicedbPermissionRegex().MatchString(val)
2990 case "type":
2991 return spicedbTypeRegex().MatchString(val)
2992 case "id", "":
2993 return spicedbIDRegex().MatchString(val)
2994 }
2995 2996 panic("Unrecognized parameter: " + param)
2997 }
2998 2999 // isCreditCard is the validation function for validating if the current field's value is a valid credit card number
3000 func isCreditCard(fl FieldLevel) bool {
3001 val := fl.Field().String()
3002 var creditCard bytes.Buffer
3003 segments := strings.Split(val, " ")
3004 for _, segment := range segments {
3005 if len(segment) < 3 {
3006 return false
3007 }
3008 creditCard.WriteString(segment)
3009 }
3010 3011 ccDigits := strings.Split(creditCard.String(), "")
3012 size := len(ccDigits)
3013 if size < 12 || size > 19 {
3014 return false
3015 }
3016 3017 return digitsHaveLuhnChecksum(ccDigits)
3018 }
3019 3020 // hasLuhnChecksum is the validation for validating if the current field's value has a valid Luhn checksum
3021 func hasLuhnChecksum(fl FieldLevel) bool {
3022 field := fl.Field()
3023 var str string // convert to a string which will then be split into single digits; easier and more readable than shifting/extracting single digits from a number
3024 switch field.Kind() {
3025 case reflect.String:
3026 str = field.String()
3027 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
3028 str = strconv.FormatInt(field.Int(), 10)
3029 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
3030 str = strconv.FormatUint(field.Uint(), 10)
3031 default:
3032 panic(fmt.Sprintf("Bad field type %T", field.Interface()))
3033 }
3034 size := len(str)
3035 if size < 2 { // there has to be at least one digit that carries a meaning + the checksum
3036 return false
3037 }
3038 digits := strings.Split(str, "")
3039 return digitsHaveLuhnChecksum(digits)
3040 }
3041 3042 // isCron is the validation function for validating if the current field's value is a valid cron expression
3043 func isCron(fl FieldLevel) bool {
3044 cronString := fl.Field().String()
3045 return cronRegex().MatchString(cronString)
3046 }
3047