...

Source file src/github.com/go-playground/validator/v10/baked_in.go

Documentation: github.com/go-playground/validator/v10

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

View as plain text