Browse Source

Expire user tokens.

Rafał Pitoń 11 years ago
parent
commit
37395343aa
1 changed files with 45 additions and 2 deletions
  1. 45 2
      misago/users/tokens.py

+ 45 - 2
misago/users/tokens.py

@@ -1,9 +1,31 @@
+import base64
 from hashlib import sha256
 from hashlib import sha256
+from time import time
 
 
 from django.conf import settings
 from django.conf import settings
 
 
 
 
+"""
+Token creation
+
+Token is base encoded string containing three values:
+
+- days since unix epoch (so we can validate token expiration)
+- hash unique for current state of user model
+- token checksum for discovering manipulations
+"""
 def make(user, token_type):
 def make(user, token_type):
+    user_hash = make_hash(user, token_type)
+    creation_day = days_since_epoch()
+
+    obfuscated = base64.b64encode('%s%s' % (user_hash, creation_day))
+    obfuscated = obfuscated.rstrip('=')
+    checksum = make_checksum(obfuscated)
+
+    return '%s%s' % (checksum, obfuscated)
+
+
+def make_hash(user, token_type):
     seeds = (
     seeds = (
         user.pk,
         user.pk,
         user.email,
         user.email,
@@ -13,11 +35,32 @@ def make(user, token_type):
         settings.SECRET_KEY,
         settings.SECRET_KEY,
     )
     )
 
 
-    return sha256('+'.join([unicode(s) for s in seeds])).hexdigest()[:12]
+    return sha256('+'.join([unicode(s) for s in seeds])).hexdigest()[:8]
+
+
+def days_since_epoch():
+    return int(time() / (25 * 3600))
+
+
+def make_checksum(obfuscated):
+    return sha256('%s:%s' % (settings.SECRET_KEY, obfuscated)).hexdigest()[:8]
 
 
 
 
 def is_valid(user, token_type, token):
 def is_valid(user, token_type, token):
-    return token == make(user, token_type)
+    checksum = token[:8]
+    obfuscated = token[8:]
+
+    if checksum != make_checksum(obfuscated):
+        return False
+
+    unobfuscated = base64.b64decode(obfuscated + '=' * (-len(obfuscated) % 4))
+    user_hash = unobfuscated[:8]
+
+    if user_hash != make_hash(user, token_type):
+        return False
+
+    creation_day = int(unobfuscated[8:])
+    return creation_day + 14 >= days_since_epoch()
 
 
 
 
 """
 """