PageRenderTime 47ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/github.com/asaskevich/govalidator/validator.go

https://gitlab.com/unofficial-mirrors/kubernetes
Go | 924 lines | 713 code | 95 blank | 116 comment | 245 complexity | 576080d234ff1c2997d753263466ecd7 MD5 | raw file
  1. // Package govalidator is package of validators and sanitizers for strings, structs and collections.
  2. package govalidator
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "net/url"
  8. "reflect"
  9. "regexp"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. "unicode"
  14. "unicode/utf8"
  15. )
  16. var fieldsRequiredByDefault bool
  17. // SetFieldsRequiredByDefault causes validation to fail when struct fields
  18. // do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`).
  19. // This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
  20. // type exampleStruct struct {
  21. // Name string ``
  22. // Email string `valid:"email"`
  23. // This, however, will only fail when Email is empty or an invalid email address:
  24. // type exampleStruct2 struct {
  25. // Name string `valid:"-"`
  26. // Email string `valid:"email"`
  27. // Lastly, this will only fail when Email is an invalid email address but not when it's empty:
  28. // type exampleStruct2 struct {
  29. // Name string `valid:"-"`
  30. // Email string `valid:"email,optional"`
  31. func SetFieldsRequiredByDefault(value bool) {
  32. fieldsRequiredByDefault = value
  33. }
  34. // IsEmail check if the string is an email.
  35. func IsEmail(str string) bool {
  36. // TODO uppercase letters are not supported
  37. return rxEmail.MatchString(str)
  38. }
  39. // IsURL check if the string is an URL.
  40. func IsURL(str string) bool {
  41. if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
  42. return false
  43. }
  44. u, err := url.Parse(str)
  45. if err != nil {
  46. return false
  47. }
  48. if strings.HasPrefix(u.Host, ".") {
  49. return false
  50. }
  51. if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
  52. return false
  53. }
  54. return rxURL.MatchString(str)
  55. }
  56. // IsRequestURL check if the string rawurl, assuming
  57. // it was recieved in an HTTP request, is a valid
  58. // URL confirm to RFC 3986
  59. func IsRequestURL(rawurl string) bool {
  60. url, err := url.ParseRequestURI(rawurl)
  61. if err != nil {
  62. return false //Couldn't even parse the rawurl
  63. }
  64. if len(url.Scheme) == 0 {
  65. return false //No Scheme found
  66. }
  67. return true
  68. }
  69. // IsRequestURI check if the string rawurl, assuming
  70. // it was recieved in an HTTP request, is an
  71. // absolute URI or an absolute path.
  72. func IsRequestURI(rawurl string) bool {
  73. _, err := url.ParseRequestURI(rawurl)
  74. return err == nil
  75. }
  76. // IsAlpha check if the string contains only letters (a-zA-Z). Empty string is valid.
  77. func IsAlpha(str string) bool {
  78. if IsNull(str) {
  79. return true
  80. }
  81. return rxAlpha.MatchString(str)
  82. }
  83. //IsUTFLetter check if the string contains only unicode letter characters.
  84. //Similar to IsAlpha but for all languages. Empty string is valid.
  85. func IsUTFLetter(str string) bool {
  86. if IsNull(str) {
  87. return true
  88. }
  89. for _, c := range str {
  90. if !unicode.IsLetter(c) {
  91. return false
  92. }
  93. }
  94. return true
  95. }
  96. // IsAlphanumeric check if the string contains only letters and numbers. Empty string is valid.
  97. func IsAlphanumeric(str string) bool {
  98. if IsNull(str) {
  99. return true
  100. }
  101. return rxAlphanumeric.MatchString(str)
  102. }
  103. // IsUTFLetterNumeric check if the string contains only unicode letters and numbers. Empty string is valid.
  104. func IsUTFLetterNumeric(str string) bool {
  105. if IsNull(str) {
  106. return true
  107. }
  108. for _, c := range str {
  109. if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok
  110. return false
  111. }
  112. }
  113. return true
  114. }
  115. // IsNumeric check if the string contains only numbers. Empty string is valid.
  116. func IsNumeric(str string) bool {
  117. if IsNull(str) {
  118. return true
  119. }
  120. return rxNumeric.MatchString(str)
  121. }
  122. // IsUTFNumeric check if the string contains only unicode numbers of any kind.
  123. // Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid.
  124. func IsUTFNumeric(str string) bool {
  125. if IsNull(str) {
  126. return true
  127. }
  128. if strings.IndexAny(str, "+-") > 0 {
  129. return false
  130. }
  131. if len(str) > 1 {
  132. str = strings.TrimPrefix(str, "-")
  133. str = strings.TrimPrefix(str, "+")
  134. }
  135. for _, c := range str {
  136. if unicode.IsNumber(c) == false { //numbers && minus sign are ok
  137. return false
  138. }
  139. }
  140. return true
  141. }
  142. // IsUTFDigit check if the string contains only unicode radix-10 decimal digits. Empty string is valid.
  143. func IsUTFDigit(str string) bool {
  144. if IsNull(str) {
  145. return true
  146. }
  147. if strings.IndexAny(str, "+-") > 0 {
  148. return false
  149. }
  150. if len(str) > 1 {
  151. str = strings.TrimPrefix(str, "-")
  152. str = strings.TrimPrefix(str, "+")
  153. }
  154. for _, c := range str {
  155. if !unicode.IsDigit(c) { //digits && minus sign are ok
  156. return false
  157. }
  158. }
  159. return true
  160. }
  161. // IsHexadecimal check if the string is a hexadecimal number.
  162. func IsHexadecimal(str string) bool {
  163. return rxHexadecimal.MatchString(str)
  164. }
  165. // IsHexcolor check if the string is a hexadecimal color.
  166. func IsHexcolor(str string) bool {
  167. return rxHexcolor.MatchString(str)
  168. }
  169. // IsRGBcolor check if the string is a valid RGB color in form rgb(RRR, GGG, BBB).
  170. func IsRGBcolor(str string) bool {
  171. return rxRGBcolor.MatchString(str)
  172. }
  173. // IsLowerCase check if the string is lowercase. Empty string is valid.
  174. func IsLowerCase(str string) bool {
  175. if IsNull(str) {
  176. return true
  177. }
  178. return str == strings.ToLower(str)
  179. }
  180. // IsUpperCase check if the string is uppercase. Empty string is valid.
  181. func IsUpperCase(str string) bool {
  182. if IsNull(str) {
  183. return true
  184. }
  185. return str == strings.ToUpper(str)
  186. }
  187. // IsInt check if the string is an integer. Empty string is valid.
  188. func IsInt(str string) bool {
  189. if IsNull(str) {
  190. return true
  191. }
  192. return rxInt.MatchString(str)
  193. }
  194. // IsFloat check if the string is a float.
  195. func IsFloat(str string) bool {
  196. return str != "" && rxFloat.MatchString(str)
  197. }
  198. // IsDivisibleBy check if the string is a number that's divisible by another.
  199. // If second argument is not valid integer or zero, it's return false.
  200. // Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero).
  201. func IsDivisibleBy(str, num string) bool {
  202. f, _ := ToFloat(str)
  203. p := int64(f)
  204. q, _ := ToInt(num)
  205. if q == 0 {
  206. return false
  207. }
  208. return (p == 0) || (p%q == 0)
  209. }
  210. // IsNull check if the string is null.
  211. func IsNull(str string) bool {
  212. return len(str) == 0
  213. }
  214. // IsByteLength check if the string's length (in bytes) falls in a range.
  215. func IsByteLength(str string, min, max int) bool {
  216. return len(str) >= min && len(str) <= max
  217. }
  218. // IsUUIDv3 check if the string is a UUID version 3.
  219. func IsUUIDv3(str string) bool {
  220. return rxUUID3.MatchString(str)
  221. }
  222. // IsUUIDv4 check if the string is a UUID version 4.
  223. func IsUUIDv4(str string) bool {
  224. return rxUUID4.MatchString(str)
  225. }
  226. // IsUUIDv5 check if the string is a UUID version 5.
  227. func IsUUIDv5(str string) bool {
  228. return rxUUID5.MatchString(str)
  229. }
  230. // IsUUID check if the string is a UUID (version 3, 4 or 5).
  231. func IsUUID(str string) bool {
  232. return rxUUID.MatchString(str)
  233. }
  234. // IsCreditCard check if the string is a credit card.
  235. func IsCreditCard(str string) bool {
  236. r, _ := regexp.Compile("[^0-9]+")
  237. sanitized := r.ReplaceAll([]byte(str), []byte(""))
  238. if !rxCreditCard.MatchString(string(sanitized)) {
  239. return false
  240. }
  241. var sum int64
  242. var digit string
  243. var tmpNum int64
  244. var shouldDouble bool
  245. for i := len(sanitized) - 1; i >= 0; i-- {
  246. digit = string(sanitized[i:(i + 1)])
  247. tmpNum, _ = ToInt(digit)
  248. if shouldDouble {
  249. tmpNum *= 2
  250. if tmpNum >= 10 {
  251. sum += ((tmpNum % 10) + 1)
  252. } else {
  253. sum += tmpNum
  254. }
  255. } else {
  256. sum += tmpNum
  257. }
  258. shouldDouble = !shouldDouble
  259. }
  260. if sum%10 == 0 {
  261. return true
  262. }
  263. return false
  264. }
  265. // IsISBN10 check if the string is an ISBN version 10.
  266. func IsISBN10(str string) bool {
  267. return IsISBN(str, 10)
  268. }
  269. // IsISBN13 check if the string is an ISBN version 13.
  270. func IsISBN13(str string) bool {
  271. return IsISBN(str, 13)
  272. }
  273. // IsISBN check if the string is an ISBN (version 10 or 13).
  274. // If version value is not equal to 10 or 13, it will be check both variants.
  275. func IsISBN(str string, version int) bool {
  276. r, _ := regexp.Compile("[\\s-]+")
  277. sanitized := r.ReplaceAll([]byte(str), []byte(""))
  278. var checksum int32
  279. var i int32
  280. if version == 10 {
  281. if !rxISBN10.MatchString(string(sanitized)) {
  282. return false
  283. }
  284. for i = 0; i < 9; i++ {
  285. checksum += (i + 1) * int32(sanitized[i]-'0')
  286. }
  287. if sanitized[9] == 'X' {
  288. checksum += 10 * 10
  289. } else {
  290. checksum += 10 * int32(sanitized[9]-'0')
  291. }
  292. if checksum%11 == 0 {
  293. return true
  294. }
  295. return false
  296. } else if version == 13 {
  297. if !rxISBN13.MatchString(string(sanitized)) {
  298. return false
  299. }
  300. factor := []int32{1, 3}
  301. for i = 0; i < 12; i++ {
  302. checksum += factor[i%2] * int32(sanitized[i]-'0')
  303. }
  304. if (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0 {
  305. return true
  306. }
  307. return false
  308. }
  309. return IsISBN(str, 10) || IsISBN(str, 13)
  310. }
  311. // IsJSON check if the string is valid JSON (note: uses json.Unmarshal).
  312. func IsJSON(str string) bool {
  313. var js json.RawMessage
  314. return json.Unmarshal([]byte(str), &js) == nil
  315. }
  316. // IsMultibyte check if the string contains one or more multibyte chars. Empty string is valid.
  317. func IsMultibyte(str string) bool {
  318. if IsNull(str) {
  319. return true
  320. }
  321. return rxMultibyte.MatchString(str)
  322. }
  323. // IsASCII check if the string contains ASCII chars only. Empty string is valid.
  324. func IsASCII(str string) bool {
  325. if IsNull(str) {
  326. return true
  327. }
  328. return rxASCII.MatchString(str)
  329. }
  330. // IsPrintableASCII check if the string contains printable ASCII chars only. Empty string is valid.
  331. func IsPrintableASCII(str string) bool {
  332. if IsNull(str) {
  333. return true
  334. }
  335. return rxPrintableASCII.MatchString(str)
  336. }
  337. // IsFullWidth check if the string contains any full-width chars. Empty string is valid.
  338. func IsFullWidth(str string) bool {
  339. if IsNull(str) {
  340. return true
  341. }
  342. return rxFullWidth.MatchString(str)
  343. }
  344. // IsHalfWidth check if the string contains any half-width chars. Empty string is valid.
  345. func IsHalfWidth(str string) bool {
  346. if IsNull(str) {
  347. return true
  348. }
  349. return rxHalfWidth.MatchString(str)
  350. }
  351. // IsVariableWidth check if the string contains a mixture of full and half-width chars. Empty string is valid.
  352. func IsVariableWidth(str string) bool {
  353. if IsNull(str) {
  354. return true
  355. }
  356. return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str)
  357. }
  358. // IsBase64 check if a string is base64 encoded.
  359. func IsBase64(str string) bool {
  360. return rxBase64.MatchString(str)
  361. }
  362. // IsFilePath check is a string is Win or Unix file path and returns it's type.
  363. func IsFilePath(str string) (bool, int) {
  364. if rxWinPath.MatchString(str) {
  365. //check windows path limit see:
  366. // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
  367. if len(str[3:]) > 32767 {
  368. return false, Win
  369. }
  370. return true, Win
  371. } else if rxUnixPath.MatchString(str) {
  372. return true, Unix
  373. }
  374. return false, Unknown
  375. }
  376. // IsDataURI checks if a string is base64 encoded data URI such as an image
  377. func IsDataURI(str string) bool {
  378. dataURI := strings.Split(str, ",")
  379. if !rxDataURI.MatchString(dataURI[0]) {
  380. return false
  381. }
  382. return IsBase64(dataURI[1])
  383. }
  384. // IsISO3166Alpha2 checks if a string is valid two-letter country code
  385. func IsISO3166Alpha2(str string) bool {
  386. for _, entry := range ISO3166List {
  387. if str == entry.Alpha2Code {
  388. return true
  389. }
  390. }
  391. return false
  392. }
  393. // IsISO3166Alpha3 checks if a string is valid three-letter country code
  394. func IsISO3166Alpha3(str string) bool {
  395. for _, entry := range ISO3166List {
  396. if str == entry.Alpha3Code {
  397. return true
  398. }
  399. }
  400. return false
  401. }
  402. // IsDNSName will validate the given string as a DNS name
  403. func IsDNSName(str string) bool {
  404. if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 {
  405. // constraints already violated
  406. return false
  407. }
  408. return rxDNSName.MatchString(str)
  409. }
  410. // IsDialString validates the given string for usage with the various Dial() functions
  411. func IsDialString(str string) bool {
  412. if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) {
  413. return true
  414. }
  415. return false
  416. }
  417. // IsIP checks if a string is either IP version 4 or 6.
  418. func IsIP(str string) bool {
  419. return net.ParseIP(str) != nil
  420. }
  421. // IsPort checks if a string represents a valid port
  422. func IsPort(str string) bool {
  423. if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 {
  424. return true
  425. }
  426. return false
  427. }
  428. // IsIPv4 check if the string is an IP version 4.
  429. func IsIPv4(str string) bool {
  430. ip := net.ParseIP(str)
  431. return ip != nil && strings.Contains(str, ".")
  432. }
  433. // IsIPv6 check if the string is an IP version 6.
  434. func IsIPv6(str string) bool {
  435. ip := net.ParseIP(str)
  436. return ip != nil && strings.Contains(str, ":")
  437. }
  438. // IsMAC check if a string is valid MAC address.
  439. // Possible MAC formats:
  440. // 01:23:45:67:89:ab
  441. // 01:23:45:67:89:ab:cd:ef
  442. // 01-23-45-67-89-ab
  443. // 01-23-45-67-89-ab-cd-ef
  444. // 0123.4567.89ab
  445. // 0123.4567.89ab.cdef
  446. func IsMAC(str string) bool {
  447. _, err := net.ParseMAC(str)
  448. return err == nil
  449. }
  450. // IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name
  451. func IsHost(str string) bool {
  452. return IsIP(str) || IsDNSName(str)
  453. }
  454. // IsMongoID check if the string is a valid hex-encoded representation of a MongoDB ObjectId.
  455. func IsMongoID(str string) bool {
  456. return rxHexadecimal.MatchString(str) && (len(str) == 24)
  457. }
  458. // IsLatitude check if a string is valid latitude.
  459. func IsLatitude(str string) bool {
  460. return rxLatitude.MatchString(str)
  461. }
  462. // IsLongitude check if a string is valid longitude.
  463. func IsLongitude(str string) bool {
  464. return rxLongitude.MatchString(str)
  465. }
  466. // ValidateStruct use tags for fields.
  467. // result will be equal to `false` if there are any errors.
  468. func ValidateStruct(s interface{}) (bool, error) {
  469. if s == nil {
  470. return true, nil
  471. }
  472. result := true
  473. var err error
  474. val := reflect.ValueOf(s)
  475. if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
  476. val = val.Elem()
  477. }
  478. // we only accept structs
  479. if val.Kind() != reflect.Struct {
  480. return false, fmt.Errorf("function only accepts structs; got %s", val.Kind())
  481. }
  482. var errs Errors
  483. for i := 0; i < val.NumField(); i++ {
  484. valueField := val.Field(i)
  485. typeField := val.Type().Field(i)
  486. if typeField.PkgPath != "" {
  487. continue // Private field
  488. }
  489. resultField, err2 := typeCheck(valueField, typeField, val)
  490. if err2 != nil {
  491. errs = append(errs, err2)
  492. }
  493. result = result && resultField
  494. }
  495. if len(errs) > 0 {
  496. err = errs
  497. }
  498. return result, err
  499. }
  500. // parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""}
  501. func parseTagIntoMap(tag string) tagOptionsMap {
  502. optionsMap := make(tagOptionsMap)
  503. options := strings.SplitN(tag, ",", -1)
  504. for _, option := range options {
  505. validationOptions := strings.Split(option, "~")
  506. if !isValidTag(validationOptions[0]) {
  507. continue
  508. }
  509. if len(validationOptions) == 2 {
  510. optionsMap[validationOptions[0]] = validationOptions[1]
  511. } else {
  512. optionsMap[validationOptions[0]] = ""
  513. }
  514. }
  515. return optionsMap
  516. }
  517. func isValidTag(s string) bool {
  518. if s == "" {
  519. return false
  520. }
  521. for _, c := range s {
  522. switch {
  523. case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
  524. // Backslash and quote chars are reserved, but
  525. // otherwise any punctuation chars are allowed
  526. // in a tag name.
  527. default:
  528. if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
  529. return false
  530. }
  531. }
  532. }
  533. return true
  534. }
  535. // IsSSN will validate the given string as a U.S. Social Security Number
  536. func IsSSN(str string) bool {
  537. if str == "" || len(str) != 11 {
  538. return false
  539. }
  540. return rxSSN.MatchString(str)
  541. }
  542. // IsSemver check if string is valid semantic version
  543. func IsSemver(str string) bool {
  544. return rxSemver.MatchString(str)
  545. }
  546. // ByteLength check string's length
  547. func ByteLength(str string, params ...string) bool {
  548. if len(params) == 2 {
  549. min, _ := ToInt(params[0])
  550. max, _ := ToInt(params[1])
  551. return len(str) >= int(min) && len(str) <= int(max)
  552. }
  553. return false
  554. }
  555. // StringMatches checks if a string matches a given pattern.
  556. func StringMatches(s string, params ...string) bool {
  557. if len(params) == 1 {
  558. pattern := params[0]
  559. return Matches(s, pattern)
  560. }
  561. return false
  562. }
  563. // StringLength check string's length (including multi byte strings)
  564. func StringLength(str string, params ...string) bool {
  565. if len(params) == 2 {
  566. strLength := utf8.RuneCountInString(str)
  567. min, _ := ToInt(params[0])
  568. max, _ := ToInt(params[1])
  569. return strLength >= int(min) && strLength <= int(max)
  570. }
  571. return false
  572. }
  573. func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) {
  574. if requiredOption, isRequired := options["required"]; isRequired {
  575. if len(requiredOption) > 0 {
  576. return false, Error{t.Name, fmt.Errorf(requiredOption), true}
  577. }
  578. return false, Error{t.Name, fmt.Errorf("non zero value required"), false}
  579. } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional {
  580. return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false}
  581. }
  582. // not required and empty is valid
  583. return true, nil
  584. }
  585. func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value) (bool, error) {
  586. if !v.IsValid() {
  587. return false, nil
  588. }
  589. tag := t.Tag.Get(tagName)
  590. // Check if the field should be ignored
  591. switch tag {
  592. case "":
  593. if !fieldsRequiredByDefault {
  594. return true, nil
  595. }
  596. return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false}
  597. case "-":
  598. return true, nil
  599. }
  600. options := parseTagIntoMap(tag)
  601. var customTypeErrors Errors
  602. var customTypeValidatorsExist bool
  603. for validatorName, customErrorMessage := range options {
  604. if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok {
  605. customTypeValidatorsExist = true
  606. if result := validatefunc(v.Interface(), o.Interface()); !result {
  607. if len(customErrorMessage) > 0 {
  608. customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf(customErrorMessage), CustomErrorMessageExists: true})
  609. continue
  610. }
  611. customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false})
  612. }
  613. }
  614. }
  615. if customTypeValidatorsExist {
  616. if len(customTypeErrors.Errors()) > 0 {
  617. return false, customTypeErrors
  618. }
  619. return true, nil
  620. }
  621. if isEmptyValue(v) {
  622. // an empty value is not validated, check only required
  623. return checkRequired(v, t, options)
  624. }
  625. switch v.Kind() {
  626. case reflect.Bool,
  627. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  628. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
  629. reflect.Float32, reflect.Float64,
  630. reflect.String:
  631. // for each tag option check the map of validator functions
  632. for validator, customErrorMessage := range options {
  633. var negate bool
  634. customMsgExists := (len(customErrorMessage) > 0)
  635. // Check wether the tag looks like '!something' or 'something'
  636. if validator[0] == '!' {
  637. validator = string(validator[1:])
  638. negate = true
  639. }
  640. // Check for param validators
  641. for key, value := range ParamTagRegexMap {
  642. ps := value.FindStringSubmatch(validator)
  643. if len(ps) > 0 {
  644. if validatefunc, ok := ParamTagMap[key]; ok {
  645. switch v.Kind() {
  646. case reflect.String:
  647. field := fmt.Sprint(v) // make value into string, then validate with regex
  648. if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) {
  649. var err error
  650. if !negate {
  651. if customMsgExists {
  652. err = fmt.Errorf(customErrorMessage)
  653. } else {
  654. err = fmt.Errorf("%s does not validate as %s", field, validator)
  655. }
  656. } else {
  657. if customMsgExists {
  658. err = fmt.Errorf(customErrorMessage)
  659. } else {
  660. err = fmt.Errorf("%s does validate as %s", field, validator)
  661. }
  662. }
  663. return false, Error{t.Name, err, customMsgExists}
  664. }
  665. default:
  666. // type not yet supported, fail
  667. return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false}
  668. }
  669. }
  670. }
  671. }
  672. if validatefunc, ok := TagMap[validator]; ok {
  673. switch v.Kind() {
  674. case reflect.String:
  675. field := fmt.Sprint(v) // make value into string, then validate with regex
  676. if result := validatefunc(field); !result && !negate || result && negate {
  677. var err error
  678. if !negate {
  679. if customMsgExists {
  680. err = fmt.Errorf(customErrorMessage)
  681. } else {
  682. err = fmt.Errorf("%s does not validate as %s", field, validator)
  683. }
  684. } else {
  685. if customMsgExists {
  686. err = fmt.Errorf(customErrorMessage)
  687. } else {
  688. err = fmt.Errorf("%s does validate as %s", field, validator)
  689. }
  690. }
  691. return false, Error{t.Name, err, customMsgExists}
  692. }
  693. default:
  694. //Not Yet Supported Types (Fail here!)
  695. err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v)
  696. return false, Error{t.Name, err, false}
  697. }
  698. }
  699. }
  700. return true, nil
  701. case reflect.Map:
  702. if v.Type().Key().Kind() != reflect.String {
  703. return false, &UnsupportedTypeError{v.Type()}
  704. }
  705. var sv stringValues
  706. sv = v.MapKeys()
  707. sort.Sort(sv)
  708. result := true
  709. for _, k := range sv {
  710. resultItem, err := ValidateStruct(v.MapIndex(k).Interface())
  711. if err != nil {
  712. return false, err
  713. }
  714. result = result && resultItem
  715. }
  716. return result, nil
  717. case reflect.Slice:
  718. result := true
  719. for i := 0; i < v.Len(); i++ {
  720. var resultItem bool
  721. var err error
  722. if v.Index(i).Kind() != reflect.Struct {
  723. resultItem, err = typeCheck(v.Index(i), t, o)
  724. if err != nil {
  725. return false, err
  726. }
  727. } else {
  728. resultItem, err = ValidateStruct(v.Index(i).Interface())
  729. if err != nil {
  730. return false, err
  731. }
  732. }
  733. result = result && resultItem
  734. }
  735. return result, nil
  736. case reflect.Array:
  737. result := true
  738. for i := 0; i < v.Len(); i++ {
  739. var resultItem bool
  740. var err error
  741. if v.Index(i).Kind() != reflect.Struct {
  742. resultItem, err = typeCheck(v.Index(i), t, o)
  743. if err != nil {
  744. return false, err
  745. }
  746. } else {
  747. resultItem, err = ValidateStruct(v.Index(i).Interface())
  748. if err != nil {
  749. return false, err
  750. }
  751. }
  752. result = result && resultItem
  753. }
  754. return result, nil
  755. case reflect.Interface:
  756. // If the value is an interface then encode its element
  757. if v.IsNil() {
  758. return true, nil
  759. }
  760. return ValidateStruct(v.Interface())
  761. case reflect.Ptr:
  762. // If the value is a pointer then check its element
  763. if v.IsNil() {
  764. return true, nil
  765. }
  766. return typeCheck(v.Elem(), t, o)
  767. case reflect.Struct:
  768. return ValidateStruct(v.Interface())
  769. default:
  770. return false, &UnsupportedTypeError{v.Type()}
  771. }
  772. }
  773. func isEmptyValue(v reflect.Value) bool {
  774. switch v.Kind() {
  775. case reflect.String, reflect.Array:
  776. return v.Len() == 0
  777. case reflect.Map, reflect.Slice:
  778. return v.Len() == 0 || v.IsNil()
  779. case reflect.Bool:
  780. return !v.Bool()
  781. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  782. return v.Int() == 0
  783. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  784. return v.Uint() == 0
  785. case reflect.Float32, reflect.Float64:
  786. return v.Float() == 0
  787. case reflect.Interface, reflect.Ptr:
  788. return v.IsNil()
  789. }
  790. return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
  791. }
  792. // ErrorByField returns error for specified field of the struct
  793. // validated by ValidateStruct or empty string if there are no errors
  794. // or this field doesn't exists or doesn't have any errors.
  795. func ErrorByField(e error, field string) string {
  796. if e == nil {
  797. return ""
  798. }
  799. return ErrorsByField(e)[field]
  800. }
  801. // ErrorsByField returns map of errors of the struct validated
  802. // by ValidateStruct or empty map if there are no errors.
  803. func ErrorsByField(e error) map[string]string {
  804. m := make(map[string]string)
  805. if e == nil {
  806. return m
  807. }
  808. // prototype for ValidateStruct
  809. switch e.(type) {
  810. case Error:
  811. m[e.(Error).Name] = e.(Error).Err.Error()
  812. case Errors:
  813. for _, item := range e.(Errors).Errors() {
  814. n := ErrorsByField(item)
  815. for k, v := range n {
  816. m[k] = v
  817. }
  818. }
  819. }
  820. return m
  821. }
  822. // Error returns string equivalent for reflect.Type
  823. func (e *UnsupportedTypeError) Error() string {
  824. return "validator: unsupported type: " + e.Type.String()
  825. }
  826. func (sv stringValues) Len() int { return len(sv) }
  827. func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
  828. func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
  829. func (sv stringValues) get(i int) string { return sv[i].String() }