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