app/django/contrib/auth/tokens.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 from datetime import date
       
     2 from django.conf import settings
       
     3 from django.utils.http import int_to_base36, base36_to_int
       
     4 
       
     5 class PasswordResetTokenGenerator(object):
       
     6     """
       
     7     Stratgy object used to generate and check tokens for the password
       
     8     reset mechanism.
       
     9     """
       
    10     def make_token(self, user):
       
    11         """
       
    12         Returns a token that can be used once to do a password reset
       
    13         for the given user.
       
    14         """
       
    15         return self._make_token_with_timestamp(user, self._num_days(self._today()))
       
    16 
       
    17     def check_token(self, user, token):
       
    18         """
       
    19         Check that a password reset token is correct for a given user.
       
    20         """
       
    21         # Parse the tokem
       
    22         try:
       
    23             ts_b36, hash = token.split("-")
       
    24         except ValueError:
       
    25             return False
       
    26 
       
    27         try:
       
    28             ts = base36_to_int(ts_b36)
       
    29         except ValueError:
       
    30             return False
       
    31 
       
    32         # Check that the timestamp/uid has not been tampered with
       
    33         if self._make_token_with_timestamp(user, ts) != token:
       
    34             return False
       
    35 
       
    36         # Check the timestamp is within limit
       
    37         if (self._num_days(self._today()) - ts) > settings.PASSWORD_RESET_TIMEOUT_DAYS:
       
    38             return False
       
    39 
       
    40         return True
       
    41 
       
    42     def _make_token_with_timestamp(self, user, timestamp):
       
    43         # timestamp is number of days since 2001-1-1.  Converted to
       
    44         # base 36, this gives us a 3 digit string until about 2121
       
    45         ts_b36 = int_to_base36(timestamp)
       
    46 
       
    47         # By hashing on the internal state of the user and using state
       
    48         # that is sure to change (the password salt will change as soon as
       
    49         # the password is set, at least for current Django auth, and
       
    50         # last_login will also change), we produce a hash that will be
       
    51         # invalid as soon as it is used.
       
    52         # We limit the hash to 20 chars to keep URL short
       
    53         from django.utils.hashcompat import sha_constructor
       
    54         hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
       
    55                                user.password + unicode(user.last_login) +
       
    56                                unicode(timestamp)).hexdigest()[::2]
       
    57         return "%s-%s" % (ts_b36, hash)
       
    58 
       
    59     def _num_days(self, dt):
       
    60         return (dt - date(2001,1,1)).days
       
    61 
       
    62     def _today(self):
       
    63         # Used for mocking in tests
       
    64         return date.today()
       
    65 
       
    66 default_token_generator = PasswordResetTokenGenerator()