gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

baked_in.go (84767B)


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