tokens.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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. hash = hashlib.sha1(settings.SECRET_KEY + unicode(user.id) +
  42. user.password +
  43. unicode(timestamp)).hexdigest()[::2]
  44. return "%s-%s" % (ts_b36, hash)
  45. def _num_days(self, dt):
  46. return (dt - date(2001,1,1)).days
  47. def _today(self):
  48. # Used for mocking in tests
  49. return date.today()
  50. token_generator = TokenGenerator()