Added/tweaked docs for exceptions, middleware, and signals. Minor formatting tweaks...
[philo.git] / philo / contrib / waldo / tokens.py
1 """
2 Based on django.contrib.auth.tokens
3 """
4
5 from hashlib import sha1
6 from datetime import date
7
8 from django.conf import settings
9 from django.utils.http import int_to_base36, base36_to_int
10 from django.contrib.auth.tokens import PasswordResetTokenGenerator
11
12
13 REGISTRATION_TIMEOUT_DAYS = getattr(settings, 'WALDO_REGISTRATION_TIMEOUT_DAYS', 1)
14 EMAIL_TIMEOUT_DAYS = getattr(settings, 'WALDO_EMAIL_TIMEOUT_DAYS', 1)
15
16
17 class RegistrationTokenGenerator(PasswordResetTokenGenerator):
18         """
19         Strategy object used to generate and check tokens for the user registration mechanism.
20         """
21         def check_token(self, user, token):
22                 """
23                 Check that a registration token is correct for a given user.
24                 """
25                 # If the user is active, the hash can't be valid.
26                 if user.is_active:
27                         return False
28                 
29                 # Parse the token
30                 try:
31                         ts_b36, hash = token.split('-')
32                 except ValueError:
33                         return False
34                 
35                 try:
36                         ts = base36_to_int(ts_b36)
37                 except ValueError:
38                         return False
39                 
40                 # Check that the timestamp and uid have not been tampered with.
41                 if self._make_token_with_timestamp(user, ts) != token:
42                         return False
43                 
44                 # Check that the timestamp is within limit
45                 if (self._num_days(self._today()) - ts) > REGISTRATION_TIMEOUT_DAYS:
46                         return False
47                 
48                 return True
49         
50         def _make_token_with_timestamp(self, user, timestamp):
51                 ts_b36 = int_to_base36(timestamp)
52                 
53                 # By hashing on the internal state of the user and using state that is
54                 # sure to change, we produce a hash that will be invalid as soon as it
55                 # is used.
56                 hash = sha1(settings.SECRET_KEY + unicode(user.id) + unicode(user.is_active) + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + unicode(timestamp)).hexdigest()[::2]
57                 return '%s-%s' % (ts_b36, hash)
58
59
60 registration_token_generator = RegistrationTokenGenerator()
61
62
63 class EmailTokenGenerator(PasswordResetTokenGenerator):
64         """
65         Strategy object used to generate and check tokens for a user email change mechanism.
66         """
67         def make_token(self, user, email):
68                 """
69                 Returns a token that can be used once to do an email change for the given user and email.
70                 """
71                 return self._make_token_with_timestamp(user, email, self._num_days(self._today()))
72         
73         def check_token(self, user, email, token):
74                 if email == user.email:
75                         return False
76                 
77                 # Parse the token
78                 try:
79                         ts_b36, hash = token.split('-')
80                 except ValueError:
81                         return False
82                 
83                 try:
84                         ts = base36_to_int(ts_b36)
85                 except ValueError:
86                         return False
87                 
88                 # Check that the timestamp and uid have not been tampered with.
89                 if self._make_token_with_timestamp(user, email, ts) != token:
90                         return False
91                 
92                 # Check that the timestamp is within limit
93                 if (self._num_days(self._today()) - ts) > EMAIL_TIMEOUT_DAYS:
94                         return False
95                 
96                 return True
97         
98         def _make_token_with_timestamp(self, user, email, timestamp):
99                 ts_b36 = int_to_base36(timestamp)
100                 
101                 hash = sha1(settings.SECRET_KEY + unicode(user.id) + user.email + email + unicode(timestamp)).hexdigest()[::2]
102                 return '%s-%s' % (ts_b36, hash)
103
104
105 email_token_generator = EmailTokenGenerator()