git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/validate/validator.go (about)

     1  // Package govalidator is package of validators and sanitizers for strings, structs and collections.
     2  package validate
     3  
     4  import (
     5  	"bytes"
     6  	"crypto/rsa"
     7  	"crypto/x509"
     8  	"encoding/base64"
     9  	"encoding/json"
    10  	"encoding/pem"
    11  	"fmt"
    12  	"io"
    13  	"net"
    14  	"net/url"
    15  	"reflect"
    16  	"regexp"
    17  	"sort"
    18  	"strconv"
    19  	"strings"
    20  	"time"
    21  	"unicode"
    22  	"unicode/utf8"
    23  )
    24  
    25  var (
    26  	fieldsRequiredByDefault bool
    27  	nilPtrAllowedByRequired = false
    28  	notNumberRegexp         = regexp.MustCompile("[^0-9]+")
    29  	whiteSpacesAndMinus     = regexp.MustCompile(`[\s-]+`)
    30  	paramsRegexp            = regexp.MustCompile(`\(.*\)$`)
    31  )
    32  
    33  const maxURLRuneCount = 2083
    34  const minURLRuneCount = 3
    35  const rfc3339WithoutZone = "2006-01-02T15:04:05"
    36  
    37  // SetFieldsRequiredByDefault causes validation to fail when struct fields
    38  // do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`).
    39  // This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
    40  //
    41  //	type exampleStruct struct {
    42  //	    Name  string ``
    43  //	    Email string `valid:"email"`
    44  //
    45  // This, however, will only fail when Email is empty or an invalid email address:
    46  //
    47  //	type exampleStruct2 struct {
    48  //	    Name  string `valid:"-"`
    49  //	    Email string `valid:"email"`
    50  //
    51  // Lastly, this will only fail when Email is an invalid email address but not when it's empty:
    52  //
    53  //	type exampleStruct2 struct {
    54  //	    Name  string `valid:"-"`
    55  //	    Email string `valid:"email,optional"`
    56  func SetFieldsRequiredByDefault(value bool) {
    57  	fieldsRequiredByDefault = value
    58  }
    59  
    60  // SetNilPtrAllowedByRequired causes validation to pass for nil ptrs when a field is set to required.
    61  // The validation will still reject ptr fields in their zero value state. Example with this enabled:
    62  //
    63  //	type exampleStruct struct {
    64  //	    Name  *string `valid:"required"`
    65  //
    66  // With `Name` set to "", this will be considered invalid input and will cause a validation error.
    67  // With `Name` set to nil, this will be considered valid by validation.
    68  // By default this is disabled.
    69  func SetNilPtrAllowedByRequired(value bool) {
    70  	nilPtrAllowedByRequired = value
    71  }
    72  
    73  // IsEmail checks if the string is an email.
    74  func IsEmail(str string) bool {
    75  	// TODO uppercase letters are not supported
    76  	return rxEmail.MatchString(str)
    77  }
    78  
    79  // IsExistingEmail checks if the string is an email of existing domain
    80  func IsExistingEmail(email string) bool {
    81  
    82  	if len(email) < 6 || len(email) > 254 {
    83  		return false
    84  	}
    85  	at := strings.LastIndex(email, "@")
    86  	if at <= 0 || at > len(email)-3 {
    87  		return false
    88  	}
    89  	user := email[:at]
    90  	host := email[at+1:]
    91  	if len(user) > 64 {
    92  		return false
    93  	}
    94  	switch host {
    95  	case "localhost", "example.com":
    96  		return true
    97  	}
    98  	if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) {
    99  		return false
   100  	}
   101  	if _, err := net.LookupMX(host); err != nil {
   102  		if _, err := net.LookupIP(host); err != nil {
   103  			return false
   104  		}
   105  	}
   106  
   107  	return true
   108  }
   109  
   110  // IsURL checks if the string is an URL.
   111  func IsURL(str string) bool {
   112  	if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") {
   113  		return false
   114  	}
   115  	strTemp := str
   116  	if strings.Contains(str, ":") && !strings.Contains(str, "://") {
   117  		// support no indicated urlscheme but with colon for port number
   118  		// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
   119  		strTemp = "http://" + str
   120  	}
   121  	u, err := url.Parse(strTemp)
   122  	if err != nil {
   123  		return false
   124  	}
   125  	if strings.HasPrefix(u.Host, ".") {
   126  		return false
   127  	}
   128  	if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
   129  		return false
   130  	}
   131  	return rxURL.MatchString(str)
   132  }
   133  
   134  // IsRequestURL checks if the string rawurl, assuming
   135  // it was received in an HTTP request, is a valid
   136  // URL confirm to RFC 3986
   137  func IsRequestURL(rawurl string) bool {
   138  	url, err := url.ParseRequestURI(rawurl)
   139  	if err != nil {
   140  		return false //Couldn't even parse the rawurl
   141  	}
   142  	if len(url.Scheme) == 0 {
   143  		return false //No Scheme found
   144  	}
   145  	return true
   146  }
   147  
   148  // IsRequestURI checks if the string rawurl, assuming
   149  // it was received in an HTTP request, is an
   150  // absolute URI or an absolute path.
   151  func IsRequestURI(rawurl string) bool {
   152  	_, err := url.ParseRequestURI(rawurl)
   153  	return err == nil
   154  }
   155  
   156  // IsAlpha checks if the string contains only letters (a-zA-Z). Empty string is valid.
   157  func IsAlpha(str string) bool {
   158  	if IsNull(str) {
   159  		return true
   160  	}
   161  	return rxAlpha.MatchString(str)
   162  }
   163  
   164  // IsUTFLetter checks if the string contains only unicode letter characters.
   165  // Similar to IsAlpha but for all languages. Empty string is valid.
   166  func IsUTFLetter(str string) bool {
   167  	if IsNull(str) {
   168  		return true
   169  	}
   170  
   171  	for _, c := range str {
   172  		if !unicode.IsLetter(c) {
   173  			return false
   174  		}
   175  	}
   176  	return true
   177  
   178  }
   179  
   180  // IsAlphanumeric checks if the string contains only letters and numbers. Empty string is valid.
   181  func IsAlphanumeric(str string) bool {
   182  	if IsNull(str) {
   183  		return true
   184  	}
   185  	return rxAlphanumeric.MatchString(str)
   186  }
   187  
   188  // IsUTFLetterNumeric checks if the string contains only unicode letters and numbers. Empty string is valid.
   189  func IsUTFLetterNumeric(str string) bool {
   190  	if IsNull(str) {
   191  		return true
   192  	}
   193  	for _, c := range str {
   194  		if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok
   195  			return false
   196  		}
   197  	}
   198  	return true
   199  
   200  }
   201  
   202  // IsNumeric checks if the string contains only numbers. Empty string is valid.
   203  func IsNumeric(str string) bool {
   204  	if IsNull(str) {
   205  		return true
   206  	}
   207  	return rxNumeric.MatchString(str)
   208  }
   209  
   210  // IsUTFNumeric checks if the string contains only unicode numbers of any kind.
   211  // Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid.
   212  func IsUTFNumeric(str string) bool {
   213  	if IsNull(str) {
   214  		return true
   215  	}
   216  	if strings.IndexAny(str, "+-") > 0 {
   217  		return false
   218  	}
   219  	if len(str) > 1 {
   220  		str = strings.TrimPrefix(str, "-")
   221  		str = strings.TrimPrefix(str, "+")
   222  	}
   223  	for _, c := range str {
   224  		if !unicode.IsNumber(c) { //numbers && minus sign are ok
   225  			return false
   226  		}
   227  	}
   228  	return true
   229  
   230  }
   231  
   232  // IsUTFDigit checks if the string contains only unicode radix-10 decimal digits. Empty string is valid.
   233  func IsUTFDigit(str string) bool {
   234  	if IsNull(str) {
   235  		return true
   236  	}
   237  	if strings.IndexAny(str, "+-") > 0 {
   238  		return false
   239  	}
   240  	if len(str) > 1 {
   241  		str = strings.TrimPrefix(str, "-")
   242  		str = strings.TrimPrefix(str, "+")
   243  	}
   244  	for _, c := range str {
   245  		if !unicode.IsDigit(c) { //digits && minus sign are ok
   246  			return false
   247  		}
   248  	}
   249  	return true
   250  
   251  }
   252  
   253  // IsHexadecimal checks if the string is a hexadecimal number.
   254  func IsHexadecimal(str string) bool {
   255  	return rxHexadecimal.MatchString(str)
   256  }
   257  
   258  // IsHexcolor checks if the string is a hexadecimal color.
   259  func IsHexcolor(str string) bool {
   260  	return rxHexcolor.MatchString(str)
   261  }
   262  
   263  // IsRGBcolor checks if the string is a valid RGB color in form rgb(RRR, GGG, BBB).
   264  func IsRGBcolor(str string) bool {
   265  	return rxRGBcolor.MatchString(str)
   266  }
   267  
   268  // IsLowerCase checks if the string is lowercase. Empty string is valid.
   269  func IsLowerCase(str string) bool {
   270  	if IsNull(str) {
   271  		return true
   272  	}
   273  	return str == strings.ToLower(str)
   274  }
   275  
   276  // IsUpperCase checks if the string is uppercase. Empty string is valid.
   277  func IsUpperCase(str string) bool {
   278  	if IsNull(str) {
   279  		return true
   280  	}
   281  	return str == strings.ToUpper(str)
   282  }
   283  
   284  // HasLowerCase checks if the string contains at least 1 lowercase. Empty string is valid.
   285  func HasLowerCase(str string) bool {
   286  	if IsNull(str) {
   287  		return true
   288  	}
   289  	return rxHasLowerCase.MatchString(str)
   290  }
   291  
   292  // HasUpperCase checks if the string contains as least 1 uppercase. Empty string is valid.
   293  func HasUpperCase(str string) bool {
   294  	if IsNull(str) {
   295  		return true
   296  	}
   297  	return rxHasUpperCase.MatchString(str)
   298  }
   299  
   300  // IsInt checks if the string is an integer. Empty string is valid.
   301  func IsInt(str string) bool {
   302  	if IsNull(str) {
   303  		return true
   304  	}
   305  	return rxInt.MatchString(str)
   306  }
   307  
   308  // IsFloat checks if the string is a float.
   309  func IsFloat(str string) bool {
   310  	return str != "" && rxFloat.MatchString(str)
   311  }
   312  
   313  // IsDivisibleBy checks if the string is a number that's divisible by another.
   314  // If second argument is not valid integer or zero, it's return false.
   315  // Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero).
   316  func IsDivisibleBy(str, num string) bool {
   317  	f, _ := ToFloat(str)
   318  	p := int64(f)
   319  	q, _ := ToInt(num)
   320  	if q == 0 {
   321  		return false
   322  	}
   323  	return (p == 0) || (p%q == 0)
   324  }
   325  
   326  // IsNull checks if the string is null.
   327  func IsNull(str string) bool {
   328  	return len(str) == 0
   329  }
   330  
   331  // IsNotNull checks if the string is not null.
   332  func IsNotNull(str string) bool {
   333  	return !IsNull(str)
   334  }
   335  
   336  // HasWhitespaceOnly checks the string only contains whitespace
   337  func HasWhitespaceOnly(str string) bool {
   338  	return len(str) > 0 && rxHasWhitespaceOnly.MatchString(str)
   339  }
   340  
   341  // HasWhitespace checks if the string contains any whitespace
   342  func HasWhitespace(str string) bool {
   343  	return len(str) > 0 && rxHasWhitespace.MatchString(str)
   344  }
   345  
   346  // IsByteLength checks if the string's length (in bytes) falls in a range.
   347  func IsByteLength(str string, min, max int) bool {
   348  	return len(str) >= min && len(str) <= max
   349  }
   350  
   351  // IsUUIDv3 checks if the string is a UUID version 3.
   352  func IsUUIDv3(str string) bool {
   353  	return rxUUID3.MatchString(str)
   354  }
   355  
   356  // IsUUIDv4 checks if the string is a UUID version 4.
   357  func IsUUIDv4(str string) bool {
   358  	return rxUUID4.MatchString(str)
   359  }
   360  
   361  // IsUUIDv5 checks if the string is a UUID version 5.
   362  func IsUUIDv5(str string) bool {
   363  	return rxUUID5.MatchString(str)
   364  }
   365  
   366  // IsUUID checks if the string is a UUID (version 3, 4 or 5).
   367  func IsUUID(str string) bool {
   368  	return rxUUID.MatchString(str)
   369  }
   370  
   371  // Byte to index table for O(1) lookups when unmarshaling.
   372  // We use 0xFF as sentinel value for invalid indexes.
   373  var ulidDec = [...]byte{
   374  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   375  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   376  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   377  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   378  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
   379  	0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF,
   380  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
   381  	0x0F, 0x10, 0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14, 0x15, 0xFF,
   382  	0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C, 0x1D, 0x1E,
   383  	0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C,
   384  	0x0D, 0x0E, 0x0F, 0x10, 0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14,
   385  	0x15, 0xFF, 0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C,
   386  	0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   387  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   388  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   389  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   390  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   391  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   392  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   393  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   394  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   395  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   396  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   397  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   398  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   399  	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   400  }
   401  
   402  // EncodedSize is the length of a text encoded ULID.
   403  const ulidEncodedSize = 26
   404  
   405  // IsULID checks if the string is a ULID.
   406  //
   407  // Implementation got from:
   408  //
   409  //	https://github.com/oklog/ulid (Apache-2.0 License)
   410  func IsULID(str string) bool {
   411  	// Check if a base32 encoded ULID is the right length.
   412  	if len(str) != ulidEncodedSize {
   413  		return false
   414  	}
   415  
   416  	// Check if all the characters in a base32 encoded ULID are part of the
   417  	// expected base32 character set.
   418  	if ulidDec[str[0]] == 0xFF ||
   419  		ulidDec[str[1]] == 0xFF ||
   420  		ulidDec[str[2]] == 0xFF ||
   421  		ulidDec[str[3]] == 0xFF ||
   422  		ulidDec[str[4]] == 0xFF ||
   423  		ulidDec[str[5]] == 0xFF ||
   424  		ulidDec[str[6]] == 0xFF ||
   425  		ulidDec[str[7]] == 0xFF ||
   426  		ulidDec[str[8]] == 0xFF ||
   427  		ulidDec[str[9]] == 0xFF ||
   428  		ulidDec[str[10]] == 0xFF ||
   429  		ulidDec[str[11]] == 0xFF ||
   430  		ulidDec[str[12]] == 0xFF ||
   431  		ulidDec[str[13]] == 0xFF ||
   432  		ulidDec[str[14]] == 0xFF ||
   433  		ulidDec[str[15]] == 0xFF ||
   434  		ulidDec[str[16]] == 0xFF ||
   435  		ulidDec[str[17]] == 0xFF ||
   436  		ulidDec[str[18]] == 0xFF ||
   437  		ulidDec[str[19]] == 0xFF ||
   438  		ulidDec[str[20]] == 0xFF ||
   439  		ulidDec[str[21]] == 0xFF ||
   440  		ulidDec[str[22]] == 0xFF ||
   441  		ulidDec[str[23]] == 0xFF ||
   442  		ulidDec[str[24]] == 0xFF ||
   443  		ulidDec[str[25]] == 0xFF {
   444  		return false
   445  	}
   446  
   447  	// Check if the first character in a base32 encoded ULID will overflow. This
   448  	// happens because the base32 representation encodes 130 bits, while the
   449  	// ULID is only 128 bits.
   450  	//
   451  	// See https://github.com/oklog/ulid/issues/9 for details.
   452  	if str[0] > '7' {
   453  		return false
   454  	}
   455  	return true
   456  }
   457  
   458  // IsCreditCard checks if the string is a credit card.
   459  func IsCreditCard(str string) bool {
   460  	sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "")
   461  	if !rxCreditCard.MatchString(sanitized) {
   462  		return false
   463  	}
   464  	var sum int64
   465  	var digit string
   466  	var tmpNum int64
   467  	var shouldDouble bool
   468  	for i := len(sanitized) - 1; i >= 0; i-- {
   469  		digit = sanitized[i:(i + 1)]
   470  		tmpNum, _ = ToInt(digit)
   471  		if shouldDouble {
   472  			tmpNum *= 2
   473  			if tmpNum >= 10 {
   474  				sum += (tmpNum % 10) + 1
   475  			} else {
   476  				sum += tmpNum
   477  			}
   478  		} else {
   479  			sum += tmpNum
   480  		}
   481  		shouldDouble = !shouldDouble
   482  	}
   483  
   484  	return sum%10 == 0
   485  }
   486  
   487  // IsISBN10 checks if the string is an ISBN version 10.
   488  func IsISBN10(str string) bool {
   489  	return IsISBN(str, 10)
   490  }
   491  
   492  // IsISBN13 checks if the string is an ISBN version 13.
   493  func IsISBN13(str string) bool {
   494  	return IsISBN(str, 13)
   495  }
   496  
   497  // IsISBN checks if the string is an ISBN (version 10 or 13).
   498  // If version value is not equal to 10 or 13, it will be checks both variants.
   499  func IsISBN(str string, version int) bool {
   500  	sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "")
   501  	var checksum int32
   502  	var i int32
   503  	if version == 10 {
   504  		if !rxISBN10.MatchString(sanitized) {
   505  			return false
   506  		}
   507  		for i = 0; i < 9; i++ {
   508  			checksum += (i + 1) * int32(sanitized[i]-'0')
   509  		}
   510  		if sanitized[9] == 'X' {
   511  			checksum += 10 * 10
   512  		} else {
   513  			checksum += 10 * int32(sanitized[9]-'0')
   514  		}
   515  		if checksum%11 == 0 {
   516  			return true
   517  		}
   518  		return false
   519  	} else if version == 13 {
   520  		if !rxISBN13.MatchString(sanitized) {
   521  			return false
   522  		}
   523  		factor := []int32{1, 3}
   524  		for i = 0; i < 12; i++ {
   525  			checksum += factor[i%2] * int32(sanitized[i]-'0')
   526  		}
   527  		return (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0
   528  	}
   529  	return IsISBN(str, 10) || IsISBN(str, 13)
   530  }
   531  
   532  // IsJSON checks if the string is valid JSON (note: uses json.Unmarshal).
   533  func IsJSON(str string) bool {
   534  	var js json.RawMessage
   535  	return json.Unmarshal([]byte(str), &js) == nil
   536  }
   537  
   538  // IsMultibyte checks if the string contains one or more multibyte chars. Empty string is valid.
   539  func IsMultibyte(str string) bool {
   540  	if IsNull(str) {
   541  		return true
   542  	}
   543  	return rxMultibyte.MatchString(str)
   544  }
   545  
   546  // IsASCII checks if the string contains ASCII chars only. Empty string is valid.
   547  func IsASCII(str string) bool {
   548  	if IsNull(str) {
   549  		return true
   550  	}
   551  	return rxASCII.MatchString(str)
   552  }
   553  
   554  // IsPrintableASCII checks if the string contains printable ASCII chars only. Empty string is valid.
   555  func IsPrintableASCII(str string) bool {
   556  	if IsNull(str) {
   557  		return true
   558  	}
   559  	return rxPrintableASCII.MatchString(str)
   560  }
   561  
   562  // IsFullWidth checks if the string contains any full-width chars. Empty string is valid.
   563  func IsFullWidth(str string) bool {
   564  	if IsNull(str) {
   565  		return true
   566  	}
   567  	return rxFullWidth.MatchString(str)
   568  }
   569  
   570  // IsHalfWidth checks if the string contains any half-width chars. Empty string is valid.
   571  func IsHalfWidth(str string) bool {
   572  	if IsNull(str) {
   573  		return true
   574  	}
   575  	return rxHalfWidth.MatchString(str)
   576  }
   577  
   578  // IsVariableWidth checks if the string contains a mixture of full and half-width chars. Empty string is valid.
   579  func IsVariableWidth(str string) bool {
   580  	if IsNull(str) {
   581  		return true
   582  	}
   583  	return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str)
   584  }
   585  
   586  // IsBase64 checks if a string is base64 encoded.
   587  func IsBase64(str string) bool {
   588  	return rxBase64.MatchString(str)
   589  }
   590  
   591  // IsFilePath checks is a string is Win or Unix file path and returns it's type.
   592  func IsFilePath(str string) (bool, int) {
   593  	if rxWinPath.MatchString(str) {
   594  		//check windows path limit see:
   595  		//  http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
   596  		if len(str[3:]) > 32767 {
   597  			return false, Win
   598  		}
   599  		return true, Win
   600  	} else if rxUnixPath.MatchString(str) {
   601  		return true, Unix
   602  	}
   603  	return false, Unknown
   604  }
   605  
   606  // IsWinFilePath checks both relative & absolute paths in Windows
   607  func IsWinFilePath(str string) bool {
   608  	if rxARWinPath.MatchString(str) {
   609  		//check windows path limit see:
   610  		//  http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
   611  		if len(str[3:]) > 32767 {
   612  			return false
   613  		}
   614  		return true
   615  	}
   616  	return false
   617  }
   618  
   619  // IsUnixFilePath checks both relative & absolute paths in Unix
   620  func IsUnixFilePath(str string) bool {
   621  	if rxARUnixPath.MatchString(str) {
   622  		return true
   623  	}
   624  	return false
   625  }
   626  
   627  // IsDataURI checks if a string is base64 encoded data URI such as an image
   628  func IsDataURI(str string) bool {
   629  	dataURI := strings.Split(str, ",")
   630  	if !rxDataURI.MatchString(dataURI[0]) {
   631  		return false
   632  	}
   633  	return IsBase64(dataURI[1])
   634  }
   635  
   636  // IsMagnetURI checks if a string is valid magnet URI
   637  func IsMagnetURI(str string) bool {
   638  	return rxMagnetURI.MatchString(str)
   639  }
   640  
   641  // IsISO3166Alpha2 checks if a string is valid two-letter country code
   642  func IsISO3166Alpha2(str string) bool {
   643  	for _, entry := range ISO3166List {
   644  		if str == entry.Alpha2Code {
   645  			return true
   646  		}
   647  	}
   648  	return false
   649  }
   650  
   651  // IsISO3166Alpha3 checks if a string is valid three-letter country code
   652  func IsISO3166Alpha3(str string) bool {
   653  	for _, entry := range ISO3166List {
   654  		if str == entry.Alpha3Code {
   655  			return true
   656  		}
   657  	}
   658  	return false
   659  }
   660  
   661  // IsISO693Alpha2 checks if a string is valid two-letter language code
   662  func IsISO693Alpha2(str string) bool {
   663  	for _, entry := range ISO693List {
   664  		if str == entry.Alpha2Code {
   665  			return true
   666  		}
   667  	}
   668  	return false
   669  }
   670  
   671  // IsISO693Alpha3b checks if a string is valid three-letter language code
   672  func IsISO693Alpha3b(str string) bool {
   673  	for _, entry := range ISO693List {
   674  		if str == entry.Alpha3bCode {
   675  			return true
   676  		}
   677  	}
   678  	return false
   679  }
   680  
   681  // IsDNSName will validate the given string as a DNS name
   682  func IsDNSName(str string) bool {
   683  	if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 {
   684  		// constraints already violated
   685  		return false
   686  	}
   687  	return !IsIP(str) && rxDNSName.MatchString(str)
   688  }
   689  
   690  // IsHash checks if a string is a hash of type algorithm.
   691  // Algorithm is one of ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']
   692  func IsHash(str string, algorithm string) bool {
   693  	var len string
   694  	algo := strings.ToLower(algorithm)
   695  
   696  	if algo == "crc32" || algo == "crc32b" {
   697  		len = "8"
   698  	} else if algo == "md5" || algo == "md4" || algo == "ripemd128" || algo == "tiger128" {
   699  		len = "32"
   700  	} else if algo == "sha1" || algo == "ripemd160" || algo == "tiger160" {
   701  		len = "40"
   702  	} else if algo == "tiger192" {
   703  		len = "48"
   704  	} else if algo == "sha3-224" {
   705  		len = "56"
   706  	} else if algo == "sha256" || algo == "sha3-256" {
   707  		len = "64"
   708  	} else if algo == "sha384" || algo == "sha3-384" {
   709  		len = "96"
   710  	} else if algo == "sha512" || algo == "sha3-512" {
   711  		len = "128"
   712  	} else {
   713  		return false
   714  	}
   715  
   716  	return Matches(str, "^[a-f0-9]{"+len+"}$")
   717  }
   718  
   719  // IsSHA3224 checks is a string is a SHA3-224 hash. Alias for `IsHash(str, "sha3-224")`
   720  func IsSHA3224(str string) bool {
   721  	return IsHash(str, "sha3-224")
   722  }
   723  
   724  // IsSHA3256 checks is a string is a SHA3-256 hash. Alias for `IsHash(str, "sha3-256")`
   725  func IsSHA3256(str string) bool {
   726  	return IsHash(str, "sha3-256")
   727  }
   728  
   729  // IsSHA3384 checks is a string is a SHA3-384 hash. Alias for `IsHash(str, "sha3-384")`
   730  func IsSHA3384(str string) bool {
   731  	return IsHash(str, "sha3-384")
   732  }
   733  
   734  // IsSHA3512 checks is a string is a SHA3-512 hash. Alias for `IsHash(str, "sha3-512")`
   735  func IsSHA3512(str string) bool {
   736  	return IsHash(str, "sha3-512")
   737  }
   738  
   739  // IsSHA512 checks is a string is a SHA512 hash. Alias for `IsHash(str, "sha512")`
   740  func IsSHA512(str string) bool {
   741  	return IsHash(str, "sha512")
   742  }
   743  
   744  // IsSHA384 checks is a string is a SHA384 hash. Alias for `IsHash(str, "sha384")`
   745  func IsSHA384(str string) bool {
   746  	return IsHash(str, "sha384")
   747  }
   748  
   749  // IsSHA256 checks is a string is a SHA256 hash. Alias for `IsHash(str, "sha256")`
   750  func IsSHA256(str string) bool {
   751  	return IsHash(str, "sha256")
   752  }
   753  
   754  // IsTiger192 checks is a string is a Tiger192 hash. Alias for `IsHash(str, "tiger192")`
   755  func IsTiger192(str string) bool {
   756  	return IsHash(str, "tiger192")
   757  }
   758  
   759  // IsTiger160 checks is a string is a Tiger160 hash. Alias for `IsHash(str, "tiger160")`
   760  func IsTiger160(str string) bool {
   761  	return IsHash(str, "tiger160")
   762  }
   763  
   764  // IsRipeMD160 checks is a string is a RipeMD160 hash. Alias for `IsHash(str, "ripemd160")`
   765  func IsRipeMD160(str string) bool {
   766  	return IsHash(str, "ripemd160")
   767  }
   768  
   769  // IsSHA1 checks is a string is a SHA-1 hash. Alias for `IsHash(str, "sha1")`
   770  func IsSHA1(str string) bool {
   771  	return IsHash(str, "sha1")
   772  }
   773  
   774  // IsTiger128 checks is a string is a Tiger128 hash. Alias for `IsHash(str, "tiger128")`
   775  func IsTiger128(str string) bool {
   776  	return IsHash(str, "tiger128")
   777  }
   778  
   779  // IsRipeMD128 checks is a string is a RipeMD128 hash. Alias for `IsHash(str, "ripemd128")`
   780  func IsRipeMD128(str string) bool {
   781  	return IsHash(str, "ripemd128")
   782  }
   783  
   784  // IsCRC32 checks is a string is a CRC32 hash. Alias for `IsHash(str, "crc32")`
   785  func IsCRC32(str string) bool {
   786  	return IsHash(str, "crc32")
   787  }
   788  
   789  // IsCRC32b checks is a string is a CRC32b hash. Alias for `IsHash(str, "crc32b")`
   790  func IsCRC32b(str string) bool {
   791  	return IsHash(str, "crc32b")
   792  }
   793  
   794  // IsMD5 checks is a string is a MD5 hash. Alias for `IsHash(str, "md5")`
   795  func IsMD5(str string) bool {
   796  	return IsHash(str, "md5")
   797  }
   798  
   799  // IsMD4 checks is a string is a MD4 hash. Alias for `IsHash(str, "md4")`
   800  func IsMD4(str string) bool {
   801  	return IsHash(str, "md4")
   802  }
   803  
   804  // IsDialString validates the given string for usage with the various Dial() functions
   805  func IsDialString(str string) bool {
   806  	if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) {
   807  		return true
   808  	}
   809  
   810  	return false
   811  }
   812  
   813  // IsIP checks if a string is either IP version 4 or 6. Alias for `net.ParseIP`
   814  func IsIP(str string) bool {
   815  	return net.ParseIP(str) != nil
   816  }
   817  
   818  // IsPort checks if a string represents a valid port
   819  func IsPort(str string) bool {
   820  	if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 {
   821  		return true
   822  	}
   823  	return false
   824  }
   825  
   826  // IsIPv4 checks if the string is an IP version 4.
   827  func IsIPv4(str string) bool {
   828  	ip := net.ParseIP(str)
   829  	return ip != nil && strings.Contains(str, ".")
   830  }
   831  
   832  // IsIPv6 checks if the string is an IP version 6.
   833  func IsIPv6(str string) bool {
   834  	ip := net.ParseIP(str)
   835  	return ip != nil && strings.Contains(str, ":")
   836  }
   837  
   838  // IsCIDR checks if the string is an valid CIDR notiation (IPV4 & IPV6)
   839  func IsCIDR(str string) bool {
   840  	_, _, err := net.ParseCIDR(str)
   841  	return err == nil
   842  }
   843  
   844  // IsMAC checks if a string is valid MAC address.
   845  // Possible MAC formats:
   846  // 01:23:45:67:89:ab
   847  // 01:23:45:67:89:ab:cd:ef
   848  // 01-23-45-67-89-ab
   849  // 01-23-45-67-89-ab-cd-ef
   850  // 0123.4567.89ab
   851  // 0123.4567.89ab.cdef
   852  func IsMAC(str string) bool {
   853  	_, err := net.ParseMAC(str)
   854  	return err == nil
   855  }
   856  
   857  // IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name
   858  func IsHost(str string) bool {
   859  	return IsIP(str) || IsDNSName(str)
   860  }
   861  
   862  // IsMongoID checks if the string is a valid hex-encoded representation of a MongoDB ObjectId.
   863  func IsMongoID(str string) bool {
   864  	return rxHexadecimal.MatchString(str) && (len(str) == 24)
   865  }
   866  
   867  // IsLatitude checks if a string is valid latitude.
   868  func IsLatitude(str string) bool {
   869  	return rxLatitude.MatchString(str)
   870  }
   871  
   872  // IsLongitude checks if a string is valid longitude.
   873  func IsLongitude(str string) bool {
   874  	return rxLongitude.MatchString(str)
   875  }
   876  
   877  // IsIMEI checks if a string is valid IMEI
   878  func IsIMEI(str string) bool {
   879  	return rxIMEI.MatchString(str)
   880  }
   881  
   882  // IsIMSI checks if a string is valid IMSI
   883  func IsIMSI(str string) bool {
   884  	if !rxIMSI.MatchString(str) {
   885  		return false
   886  	}
   887  
   888  	mcc, err := strconv.ParseInt(str[0:3], 10, 32)
   889  	if err != nil {
   890  		return false
   891  	}
   892  
   893  	switch mcc {
   894  	case 202, 204, 206, 208, 212, 213, 214, 216, 218, 219:
   895  	case 220, 221, 222, 226, 228, 230, 231, 232, 234, 235:
   896  	case 238, 240, 242, 244, 246, 247, 248, 250, 255, 257:
   897  	case 259, 260, 262, 266, 268, 270, 272, 274, 276, 278:
   898  	case 280, 282, 283, 284, 286, 288, 289, 290, 292, 293:
   899  	case 294, 295, 297, 302, 308, 310, 311, 312, 313, 314:
   900  	case 315, 316, 330, 332, 334, 338, 340, 342, 344, 346:
   901  	case 348, 350, 352, 354, 356, 358, 360, 362, 363, 364:
   902  	case 365, 366, 368, 370, 372, 374, 376, 400, 401, 402:
   903  	case 404, 405, 406, 410, 412, 413, 414, 415, 416, 417:
   904  	case 418, 419, 420, 421, 422, 424, 425, 426, 427, 428:
   905  	case 429, 430, 431, 432, 434, 436, 437, 438, 440, 441:
   906  	case 450, 452, 454, 455, 456, 457, 460, 461, 466, 467:
   907  	case 470, 472, 502, 505, 510, 514, 515, 520, 525, 528:
   908  	case 530, 536, 537, 539, 540, 541, 542, 543, 544, 545:
   909  	case 546, 547, 548, 549, 550, 551, 552, 553, 554, 555:
   910  	case 602, 603, 604, 605, 606, 607, 608, 609, 610, 611:
   911  	case 612, 613, 614, 615, 616, 617, 618, 619, 620, 621:
   912  	case 622, 623, 624, 625, 626, 627, 628, 629, 630, 631:
   913  	case 632, 633, 634, 635, 636, 637, 638, 639, 640, 641:
   914  	case 642, 643, 645, 646, 647, 648, 649, 650, 651, 652:
   915  	case 653, 654, 655, 657, 658, 659, 702, 704, 706, 708:
   916  	case 710, 712, 714, 716, 722, 724, 730, 732, 734, 736:
   917  	case 738, 740, 742, 744, 746, 748, 750, 995:
   918  		return true
   919  	default:
   920  		return false
   921  	}
   922  	return true
   923  }
   924  
   925  // IsRsaPublicKey checks if a string is valid public key with provided length
   926  func IsRsaPublicKey(str string, keylen int) bool {
   927  	bb := bytes.NewBufferString(str)
   928  	pemBytes, err := io.ReadAll(bb)
   929  	if err != nil {
   930  		return false
   931  	}
   932  	block, _ := pem.Decode(pemBytes)
   933  	if block != nil && block.Type != "PUBLIC KEY" {
   934  		return false
   935  	}
   936  	var der []byte
   937  
   938  	if block != nil {
   939  		der = block.Bytes
   940  	} else {
   941  		der, err = base64.StdEncoding.DecodeString(str)
   942  		if err != nil {
   943  			return false
   944  		}
   945  	}
   946  
   947  	key, err := x509.ParsePKIXPublicKey(der)
   948  	if err != nil {
   949  		return false
   950  	}
   951  	pubkey, ok := key.(*rsa.PublicKey)
   952  	if !ok {
   953  		return false
   954  	}
   955  	bitlen := len(pubkey.N.Bytes()) * 8
   956  	return bitlen == int(keylen)
   957  }
   958  
   959  // IsRegex checks if a give string is a valid regex with RE2 syntax or not
   960  func IsRegex(str string) bool {
   961  	if _, err := regexp.Compile(str); err == nil {
   962  		return true
   963  	}
   964  	return false
   965  }
   966  
   967  func toJSONName(tag string) string {
   968  	if tag == "" {
   969  		return ""
   970  	}
   971  
   972  	// JSON name always comes first. If there's no options then split[0] is
   973  	// JSON name, if JSON name is not set, then split[0] is an empty string.
   974  	split := strings.SplitN(tag, ",", 2)
   975  
   976  	name := split[0]
   977  
   978  	// However it is possible that the field is skipped when
   979  	// (de-)serializing from/to JSON, in which case assume that there is no
   980  	// tag name to use
   981  	if name == "-" {
   982  		return ""
   983  	}
   984  	return name
   985  }
   986  
   987  func prependPathToErrors(err error, path string) error {
   988  	switch err2 := err.(type) {
   989  	case Error:
   990  		err2.Path = append([]string{path}, err2.Path...)
   991  		return err2
   992  	case Errors:
   993  		errors := err2.Errors()
   994  		for i, err3 := range errors {
   995  			errors[i] = prependPathToErrors(err3, path)
   996  		}
   997  		return err2
   998  	}
   999  	return err
  1000  }
  1001  
  1002  // ValidateArray performs validation according to condition iterator that validates every element of the array
  1003  func ValidateArray(array []interface{}, iterator ConditionIterator) bool {
  1004  	return Every(array, iterator)
  1005  }
  1006  
  1007  // ValidateMap use validation map for fields.
  1008  // result will be equal to `false` if there are any errors.
  1009  // s is the map containing the data to be validated.
  1010  // m is the validation map in the form:
  1011  //
  1012  //	map[string]interface{}{"name":"required,alpha","address":map[string]interface{}{"line1":"required,alphanum"}}
  1013  func ValidateMap(s map[string]interface{}, m map[string]interface{}) (bool, error) {
  1014  	if s == nil {
  1015  		return true, nil
  1016  	}
  1017  	result := true
  1018  	var err error
  1019  	var errs Errors
  1020  	var index int
  1021  	val := reflect.ValueOf(s)
  1022  	for key, value := range s {
  1023  		presentResult := true
  1024  		validator, ok := m[key]
  1025  		if !ok {
  1026  			presentResult = false
  1027  			var err error
  1028  			err = fmt.Errorf("all map keys has to be present in the validation map; got %s", key)
  1029  			err = prependPathToErrors(err, key)
  1030  			errs = append(errs, err)
  1031  		}
  1032  		valueField := reflect.ValueOf(value)
  1033  		mapResult := true
  1034  		typeResult := true
  1035  		structResult := true
  1036  		resultField := true
  1037  		switch subValidator := validator.(type) {
  1038  		case map[string]interface{}:
  1039  			var err error
  1040  			if v, ok := value.(map[string]interface{}); !ok {
  1041  				mapResult = false
  1042  				err = fmt.Errorf("map validator has to be for the map type only; got %s", valueField.Type().String())
  1043  				err = prependPathToErrors(err, key)
  1044  				errs = append(errs, err)
  1045  			} else {
  1046  				mapResult, err = ValidateMap(v, subValidator)
  1047  				if err != nil {
  1048  					mapResult = false
  1049  					err = prependPathToErrors(err, key)
  1050  					errs = append(errs, err)
  1051  				}
  1052  			}
  1053  		case string:
  1054  			if (valueField.Kind() == reflect.Struct ||
  1055  				(valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) &&
  1056  				subValidator != "-" {
  1057  				var err error
  1058  				structResult, err = ValidateStruct(valueField.Interface())
  1059  				if err != nil {
  1060  					err = prependPathToErrors(err, key)
  1061  					errs = append(errs, err)
  1062  				}
  1063  			}
  1064  			resultField, err = typeCheck(valueField, reflect.StructField{
  1065  				Name:      key,
  1066  				PkgPath:   "",
  1067  				Type:      val.Type(),
  1068  				Tag:       reflect.StructTag(fmt.Sprintf("%s:%q", tagName, subValidator)),
  1069  				Offset:    0,
  1070  				Index:     []int{index},
  1071  				Anonymous: false,
  1072  			}, val, nil)
  1073  			if err != nil {
  1074  				errs = append(errs, err)
  1075  			}
  1076  		case nil:
  1077  			// already handlerd when checked before
  1078  		default:
  1079  			typeResult = false
  1080  			err = fmt.Errorf("map validator has to be either map[string]interface{} or string; got %s", valueField.Type().String())
  1081  			err = prependPathToErrors(err, key)
  1082  			errs = append(errs, err)
  1083  		}
  1084  		result = result && presentResult && typeResult && resultField && structResult && mapResult
  1085  		index++
  1086  	}
  1087  	// checks required keys
  1088  	requiredResult := true
  1089  	for key, value := range m {
  1090  		if schema, ok := value.(string); ok {
  1091  			tags := parseTagIntoMap(schema)
  1092  			if required, ok := tags["required"]; ok {
  1093  				if _, ok := s[key]; !ok {
  1094  					requiredResult = false
  1095  					if required.customErrorMessage != "" {
  1096  						err = Error{key, fmt.Errorf(required.customErrorMessage), true, "required", []string{}}
  1097  					} else {
  1098  						err = Error{key, fmt.Errorf("required field missing"), false, "required", []string{}}
  1099  					}
  1100  					errs = append(errs, err)
  1101  				}
  1102  			}
  1103  		}
  1104  	}
  1105  
  1106  	if len(errs) > 0 {
  1107  		err = errs
  1108  	}
  1109  	return result && requiredResult, err
  1110  }
  1111  
  1112  // ValidateStruct use tags for fields.
  1113  // result will be equal to `false` if there are any errors.
  1114  // todo currently there is no guarantee that errors will be returned in predictable order (tests may to fail)
  1115  func ValidateStruct(s interface{}) (bool, error) {
  1116  	if s == nil {
  1117  		return true, nil
  1118  	}
  1119  	result := true
  1120  	var err error
  1121  	val := reflect.ValueOf(s)
  1122  	if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
  1123  		val = val.Elem()
  1124  	}
  1125  	// we only accept structs
  1126  	if val.Kind() != reflect.Struct {
  1127  		return false, fmt.Errorf("function only accepts structs; got %s", val.Kind())
  1128  	}
  1129  	var errs Errors
  1130  	for i := 0; i < val.NumField(); i++ {
  1131  		valueField := val.Field(i)
  1132  		typeField := val.Type().Field(i)
  1133  		if typeField.PkgPath != "" {
  1134  			continue // Private field
  1135  		}
  1136  		structResult := true
  1137  		if valueField.Kind() == reflect.Interface {
  1138  			valueField = valueField.Elem()
  1139  		}
  1140  		if (valueField.Kind() == reflect.Struct ||
  1141  			(valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) &&
  1142  			typeField.Tag.Get(tagName) != "-" {
  1143  			var err error
  1144  			structResult, err = ValidateStruct(valueField.Interface())
  1145  			if err != nil {
  1146  				err = prependPathToErrors(err, typeField.Name)
  1147  				errs = append(errs, err)
  1148  			}
  1149  		}
  1150  		resultField, err2 := typeCheck(valueField, typeField, val, nil)
  1151  		if err2 != nil {
  1152  
  1153  			// Replace structure name with JSON name if there is a tag on the variable
  1154  			jsonTag := toJSONName(typeField.Tag.Get("json"))
  1155  			if jsonTag != "" {
  1156  				switch jsonError := err2.(type) {
  1157  				case Error:
  1158  					jsonError.Name = jsonTag
  1159  					err2 = jsonError
  1160  				case Errors:
  1161  					for i2, err3 := range jsonError {
  1162  						switch customErr := err3.(type) {
  1163  						case Error:
  1164  							customErr.Name = jsonTag
  1165  							jsonError[i2] = customErr
  1166  						}
  1167  					}
  1168  
  1169  					err2 = jsonError
  1170  				}
  1171  			}
  1172  
  1173  			errs = append(errs, err2)
  1174  		}
  1175  		result = result && resultField && structResult
  1176  	}
  1177  	if len(errs) > 0 {
  1178  		err = errs
  1179  	}
  1180  	return result, err
  1181  }
  1182  
  1183  // ValidateStructAsync performs async validation of the struct and returns results through the channels
  1184  func ValidateStructAsync(s interface{}) (<-chan bool, <-chan error) {
  1185  	res := make(chan bool)
  1186  	errors := make(chan error)
  1187  
  1188  	go func() {
  1189  		defer close(res)
  1190  		defer close(errors)
  1191  
  1192  		isValid, isFailed := ValidateStruct(s)
  1193  
  1194  		res <- isValid
  1195  		errors <- isFailed
  1196  	}()
  1197  
  1198  	return res, errors
  1199  }
  1200  
  1201  // ValidateMapAsync performs async validation of the map and returns results through the channels
  1202  func ValidateMapAsync(s map[string]interface{}, m map[string]interface{}) (<-chan bool, <-chan error) {
  1203  	res := make(chan bool)
  1204  	errors := make(chan error)
  1205  
  1206  	go func() {
  1207  		defer close(res)
  1208  		defer close(errors)
  1209  
  1210  		isValid, isFailed := ValidateMap(s, m)
  1211  
  1212  		res <- isValid
  1213  		errors <- isFailed
  1214  	}()
  1215  
  1216  	return res, errors
  1217  }
  1218  
  1219  // parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""}
  1220  func parseTagIntoMap(tag string) tagOptionsMap {
  1221  	optionsMap := make(tagOptionsMap)
  1222  	options := strings.Split(tag, ",")
  1223  
  1224  	for i, option := range options {
  1225  		option = strings.TrimSpace(option)
  1226  
  1227  		validationOptions := strings.Split(option, "~")
  1228  		if !isValidTag(validationOptions[0]) {
  1229  			continue
  1230  		}
  1231  		if len(validationOptions) == 2 {
  1232  			optionsMap[validationOptions[0]] = tagOption{validationOptions[0], validationOptions[1], i}
  1233  		} else {
  1234  			optionsMap[validationOptions[0]] = tagOption{validationOptions[0], "", i}
  1235  		}
  1236  	}
  1237  	return optionsMap
  1238  }
  1239  
  1240  func isValidTag(s string) bool {
  1241  	if s == "" {
  1242  		return false
  1243  	}
  1244  	for _, c := range s {
  1245  		switch {
  1246  		case strings.ContainsRune("\\'\"!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
  1247  			// Backslash and quote chars are reserved, but
  1248  			// otherwise any punctuation chars are allowed
  1249  			// in a tag name.
  1250  		default:
  1251  			if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
  1252  				return false
  1253  			}
  1254  		}
  1255  	}
  1256  	return true
  1257  }
  1258  
  1259  // IsSSN will validate the given string as a U.S. Social Security Number
  1260  func IsSSN(str string) bool {
  1261  	if str == "" || len(str) != 11 {
  1262  		return false
  1263  	}
  1264  	return rxSSN.MatchString(str)
  1265  }
  1266  
  1267  // IsSemver checks if string is valid semantic version
  1268  func IsSemver(str string) bool {
  1269  	return rxSemver.MatchString(str)
  1270  }
  1271  
  1272  // IsType checks if interface is of some type
  1273  func IsType(v interface{}, params ...string) bool {
  1274  	if len(params) == 1 {
  1275  		typ := params[0]
  1276  		return strings.Replace(reflect.TypeOf(v).String(), " ", "", -1) == strings.Replace(typ, " ", "", -1)
  1277  	}
  1278  	return false
  1279  }
  1280  
  1281  // IsTime checks if string is valid according to given format
  1282  func IsTime(str string, format string) bool {
  1283  	_, err := time.Parse(format, str)
  1284  	return err == nil
  1285  }
  1286  
  1287  // IsUnixTime checks if string is valid unix timestamp value
  1288  func IsUnixTime(str string) bool {
  1289  	if _, err := strconv.Atoi(str); err == nil {
  1290  		return true
  1291  	}
  1292  	return false
  1293  }
  1294  
  1295  // IsRFC3339 checks if string is valid timestamp value according to RFC3339
  1296  func IsRFC3339(str string) bool {
  1297  	return IsTime(str, time.RFC3339)
  1298  }
  1299  
  1300  // IsRFC3339WithoutZone checks if string is valid timestamp value according to RFC3339 which excludes the timezone.
  1301  func IsRFC3339WithoutZone(str string) bool {
  1302  	return IsTime(str, rfc3339WithoutZone)
  1303  }
  1304  
  1305  // IsISO4217 checks if string is valid ISO currency code
  1306  func IsISO4217(str string) bool {
  1307  	for _, currency := range ISO4217List {
  1308  		if str == currency {
  1309  			return true
  1310  		}
  1311  	}
  1312  
  1313  	return false
  1314  }
  1315  
  1316  // ByteLength checks string's length
  1317  func ByteLength(str string, params ...string) bool {
  1318  	if len(params) == 2 {
  1319  		min, _ := ToInt(params[0])
  1320  		max, _ := ToInt(params[1])
  1321  		return len(str) >= int(min) && len(str) <= int(max)
  1322  	}
  1323  
  1324  	return false
  1325  }
  1326  
  1327  // RuneLength checks string's length
  1328  // Alias for StringLength
  1329  func RuneLength(str string, params ...string) bool {
  1330  	return StringLength(str, params...)
  1331  }
  1332  
  1333  // IsRsaPub checks whether string is valid RSA key
  1334  // Alias for IsRsaPublicKey
  1335  func IsRsaPub(str string, params ...string) bool {
  1336  	if len(params) == 1 {
  1337  		len, _ := ToInt(params[0])
  1338  		return IsRsaPublicKey(str, int(len))
  1339  	}
  1340  
  1341  	return false
  1342  }
  1343  
  1344  // StringMatches checks if a string matches a given pattern.
  1345  func StringMatches(s string, params ...string) bool {
  1346  	if len(params) == 1 {
  1347  		pattern := params[0]
  1348  		return Matches(s, pattern)
  1349  	}
  1350  	return false
  1351  }
  1352  
  1353  // StringLength checks string's length (including multi byte strings)
  1354  func StringLength(str string, params ...string) bool {
  1355  
  1356  	if len(params) == 2 {
  1357  		strLength := utf8.RuneCountInString(str)
  1358  		min, _ := ToInt(params[0])
  1359  		max, _ := ToInt(params[1])
  1360  		return strLength >= int(min) && strLength <= int(max)
  1361  	}
  1362  
  1363  	return false
  1364  }
  1365  
  1366  // MinStringLength checks string's minimum length (including multi byte strings)
  1367  func MinStringLength(str string, params ...string) bool {
  1368  
  1369  	if len(params) == 1 {
  1370  		strLength := utf8.RuneCountInString(str)
  1371  		min, _ := ToInt(params[0])
  1372  		return strLength >= int(min)
  1373  	}
  1374  
  1375  	return false
  1376  }
  1377  
  1378  // MaxStringLength checks string's maximum length (including multi byte strings)
  1379  func MaxStringLength(str string, params ...string) bool {
  1380  
  1381  	if len(params) == 1 {
  1382  		strLength := utf8.RuneCountInString(str)
  1383  		max, _ := ToInt(params[0])
  1384  		return strLength <= int(max)
  1385  	}
  1386  
  1387  	return false
  1388  }
  1389  
  1390  // Range checks string's length
  1391  func Range(str string, params ...string) bool {
  1392  	if len(params) == 2 {
  1393  		value, _ := ToFloat(str)
  1394  		min, _ := ToFloat(params[0])
  1395  		max, _ := ToFloat(params[1])
  1396  		return InRange(value, min, max)
  1397  	}
  1398  
  1399  	return false
  1400  }
  1401  
  1402  // IsInRaw checks if string is in list of allowed values
  1403  func IsInRaw(str string, params ...string) bool {
  1404  	if len(params) == 1 {
  1405  		rawParams := params[0]
  1406  
  1407  		parsedParams := strings.Split(rawParams, "|")
  1408  
  1409  		return IsIn(str, parsedParams...)
  1410  	}
  1411  
  1412  	return false
  1413  }
  1414  
  1415  // IsIn checks if string str is a member of the set of strings params
  1416  func IsIn(str string, params ...string) bool {
  1417  	for _, param := range params {
  1418  		if str == param {
  1419  			return true
  1420  		}
  1421  	}
  1422  
  1423  	return false
  1424  }
  1425  
  1426  func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) {
  1427  	if nilPtrAllowedByRequired {
  1428  		k := v.Kind()
  1429  		if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() {
  1430  			return true, nil
  1431  		}
  1432  	}
  1433  
  1434  	if requiredOption, isRequired := options["required"]; isRequired {
  1435  		if len(requiredOption.customErrorMessage) > 0 {
  1436  			return false, Error{t.Name, fmt.Errorf(requiredOption.customErrorMessage), true, "required", []string{}}
  1437  		}
  1438  		return false, Error{t.Name, fmt.Errorf("non zero value required"), false, "required", []string{}}
  1439  	} else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional {
  1440  		return false, Error{t.Name, fmt.Errorf("Missing required field"), false, "required", []string{}}
  1441  	}
  1442  	// not required and empty is valid
  1443  	return true, nil
  1444  }
  1445  
  1446  func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) {
  1447  	if !v.IsValid() {
  1448  		return false, nil
  1449  	}
  1450  
  1451  	tag := t.Tag.Get(tagName)
  1452  
  1453  	// checks if the field should be ignored
  1454  	switch tag {
  1455  	case "":
  1456  		if v.Kind() != reflect.Slice && v.Kind() != reflect.Map {
  1457  			if !fieldsRequiredByDefault {
  1458  				return true, nil
  1459  			}
  1460  			return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false, "required", []string{}}
  1461  		}
  1462  	case "-":
  1463  		return true, nil
  1464  	}
  1465  
  1466  	isRootType := false
  1467  	if options == nil {
  1468  		isRootType = true
  1469  		options = parseTagIntoMap(tag)
  1470  	}
  1471  
  1472  	if isEmptyValue(v) {
  1473  		// an empty value is not validated, checks only required
  1474  		isValid, resultErr = checkRequired(v, t, options)
  1475  		for key := range options {
  1476  			delete(options, key)
  1477  		}
  1478  		return isValid, resultErr
  1479  	}
  1480  
  1481  	var customTypeErrors Errors
  1482  	optionsOrder := options.orderedKeys()
  1483  	for _, validatorName := range optionsOrder {
  1484  		validatorStruct := options[validatorName]
  1485  		if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok {
  1486  			delete(options, validatorName)
  1487  
  1488  			if result := validatefunc(v.Interface(), o.Interface()); !result {
  1489  				if len(validatorStruct.customErrorMessage) > 0 {
  1490  					customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: TruncatingErrorf(validatorStruct.customErrorMessage, fmt.Sprint(v), validatorName), CustomErrorMessageExists: true, Validator: stripParams(validatorName)})
  1491  					continue
  1492  				}
  1493  				customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false, Validator: stripParams(validatorName)})
  1494  			}
  1495  		}
  1496  	}
  1497  
  1498  	if len(customTypeErrors.Errors()) > 0 {
  1499  		return false, customTypeErrors
  1500  	}
  1501  
  1502  	if isRootType {
  1503  		// Ensure that we've checked the value by all specified validators before report that the value is valid
  1504  		defer func() {
  1505  			delete(options, "optional")
  1506  			delete(options, "required")
  1507  
  1508  			if isValid && resultErr == nil && len(options) != 0 {
  1509  				optionsOrder := options.orderedKeys()
  1510  				for _, validator := range optionsOrder {
  1511  					isValid = false
  1512  					resultErr = Error{t.Name, fmt.Errorf(
  1513  						"The following validator is invalid or can't be applied to the field: %q", validator), false, stripParams(validator), []string{}}
  1514  					return
  1515  				}
  1516  			}
  1517  		}()
  1518  	}
  1519  
  1520  	for _, validatorSpec := range optionsOrder {
  1521  		validatorStruct := options[validatorSpec]
  1522  		var negate bool
  1523  		validator := validatorSpec
  1524  		customMsgExists := len(validatorStruct.customErrorMessage) > 0
  1525  
  1526  		// checks whether the tag looks like '!something' or 'something'
  1527  		if validator[0] == '!' {
  1528  			validator = validator[1:]
  1529  			negate = true
  1530  		}
  1531  
  1532  		// checks for interface param validators
  1533  		for key, value := range InterfaceParamTagRegexMap {
  1534  			ps := value.FindStringSubmatch(validator)
  1535  			if len(ps) == 0 {
  1536  				continue
  1537  			}
  1538  
  1539  			validatefunc, ok := InterfaceParamTagMap[key]
  1540  			if !ok {
  1541  				continue
  1542  			}
  1543  
  1544  			delete(options, validatorSpec)
  1545  
  1546  			field := fmt.Sprint(v)
  1547  			if result := validatefunc(v.Interface(), ps[1:]...); (!result && !negate) || (result && negate) {
  1548  				if customMsgExists {
  1549  					return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1550  				}
  1551  				if negate {
  1552  					return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1553  				}
  1554  				return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1555  			}
  1556  		}
  1557  	}
  1558  
  1559  	switch v.Kind() {
  1560  	case reflect.Bool,
  1561  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  1562  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
  1563  		reflect.Float32, reflect.Float64,
  1564  		reflect.String:
  1565  		// for each tag option checks the map of validator functions
  1566  		for _, validatorSpec := range optionsOrder {
  1567  			validatorStruct := options[validatorSpec]
  1568  			var negate bool
  1569  			validator := validatorSpec
  1570  			customMsgExists := len(validatorStruct.customErrorMessage) > 0
  1571  
  1572  			// checks whether the tag looks like '!something' or 'something'
  1573  			if validator[0] == '!' {
  1574  				validator = validator[1:]
  1575  				negate = true
  1576  			}
  1577  
  1578  			// checks for param validators
  1579  			for key, value := range ParamTagRegexMap {
  1580  				ps := value.FindStringSubmatch(validator)
  1581  				if len(ps) == 0 {
  1582  					continue
  1583  				}
  1584  
  1585  				validatefunc, ok := ParamTagMap[key]
  1586  				if !ok {
  1587  					continue
  1588  				}
  1589  
  1590  				delete(options, validatorSpec)
  1591  
  1592  				switch v.Kind() {
  1593  				case reflect.String,
  1594  					reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  1595  					reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  1596  					reflect.Float32, reflect.Float64:
  1597  
  1598  					field := fmt.Sprint(v) // make value into string, then validate with regex
  1599  					if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) {
  1600  						if customMsgExists {
  1601  							return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1602  						}
  1603  						if negate {
  1604  							return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1605  						}
  1606  						return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1607  					}
  1608  				default:
  1609  					// type not yet supported, fail
  1610  					return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false, stripParams(validatorSpec), []string{}}
  1611  				}
  1612  			}
  1613  
  1614  			if validatefunc, ok := TagMap[validator]; ok {
  1615  				delete(options, validatorSpec)
  1616  
  1617  				switch v.Kind() {
  1618  				case reflect.String,
  1619  					reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  1620  					reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  1621  					reflect.Float32, reflect.Float64:
  1622  					field := fmt.Sprint(v) // make value into string, then validate with regex
  1623  					if result := validatefunc(field); !result && !negate || result && negate {
  1624  						if customMsgExists {
  1625  							return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1626  						}
  1627  						if negate {
  1628  							return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1629  						}
  1630  						return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  1631  					}
  1632  				default:
  1633  					//Not Yet Supported Types (Fail here!)
  1634  					err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v)
  1635  					return false, Error{t.Name, err, false, stripParams(validatorSpec), []string{}}
  1636  				}
  1637  			}
  1638  		}
  1639  		return true, nil
  1640  	case reflect.Map:
  1641  		if v.Type().Key().Kind() != reflect.String {
  1642  			return false, &UnsupportedTypeError{v.Type()}
  1643  		}
  1644  		var sv stringValues
  1645  		sv = v.MapKeys()
  1646  		sort.Sort(sv)
  1647  		result := true
  1648  		for i, k := range sv {
  1649  			var resultItem bool
  1650  			var err error
  1651  			if v.MapIndex(k).Kind() != reflect.Struct {
  1652  				resultItem, err = typeCheck(v.MapIndex(k), t, o, options)
  1653  				if err != nil {
  1654  					return false, err
  1655  				}
  1656  			} else {
  1657  				resultItem, err = ValidateStruct(v.MapIndex(k).Interface())
  1658  				if err != nil {
  1659  					err = prependPathToErrors(err, t.Name+"."+sv[i].Interface().(string))
  1660  					return false, err
  1661  				}
  1662  			}
  1663  			result = result && resultItem
  1664  		}
  1665  		return result, nil
  1666  	case reflect.Slice, reflect.Array:
  1667  		result := true
  1668  		for i := 0; i < v.Len(); i++ {
  1669  			var resultItem bool
  1670  			var err error
  1671  			if v.Index(i).Kind() != reflect.Struct {
  1672  				resultItem, err = typeCheck(v.Index(i), t, o, options)
  1673  				if err != nil {
  1674  					return false, err
  1675  				}
  1676  			} else {
  1677  				resultItem, err = ValidateStruct(v.Index(i).Interface())
  1678  				if err != nil {
  1679  					err = prependPathToErrors(err, t.Name+"."+strconv.Itoa(i))
  1680  					return false, err
  1681  				}
  1682  			}
  1683  			result = result && resultItem
  1684  		}
  1685  		return result, nil
  1686  	case reflect.Interface:
  1687  		// If the value is an interface then encode its element
  1688  		if v.IsNil() {
  1689  			return true, nil
  1690  		}
  1691  		return ValidateStruct(v.Interface())
  1692  	case reflect.Ptr:
  1693  		// If the value is a pointer then checks its element
  1694  		if v.IsNil() {
  1695  			return true, nil
  1696  		}
  1697  		return typeCheck(v.Elem(), t, o, options)
  1698  	case reflect.Struct:
  1699  		return true, nil
  1700  	default:
  1701  		return false, &UnsupportedTypeError{v.Type()}
  1702  	}
  1703  }
  1704  
  1705  func stripParams(validatorString string) string {
  1706  	return paramsRegexp.ReplaceAllString(validatorString, "")
  1707  }
  1708  
  1709  // isEmptyValue checks whether value empty or not
  1710  func isEmptyValue(v reflect.Value) bool {
  1711  	switch v.Kind() {
  1712  	case reflect.String, reflect.Array:
  1713  		return v.Len() == 0
  1714  	case reflect.Map, reflect.Slice:
  1715  		return v.Len() == 0 || v.IsNil()
  1716  	case reflect.Bool:
  1717  		return !v.Bool()
  1718  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1719  		return v.Int() == 0
  1720  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  1721  		return v.Uint() == 0
  1722  	case reflect.Float32, reflect.Float64:
  1723  		return v.Float() == 0
  1724  	case reflect.Interface, reflect.Ptr:
  1725  		return v.IsNil()
  1726  	}
  1727  
  1728  	return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
  1729  }
  1730  
  1731  // ErrorByField returns error for specified field of the struct
  1732  // validated by ValidateStruct or empty string if there are no errors
  1733  // or this field doesn't exists or doesn't have any errors.
  1734  func ErrorByField(e error, field string) string {
  1735  	if e == nil {
  1736  		return ""
  1737  	}
  1738  	return ErrorsByField(e)[field]
  1739  }
  1740  
  1741  // ErrorsByField returns map of errors of the struct validated
  1742  // by ValidateStruct or empty map if there are no errors.
  1743  func ErrorsByField(e error) map[string]string {
  1744  	m := make(map[string]string)
  1745  	if e == nil {
  1746  		return m
  1747  	}
  1748  	// prototype for ValidateStruct
  1749  
  1750  	switch e := e.(type) {
  1751  	case Error:
  1752  		m[e.Name] = e.Err.Error()
  1753  	case Errors:
  1754  		for _, item := range e.Errors() {
  1755  			n := ErrorsByField(item)
  1756  			for k, v := range n {
  1757  				m[k] = v
  1758  			}
  1759  		}
  1760  	}
  1761  
  1762  	return m
  1763  }
  1764  
  1765  // Error returns string equivalent for reflect.Type
  1766  func (e *UnsupportedTypeError) Error() string {
  1767  	return "validator: unsupported type: " + e.Type.String()
  1768  }
  1769  
  1770  func (sv stringValues) Len() int           { return len(sv) }
  1771  func (sv stringValues) Swap(i, j int)      { sv[i], sv[j] = sv[j], sv[i] }
  1772  func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
  1773  func (sv stringValues) get(i int) string   { return sv[i].String() }
  1774  
  1775  func IsE164(str string) bool {
  1776  	return rxE164.MatchString(str)
  1777  }