validators.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import json
  2. import re
  3. from importlib import import_module
  4. import requests
  5. from django.contrib.auth import get_user_model
  6. from django.core.exceptions import ValidationError
  7. from django.core.validators import validate_email as validate_email_content
  8. from django.utils.encoding import force_str
  9. from django.utils.translation import ugettext_lazy as _
  10. from django.utils.translation import ungettext
  11. from misago.conf import settings
  12. from .bans import get_email_ban, get_username_ban
  13. USERNAME_RE = re.compile(r'^[0-9a-z]+$', re.IGNORECASE)
  14. """
  15. Email validators
  16. """
  17. def validate_email_available(value, exclude=None):
  18. User = get_user_model()
  19. try:
  20. user = User.objects.get_by_email(value)
  21. if not exclude or user.pk != exclude.pk:
  22. raise ValidationError(_("This e-mail address is not available."))
  23. except User.DoesNotExist:
  24. pass
  25. def validate_email_banned(value):
  26. ban = get_email_ban(value)
  27. if ban:
  28. if ban.user_message:
  29. raise ValidationError(ban.user_message)
  30. else:
  31. raise ValidationError(_("This e-mail address is not allowed."))
  32. def validate_email(value, exclude=None):
  33. """shortcut function that does complete validation of email"""
  34. validate_email_content(value)
  35. validate_email_available(value, exclude)
  36. validate_email_banned(value)
  37. """
  38. Password validators
  39. """
  40. def validate_password(value):
  41. if len(value) < settings.password_length_min:
  42. message = ungettext(
  43. 'Valid password must be at least %(limit_value)s character long.',
  44. 'Valid password must be at least %(limit_value)s characters long.',
  45. settings.password_length_min)
  46. message = message % {'limit_value': settings.password_length_min}
  47. raise ValidationError(message)
  48. """
  49. Username validators
  50. """
  51. def validate_username_available(value, exclude=None):
  52. User = get_user_model()
  53. try:
  54. user = User.objects.get_by_username(value)
  55. if not exclude or user.pk != exclude.pk:
  56. raise ValidationError(_("This username is not available."))
  57. except User.DoesNotExist:
  58. pass
  59. def validate_username_banned(value):
  60. ban = get_username_ban(value)
  61. if ban:
  62. if ban.user_message:
  63. raise ValidationError(ban.user_message)
  64. else:
  65. raise ValidationError(_("This username is not allowed."))
  66. def validate_username_content(value):
  67. if not USERNAME_RE.match(value):
  68. raise ValidationError(
  69. _("Username can only contain latin alphabet letters and digits."))
  70. def validate_username_length(value):
  71. if len(value) < settings.username_length_min:
  72. message = ungettext(
  73. "Username must be at least %(limit_value)s character long.",
  74. "Username must be at least %(limit_value)s characters long.",
  75. settings.username_length_min)
  76. message = message % {'limit_value': settings.username_length_min}
  77. raise ValidationError(message)
  78. if len(value) > settings.username_length_max:
  79. message = ungettext(
  80. "Username cannot be longer than %(limit_value)s characters.",
  81. "Username cannot be longer than %(limit_value)s characters.",
  82. settings.username_length_max)
  83. message = message % {'limit_value': settings.username_length_max}
  84. raise ValidationError(message)
  85. def validate_username(value, exclude=None):
  86. """shortcut function that does complete validation of username"""
  87. validate_username_length(value)
  88. validate_username_content(value)
  89. validate_username_available(value, exclude)
  90. validate_username_banned(value)
  91. """
  92. New account validators
  93. """
  94. SFS_API_URL = u'http://api.stopforumspam.org/api?email=%(email)s&ip=%(ip)s&f=json&confidence' # noqa
  95. def validate_with_sfs(request, form, cleaned_data):
  96. if settings.MISAGO_USE_STOP_FORUM_SPAM and cleaned_data.get('email'):
  97. _real_validate_with_sfs(request.user_ip, cleaned_data['email'])
  98. def _real_validate_with_sfs(ip, email):
  99. try:
  100. r = requests.get(SFS_API_URL % {
  101. 'email': email,
  102. 'ip': ip
  103. }, timeout=5)
  104. r.raise_for_status()
  105. api_response = json.loads(force_str(r.content))
  106. ip_score = api_response.get('ip', {}).get('confidence', 0)
  107. email_score = api_response.get('email', {}).get('confidence', 0)
  108. api_score = max((ip_score, email_score))
  109. if api_score > settings.MISAGO_STOP_FORUM_SPAM_MIN_CONFIDENCE:
  110. raise ValidationError(_("Data entered was found in spammers database."))
  111. except requests.exceptions.RequestException:
  112. pass # todo: log those somewhere
  113. def validate_gmail_email(request, form, cleaned_data):
  114. email = cleaned_data.get('email', '')
  115. if '@' not in email:
  116. return
  117. username, domain = email.lower().split('@')
  118. if domain == 'gmail.com' and username.count('.') > 5:
  119. form.add_error('email', ValidationError(_("This email is not allowed.")))
  120. """
  121. Registration validation
  122. """
  123. def load_registration_validators(validators_list):
  124. loaded_validators = []
  125. for path in validators_list:
  126. module = import_module('.'.join(path.split('.')[:-1]))
  127. loaded_validators.append(getattr(module, path.split('.')[-1]))
  128. return loaded_validators
  129. validators_list = settings.MISAGO_NEW_REGISTRATIONS_VALIDATORS
  130. REGISTRATION_VALIDATORS = load_registration_validators(validators_list)
  131. def validate_new_registration(request, form, cleaned_data, validators=None):
  132. validators = validators or REGISTRATION_VALIDATORS
  133. for validator in validators:
  134. validator(request, form, cleaned_data)