diff --git a/django/core/signing.py b/django/core/signing.py index 054777a260..3165cf8a38 100644 --- a/django/core/signing.py +++ b/django/core/signing.py @@ -158,8 +158,12 @@ class Signer(object): class TimestampSigner(Signer): + def __init__(self, *args, **kwargs): + self.time_func = kwargs.pop('time', time.time) + super(TimestampSigner, self).__init__(*args, **kwargs) + def timestamp(self): - return baseconv.base62.encode(int(time.time())) + return baseconv.base62.encode(int(self.time_func() * 10000)) def sign(self, value): value = smart_str('%s%s%s' % (value, self.sep, self.timestamp())) @@ -168,10 +172,10 @@ class TimestampSigner(Signer): def unsign(self, value, max_age=None): result = super(TimestampSigner, self).unsign(value) value, timestamp = result.rsplit(self.sep, 1) - timestamp = baseconv.base62.decode(timestamp) + timestamp = baseconv.base62.decode(timestamp) / 10000.0 if max_age is not None: # Check timestamp is not older than max_age - age = time.time() - timestamp + age = self.time_func() - timestamp if age > max_age: raise SignatureExpired( 'Signature age %s > %s seconds' % (age, max_age)) diff --git a/tests/regressiontests/signing/tests.py b/tests/regressiontests/signing/tests.py index 0b0cacf10e..bc16214600 100644 --- a/tests/regressiontests/signing/tests.py +++ b/tests/regressiontests/signing/tests.py @@ -1,5 +1,3 @@ -import time - from django.core import signing from django.test import TestCase from django.utils.encoding import force_unicode @@ -98,19 +96,21 @@ class TestTimestampSigner(TestCase): def test_timestamp_signer(self): value = u'hello' - _time = time.time - time.time = lambda: 123456789 - try: - signer = signing.TimestampSigner('predictable-key') - ts = signer.sign(value) - self.assertNotEqual(ts, - signing.Signer('predictable-key').sign(value)) + signer = signing.TimestampSigner('predictable-key', + time=lambda: 123456789) + ts = signer.sign(value) + self.assertNotEqual(ts, + signing.Signer('predictable-key').sign(value)) - self.assertEqual(signer.unsign(ts), value) - time.time = lambda: 123456800 - self.assertEqual(signer.unsign(ts, max_age=12), value) - self.assertEqual(signer.unsign(ts, max_age=11), value) - self.assertRaises( - signing.SignatureExpired, signer.unsign, ts, max_age=10) - finally: - time.time = _time + self.assertEqual(signer.unsign(ts), value) + signer = signing.TimestampSigner('predictable-key', + time=lambda: 123456800) + self.assertEqual(signer.unsign(ts, max_age=12), value) + self.assertEqual(signer.unsign(ts, max_age=11), value) + self.assertRaises( + signing.SignatureExpired, signer.unsign, ts, max_age=10) + + def test_timestamp_precision(self): + one = signing.TimestampSigner('key', time=lambda: 123.4567).sign('v') + two = signing.TimestampSigner('key', time=lambda: 123.4568).sign('v') + self.assertNotEqual(one, two)