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