@@ -395,47 +395,16 @@ def create_signed_value(self, name, value):
395
395
method for non-cookie uses. To decode a value not stored
396
396
as a cookie use the optional value argument to get_secure_cookie.
397
397
"""
398
- timestamp = utf8 (str (int (time .time ())))
399
- value = base64 .b64encode (utf8 (value ))
400
- signature = self ._cookie_signature (name , value , timestamp )
401
- value = b ("|" ).join ([value , timestamp , signature ])
402
- return value
398
+ self .require_setting ("cookie_secret" , "secure cookies" )
399
+ return create_signed_value (self .application .settings ["cookie_secret" ],
400
+ name , value )
403
401
404
402
def get_secure_cookie (self , name , value = None , max_age_days = 31 ):
405
403
"""Returns the given signed cookie if it validates, or None."""
406
- if value is None : value = self .get_cookie (name )
407
- if not value : return None
408
- parts = utf8 (value ).split (b ("|" ))
409
- if len (parts ) != 3 : return None
410
- signature = self ._cookie_signature (name , parts [0 ], parts [1 ])
411
- if not _time_independent_equals (parts [2 ], signature ):
412
- logging .warning ("Invalid cookie signature %r" , value )
413
- return None
414
- timestamp = int (parts [1 ])
415
- if timestamp < time .time () - max_age_days * 86400 :
416
- logging .warning ("Expired cookie %r" , value )
417
- return None
418
- if timestamp > time .time () + 31 * 86400 :
419
- # _cookie_signature does not hash a delimiter between the
420
- # parts of the cookie, so an attacker could transfer trailing
421
- # digits from the payload to the timestamp without altering the
422
- # signature. For backwards compatibility, sanity-check timestamp
423
- # here instead of modifying _cookie_signature.
424
- logging .warning ("Cookie timestamp in future; possible tampering %r" , value )
425
- return None
426
- if parts [1 ].startswith (b ("0" )):
427
- logging .warning ("Tampered cookie %r" , value )
428
- try :
429
- return base64 .b64decode (parts [0 ])
430
- except Exception :
431
- return None
432
-
433
- def _cookie_signature (self , * parts ):
434
404
self .require_setting ("cookie_secret" , "secure cookies" )
435
- hash = hmac .new (utf8 (self .application .settings ["cookie_secret" ]),
436
- digestmod = hashlib .sha1 )
437
- for part in parts : hash .update (utf8 (part ))
438
- return utf8 (hash .hexdigest ())
405
+ if value is None : value = self .get_cookie (name )
406
+ return decode_signed_value (self .application .settings ["cookie_secret" ],
407
+ name , value , max_age_days = max_age_days )
439
408
440
409
def redirect (self , url , permanent = False ):
441
410
"""Sends a redirect to the given (optionally relative) URL."""
@@ -1904,6 +1873,45 @@ def _time_independent_equals(a, b):
1904
1873
result |= ord (x ) ^ ord (y )
1905
1874
return result == 0
1906
1875
1876
+ def create_signed_value (secret , name , value ):
1877
+ timestamp = utf8 (str (int (time .time ())))
1878
+ value = base64 .b64encode (utf8 (value ))
1879
+ signature = _create_signature (secret , name , value , timestamp )
1880
+ value = b ("|" ).join ([value , timestamp , signature ])
1881
+ return value
1882
+
1883
+ def decode_signed_value (secret , name , value , max_age_days = 31 ):
1884
+ if not value : return None
1885
+ parts = utf8 (value ).split (b ("|" ))
1886
+ if len (parts ) != 3 : return None
1887
+ signature = _create_signature (secret , name , parts [0 ], parts [1 ])
1888
+ if not _time_independent_equals (parts [2 ], signature ):
1889
+ logging .warning ("Invalid cookie signature %r" , value )
1890
+ return None
1891
+ timestamp = int (parts [1 ])
1892
+ if timestamp < time .time () - max_age_days * 86400 :
1893
+ logging .warning ("Expired cookie %r" , value )
1894
+ return None
1895
+ if timestamp > time .time () + 31 * 86400 :
1896
+ # _cookie_signature does not hash a delimiter between the
1897
+ # parts of the cookie, so an attacker could transfer trailing
1898
+ # digits from the payload to the timestamp without altering the
1899
+ # signature. For backwards compatibility, sanity-check timestamp
1900
+ # here instead of modifying _cookie_signature.
1901
+ logging .warning ("Cookie timestamp in future; possible tampering %r" , value )
1902
+ return None
1903
+ if parts [1 ].startswith (b ("0" )):
1904
+ logging .warning ("Tampered cookie %r" , value )
1905
+ try :
1906
+ return base64 .b64decode (parts [0 ])
1907
+ except Exception :
1908
+ return None
1909
+
1910
+ def _create_signature (secret , * parts ):
1911
+ hash = hmac .new (utf8 (secret ), digestmod = hashlib .sha1 )
1912
+ for part in parts : hash .update (utf8 (part ))
1913
+ return utf8 (hash .hexdigest ())
1914
+
1907
1915
1908
1916
class _O (dict ):
1909
1917
"""Makes a dictionary behave like an object."""
0 commit comments