rule.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package is
  2. import (
  3. "regexp"
  4. "unicode"
  5. "kpt-tmr-group/pkg/valid"
  6. "github.com/asaskevich/govalidator"
  7. "github.com/nyaruka/phonenumbers"
  8. )
  9. var (
  10. // ErrEmail is the error that returns in case of an invalid email.
  11. ErrEmail = valid.NewError("validation_is_email", "must be a valid email address")
  12. // ErrURL is the error that returns in case of an invalid URL.
  13. ErrURL = valid.NewError("validation_is_url", "must be a valid URL")
  14. // ErrRequestURL is the error that returns in case of an invalid request URL.
  15. ErrRequestURL = valid.NewError("validation_is_request_url", "must be a valid request URL")
  16. // ErrRequestURI is the error that returns in case of an invalid request URI.
  17. ErrRequestURI = valid.NewError("validation_request_is_request_uri", "must be a valid request URI")
  18. // ErrAlpha is the error that returns in case of an invalid alpha value.
  19. ErrAlpha = valid.NewError("validation_is_alpha", "must contain English letters only")
  20. // ErrDigit is the error that returns in case of an invalid digit value.
  21. ErrDigit = valid.NewError("validation_is_digit", "must contain digits only")
  22. // ErrAlphanumeric is the error that returns in case of an invalid alphanumeric value.
  23. ErrAlphanumeric = valid.NewError("validation_is_alphanumeric", "must contain English letters and digits only")
  24. // ErrUTFLetter is the error that returns in case of an invalid utf letter value.
  25. ErrUTFLetter = valid.NewError("validation_is_utf_letter", "must contain unicode letter characters only")
  26. // ErrUTFDigit is the error that returns in case of an invalid utf digit value.
  27. ErrUTFDigit = valid.NewError("validation_is_utf_digit", "must contain unicode decimal digits only")
  28. // ErrUTFLetterNumeric is the error that returns in case of an invalid utf numeric or letter value.
  29. ErrUTFLetterNumeric = valid.NewError("validation_is utf_letter_numeric", "must contain unicode letters and numbers only")
  30. // ErrUTFNumeric is the error that returns in case of an invalid utf numeric value.
  31. ErrUTFNumeric = valid.NewError("validation_is_utf_numeric", "must contain unicode number characters only")
  32. // ErrLowerCase is the error that returns in case of an invalid lower case value.
  33. ErrLowerCase = valid.NewError("validation_is_lower_case", "must be in lower case")
  34. // ErrUpperCase is the error that returns in case of an invalid upper case value.
  35. ErrUpperCase = valid.NewError("validation_is_upper_case", "must be in upper case")
  36. // ErrHexadecimal is the error that returns in case of an invalid hexadecimal number.
  37. ErrHexadecimal = valid.NewError("validation_is_hexadecimal", "must be a valid hexadecimal number")
  38. // ErrHexColor is the error that returns in case of an invalid hexadecimal color code.
  39. ErrHexColor = valid.NewError("validation_is_hex_color", "must be a valid hexadecimal color code")
  40. // ErrRGBColor is the error that returns in case of an invalid RGB color code.
  41. ErrRGBColor = valid.NewError("validation_is_rgb_color", "must be a valid RGB color code")
  42. // ErrInt is the error that returns in case of an invalid integer value.
  43. ErrInt = valid.NewError("validation_is_int", "must be an integer number")
  44. // ErrFloat is the error that returns in case of an invalid float value.
  45. ErrFloat = valid.NewError("validation_is_float", "must be a floating point number")
  46. // ErrUUIDv3 is the error that returns in case of an invalid UUIDv3 value.
  47. ErrUUIDv3 = valid.NewError("validation_is_uuid_v3", "must be a valid UUID v3")
  48. // ErrUUIDv4 is the error that returns in case of an invalid UUIDv4 value.
  49. ErrUUIDv4 = valid.NewError("validation_is_uuid_v4", "must be a valid UUID v4")
  50. // ErrUUIDv5 is the error that returns in case of an invalid UUIDv5 value.
  51. ErrUUIDv5 = valid.NewError("validation_is_uuid_v5", "must be a valid UUID v5")
  52. // ErrUUID is the error that returns in case of an invalid UUID value.
  53. ErrUUID = valid.NewError("validation_is_uuid", "must be a valid UUID")
  54. // ErrCreditCard is the error that returns in case of an invalid credit card number.
  55. ErrCreditCard = valid.NewError("validation_is_credit_card", "must be a valid credit card number")
  56. // ErrISBN10 is the error that returns in case of an invalid ISBN-10 value.
  57. ErrISBN10 = valid.NewError("validation_is_isbn_10", "must be a valid ISBN-10")
  58. // ErrISBN13 is the error that returns in case of an invalid ISBN-13 value.
  59. ErrISBN13 = valid.NewError("validation_is_isbn_13", "must be a valid ISBN-13")
  60. // ErrISBN is the error that returns in case of an invalid ISBN value.
  61. ErrISBN = valid.NewError("validation_is_isbn", "must be a valid ISBN")
  62. // ErrJSON is the error that returns in case of an invalid JSON.
  63. ErrJSON = valid.NewError("validation_is_json", "must be in valid JSON format")
  64. // ErrASCII is the error that returns in case of an invalid ASCII.
  65. ErrASCII = valid.NewError("validation_is_ascii", "must contain ASCII characters only")
  66. // ErrPrintableASCII is the error that returns in case of an invalid printable ASCII value.
  67. ErrPrintableASCII = valid.NewError("validation_is_printable_ascii", "must contain printable ASCII characters only")
  68. // ErrMultibyte is the error that returns in case of an invalid multibyte value.
  69. ErrMultibyte = valid.NewError("validation_is_multibyte", "must contain multibyte characters")
  70. // ErrFullWidth is the error that returns in case of an invalid full-width value.
  71. ErrFullWidth = valid.NewError("validation_is_full_width", "must contain full-width characters")
  72. // ErrHalfWidth is the error that returns in case of an invalid half-width value.
  73. ErrHalfWidth = valid.NewError("validation_is_half_width", "must contain half-width characters")
  74. // ErrVariableWidth is the error that returns in case of an invalid variable width value.
  75. ErrVariableWidth = valid.NewError("validation_is_variable_width", "must contain both full-width and half-width characters")
  76. // ErrBase64 is the error that returns in case of an invalid base54 value.
  77. ErrBase64 = valid.NewError("validation_is_base64", "must be encoded in Base64")
  78. // ErrDataURI is the error that returns in case of an invalid data URI.
  79. ErrDataURI = valid.NewError("validation_is_data_uri", "must be a Base64-encoded data URI")
  80. // ErrE164 is the error that returns in case of an invalid e165.
  81. ErrE164 = valid.NewError("validation_is_e164_number", "must be a valid E164 number")
  82. // ErrCountryCode2 is the error that returns in case of an invalid two-letter country code.
  83. ErrCountryCode2 = valid.NewError("validation_is_country_code_2_letter", "must be a valid two-letter country code")
  84. // ErrCountryCode3 is the error that returns in case of an invalid three-letter country code.
  85. ErrCountryCode3 = valid.NewError("validation_is_country_code_3_letter", "must be a valid three-letter country code")
  86. // ErrCurrencyCode is the error that returns in case of an invalid currency code.
  87. ErrCurrencyCode = valid.NewError("validation_is_currency_code", "must be valid ISO 4217 currency code")
  88. // ErrDialString is the error that returns in case of an invalid string.
  89. ErrDialString = valid.NewError("validation_is_dial_string", "must be a valid dial string")
  90. // ErrMac is the error that returns in case of an invalid mac address.
  91. ErrMac = valid.NewError("validation_is_mac_address", "must be a valid MAC address")
  92. // ErrIP is the error that returns in case of an invalid IP.
  93. ErrIP = valid.NewError("validation_is_ip", "must be a valid IP address")
  94. // ErrIPv4 is the error that returns in case of an invalid IPv4.
  95. ErrIPv4 = valid.NewError("validation_is_ipv4", "must be a valid IPv4 address")
  96. // ErrIPv6 is the error that returns in case of an invalid IPv6.
  97. ErrIPv6 = valid.NewError("validation_is_ipv6", "must be a valid IPv6 address")
  98. // ErrSubdomain is the error that returns in case of an invalid subdomain.
  99. ErrSubdomain = valid.NewError("validation_is_sub_domain", "must be a valid subdomain")
  100. // ErrDomain is the error that returns in case of an invalid domain.
  101. ErrDomain = valid.NewError("validation_is_domain", "must be a valid domain")
  102. // ErrDNSName is the error that returns in case of an invalid DNS name.
  103. ErrDNSName = valid.NewError("validation_is_dns_name", "must be a valid DNS name")
  104. // ErrHost is the error that returns in case of an invalid host.
  105. ErrHost = valid.NewError("validation_is_host", "must be a valid IP address or DNS name")
  106. // ErrPort is the error that returns in case of an invalid port.
  107. ErrPort = valid.NewError("validation_is_port", "must be a valid port number")
  108. // ErrMongoID is the error that returns in case of an invalid MongoID.
  109. ErrMongoID = valid.NewError("validation_is_mongo_id", "must be a valid hex-encoded MongoDB ObjectId")
  110. // ErrLatitude is the error that returns in case of an invalid latitude.
  111. ErrLatitude = valid.NewError("validation_is_latitude", "must be a valid latitude")
  112. // ErrLongitude is the error that returns in case of an invalid longitude.
  113. ErrLongitude = valid.NewError("validation_is_longitude", "must be a valid longitude")
  114. // ErrSSN is the error that returns in case of an invalid SSN.
  115. ErrSSN = valid.NewError("validation_is_ssn", "must be a valid social security number")
  116. // ErrSemver is the error that returns in case of an invalid semver.
  117. ErrSemver = valid.NewError("validation_is_semver", "must be a valid semantic version")
  118. )
  119. var (
  120. // Email validates if a string is an email or not. It also checks if the MX record exists for the email domain.
  121. Email = valid.NewStringRuleWithError(govalidator.IsExistingEmail, ErrEmail)
  122. // EmailFormat validates if a string is an email or not. Note that it does NOT check if the MX record exists or not.
  123. EmailFormat = valid.NewStringRuleWithError(govalidator.IsEmail, ErrEmail)
  124. // EmailUser validates if a string is an user email or not.
  125. EmailUser = valid.NewStringRuleWithError(isUserEmail, ErrEmail)
  126. // URL validates if a string is a valid URL
  127. URL = valid.NewStringRuleWithError(govalidator.IsURL, ErrURL)
  128. // RequestURL validates if a string is a valid request URL
  129. RequestURL = valid.NewStringRuleWithError(govalidator.IsRequestURL, ErrRequestURL)
  130. // RequestURI validates if a string is a valid request URI
  131. RequestURI = valid.NewStringRuleWithError(govalidator.IsRequestURI, ErrRequestURI)
  132. // Alpha validates if a string contains English letters only (a-zA-Z)
  133. Alpha = valid.NewStringRuleWithError(govalidator.IsAlpha, ErrAlpha)
  134. // Digit validates if a string contains digits only (0-9)
  135. Digit = valid.NewStringRuleWithError(isDigit, ErrDigit)
  136. // Alphanumeric validates if a string contains English letters and digits only (a-zA-Z0-9)
  137. Alphanumeric = valid.NewStringRuleWithError(govalidator.IsAlphanumeric, ErrAlphanumeric)
  138. // UTFLetter validates if a string contains unicode letters only
  139. UTFLetter = valid.NewStringRuleWithError(govalidator.IsUTFLetter, ErrUTFLetter)
  140. // UTFDigit validates if a string contains unicode decimal digits only
  141. UTFDigit = valid.NewStringRuleWithError(govalidator.IsUTFDigit, ErrUTFDigit)
  142. // UTFLetterNumeric validates if a string contains unicode letters and numbers only
  143. UTFLetterNumeric = valid.NewStringRuleWithError(govalidator.IsUTFLetterNumeric, ErrUTFLetterNumeric)
  144. // UTFNumeric validates if a string contains unicode number characters (category N) only
  145. UTFNumeric = valid.NewStringRuleWithError(isUTFNumeric, ErrUTFNumeric)
  146. // LowerCase validates if a string contains lower case unicode letters only
  147. LowerCase = valid.NewStringRuleWithError(govalidator.IsLowerCase, ErrLowerCase)
  148. // UpperCase validates if a string contains upper case unicode letters only
  149. UpperCase = valid.NewStringRuleWithError(govalidator.IsUpperCase, ErrUpperCase)
  150. // Hexadecimal validates if a string is a valid hexadecimal number
  151. Hexadecimal = valid.NewStringRuleWithError(govalidator.IsHexadecimal, ErrHexadecimal)
  152. // HexColor validates if a string is a valid hexadecimal color code
  153. HexColor = valid.NewStringRuleWithError(govalidator.IsHexcolor, ErrHexColor)
  154. // RGBColor validates if a string is a valid RGB color in the form of rgb(R, G, B)
  155. RGBColor = valid.NewStringRuleWithError(govalidator.IsRGBcolor, ErrRGBColor)
  156. // Int validates if a string is a valid integer number
  157. Int = valid.NewStringRuleWithError(govalidator.IsInt, ErrInt)
  158. // Float validates if a string is a floating point number
  159. Float = valid.NewStringRuleWithError(govalidator.IsFloat, ErrFloat)
  160. // UUIDv3 validates if a string is a valid version 3 UUID
  161. UUIDv3 = valid.NewStringRuleWithError(govalidator.IsUUIDv3, ErrUUIDv3)
  162. // UUIDv4 validates if a string is a valid version 4 UUID
  163. UUIDv4 = valid.NewStringRuleWithError(govalidator.IsUUIDv4, ErrUUIDv4)
  164. // UUIDv5 validates if a string is a valid version 5 UUID
  165. UUIDv5 = valid.NewStringRuleWithError(govalidator.IsUUIDv5, ErrUUIDv5)
  166. // UUID validates if a string is a valid UUID
  167. UUID = valid.NewStringRuleWithError(govalidator.IsUUID, ErrUUID)
  168. // CreditCard validates if a string is a valid credit card number
  169. CreditCard = valid.NewStringRuleWithError(govalidator.IsCreditCard, ErrCreditCard)
  170. // ISBN10 validates if a string is an ISBN version 10
  171. ISBN10 = valid.NewStringRuleWithError(govalidator.IsISBN10, ErrISBN10)
  172. // ISBN13 validates if a string is an ISBN version 13
  173. ISBN13 = valid.NewStringRuleWithError(govalidator.IsISBN13, ErrISBN13)
  174. // ISBN validates if a string is an ISBN (either version 10 or 13)
  175. ISBN = valid.NewStringRuleWithError(isISBN, ErrISBN)
  176. // JSON validates if a string is in valid JSON format
  177. JSON = valid.NewStringRuleWithError(govalidator.IsJSON, ErrJSON)
  178. // ASCII validates if a string contains ASCII characters only
  179. ASCII = valid.NewStringRuleWithError(govalidator.IsASCII, ErrASCII)
  180. // PrintableASCII validates if a string contains printable ASCII characters only
  181. PrintableASCII = valid.NewStringRuleWithError(govalidator.IsPrintableASCII, ErrPrintableASCII)
  182. // Multibyte validates if a string contains multibyte characters
  183. Multibyte = valid.NewStringRuleWithError(govalidator.IsMultibyte, ErrMultibyte)
  184. // FullWidth validates if a string contains full-width characters
  185. FullWidth = valid.NewStringRuleWithError(govalidator.IsFullWidth, ErrFullWidth)
  186. // HalfWidth validates if a string contains half-width characters
  187. HalfWidth = valid.NewStringRuleWithError(govalidator.IsHalfWidth, ErrHalfWidth)
  188. // VariableWidth validates if a string contains both full-width and half-width characters
  189. VariableWidth = valid.NewStringRuleWithError(govalidator.IsVariableWidth, ErrVariableWidth)
  190. // Base64 validates if a string is encoded in Base64
  191. Base64 = valid.NewStringRuleWithError(govalidator.IsBase64, ErrBase64)
  192. // DataURI validates if a string is a valid base64-encoded data URI
  193. DataURI = valid.NewStringRuleWithError(govalidator.IsDataURI, ErrDataURI)
  194. // E164 validates if a string is a valid ISO3166 Alpha 2 country code
  195. E164 = valid.NewStringRuleWithError(isE164Number, ErrE164)
  196. // CountryCode2 validates if a string is a valid ISO3166 Alpha 2 country code
  197. CountryCode2 = valid.NewStringRuleWithError(govalidator.IsISO3166Alpha2, ErrCountryCode2)
  198. // CountryCode3 validates if a string is a valid ISO3166 Alpha 3 country code
  199. CountryCode3 = valid.NewStringRuleWithError(govalidator.IsISO3166Alpha3, ErrCountryCode3)
  200. // CurrencyCode validates if a string is a valid IsISO4217 currency code.
  201. CurrencyCode = valid.NewStringRuleWithError(govalidator.IsISO4217, ErrCurrencyCode)
  202. // DialString validates if a string is a valid dial string that can be passed to Dial()
  203. DialString = valid.NewStringRuleWithError(govalidator.IsDialString, ErrDialString)
  204. // MAC validates if a string is a MAC address
  205. MAC = valid.NewStringRuleWithError(govalidator.IsMAC, ErrMac)
  206. // IP validates if a string is a valid IP address (either version 4 or 6)
  207. IP = valid.NewStringRuleWithError(govalidator.IsIP, ErrIP)
  208. // IPv4 validates if a string is a valid version 4 IP address
  209. IPv4 = valid.NewStringRuleWithError(govalidator.IsIPv4, ErrIPv4)
  210. // IPv6 validates if a string is a valid version 6 IP address
  211. IPv6 = valid.NewStringRuleWithError(govalidator.IsIPv6, ErrIPv6)
  212. // Subdomain validates if a string is valid subdomain
  213. Subdomain = valid.NewStringRuleWithError(isSubdomain, ErrSubdomain)
  214. // Domain validates if a string is valid domain
  215. Domain = valid.NewStringRuleWithError(isDomain, ErrDomain)
  216. // DNSName validates if a string is valid DNS name
  217. DNSName = valid.NewStringRuleWithError(govalidator.IsDNSName, ErrDNSName)
  218. // Host validates if a string is a valid IP (both v4 and v6) or a valid DNS name
  219. Host = valid.NewStringRuleWithError(govalidator.IsHost, ErrHost)
  220. // Port validates if a string is a valid port number
  221. Port = valid.NewStringRuleWithError(govalidator.IsPort, ErrPort)
  222. // MongoID validates if a string is a valid Mongo ID
  223. MongoID = valid.NewStringRuleWithError(govalidator.IsMongoID, ErrMongoID)
  224. // Latitude validates if a string is a valid latitude
  225. Latitude = valid.NewStringRuleWithError(govalidator.IsLatitude, ErrLatitude)
  226. // Longitude validates if a string is a valid longitude
  227. Longitude = valid.NewStringRuleWithError(govalidator.IsLongitude, ErrLongitude)
  228. // SSN validates if a string is a social security number (SSN)
  229. SSN = valid.NewStringRuleWithError(govalidator.IsSSN, ErrSSN)
  230. // Semver validates if a string is a valid semantic version
  231. Semver = valid.NewStringRuleWithError(govalidator.IsSemver, ErrSemver)
  232. )
  233. var (
  234. reDigit = regexp.MustCompile("^[0-9]+$")
  235. // Subdomain regex source: https://stackoverflow.com/a/7933253
  236. reSubdomain = regexp.MustCompile(`^[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?$`)
  237. // Domain regex source: https://stackoverflow.com/a/7933253
  238. // Slightly modified: Removed 255 max length validation since Go regex does not
  239. // support lookarounds. More info: https://stackoverflow.com/a/38935027
  240. reDomain = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-z0-9])?\.)+(?:[a-zA-Z]{1,63}| xn--[a-z0-9]{1,59})$`)
  241. // UserEmail regex 来源自 Russell 的代码,这里作为用户邮箱的校验逻辑
  242. reUserEmail = regexp.MustCompile(`\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`)
  243. )
  244. func isISBN(value string) bool {
  245. return govalidator.IsISBN(value, 10) || govalidator.IsISBN(value, 13)
  246. }
  247. func isDigit(value string) bool {
  248. return reDigit.MatchString(value)
  249. }
  250. func isE164Number(value string) bool {
  251. phoneNumber, err := phonenumbers.Parse(value, "CN")
  252. if err != nil {
  253. return false
  254. }
  255. if !phonenumbers.IsValidNumber(phoneNumber) {
  256. return false
  257. }
  258. return true
  259. }
  260. func isSubdomain(value string) bool {
  261. return reSubdomain.MatchString(value)
  262. }
  263. func isDomain(value string) bool {
  264. if len(value) > 255 {
  265. return false
  266. }
  267. return reDomain.MatchString(value)
  268. }
  269. func isUTFNumeric(value string) bool {
  270. for _, c := range value {
  271. if unicode.IsNumber(c) == false {
  272. return false
  273. }
  274. }
  275. return true
  276. }
  277. func isUserEmail(value string) bool {
  278. return reUserEmail.MatchString(value)
  279. }