sessions.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. from datetime import timedelta
  2. from django.conf import settings
  3. from django.contrib.sessions.backends.base import SessionBase, CreateError
  4. from django.db.models.loading import cache as model_cache
  5. from django.utils import timezone
  6. from django.utils.crypto import salted_hmac
  7. from django.utils.encoding import force_unicode
  8. from misago.auth import auth_remember, AuthException
  9. from misago.models import Session, Token, Guest, User
  10. from misago.utils.strings import random_string
  11. # Assert models are loaded
  12. if not model_cache.loaded:
  13. model_cache.get_models()
  14. class IncorrectSessionException(Exception):
  15. pass
  16. class MisagoSession(SessionBase):
  17. """
  18. Abstract class for sessions to inherit and extend
  19. """
  20. def _get_new_session_key(self):
  21. return random_string(42)
  22. def _get_session(self):
  23. try:
  24. return self._session_cache
  25. except AttributeError:
  26. self._session_cache = self.load()
  27. return self._session_cache
  28. def _hash(self, value):
  29. key_salt = "misago.sessions" + self.__class__.__name__
  30. return salted_hmac(key_salt, value).hexdigest()
  31. def delete(self):
  32. """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
  33. pass
  34. def flush(self):
  35. """We use sessions to track onlines so sorry, only sessions cleaner may delete sessions"""
  36. pass
  37. def load(self):
  38. return self.decode(force_unicode(self._session_rk.data))
  39. def session_expired(self):
  40. return False
  41. def get_hidden(self):
  42. return False
  43. def set_hidden(self, hidden=False):
  44. pass
  45. def get_ip(self, request):
  46. return request.META.get('HTTP_X_FORWARDED_FOR', '') or request.META.get('REMOTE_ADDR')
  47. def set_user(self, user=None):
  48. pass
  49. def get_ban(self):
  50. return False
  51. def set_ban(self, ban):
  52. return False
  53. def save(self):
  54. self._session_rk.data = self.encode(self._get_session())
  55. self._session_rk.last = timezone.now()
  56. self._session_rk.save(force_update=True)
  57. class CrawlerSession(MisagoSession):
  58. """
  59. Crawler Session controller
  60. """
  61. def __init__(self, request):
  62. self.hidden = False
  63. self.team = False
  64. self._ip = self.get_ip(request)
  65. try:
  66. self._session_rk = Session.objects.get(crawler=request.user.username, ip=self._ip)
  67. self._session_key = self._session_rk.id
  68. except Session.DoesNotExist:
  69. self.create(request)
  70. def create(self, request):
  71. while True:
  72. try:
  73. self._session_key = self._get_new_session_key()
  74. self._session_rk = Session(
  75. id=self._session_key,
  76. data=self.encode({}),
  77. crawler=request.user.username,
  78. ip=self._ip,
  79. agent=request.META.get('HTTP_USER_AGENT', ''),
  80. start=timezone.now(),
  81. last=timezone.now(),
  82. matched=True
  83. )
  84. self._session_rk.save(force_insert=True)
  85. break
  86. except CreateError:
  87. # Key wasn't unique. Try again.
  88. continue
  89. def human_session(self):
  90. return False
  91. class HumanSession(MisagoSession):
  92. """
  93. Human Session controller
  94. """
  95. def __init__(self, request):
  96. self.expired = False
  97. self.hidden = False
  98. self.team = False
  99. self.rank = None
  100. self.remember_me = None
  101. self._user = None
  102. self._ip = self.get_ip(request)
  103. self._session_token = None
  104. if request.firewall.admin:
  105. self._cookie_sid = settings.COOKIES_PREFIX + 'ASID'
  106. else:
  107. self._cookie_sid = settings.COOKIES_PREFIX + 'SID'
  108. try:
  109. # Do we have correct session ID?
  110. if self._cookie_sid not in request.COOKIES or len(request.COOKIES[self._cookie_sid]) != 42:
  111. raise IncorrectSessionException()
  112. self._session_key = request.COOKIES[self._cookie_sid]
  113. self._session_rk = Session.objects.select_related().get(
  114. pk=self._session_key,
  115. admin=request.firewall.admin
  116. )
  117. # IP invalid
  118. if request.settings.sessions_validate_ip and self._session_rk.ip != self._ip:
  119. raise IncorrectSessionException()
  120. # Session expired
  121. if timezone.now() - self._session_rk.last > timedelta(seconds=settings.SESSION_LIFETIME):
  122. self.expired = True
  123. raise IncorrectSessionException()
  124. # Change session to matched and extract session user and hidden flag
  125. self._session_rk.matched = True
  126. self._user = self._session_rk.user
  127. self.hidden = self._session_rk.hidden
  128. self.team = self._session_rk.team
  129. except (Session.DoesNotExist, IncorrectSessionException):
  130. # Attempt autolog
  131. try:
  132. self.remember_me = auth_remember(request, self.get_ip(request))
  133. self.create(request, user=self.remember_me.user)
  134. except AuthException as e:
  135. # Autolog failed
  136. self.create(request)
  137. self.id = self._session_rk.id
  138. # Make cookie live longer
  139. if request.firewall.admin:
  140. request.cookiejar.set('ASID', self._session_rk.id)
  141. else:
  142. request.cookiejar.set('SID', self._session_rk.id)
  143. def create(self, request, user=None):
  144. self._user = user
  145. while True:
  146. try:
  147. self._session_key = self._get_new_session_key()
  148. self._session_rk = Session(
  149. id=self._session_key,
  150. data=self.encode({}),
  151. user=self._user,
  152. ip=self._ip,
  153. agent=request.META.get('HTTP_USER_AGENT', ''),
  154. start=timezone.now(),
  155. last=timezone.now(),
  156. admin=request.firewall.admin,
  157. )
  158. self._session_rk.save(force_insert=True)
  159. if user:
  160. # Update user data
  161. user.set_last_visit(
  162. self.get_ip(request),
  163. request.META.get('HTTP_USER_AGENT', ''),
  164. hidden=self.hidden
  165. )
  166. user.save(force_update=True)
  167. break
  168. except CreateError:
  169. # Key wasn't unique. Try again.
  170. continue
  171. def save(self):
  172. self._session_rk.user = self._user
  173. self._session_rk.hidden = self.hidden
  174. self._session_rk.team = self.team
  175. self._session_rk.rank_id = self.rank
  176. super(HumanSession, self).save()
  177. def human_session(self):
  178. return True
  179. def session_expired(self):
  180. return self.expired
  181. def get_user(self):
  182. if self._user == None:
  183. return Guest()
  184. return self._user
  185. def set_user(self, user=None):
  186. self._user = user
  187. def sign_out(self, request):
  188. try:
  189. if self._user.is_authenticated():
  190. if not request.firewall.admin:
  191. cookie_token = settings.COOKIES_PREFIX + 'TOKEN'
  192. if cookie_token in request.COOKIES:
  193. if len(request.COOKIES[cookie_token]) > 0:
  194. Token.objects.filter(id=request.COOKIES[cookie_token]).delete()
  195. request.cookiejar.delete('TOKEN')
  196. self.hidden = False
  197. self._user = None
  198. request.user = Guest()
  199. except AttributeError:
  200. pass
  201. def get_hidden(self):
  202. return self.hidden
  203. def set_hidden(self, hidden=False):
  204. self.hidden = hidden
  205. class SessionMock(object):
  206. def get_ip(self, request):
  207. try:
  208. return self.ip
  209. except AttributeError:
  210. return '127.0.0.1'