bans.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. """
  2. API for testing values for bans
  3. Calling this instead of Ban.objects.find_ban is preffered, if you don't want
  4. to use validate_X_banned validators
  5. """
  6. from datetime import date, datetime, timedelta
  7. from django.utils import timezone
  8. from misago.core import cachebuster
  9. from misago.users.models import BAN_IP, Ban, BanCache
  10. BAN_CACHE_SESSION_KEY = 'misago_ip_check'
  11. BAN_VERSION_KEY = 'misago_bans'
  12. def get_username_ban(username):
  13. try:
  14. return Ban.objects.find_ban(username=username)
  15. except Ban.DoesNotExist:
  16. return None
  17. def get_email_ban(email):
  18. try:
  19. return Ban.objects.find_ban(email=email)
  20. except Ban.DoesNotExist:
  21. return None
  22. def get_ip_ban(ip):
  23. try:
  24. return Ban.objects.find_ban(ip=ip)
  25. except Ban.DoesNotExist:
  26. return None
  27. def get_user_ban(user):
  28. """
  29. This function checks if user is banned
  30. When user model is available, this is preffered to calling
  31. get_email_ban(user.email) and get_username_ban(user.username)
  32. because it sets ban cache on user model
  33. """
  34. try:
  35. ban_cache = user.ban_cache
  36. if not ban_cache.is_valid:
  37. _set_user_ban_cache(user)
  38. except BanCache.DoesNotExist:
  39. user.ban_cache = BanCache(user=user)
  40. user.ban_cache = _set_user_ban_cache(user)
  41. if user.ban_cache.ban:
  42. return user.ban_cache
  43. else:
  44. return None
  45. def _set_user_ban_cache(user):
  46. ban_cache = user.ban_cache
  47. ban_cache.bans_version = cachebuster.get_version(BAN_VERSION_KEY)
  48. try:
  49. user_ban = Ban.objects.find_ban(username=user.username,
  50. email=user.email)
  51. ban_cache.ban = user_ban
  52. ban_cache.valid_until = user_ban.valid_until
  53. ban_cache.user_message = user_ban.user_message
  54. ban_cache.staff_message = user_ban.staff_message
  55. except Ban.DoesNotExist:
  56. ban_cache.ban = None
  57. ban_cache.valid_until = None
  58. ban_cache.user_message = None
  59. ban_cache.staff_message = None
  60. ban_cache.save()
  61. return ban_cache
  62. """
  63. Utility for checking if request came from banned IP
  64. This check may be performed frequently, which is why there is extra
  65. boilerplate that caches ban check result in session
  66. """
  67. def get_request_ip_ban(request):
  68. session_ban_cache = _get_session_bancache(request)
  69. if session_ban_cache:
  70. if session_ban_cache['is_banned']:
  71. return session_ban_cache
  72. else:
  73. return False
  74. found_ban = get_ip_ban(request._misago_real_ip)
  75. ban_cache = request.session[BAN_CACHE_SESSION_KEY] = {
  76. 'version': cachebuster.get_version(BAN_VERSION_KEY),
  77. 'ip': request._misago_real_ip,
  78. }
  79. if found_ban:
  80. if found_ban.valid_until:
  81. valid_until_as_string = found_ban.valid_until.strftime('%Y-%m-%d')
  82. ban_cache['valid_until'] = valid_until_as_string
  83. else:
  84. ban_cache['valid_until'] = None
  85. ban_cache.update({
  86. 'is_banned': True,
  87. 'message': found_ban.user_message
  88. })
  89. request.session[BAN_CACHE_SESSION_KEY] = ban_cache
  90. return _hydrate_session_cache(request.session[BAN_CACHE_SESSION_KEY])
  91. else:
  92. ban_cache['is_banned'] = False
  93. request.session[BAN_CACHE_SESSION_KEY] = ban_cache
  94. return None
  95. def _get_session_bancache(request):
  96. try:
  97. ban_cache = request.session[BAN_CACHE_SESSION_KEY]
  98. ban_cache = _hydrate_session_cache(ban_cache)
  99. if ban_cache['ip'] != request._misago_real_ip:
  100. return None
  101. if not cachebuster.is_valid(BAN_VERSION_KEY, ban_cache['version']):
  102. return None
  103. if ban_cache.get('valid_until'):
  104. """
  105. Make two timezone unaware dates and compare them
  106. """
  107. if ban_cache.get('valid_until') < date.today():
  108. return None
  109. return ban_cache
  110. except KeyError:
  111. return None
  112. def _hydrate_session_cache(ban_cache):
  113. hydrated = ban_cache.copy()
  114. if hydrated.get('valid_until'):
  115. expiration_datetime = datetime.strptime(ban_cache.get('valid_until'),
  116. '%Y-%m-%d')
  117. hydrated['valid_until'] = expiration_datetime.date()
  118. return hydrated
  119. """
  120. Utility for banning naughty IPs
  121. """
  122. def ban_ip(ip, user_message=None, staff_message=None, length=None):
  123. if length:
  124. valid_until = (timezone.now() + timedelta(days=length)).date()
  125. else:
  126. valid_until = None
  127. Ban.objects.create(
  128. test=BAN_IP,
  129. banned_value=ip,
  130. user_message=user_message,
  131. staff_message=staff_message,
  132. valid_until=valid_until
  133. )
  134. Ban.objects.invalidate_cache()