...

Source file src/github.com/asaskevich/govalidator/validator.go

Documentation: github.com/asaskevich/govalidator

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

View as plain text