From 5eaa7008660d487e50d0ddf596108a58a672f944 Mon Sep 17 00:00:00 2001 From: Ronald van Zon Date: Wed, 13 Dec 2017 14:49:07 +0100 Subject: [PATCH] Reverting core_signing to the old way. By reverting django.core.signing to Django 1.11.8 version Django-Q works This is not designed as a 'good' solution just to show where I think the problem is. --- django_q/core_signing.py | 76 ++++++++++++++++++++++++++++++++++++++++ django_q/signing.py | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 django_q/core_signing.py diff --git a/django_q/core_signing.py b/django_q/core_signing.py new file mode 100644 index 0000000..1790a0b --- /dev/null +++ b/django_q/core_signing.py @@ -0,0 +1,76 @@ +from __future__ import unicode_literals + +import datetime +import time +import zlib + +from django.utils import baseconv +from django.utils.crypto import constant_time_compare +from django.utils.encoding import force_bytes, force_str, force_text +from django.core.signing import BadSignature, SignatureExpired, b64_decode, JSONSerializer, \ + Signer as Sgnr, TimestampSigner as TsS, dumps + +dumps = dumps + + +""" +The loads function is the same as the `django.core.signing.loads` function +The difference is that `this` loads function calls `TimestampSigner` and `Signer` +""" +def loads(s, key=None, salt='django.core.signing', serializer=JSONSerializer, max_age=None): + """ + Reverse of dumps(), raise BadSignature if signature fails. + + The serializer is expected to accept a bytestring. + """ + # TimestampSigner.unsign() returns str but base64 and zlib compression + # operate on bytes. + base64d = force_bytes(TimestampSigner(key, salt=salt).unsign(s, max_age=max_age)) + decompress = False + if base64d[:1] == b'.': + # It's compressed; uncompress it first + base64d = base64d[1:] + decompress = True + data = b64_decode(base64d) + if decompress: + data = zlib.decompress(data) + return serializer().loads(data) + + +class Signer(Sgnr): + + def unsign(self, signed_value): + # force_str is removed in Django 2.0 + signed_value = force_str(signed_value) + if self.sep not in signed_value: + raise BadSignature('No "%s" found in value' % self.sep) + value, sig = signed_value.rsplit(self.sep, 1) + if constant_time_compare(sig, self.signature(value)): + # force_text is removed in Django 2.0 + return force_text(value) + raise BadSignature('Signature "%s" does not match' % sig) + + +""" +TimestampSigner is also the same as `django.core.signing.TimestampSigner` but is +calling `this` Signer. +""" +class TimestampSigner(Signer, TsS): + + def unsign(self, value, max_age=None): + """ + Retrieve original value and check it wasn't signed more + than max_age seconds ago. + """ + result = super().unsign(value) + value, timestamp = result.rsplit(self.sep, 1) + timestamp = baseconv.base62.decode(timestamp) + if max_age is not None: + if isinstance(max_age, datetime.timedelta): + max_age = max_age.total_seconds() + # Check timestamp is not older than max_age + age = time.time() - timestamp + if age > max_age: + raise SignatureExpired( + 'Signature age %s > %s seconds' % (age, max_age)) + return value diff --git a/django_q/signing.py b/django_q/signing.py index 4ee8bf3..2460aaa 100644 --- a/django_q/signing.py +++ b/django_q/signing.py @@ -4,7 +4,7 @@ try: except ImportError: import pickle -from django.core import signing +from django_q import core_signing as signing from django_q.conf import Conf