本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1279 lines
34KB

  1. // Package govalidator is package of validators and sanitizers for strings, structs and collections.
  2. package govalidator
  3. import (
  4. "bytes"
  5. "crypto/rsa"
  6. "crypto/x509"
  7. "encoding/base64"
  8. "encoding/json"
  9. "encoding/pem"
  10. "fmt"
  11. "io/ioutil"
  12. "net"
  13. "net/url"
  14. "reflect"
  15. "regexp"
  16. "sort"
  17. "strconv"
  18. "strings"
  19. "time"
  20. "unicode"
  21. "unicode/utf8"
  22. )
  23. var (
  24. fieldsRequiredByDefault bool
  25. nilPtrAllowedByRequired = false
  26. notNumberRegexp = regexp.MustCompile("[^0-9]+")
  27. whiteSpacesAndMinus = regexp.MustCompile(`[\s-]+`)
  28. paramsRegexp = regexp.MustCompile(`\(.*\)$`)
  29. )
  30. const maxURLRuneCount = 2083
  31. const minURLRuneCount = 3
  32. const RF3339WithoutZone = "2006-01-02T15:04:05"
  33. // SetFieldsRequiredByDefault causes validation to fail when struct fields
  34. // do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`).
  35. // This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
  36. // type exampleStruct struct {
  37. // Name string ``
  38. // Email string `valid:"email"`
  39. // This, however, will only fail when Email is empty or an invalid email address:
  40. // type exampleStruct2 struct {
  41. // Name string `valid:"-"`
  42. // Email string `valid:"email"`
  43. // Lastly, this will only fail when Email is an invalid email address but not when it's empty:
  44. // type exampleStruct2 struct {
  45. // Name string `valid:"-"`
  46. // Email string `valid:"email,optional"`
  47. func SetFieldsRequiredByDefault(value bool) {
  48. fieldsRequiredByDefault = value
  49. }
  50. // SetNilPtrAllowedByRequired causes validation to pass for nil ptrs when a field is set to required.
  51. // The validation will still reject ptr fields in their zero value state. Example with this enabled:
  52. // type exampleStruct struct {
  53. // Name *string `valid:"required"`
  54. // With `Name` set to "", this will be considered invalid input and will cause a validation error.
  55. // With `Name` set to nil, this will be considered valid by validation.
  56. // By default this is disabled.
  57. func SetNilPtrAllowedByRequired(value bool) {
  58. nilPtrAllowedByRequired = value
  59. }
  60. // IsEmail check if the string is an email.
  61. func IsEmail(str string) bool {
  62. // TODO uppercase letters are not supported
  63. return rxEmail.MatchString(str)
  64. }
  65. // IsExistingEmail check if the string is an email of existing domain
  66. func IsExistingEmail(email string) bool {
  67. if len(email) < 6 || len(email) > 254 {
  68. return false
  69. }
  70. at := strings.LastIndex(email, "@")
  71. if at <= 0 || at > len(email)-3 {
  72. return false
  73. }
  74. user := email[:at]
  75. host := email[at+1:]
  76. if len(user) > 64 {
  77. return false
  78. }
  79. if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) {
  80. return false
  81. }
  82. switch host {
  83. case "localhost", "example.com":
  84. return true
  85. }
  86. if _, err := net.LookupMX(host); err != nil {
  87. if _, err := net.LookupIP(host); err != nil {
  88. return false
  89. }
  90. }
  91. return true
  92. }
  93. // IsURL check if the string is an URL.
  94. func IsURL(str string) bool {
  95. if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") {
  96. return false
  97. }
  98. strTemp := str
  99. if strings.Contains(str, ":") && !strings.Contains(str, "://") {
  100. // support no indicated urlscheme but with colon for port number
  101. // http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
  102. strTemp = "http://" + str
  103. }
  104. u, err := url.Parse(strTemp)
  105. if err != nil {
  106. return false
  107. }
  108. if strings.HasPrefix(u.Host, ".") {
  109. return false
  110. }
  111. if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
  112. return false
  113. }
  114. return rxURL.MatchString(str)
  115. }
  116. // IsRequestURL check if the string rawurl, assuming
  117. // it was received in an HTTP request, is a valid
  118. // URL confirm to RFC 3986
  119. func IsRequestURL(rawurl string) bool {
  120. url, err := url.ParseRequestURI(rawurl)
  121. if err != nil {
  122. return false //Couldn't even parse the rawurl
  123. }
  124. if len(url.Scheme) == 0 {
  125. return false //No Scheme found
  126. }
  127. return true
  128. }
  129. // IsRequestURI check if the string rawurl, assuming
  130. // it was received in an HTTP request, is an
  131. // absolute URI or an absolute path.
  132. func IsRequestURI(rawurl string) bool {
  133. _, err := url.ParseRequestURI(rawurl)
  134. return err == nil
  135. }
  136. // IsAlpha check if the string contains only letters (a-zA-Z). Empty string is valid.
  137. func IsAlpha(str string) bool {
  138. if IsNull(str) {
  139. return true
  140. }
  141. return rxAlpha.MatchString(str)
  142. }
  143. //IsUTFLetter check if the string contains only unicode letter characters.
  144. //Similar to IsAlpha but for all languages. Empty string is valid.
  145. func IsUTFLetter(str string) bool {
  146. if IsNull(str) {
  147. return true
  148. }
  149. for _, c := range str {
  150. if !unicode.IsLetter(c) {
  151. return false
  152. }
  153. }
  154. return true
  155. }
  156. // IsAlphanumeric check if the string contains only letters and numbers. Empty string is valid.
  157. func IsAlphanumeric(str string) bool {
  158. if IsNull(str) {
  159. return true
  160. }
  161. return rxAlphanumeric.MatchString(str)
  162. }
  163. // IsUTFLetterNumeric check if the string contains only unicode letters and numbers. Empty string is valid.
  164. func IsUTFLetterNumeric(str string) bool {
  165. if IsNull(str) {
  166. return true
  167. }
  168. for _, c := range str {
  169. if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok
  170. return false
  171. }
  172. }
  173. return true
  174. }
  175. // IsNumeric check if the string contains only numbers. Empty string is valid.
  176. func IsNumeric(str string) bool {
  177. if IsNull(str) {
  178. return true
  179. }
  180. return rxNumeric.MatchString(str)
  181. }
  182. // IsUTFNumeric check if the string contains only unicode numbers of any kind.
  183. // Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid.
  184. func IsUTFNumeric(str string) bool {
  185. if IsNull(str) {
  186. return true
  187. }
  188. if strings.IndexAny(str, "+-") > 0 {
  189. return false
  190. }
  191. if len(str) > 1 {
  192. str = strings.TrimPrefix(str, "-")
  193. str = strings.TrimPrefix(str, "+")
  194. }
  195. for _, c := range str {
  196. if !unicode.IsNumber(c) { //numbers && minus sign are ok
  197. return false
  198. }
  199. }
  200. return true
  201. }
  202. // IsUTFDigit check if the string contains only unicode radix-10 decimal digits. Empty string is valid.
  203. func IsUTFDigit(str string) bool {
  204. if IsNull(str) {
  205. return true
  206. }
  207. if strings.IndexAny(str, "+-") > 0 {
  208. return false
  209. }
  210. if len(str) > 1 {
  211. str = strings.TrimPrefix(str, "-")
  212. str = strings.TrimPrefix(str, "+")
  213. }
  214. for _, c := range str {
  215. if !unicode.IsDigit(c) { //digits && minus sign are ok
  216. return false
  217. }
  218. }
  219. return true
  220. }
  221. // IsHexadecimal check if the string is a hexadecimal number.
  222. func IsHexadecimal(str string) bool {
  223. return rxHexadecimal.MatchString(str)
  224. }
  225. // IsHexcolor check if the string is a hexadecimal color.
  226. func IsHexcolor(str string) bool {
  227. return rxHexcolor.MatchString(str)
  228. }
  229. // IsRGBcolor check if the string is a valid RGB color in form rgb(RRR, GGG, BBB).
  230. func IsRGBcolor(str string) bool {
  231. return rxRGBcolor.MatchString(str)
  232. }
  233. // IsLowerCase check if the string is lowercase. Empty string is valid.
  234. func IsLowerCase(str string) bool {
  235. if IsNull(str) {
  236. return true
  237. }
  238. return str == strings.ToLower(str)
  239. }
  240. // IsUpperCase check if the string is uppercase. Empty string is valid.
  241. func IsUpperCase(str string) bool {
  242. if IsNull(str) {
  243. return true
  244. }
  245. return str == strings.ToUpper(str)
  246. }
  247. // HasLowerCase check if the string contains at least 1 lowercase. Empty string is valid.
  248. func HasLowerCase(str string) bool {
  249. if IsNull(str) {
  250. return true
  251. }
  252. return rxHasLowerCase.MatchString(str)
  253. }
  254. // HasUpperCase check if the string contians as least 1 uppercase. Empty string is valid.
  255. func HasUpperCase(str string) bool {
  256. if IsNull(str) {
  257. return true
  258. }
  259. return rxHasUpperCase.MatchString(str)
  260. }
  261. // IsInt check if the string is an integer. Empty string is valid.
  262. func IsInt(str string) bool {
  263. if IsNull(str) {
  264. return true
  265. }
  266. return rxInt.MatchString(str)
  267. }
  268. // IsFloat check if the string is a float.
  269. func IsFloat(str string) bool {
  270. return str != "" && rxFloat.MatchString(str)
  271. }
  272. // IsDivisibleBy check if the string is a number that's divisible by another.
  273. // If second argument is not valid integer or zero, it's return false.
  274. // Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero).
  275. func IsDivisibleBy(str, num string) bool {
  276. f, _ := ToFloat(str)
  277. p := int64(f)
  278. q, _ := ToInt(num)
  279. if q == 0 {
  280. return false
  281. }
  282. return (p == 0) || (p%q == 0)
  283. }
  284. // IsNull check if the string is null.
  285. func IsNull(str string) bool {
  286. return len(str) == 0
  287. }
  288. // HasWhitespaceOnly checks the string only contains whitespace
  289. func HasWhitespaceOnly(str string) bool {
  290. return len(str) > 0 && rxHasWhitespaceOnly.MatchString(str)
  291. }
  292. // HasWhitespace checks if the string contains any whitespace
  293. func HasWhitespace(str string) bool {
  294. return len(str) > 0 && rxHasWhitespace.MatchString(str)
  295. }
  296. // IsByteLength check if the string's length (in bytes) falls in a range.
  297. func IsByteLength(str string, min, max int) bool {
  298. return len(str) >= min && len(str) <= max
  299. }
  300. // IsUUIDv3 check if the string is a UUID version 3.
  301. func IsUUIDv3(str string) bool {
  302. return rxUUID3.MatchString(str)
  303. }
  304. // IsUUIDv4 check if the string is a UUID version 4.
  305. func IsUUIDv4(str string) bool {
  306. return rxUUID4.MatchString(str)
  307. }
  308. // IsUUIDv5 check if the string is a UUID version 5.
  309. func IsUUIDv5(str string) bool {
  310. return rxUUID5.MatchString(str)
  311. }
  312. // IsUUID check if the string is a UUID (version 3, 4 or 5).
  313. func IsUUID(str string) bool {
  314. return rxUUID.MatchString(str)
  315. }
  316. // IsCreditCard check if the string is a credit card.
  317. func IsCreditCard(str string) bool {
  318. sanitized := notNumberRegexp.ReplaceAllString(str, "")
  319. if !rxCreditCard.MatchString(sanitized) {
  320. return false
  321. }
  322. var sum int64
  323. var digit string
  324. var tmpNum int64
  325. var shouldDouble bool
  326. for i := len(sanitized) - 1; i >= 0; i-- {
  327. digit = sanitized[i:(i + 1)]
  328. tmpNum, _ = ToInt(digit)
  329. if shouldDouble {
  330. tmpNum *= 2
  331. if tmpNum >= 10 {
  332. sum += ((tmpNum % 10) + 1)
  333. } else {
  334. sum += tmpNum
  335. }
  336. } else {
  337. sum += tmpNum
  338. }
  339. shouldDouble = !shouldDouble
  340. }
  341. return sum%10 == 0
  342. }
  343. // IsISBN10 check if the string is an ISBN version 10.
  344. func IsISBN10(str string) bool {
  345. return IsISBN(str, 10)
  346. }
  347. // IsISBN13 check if the string is an ISBN version 13.
  348. func IsISBN13(str string) bool {
  349. return IsISBN(str, 13)
  350. }
  351. // IsISBN check if the string is an ISBN (version 10 or 13).
  352. // If version value is not equal to 10 or 13, it will be check both variants.
  353. func IsISBN(str string, version int) bool {
  354. sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "")
  355. var checksum int32
  356. var i int32
  357. if version == 10 {
  358. if !rxISBN10.MatchString(sanitized) {
  359. return false
  360. }
  361. for i = 0; i < 9; i++ {
  362. checksum += (i + 1) * int32(sanitized[i]-'0')
  363. }
  364. if sanitized[9] == 'X' {
  365. checksum += 10 * 10
  366. } else {
  367. checksum += 10 * int32(sanitized[9]-'0')
  368. }
  369. if checksum%11 == 0 {
  370. return true
  371. }
  372. return false
  373. } else if version == 13 {
  374. if !rxISBN13.MatchString(sanitized) {
  375. return false
  376. }
  377. factor := []int32{1, 3}
  378. for i = 0; i < 12; i++ {
  379. checksum += factor[i%2] * int32(sanitized[i]-'0')
  380. }
  381. return (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0
  382. }
  383. return IsISBN(str, 10) || IsISBN(str, 13)
  384. }
  385. // IsJSON check if the string is valid JSON (note: uses json.Unmarshal).
  386. func IsJSON(str string) bool {
  387. var js json.RawMessage
  388. return json.Unmarshal([]byte(str), &js) == nil
  389. }
  390. // IsMultibyte check if the string contains one or more multibyte chars. Empty string is valid.
  391. func IsMultibyte(str string) bool {
  392. if IsNull(str) {
  393. return true
  394. }
  395. return rxMultibyte.MatchString(str)
  396. }
  397. // IsASCII check if the string contains ASCII chars only. Empty string is valid.
  398. func IsASCII(str string) bool {
  399. if IsNull(str) {
  400. return true
  401. }
  402. return rxASCII.MatchString(str)
  403. }
  404. // IsPrintableASCII check if the string contains printable ASCII chars only. Empty string is valid.
  405. func IsPrintableASCII(str string) bool {
  406. if IsNull(str) {
  407. return true
  408. }
  409. return rxPrintableASCII.MatchString(str)
  410. }
  411. // IsFullWidth check if the string contains any full-width chars. Empty string is valid.
  412. func IsFullWidth(str string) bool {
  413. if IsNull(str) {
  414. return true
  415. }
  416. return rxFullWidth.MatchString(str)
  417. }
  418. // IsHalfWidth check if the string contains any half-width chars. Empty string is valid.
  419. func IsHalfWidth(str string) bool {
  420. if IsNull(str) {
  421. return true
  422. }
  423. return rxHalfWidth.MatchString(str)
  424. }
  425. // IsVariableWidth check if the string contains a mixture of full and half-width chars. Empty string is valid.
  426. func IsVariableWidth(str string) bool {
  427. if IsNull(str) {
  428. return true
  429. }
  430. return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str)
  431. }
  432. // IsBase64 check if a string is base64 encoded.
  433. func IsBase64(str string) bool {
  434. return rxBase64.MatchString(str)
  435. }
  436. // IsFilePath check is a string is Win or Unix file path and returns it's type.
  437. func IsFilePath(str string) (bool, int) {
  438. if rxWinPath.MatchString(str) {
  439. //check windows path limit see:
  440. // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
  441. if len(str[3:]) > 32767 {
  442. return false, Win
  443. }
  444. return true, Win
  445. } else if rxUnixPath.MatchString(str) {
  446. return true, Unix
  447. }
  448. return false, Unknown
  449. }
  450. // IsDataURI checks if a string is base64 encoded data URI such as an image
  451. func IsDataURI(str string) bool {
  452. dataURI := strings.Split(str, ",")
  453. if !rxDataURI.MatchString(dataURI[0]) {
  454. return false
  455. }
  456. return IsBase64(dataURI[1])
  457. }
  458. // IsISO3166Alpha2 checks if a string is valid two-letter country code
  459. func IsISO3166Alpha2(str string) bool {
  460. for _, entry := range ISO3166List {
  461. if str == entry.Alpha2Code {
  462. return true
  463. }
  464. }
  465. return false
  466. }
  467. // IsISO3166Alpha3 checks if a string is valid three-letter country code
  468. func IsISO3166Alpha3(str string) bool {
  469. for _, entry := range ISO3166List {
  470. if str == entry.Alpha3Code {
  471. return true
  472. }
  473. }
  474. return false
  475. }
  476. // IsISO693Alpha2 checks if a string is valid two-letter language code
  477. func IsISO693Alpha2(str string) bool {
  478. for _, entry := range ISO693List {
  479. if str == entry.Alpha2Code {
  480. return true
  481. }
  482. }
  483. return false
  484. }
  485. // IsISO693Alpha3b checks if a string is valid three-letter language code
  486. func IsISO693Alpha3b(str string) bool {
  487. for _, entry := range ISO693List {
  488. if str == entry.Alpha3bCode {
  489. return true
  490. }
  491. }
  492. return false
  493. }
  494. // IsDNSName will validate the given string as a DNS name
  495. func IsDNSName(str string) bool {
  496. if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 {
  497. // constraints already violated
  498. return false
  499. }
  500. return !IsIP(str) && rxDNSName.MatchString(str)
  501. }
  502. // IsHash checks if a string is a hash of type algorithm.
  503. // Algorithm is one of ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']
  504. func IsHash(str string, algorithm string) bool {
  505. len := "0"
  506. algo := strings.ToLower(algorithm)
  507. if algo == "crc32" || algo == "crc32b" {
  508. len = "8"
  509. } else if algo == "md5" || algo == "md4" || algo == "ripemd128" || algo == "tiger128" {
  510. len = "32"
  511. } else if algo == "sha1" || algo == "ripemd160" || algo == "tiger160" {
  512. len = "40"
  513. } else if algo == "tiger192" {
  514. len = "48"
  515. } else if algo == "sha256" {
  516. len = "64"
  517. } else if algo == "sha384" {
  518. len = "96"
  519. } else if algo == "sha512" {
  520. len = "128"
  521. } else {
  522. return false
  523. }
  524. return Matches(str, "^[a-f0-9]{"+len+"}$")
  525. }
  526. // IsDialString validates the given string for usage with the various Dial() functions
  527. func IsDialString(str string) bool {
  528. if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) {
  529. return true
  530. }
  531. return false
  532. }
  533. // IsIP checks if a string is either IP version 4 or 6.
  534. func IsIP(str string) bool {
  535. return net.ParseIP(str) != nil
  536. }
  537. // IsPort checks if a string represents a valid port
  538. func IsPort(str string) bool {
  539. if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 {
  540. return true
  541. }
  542. return false
  543. }
  544. // IsIPv4 check if the string is an IP version 4.
  545. func IsIPv4(str string) bool {
  546. ip := net.ParseIP(str)
  547. return ip != nil && strings.Contains(str, ".")
  548. }
  549. // IsIPv6 check if the string is an IP version 6.
  550. func IsIPv6(str string) bool {
  551. ip := net.ParseIP(str)
  552. return ip != nil && strings.Contains(str, ":")
  553. }
  554. // IsCIDR check if the string is an valid CIDR notiation (IPV4 & IPV6)
  555. func IsCIDR(str string) bool {
  556. _, _, err := net.ParseCIDR(str)
  557. return err == nil
  558. }
  559. // IsMAC check if a string is valid MAC address.
  560. // Possible MAC formats:
  561. // 01:23:45:67:89:ab
  562. // 01:23:45:67:89:ab:cd:ef
  563. // 01-23-45-67-89-ab
  564. // 01-23-45-67-89-ab-cd-ef
  565. // 0123.4567.89ab
  566. // 0123.4567.89ab.cdef
  567. func IsMAC(str string) bool {
  568. _, err := net.ParseMAC(str)
  569. return err == nil
  570. }
  571. // IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name
  572. func IsHost(str string) bool {
  573. return IsIP(str) || IsDNSName(str)
  574. }
  575. // IsMongoID check if the string is a valid hex-encoded representation of a MongoDB ObjectId.
  576. func IsMongoID(str string) bool {
  577. return rxHexadecimal.MatchString(str) && (len(str) == 24)
  578. }
  579. // IsLatitude check if a string is valid latitude.
  580. func IsLatitude(str string) bool {
  581. return rxLatitude.MatchString(str)
  582. }
  583. // IsLongitude check if a string is valid longitude.
  584. func IsLongitude(str string) bool {
  585. return rxLongitude.MatchString(str)
  586. }
  587. // IsRsaPublicKey check if a string is valid public key with provided length
  588. func IsRsaPublicKey(str string, keylen int) bool {
  589. bb := bytes.NewBufferString(str)
  590. pemBytes, err := ioutil.ReadAll(bb)
  591. if err != nil {
  592. return false
  593. }
  594. block, _ := pem.Decode(pemBytes)
  595. if block != nil && block.Type != "PUBLIC KEY" {
  596. return false
  597. }
  598. var der []byte
  599. if block != nil {
  600. der = block.Bytes
  601. } else {
  602. der, err = base64.StdEncoding.DecodeString(str)
  603. if err != nil {
  604. return false
  605. }
  606. }
  607. key, err := x509.ParsePKIXPublicKey(der)
  608. if err != nil {
  609. return false
  610. }
  611. pubkey, ok := key.(*rsa.PublicKey)
  612. if !ok {
  613. return false
  614. }
  615. bitlen := len(pubkey.N.Bytes()) * 8
  616. return bitlen == int(keylen)
  617. }
  618. func toJSONName(tag string) string {
  619. if tag == "" {
  620. return ""
  621. }
  622. // JSON name always comes first. If there's no options then split[0] is
  623. // JSON name, if JSON name is not set, then split[0] is an empty string.
  624. split := strings.SplitN(tag, ",", 2)
  625. name := split[0]
  626. // However it is possible that the field is skipped when
  627. // (de-)serializing from/to JSON, in which case assume that there is no
  628. // tag name to use
  629. if name == "-" {
  630. return ""
  631. }
  632. return name
  633. }
  634. func PrependPathToErrors(err error, path string) error {
  635. switch err2 := err.(type) {
  636. case Error:
  637. err2.Path = append([]string{path}, err2.Path...)
  638. return err2
  639. case Errors:
  640. errors := err2.Errors()
  641. for i, err3 := range errors {
  642. errors[i] = PrependPathToErrors(err3, path)
  643. }
  644. return err2
  645. }
  646. fmt.Println(err)
  647. return err
  648. }
  649. // ValidateStruct use tags for fields.
  650. // result will be equal to `false` if there are any errors.
  651. func ValidateStruct(s interface{}) (bool, error) {
  652. if s == nil {
  653. return true, nil
  654. }
  655. result := true
  656. var err error
  657. val := reflect.ValueOf(s)
  658. if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
  659. val = val.Elem()
  660. }
  661. // we only accept structs
  662. if val.Kind() != reflect.Struct {
  663. return false, fmt.Errorf("function only accepts structs; got %s", val.Kind())
  664. }
  665. var errs Errors
  666. for i := 0; i < val.NumField(); i++ {
  667. valueField := val.Field(i)
  668. typeField := val.Type().Field(i)
  669. if typeField.PkgPath != "" {
  670. continue // Private field
  671. }
  672. structResult := true
  673. if valueField.Kind() == reflect.Interface {
  674. valueField = valueField.Elem()
  675. }
  676. if (valueField.Kind() == reflect.Struct ||
  677. (valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) &&
  678. typeField.Tag.Get(tagName) != "-" {
  679. var err error
  680. structResult, err = ValidateStruct(valueField.Interface())
  681. if err != nil {
  682. err = PrependPathToErrors(err, typeField.Name)
  683. errs = append(errs, err)
  684. }
  685. }
  686. resultField, err2 := typeCheck(valueField, typeField, val, nil)
  687. if err2 != nil {
  688. // Replace structure name with JSON name if there is a tag on the variable
  689. jsonTag := toJSONName(typeField.Tag.Get("json"))
  690. if jsonTag != "" {
  691. switch jsonError := err2.(type) {
  692. case Error:
  693. jsonError.Name = jsonTag
  694. err2 = jsonError
  695. case Errors:
  696. for i2, err3 := range jsonError {
  697. switch customErr := err3.(type) {
  698. case Error:
  699. customErr.Name = jsonTag
  700. jsonError[i2] = customErr
  701. }
  702. }
  703. err2 = jsonError
  704. }
  705. }
  706. errs = append(errs, err2)
  707. }
  708. result = result && resultField && structResult
  709. }
  710. if len(errs) > 0 {
  711. err = errs
  712. }
  713. return result, err
  714. }
  715. // parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""}
  716. func parseTagIntoMap(tag string) tagOptionsMap {
  717. optionsMap := make(tagOptionsMap)
  718. options := strings.Split(tag, ",")
  719. for i, option := range options {
  720. option = strings.TrimSpace(option)
  721. validationOptions := strings.Split(option, "~")
  722. if !isValidTag(validationOptions[0]) {
  723. continue
  724. }
  725. if len(validationOptions) == 2 {
  726. optionsMap[validationOptions[0]] = tagOption{validationOptions[0], validationOptions[1], i}
  727. } else {
  728. optionsMap[validationOptions[0]] = tagOption{validationOptions[0], "", i}
  729. }
  730. }
  731. return optionsMap
  732. }
  733. func isValidTag(s string) bool {
  734. if s == "" {
  735. return false
  736. }
  737. for _, c := range s {
  738. switch {
  739. case strings.ContainsRune("\\'\"!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
  740. // Backslash and quote chars are reserved, but
  741. // otherwise any punctuation chars are allowed
  742. // in a tag name.
  743. default:
  744. if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
  745. return false
  746. }
  747. }
  748. }
  749. return true
  750. }
  751. // IsSSN will validate the given string as a U.S. Social Security Number
  752. func IsSSN(str string) bool {
  753. if str == "" || len(str) != 11 {
  754. return false
  755. }
  756. return rxSSN.MatchString(str)
  757. }
  758. // IsSemver check if string is valid semantic version
  759. func IsSemver(str string) bool {
  760. return rxSemver.MatchString(str)
  761. }
  762. // IsTime check if string is valid according to given format
  763. func IsTime(str string, format string) bool {
  764. _, err := time.Parse(format, str)
  765. return err == nil
  766. }
  767. // IsRFC3339 check if string is valid timestamp value according to RFC3339
  768. func IsRFC3339(str string) bool {
  769. return IsTime(str, time.RFC3339)
  770. }
  771. // IsRFC3339WithoutZone check if string is valid timestamp value according to RFC3339 which excludes the timezone.
  772. func IsRFC3339WithoutZone(str string) bool {
  773. return IsTime(str, RF3339WithoutZone)
  774. }
  775. // IsISO4217 check if string is valid ISO currency code
  776. func IsISO4217(str string) bool {
  777. for _, currency := range ISO4217List {
  778. if str == currency {
  779. return true
  780. }
  781. }
  782. return false
  783. }
  784. // ByteLength check string's length
  785. func ByteLength(str string, params ...string) bool {
  786. if len(params) == 2 {
  787. min, _ := ToInt(params[0])
  788. max, _ := ToInt(params[1])
  789. return len(str) >= int(min) && len(str) <= int(max)
  790. }
  791. return false
  792. }
  793. // RuneLength check string's length
  794. // Alias for StringLength
  795. func RuneLength(str string, params ...string) bool {
  796. return StringLength(str, params...)
  797. }
  798. // IsRsaPub check whether string is valid RSA key
  799. // Alias for IsRsaPublicKey
  800. func IsRsaPub(str string, params ...string) bool {
  801. if len(params) == 1 {
  802. len, _ := ToInt(params[0])
  803. return IsRsaPublicKey(str, int(len))
  804. }
  805. return false
  806. }
  807. // StringMatches checks if a string matches a given pattern.
  808. func StringMatches(s string, params ...string) bool {
  809. if len(params) == 1 {
  810. pattern := params[0]
  811. return Matches(s, pattern)
  812. }
  813. return false
  814. }
  815. // StringLength check string's length (including multi byte strings)
  816. func StringLength(str string, params ...string) bool {
  817. if len(params) == 2 {
  818. strLength := utf8.RuneCountInString(str)
  819. min, _ := ToInt(params[0])
  820. max, _ := ToInt(params[1])
  821. return strLength >= int(min) && strLength <= int(max)
  822. }
  823. return false
  824. }
  825. // Range check string's length
  826. func Range(str string, params ...string) bool {
  827. if len(params) == 2 {
  828. value, _ := ToFloat(str)
  829. min, _ := ToFloat(params[0])
  830. max, _ := ToFloat(params[1])
  831. return InRange(value, min, max)
  832. }
  833. return false
  834. }
  835. func isInRaw(str string, params ...string) bool {
  836. if len(params) == 1 {
  837. rawParams := params[0]
  838. parsedParams := strings.Split(rawParams, "|")
  839. return IsIn(str, parsedParams...)
  840. }
  841. return false
  842. }
  843. // IsIn check if string str is a member of the set of strings params
  844. func IsIn(str string, params ...string) bool {
  845. for _, param := range params {
  846. if str == param {
  847. return true
  848. }
  849. }
  850. return false
  851. }
  852. func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) {
  853. if nilPtrAllowedByRequired {
  854. k := v.Kind()
  855. if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() {
  856. return true, nil
  857. }
  858. }
  859. if requiredOption, isRequired := options["required"]; isRequired {
  860. if len(requiredOption.customErrorMessage) > 0 {
  861. return false, Error{t.Name, fmt.Errorf(requiredOption.customErrorMessage), true, "required", []string{}}
  862. }
  863. return false, Error{t.Name, fmt.Errorf("non zero value required"), false, "required", []string{}}
  864. } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional {
  865. return false, Error{t.Name, fmt.Errorf("Missing required field"), false, "required", []string{}}
  866. }
  867. // not required and empty is valid
  868. return true, nil
  869. }
  870. func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) {
  871. if !v.IsValid() {
  872. return false, nil
  873. }
  874. tag := t.Tag.Get(tagName)
  875. // Check if the field should be ignored
  876. switch tag {
  877. case "":
  878. if v.Kind() != reflect.Slice && v.Kind() != reflect.Map {
  879. if !fieldsRequiredByDefault {
  880. return true, nil
  881. }
  882. return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false, "required", []string{}}
  883. }
  884. case "-":
  885. return true, nil
  886. }
  887. isRootType := false
  888. if options == nil {
  889. isRootType = true
  890. options = parseTagIntoMap(tag)
  891. }
  892. if isEmptyValue(v) {
  893. // an empty value is not validated, check only required
  894. isValid, resultErr = checkRequired(v, t, options)
  895. for key := range options {
  896. delete(options, key)
  897. }
  898. return isValid, resultErr
  899. }
  900. var customTypeErrors Errors
  901. optionsOrder := options.orderedKeys()
  902. for _, validatorName := range optionsOrder {
  903. validatorStruct := options[validatorName]
  904. if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok {
  905. delete(options, validatorName)
  906. if result := validatefunc(v.Interface(), o.Interface()); !result {
  907. if len(validatorStruct.customErrorMessage) > 0 {
  908. customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: TruncatingErrorf(validatorStruct.customErrorMessage, fmt.Sprint(v), validatorName), CustomErrorMessageExists: true, Validator: stripParams(validatorName)})
  909. continue
  910. }
  911. 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)})
  912. }
  913. }
  914. }
  915. if len(customTypeErrors.Errors()) > 0 {
  916. return false, customTypeErrors
  917. }
  918. if isRootType {
  919. // Ensure that we've checked the value by all specified validators before report that the value is valid
  920. defer func() {
  921. delete(options, "optional")
  922. delete(options, "required")
  923. if isValid && resultErr == nil && len(options) != 0 {
  924. optionsOrder := options.orderedKeys()
  925. for _, validator := range optionsOrder {
  926. isValid = false
  927. resultErr = Error{t.Name, fmt.Errorf(
  928. "The following validator is invalid or can't be applied to the field: %q", validator), false, stripParams(validator), []string{}}
  929. return
  930. }
  931. }
  932. }()
  933. }
  934. switch v.Kind() {
  935. case reflect.Bool,
  936. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  937. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
  938. reflect.Float32, reflect.Float64,
  939. reflect.String:
  940. // for each tag option check the map of validator functions
  941. for _, validatorSpec := range optionsOrder {
  942. validatorStruct := options[validatorSpec]
  943. var negate bool
  944. validator := validatorSpec
  945. customMsgExists := len(validatorStruct.customErrorMessage) > 0
  946. // Check whether the tag looks like '!something' or 'something'
  947. if validator[0] == '!' {
  948. validator = validator[1:]
  949. negate = true
  950. }
  951. // Check for param validators
  952. for key, value := range ParamTagRegexMap {
  953. ps := value.FindStringSubmatch(validator)
  954. if len(ps) == 0 {
  955. continue
  956. }
  957. validatefunc, ok := ParamTagMap[key]
  958. if !ok {
  959. continue
  960. }
  961. delete(options, validatorSpec)
  962. switch v.Kind() {
  963. case reflect.String,
  964. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  965. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  966. reflect.Float32, reflect.Float64:
  967. field := fmt.Sprint(v) // make value into string, then validate with regex
  968. if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) {
  969. if customMsgExists {
  970. return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  971. }
  972. if negate {
  973. return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  974. }
  975. return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  976. }
  977. default:
  978. // type not yet supported, fail
  979. return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false, stripParams(validatorSpec), []string{}}
  980. }
  981. }
  982. if validatefunc, ok := TagMap[validator]; ok {
  983. delete(options, validatorSpec)
  984. switch v.Kind() {
  985. case reflect.String,
  986. reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  987. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  988. reflect.Float32, reflect.Float64:
  989. field := fmt.Sprint(v) // make value into string, then validate with regex
  990. if result := validatefunc(field); !result && !negate || result && negate {
  991. if customMsgExists {
  992. return false, Error{t.Name, TruncatingErrorf(validatorStruct.customErrorMessage, field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  993. }
  994. if negate {
  995. return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  996. }
  997. return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec), []string{}}
  998. }
  999. default:
  1000. //Not Yet Supported Types (Fail here!)
  1001. err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v)
  1002. return false, Error{t.Name, err, false, stripParams(validatorSpec), []string{}}
  1003. }
  1004. }
  1005. }
  1006. return true, nil
  1007. case reflect.Map:
  1008. if v.Type().Key().Kind() != reflect.String {
  1009. return false, &UnsupportedTypeError{v.Type()}
  1010. }
  1011. var sv stringValues
  1012. sv = v.MapKeys()
  1013. sort.Sort(sv)
  1014. result := true
  1015. for i, k := range sv {
  1016. var resultItem bool
  1017. var err error
  1018. if v.MapIndex(k).Kind() != reflect.Struct {
  1019. resultItem, err = typeCheck(v.MapIndex(k), t, o, options)
  1020. if err != nil {
  1021. return false, err
  1022. }
  1023. } else {
  1024. resultItem, err = ValidateStruct(v.MapIndex(k).Interface())
  1025. if err != nil {
  1026. err = PrependPathToErrors(err, t.Name+"."+sv[i].Interface().(string))
  1027. return false, err
  1028. }
  1029. }
  1030. result = result && resultItem
  1031. }
  1032. return result, nil
  1033. case reflect.Slice, reflect.Array:
  1034. result := true
  1035. for i := 0; i < v.Len(); i++ {
  1036. var resultItem bool
  1037. var err error
  1038. if v.Index(i).Kind() != reflect.Struct {
  1039. resultItem, err = typeCheck(v.Index(i), t, o, options)
  1040. if err != nil {
  1041. return false, err
  1042. }
  1043. } else {
  1044. resultItem, err = ValidateStruct(v.Index(i).Interface())
  1045. if err != nil {
  1046. err = PrependPathToErrors(err, t.Name+"."+strconv.Itoa(i))
  1047. return false, err
  1048. }
  1049. }
  1050. result = result && resultItem
  1051. }
  1052. return result, nil
  1053. case reflect.Interface:
  1054. // If the value is an interface then encode its element
  1055. if v.IsNil() {
  1056. return true, nil
  1057. }
  1058. return ValidateStruct(v.Interface())
  1059. case reflect.Ptr:
  1060. // If the value is a pointer then check its element
  1061. if v.IsNil() {
  1062. return true, nil
  1063. }
  1064. return typeCheck(v.Elem(), t, o, options)
  1065. case reflect.Struct:
  1066. return ValidateStruct(v.Interface())
  1067. default:
  1068. return false, &UnsupportedTypeError{v.Type()}
  1069. }
  1070. }
  1071. func stripParams(validatorString string) string {
  1072. return paramsRegexp.ReplaceAllString(validatorString, "")
  1073. }
  1074. func isEmptyValue(v reflect.Value) bool {
  1075. switch v.Kind() {
  1076. case reflect.String, reflect.Array:
  1077. return v.Len() == 0
  1078. case reflect.Map, reflect.Slice:
  1079. return v.Len() == 0 || v.IsNil()
  1080. case reflect.Bool:
  1081. return !v.Bool()
  1082. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1083. return v.Int() == 0
  1084. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  1085. return v.Uint() == 0
  1086. case reflect.Float32, reflect.Float64:
  1087. return v.Float() == 0
  1088. case reflect.Interface, reflect.Ptr:
  1089. return v.IsNil()
  1090. }
  1091. return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
  1092. }
  1093. // ErrorByField returns error for specified field of the struct
  1094. // validated by ValidateStruct or empty string if there are no errors
  1095. // or this field doesn't exists or doesn't have any errors.
  1096. func ErrorByField(e error, field string) string {
  1097. if e == nil {
  1098. return ""
  1099. }
  1100. return ErrorsByField(e)[field]
  1101. }
  1102. // ErrorsByField returns map of errors of the struct validated
  1103. // by ValidateStruct or empty map if there are no errors.
  1104. func ErrorsByField(e error) map[string]string {
  1105. m := make(map[string]string)
  1106. if e == nil {
  1107. return m
  1108. }
  1109. // prototype for ValidateStruct
  1110. switch e.(type) {
  1111. case Error:
  1112. m[e.(Error).Name] = e.(Error).Err.Error()
  1113. case Errors:
  1114. for _, item := range e.(Errors).Errors() {
  1115. n := ErrorsByField(item)
  1116. for k, v := range n {
  1117. m[k] = v
  1118. }
  1119. }
  1120. }
  1121. return m
  1122. }
  1123. // Error returns string equivalent for reflect.Type
  1124. func (e *UnsupportedTypeError) Error() string {
  1125. return "validator: unsupported type: " + e.Type.String()
  1126. }
  1127. func (sv stringValues) Len() int { return len(sv) }
  1128. func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
  1129. func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
  1130. func (sv stringValues) get(i int) string { return sv[i].String() }
上海开阖软件有限公司 沪ICP备12045867号-1