validators.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import json
  2. import re
  3. import requests
  4. from django.contrib.auth import get_user_model
  5. from django.core.exceptions import ValidationError
  6. from django.core.validators import validate_email as validate_email_content
  7. from django.utils.encoding import force_str
  8. from django.utils.module_loading import import_string
  9. from django.utils.translation import gettext_lazy as _
  10. from django.utils.translation import ngettext
  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. User = get_user_model()
  15. # E-mail validators
  16. def validate_email(value, exclude=None):
  17. """shortcut function that does complete validation of email"""
  18. validate_email_content(value)
  19. validate_email_available(value, exclude)
  20. validate_email_banned(value)
  21. def validate_email_available(value, exclude=None):
  22. try:
  23. user = User.objects.get_by_email(value)
  24. if not exclude or user.pk != exclude.pk:
  25. raise ValidationError(_("This e-mail address is not available."))
  26. except User.DoesNotExist:
  27. pass
  28. def validate_email_banned(value):
  29. ban = get_email_ban(value, registration_only=True)
  30. if ban:
  31. if ban.user_message:
  32. raise ValidationError(ban.user_message)
  33. else:
  34. raise ValidationError(_("This e-mail address is not allowed."))
  35. # Username validators
  36. def validate_username(settings, value, exclude=None):
  37. """shortcut function that does complete validation of username"""
  38. validate_username_length(settings, value)
  39. validate_username_content(value)
  40. validate_username_available(value, exclude)
  41. validate_username_banned(value)
  42. def validate_username_available(value, exclude=None):
  43. try:
  44. user = User.objects.get_by_username(value)
  45. if not exclude or user.pk != exclude.pk:
  46. raise ValidationError(_("This username is not available."))
  47. except User.DoesNotExist:
  48. pass
  49. def validate_username_banned(value):
  50. ban = get_username_ban(value, registration_only=True)
  51. if ban:
  52. if ban.user_message:
  53. raise ValidationError(ban.user_message)
  54. else:
  55. raise ValidationError(_("This username is not allowed."))
  56. def validate_username_content(value):
  57. if not USERNAME_RE.match(value):
  58. raise ValidationError(
  59. _("Username can only contain latin alphabet letters and digits.")
  60. )
  61. def validate_username_length(settings, value):
  62. if len(value) < settings.username_length_min:
  63. message = ngettext(
  64. "Username must be at least %(limit_value)s character long.",
  65. "Username must be at least %(limit_value)s characters long.",
  66. settings.username_length_min,
  67. )
  68. raise ValidationError(message % {"limit_value": settings.username_length_min})
  69. if len(value) > settings.username_length_max:
  70. message = ngettext(
  71. "Username cannot be longer than %(limit_value)s characters.",
  72. "Username cannot be longer than %(limit_value)s characters.",
  73. settings.username_length_max,
  74. )
  75. raise ValidationError(message % {"limit_value": settings.username_length_max})
  76. # New account validators
  77. SFS_API_URL = (
  78. "http://api.stopforumspam.org/api?email=%(email)s&ip=%(ip)s&f=json&confidence"
  79. )
  80. def validate_with_sfs(request, cleaned_data, add_error):
  81. if settings.MISAGO_USE_STOP_FORUM_SPAM and cleaned_data.get("email"):
  82. _real_validate_with_sfs(request.user_ip, cleaned_data["email"])
  83. def _real_validate_with_sfs(ip, email):
  84. try:
  85. r = requests.get(SFS_API_URL % {"email": email, "ip": ip}, timeout=5)
  86. r.raise_for_status()
  87. api_response = json.loads(force_str(r.content))
  88. ip_score = api_response.get("ip", {}).get("confidence", 0)
  89. email_score = api_response.get("email", {}).get("confidence", 0)
  90. api_score = max((ip_score, email_score))
  91. if api_score > settings.MISAGO_STOP_FORUM_SPAM_MIN_CONFIDENCE:
  92. raise ValidationError(_("Data entered was found in spammers database."))
  93. except requests.exceptions.RequestException:
  94. pass # todo: log those somewhere
  95. def validate_gmail_email(request, cleaned_data, add_error):
  96. email = cleaned_data.get("email", "")
  97. if "@" not in email:
  98. return
  99. username, domain = email.lower().split("@")
  100. if domain == "gmail.com" and username.count(".") > 5:
  101. add_error("email", ValidationError(_("This email is not allowed.")))
  102. # Registration validation
  103. validators_list = settings.MISAGO_NEW_REGISTRATIONS_VALIDATORS
  104. REGISTRATION_VALIDATORS = list(map(import_string, validators_list))
  105. def raise_validation_error(*_):
  106. raise ValidationError()
  107. def validate_new_registration(request, cleaned_data, add_error=None, validators=None):
  108. validators = validators or REGISTRATION_VALIDATORS
  109. add_error = add_error or raise_validation_error
  110. for validator in validators:
  111. validator(request, cleaned_data, add_error)