baked_in.go raw

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