tokens.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. """django.contrib.auth.tokens, but without using last_login in hash"""
  2. from datetime import date
  3. from django.conf import settings
  4. from django.utils.http import int_to_base36, base36_to_int
  5. class TokenGenerator(object):
  6. """
  7. Strategy object used to generate and check tokens
  8. """
  9. TOKEN_TIMEOUT_DAYS = getattr(settings, "TOKEN_TIMEOUT_DAYS", 7)
  10. def make_token(self, user):
  11. """
  12. Returns a token for a given user
  13. """
  14. return self._make_token_with_timestamp(user, self._num_days(self._today()))
  15. def check_token(self, user, token):
  16. """
  17. Check that a token is correct for a given user.
  18. """
  19. # Parse the token
  20. try:
  21. ts_b36, hash = token.split("-")
  22. except ValueError:
  23. return False
  24. try:
  25. ts = base36_to_int(ts_b36)
  26. except ValueError:
  27. return False
  28. # Check that the timestamp/uid has not been tampered with
  29. if self._make_token_with_timestamp(user, ts) != token:
  30. return False
  31. # Check the timestamp is within limit
  32. if (self._num_days(self._today()) - ts) > self.TOKEN_TIMEOUT_DAYS:
  33. return False
  34. return True
  35. def _make_token_with_timestamp(self, user, timestamp):
  36. # timestamp is number of days since 2001-1-1. Converted to
  37. # base 36, this gives us a 3 digit string until about 2121
  38. ts_b36 = int_to_base36(timestamp)
  39. # No longer using last login time
  40. import hashlib
  41. m = hashlib.sha1()
  42. text = settings.SECRET_KEY + str(user.id) + user.password + str(timestamp)
  43. m.update(text.encode('utf8'))
  44. hash = m.hexdigest()[::2]
  45. return "%s-%s" % (ts_b36, hash)
  46. def _num_days(self, dt):
  47. return (dt - date(2001,1,1)).days
  48. def _today(self):
  49. # Used for mocking in tests
  50. return date.today()
  51. token_generator = TokenGenerator()