PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/django/core/validators.py

https://github.com/insanemainframe/django
Python | 226 lines | 185 code | 32 blank | 9 comment | 23 complexity | 8e260d038ab30bc8b8bf683f2c16dc28 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. from __future__ import unicode_literals
  2. import re
  3. try:
  4. from urllib.parse import urlsplit, urlunsplit
  5. except ImportError: # Python 2
  6. from urlparse import urlsplit, urlunsplit
  7. from django.core.exceptions import ValidationError
  8. from django.utils.translation import ugettext_lazy as _, ungettext_lazy
  9. from django.utils.encoding import force_text
  10. from django.utils.ipv6 import is_valid_ipv6_address
  11. from django.utils import six
  12. # These values, if given to validate(), will trigger the self.required check.
  13. EMPTY_VALUES = (None, '', [], (), {})
  14. class RegexValidator(object):
  15. regex = ''
  16. message = _('Enter a valid value.')
  17. code = 'invalid'
  18. def __init__(self, regex=None, message=None, code=None):
  19. if regex is not None:
  20. self.regex = regex
  21. if message is not None:
  22. self.message = message
  23. if code is not None:
  24. self.code = code
  25. # Compile the regex if it was not passed pre-compiled.
  26. if isinstance(self.regex, six.string_types):
  27. self.regex = re.compile(self.regex)
  28. def __call__(self, value):
  29. """
  30. Validates that the input matches the regular expression.
  31. """
  32. if not self.regex.search(force_text(value)):
  33. raise ValidationError(self.message, code=self.code)
  34. class URLValidator(RegexValidator):
  35. regex = re.compile(
  36. r'^(?:http|ftp)s?://' # http:// or https://
  37. r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
  38. r'localhost|' # localhost...
  39. r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
  40. r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
  41. r'(?::\d+)?' # optional port
  42. r'(?:/?|[/?]\S+)$', re.IGNORECASE)
  43. def __call__(self, value):
  44. try:
  45. super(URLValidator, self).__call__(value)
  46. except ValidationError as e:
  47. # Trivial case failed. Try for possible IDN domain
  48. if value:
  49. value = force_text(value)
  50. scheme, netloc, path, query, fragment = urlsplit(value)
  51. try:
  52. netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
  53. except UnicodeError: # invalid domain part
  54. raise e
  55. url = urlunsplit((scheme, netloc, path, query, fragment))
  56. super(URLValidator, self).__call__(url)
  57. else:
  58. raise
  59. else:
  60. url = value
  61. def validate_integer(value):
  62. try:
  63. int(value)
  64. except (ValueError, TypeError):
  65. raise ValidationError('')
  66. class EmailValidator(object):
  67. message = _('Enter a valid e-mail address.')
  68. code = 'invalid'
  69. user_regex = re.compile(
  70. r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" # dot-atom
  71. r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', # quoted-string
  72. re.IGNORECASE)
  73. domain_regex = re.compile(
  74. r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' # domain
  75. # literal form, ipv4 address (SMTP 4.1.3)
  76. r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$',
  77. re.IGNORECASE)
  78. domain_whitelist = ['localhost']
  79. def __init__(self, message=None, code=None, whitelist=None):
  80. if message is not None:
  81. self.message = message
  82. if code is not None:
  83. self.code = code
  84. if whitelist is not None:
  85. self.domain_whitelist = whitelist
  86. def __call__(self, value):
  87. value = force_text(value)
  88. if not value or '@' not in value:
  89. raise ValidationError(self.message, code=self.code)
  90. user_part, domain_part = value.rsplit('@', 1)
  91. if not self.user_regex.match(user_part):
  92. raise ValidationError(self.message, code=self.code)
  93. if (not domain_part in self.domain_whitelist and
  94. not self.domain_regex.match(domain_part)):
  95. # Try for possible IDN domain-part
  96. try:
  97. domain_part = domain_part.encode('idna').decode('ascii')
  98. if not self.domain_regex.match(domain_part):
  99. raise ValidationError(self.message, code=self.code)
  100. else:
  101. return
  102. except UnicodeError:
  103. pass
  104. raise ValidationError(self.message, code=self.code)
  105. validate_email = EmailValidator()
  106. slug_re = re.compile(r'^[-a-zA-Z0-9_]+$')
  107. validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
  108. ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
  109. validate_ipv4_address = RegexValidator(ipv4_re, _('Enter a valid IPv4 address.'), 'invalid')
  110. def validate_ipv6_address(value):
  111. if not is_valid_ipv6_address(value):
  112. raise ValidationError(_('Enter a valid IPv6 address.'), code='invalid')
  113. def validate_ipv46_address(value):
  114. try:
  115. validate_ipv4_address(value)
  116. except ValidationError:
  117. try:
  118. validate_ipv6_address(value)
  119. except ValidationError:
  120. raise ValidationError(_('Enter a valid IPv4 or IPv6 address.'), code='invalid')
  121. ip_address_validator_map = {
  122. 'both': ([validate_ipv46_address], _('Enter a valid IPv4 or IPv6 address.')),
  123. 'ipv4': ([validate_ipv4_address], _('Enter a valid IPv4 address.')),
  124. 'ipv6': ([validate_ipv6_address], _('Enter a valid IPv6 address.')),
  125. }
  126. def ip_address_validators(protocol, unpack_ipv4):
  127. """
  128. Depending on the given parameters returns the appropriate validators for
  129. the GenericIPAddressField.
  130. This code is here, because it is exactly the same for the model and the form field.
  131. """
  132. if protocol != 'both' and unpack_ipv4:
  133. raise ValueError(
  134. "You can only use `unpack_ipv4` if `protocol` is set to 'both'")
  135. try:
  136. return ip_address_validator_map[protocol.lower()]
  137. except KeyError:
  138. raise ValueError("The protocol '%s' is unknown. Supported: %s"
  139. % (protocol, list(ip_address_validator_map)))
  140. comma_separated_int_list_re = re.compile('^[\d,]+$')
  141. validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _('Enter only digits separated by commas.'), 'invalid')
  142. class BaseValidator(object):
  143. compare = lambda self, a, b: a is not b
  144. clean = lambda self, x: x
  145. message = _('Ensure this value is %(limit_value)s (it is %(show_value)s).')
  146. code = 'limit_value'
  147. def __init__(self, limit_value):
  148. self.limit_value = limit_value
  149. def __call__(self, value):
  150. cleaned = self.clean(value)
  151. params = {'limit_value': self.limit_value, 'show_value': cleaned}
  152. if self.compare(cleaned, self.limit_value):
  153. raise ValidationError(
  154. self.message % params,
  155. code=self.code,
  156. params=params,
  157. )
  158. class MaxValueValidator(BaseValidator):
  159. compare = lambda self, a, b: a > b
  160. message = _('Ensure this value is less than or equal to %(limit_value)s.')
  161. code = 'max_value'
  162. class MinValueValidator(BaseValidator):
  163. compare = lambda self, a, b: a < b
  164. message = _('Ensure this value is greater than or equal to %(limit_value)s.')
  165. code = 'min_value'
  166. class MinLengthValidator(BaseValidator):
  167. compare = lambda self, a, b: a < b
  168. clean = lambda self, x: len(x)
  169. message = ungettext_lazy(
  170. 'Ensure this value has at least %(limit_value)d character (it has %(show_value)d).',
  171. 'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).',
  172. 'limit_value')
  173. code = 'min_length'
  174. class MaxLengthValidator(BaseValidator):
  175. compare = lambda self, a, b: a > b
  176. clean = lambda self, x: len(x)
  177. message = ungettext_lazy(
  178. 'Ensure this value has at most %(limit_value)d character (it has %(show_value)d).',
  179. 'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).',
  180. 'limit_value')
  181. code = 'max_length'