diff -r 000000000000 -r 0d40e90630ef web/lib/django/contrib/auth/tokens.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/lib/django/contrib/auth/tokens.py Wed Jan 20 00:34:04 2010 +0100 @@ -0,0 +1,66 @@ +from datetime import date +from django.conf import settings +from django.utils.http import int_to_base36, base36_to_int + +class PasswordResetTokenGenerator(object): + """ + Strategy object used to generate and check tokens for the password + reset mechanism. + """ + def make_token(self, user): + """ + Returns a token that can be used once to do a password reset + for the given user. + """ + return self._make_token_with_timestamp(user, self._num_days(self._today())) + + def check_token(self, user, token): + """ + Check that a password reset token is correct for a given user. + """ + # Parse the token + try: + ts_b36, hash = token.split("-") + except ValueError: + return False + + try: + ts = base36_to_int(ts_b36) + except ValueError: + return False + + # Check that the timestamp/uid has not been tampered with + if self._make_token_with_timestamp(user, ts) != token: + return False + + # Check the timestamp is within limit + if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS: + return False + + return True + + def _make_token_with_timestamp(self, user, timestamp): + # timestamp is number of days since 2001-1-1. Converted to + # base 36, this gives us a 3 digit string until about 2121 + ts_b36 = int_to_base36(timestamp) + + # By hashing on the internal state of the user and using state + # that is sure to change (the password salt will change as soon as + # the password is set, at least for current Django auth, and + # last_login will also change), we produce a hash that will be + # invalid as soon as it is used. + # We limit the hash to 20 chars to keep URL short + from django.utils.hashcompat import sha_constructor + hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) + + user.password + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + + unicode(timestamp)).hexdigest()[::2] + return "%s-%s" % (ts_b36, hash) + + def _num_days(self, dt): + return (dt - date(2001,1,1)).days + + def _today(self): + # Used for mocking in tests + return date.today() + +default_token_generator = PasswordResetTokenGenerator()