...

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

View as plain text