updated to upstream release 0.21; added Python 3 subpackage

This commit is contained in:
Dan Callaghan 2013-06-14 13:50:31 +10:00
parent 362ce5983b
commit 4094ead188
6 changed files with 473 additions and 13 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/itsdangerous-git-0.11.tar.xz
/itsdangerous-0.21.tar.gz

79
CHANGES Normal file
View File

@ -0,0 +1,79 @@
It's Dangerous Changelog
------------------------
Version 0.21
~~~~~~~~~~~~
- Fixed an issue on Python 3 which caused invalid errors to be
generated.
Version 0.20
~~~~~~~~~~~~
- Fixed an incorrect call into `want_bytes` that broke some
uses of itsdangerous on Python 2.6.
Version 0.19
~~~~~~~~~~~~
- Dropped support for 2.5 and added support for 3.3.
Version 0.18
~~~~~~~~~~~~
- Added support for JSON Web Signatures (JWS).
Version 0.17
~~~~~~~~~~~~
- Fixed a name error when overriding the digest method.
Version 0.16
~~~~~~~~~~~~
- made it possible to pass unicode values to `load_payload` to make it
easier to debug certain things.
Version 0.15
~~~~~~~~~~~~
- made standalone `load_payload` more robust by raising one specific
error if something goes wrong.
- refactored exceptions to catch more cases individually, added more
attributes.
- fixed an issue that caused `load_payload` not work in some situations
with timestamp based serializers
- added an `loads_unsafe` method.
Version 0.14
~~~~~~~~~~~~
- API refactoring to support different key derivations.
- Added attributes to exceptions so that you can inspect the data even
if the signature check failed.
Version 0.13
~~~~~~~~~~~~
- Small API change that enables customization of the digest module.
Version 0.12
~~~~~~~~~~~~
- Fixed a problem with the local timezone being used for the epoch
calculation. This might invalidate some of your signatures if you
were not running in UTC timezone. You can revert to the old behavior
by monkey patching itsdangerous.EPOCH.
Version 0.11
~~~~~~~~~~~~
- Fixed an uncought value error.
Version 0.10
~~~~~~~~~~~~
- Refactored interface that the underlying serializers can be swapped by
passing in a module instead of having to override the payload loaders
and dumpers. This makes the interface more compatible with Django's
recent changes.

31
LICENSE Normal file
View File

@ -0,0 +1,31 @@
Copyright (c) 2011 by Armin Ronacher and the Django Software Foundation.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,37 +1,108 @@
%global srcname itsdangerous
%global upstream_name itsdangerous
Name: python-itsdangerous
Version: 0.11
%if 0%{?fedora} || 0%{?rhel} > 6
%bcond_without python3
%else
%bcond_with python3
%endif
Name: python-%{upstream_name}
Version: 0.21
Release: 1%{?dist}
Summary: Python library for passing trusted data to untrusted environments
Group: Development/Languages
License: BSD
URL: http://packages.python.org/itsdangerous/
#Source0: http://pypi.python.org/packages/source/i/%{srcname}/%{srcname}-%{version}.tar.gz
# Tarballs on PyPi lack LICENSE and tests, so we generate our own from git instead:
# git archive --format=tar --prefix=itsdangerous-0.11/ 0.11 | xz >itsdangerous-git-0.11.tar.xz
Source0: %{srcname}-git-%{version}.tar.xz
URL: http://pythonhosted.org/itsdangerous/
Source0: http://pypi.python.org/packages/source/i/%{upstream_name}/%{upstream_name}-%{version}.tar.gz
# Tarballs on PyPi lack LICENSE, CHANGES, and tests.
# https://github.com/mitsuhiko/itsdangerous/pull/22
Source1: LICENSE
Source2: CHANGES
Source3: tests.py
BuildArch: noarch
BuildRequires: python-setuptools-devel
BuildRequires: python2-devel
BuildRequires: python-setuptools
%if %{with python3}
BuildRequires: python3-devel
BuildRequires: python3-setuptools
%endif
%description
Itsdangerous is a Python library for passing data through untrusted
environments (for example, HTTP cookies) while ensuring the data is not
tampered with.
Internally itsdangerous uses HMAC and SHA1 for signing by default and bases the
implementation on the Django signing module. It also however supports JSON Web
Signatures (JWS).
%if %{with python3}
%package -n python3-%{upstream_name}
Summary: Python 3 library for passing trusted data to untrusted environments
%description -n python3-%{upstream_name}
Itsdangerous is a Python 3 library for passing data through untrusted
environments (for example, HTTP cookies) while ensuring the data is not
tampered with.
Internally itsdangerous uses HMAC and SHA1 for signing by default and bases the
implementation on the Django signing module. It also however supports JSON Web
Signatures (JWS).
%endif
%prep
%setup -q -n %{srcname}-%{version}
%setup -q -n %{upstream_name}-%{version}
rm -r *.egg-info
cp -p %{SOURCE1} %{SOURCE2} %{SOURCE3} .
%if %{with python3}
rm -rf %{py3dir}
cp -a . %{py3dir}
%endif
%build
%{__python} setup.py build
%if %{with python3}
pushd %{py3dir}
%{__python3} setup.py build
popd
%endif
%install
%if %{with python3}
pushd %{py3dir}
%{__python3} setup.py install --skip-build --root %{buildroot}
popd
%endif
%{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT
%check
PYTHONPATH=$RPM_BUILD_ROOT%{python_sitelib} %{__python} tests.py
%if %{with python3}
pushd %{py3dir}
PYTHONPATH=$RPM_BUILD_ROOT%{python3_sitelib} %{__python3} tests.py
popd
%endif
%files
%doc LICENSE CHANGES README
%{python_sitelib}/itsdangerous*
%{python_sitelib}/%{upstream_name}.py*
%{python_sitelib}/%{upstream_name}*.egg-info
%if %{with python3}
%files -n python3-%{upstream_name}
%doc LICENSE CHANGES README
%{python3_sitelib}/%{upstream_name}.py
%{python3_sitelib}/%{upstream_name}*.egg-info
%{python3_sitelib}/__pycache__/%{upstream_name}*
%endif
%changelog
* Fri Jun 14 2013 Dan Callaghan <dcallagh@redhat.com> - 0.21-1
- updated to upstream release 0.21
- added Python 3 subpackage
* Wed Nov 11 2011 Dan Callaghan <dcallagh@redhat.com> - 0.11-1
- initial version

View File

@ -1 +1 @@
e23b61563793dd428963352166d8e80f itsdangerous-git-0.11.tar.xz
84d4b33f0a1e4d0f7f8f8755a5eb2580 itsdangerous-0.21.tar.gz

278
tests.py Normal file
View File

@ -0,0 +1,278 @@
import time
import pickle
import hashlib
import unittest
from datetime import datetime
import itsdangerous as idmod
from itsdangerous import want_bytes, text_type, PY2
# Helper function for some unsafe string manipulation on encoded
# data. This is required for Python 3 but would break on Python 2
if PY2:
def _coerce_string(reference_string, value):
return value
else:
def _coerce_string(reference_string, value):
assert isinstance(value, text_type), 'rhs needs to be a string'
if type(reference_string) != type(value):
value = value.encode('utf-8')
return value
class UtilityTestCase(unittest.TestCase):
def test_want_bytes(self):
self.assertEqual(want_bytes(b"foobar"), b"foobar")
self.assertEqual(want_bytes(u"foobar"), b"foobar")
class SerializerTestCase(unittest.TestCase):
serializer_class = idmod.Serializer
def make_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
def test_dumps_loads(self):
objects = (['a', 'list'], 'a string', u'a unicode string \u2019',
{'a': 'dictionary'}, 42, 42.5)
s = self.make_serializer('Test')
for o in objects:
value = s.dumps(o)
self.assertNotEqual(o, value)
self.assertEqual(o, s.loads(value))
def test_decode_detects_tampering(self):
s = self.make_serializer('Test')
transforms = (
lambda s: s.upper(),
lambda s: s + _coerce_string(s, 'a'),
lambda s: _coerce_string(s, 'a') + s[1:],
lambda s: s.replace(_coerce_string(s, '.'), _coerce_string(s, '')),
)
value = {
'foo': 'bar',
'baz': 1,
}
encoded = s.dumps(value)
self.assertEqual(value, s.loads(encoded))
for transform in transforms:
self.assertRaises(
idmod.BadSignature, s.loads, transform(encoded))
def test_accepts_unicode(self):
objects = (['a', 'list'], 'a string', u'a unicode string \u2019',
{'a': 'dictionary'}, 42, 42.5)
s = self.make_serializer('Test')
for o in objects:
value = s.dumps(o)
self.assertNotEqual(o, value)
self.assertEqual(o, s.loads(value))
def test_exception_attributes(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
try:
s.loads(ts + _coerce_string(ts, 'x'))
except idmod.BadSignature as e:
self.assertEqual(want_bytes(e.payload),
want_bytes(ts).rsplit(b'.', 1)[0])
self.assertEqual(s.load_payload(e.payload), value)
else:
self.fail('Did not get bad signature')
def test_unsafe_load(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
self.assertEqual(s.loads_unsafe(ts), (True, u'hello'))
self.assertEqual(s.loads_unsafe(ts, salt='modified'), (False, u'hello'))
def test_load_unsafe_with_unicode_strings(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
self.assertEqual(s.loads_unsafe(ts), (True, u'hello'))
self.assertEqual(s.loads_unsafe(ts, salt='modified'), (False, u'hello'))
try:
s.loads(ts, salt='modified')
except idmod.BadSignature as e:
self.assertEqual(s.load_payload(e.payload), u'hello')
def test_signer_kwargs(self):
secret_key = 'predictable-key'
value = 'hello'
s = self.make_serializer(secret_key, signer_kwargs=dict(
digest_method=hashlib.md5,
key_derivation='hmac'
))
ts = s.dumps(value)
self.assertEqual(s.loads(ts), u'hello')
class TimedSerializerTestCase(SerializerTestCase):
serializer_class = idmod.TimedSerializer
def setUp(self):
self._time = time.time
time.time = lambda: idmod.EPOCH
def tearDown(self):
time.time = self._time
def test_decode_with_timeout(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
self.assertNotEqual(ts, idmod.Serializer(secret_key).dumps(value))
self.assertEqual(s.loads(ts), value)
time.time = lambda: idmod.EPOCH + 10
self.assertEqual(s.loads(ts, max_age=11), value)
self.assertEqual(s.loads(ts, max_age=10), value)
self.assertRaises(
idmod.SignatureExpired, s.loads, ts, max_age=9)
def test_decode_return_timestamp(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
loaded, timestamp = s.loads(ts, return_timestamp=True)
self.assertEqual(loaded, value)
self.assertEqual(timestamp, datetime.utcfromtimestamp(time.time()))
def test_exception_attributes(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
try:
s.loads(ts, max_age=-1)
except idmod.SignatureExpired as e:
self.assertEqual(e.date_signed,
datetime.utcfromtimestamp(time.time()))
self.assertEqual(want_bytes(e.payload),
want_bytes(ts).rsplit(b'.', 2)[0])
self.assertEqual(s.load_payload(e.payload), value)
else:
self.fail('Did not get expiration')
class JSONWebSignatureSerializerTestCase(SerializerTestCase):
serializer_class = idmod.JSONWebSignatureSerializer
def test_decode_return_header(self):
secret_key = 'predictable-key'
value = u'hello'
header = {"typ": "dummy"}
s = self.make_serializer(secret_key)
full_header = header.copy()
full_header['alg'] = s.algorithm_name
ts = s.dumps(value, header_fields=header)
loaded, loaded_header = s.loads(ts, return_header=True)
self.assertEqual(loaded, value)
self.assertEqual(loaded_header, full_header)
def test_hmac_algorithms(self):
secret_key = 'predictable-key'
value = u'hello'
algorithms = ('HS256', 'HS384', 'HS512')
for algorithm in algorithms:
s = self.make_serializer(secret_key, algorithm_name=algorithm)
ts = s.dumps(value)
self.assertEqual(s.loads(ts), value)
def test_none_algorithm(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key)
ts = s.dumps(value)
self.assertEqual(s.loads(ts), value)
def test_algorithm_mismatch(self):
secret_key = 'predictable-key'
value = u'hello'
s = self.make_serializer(secret_key, algorithm_name='HS256')
ts = s.dumps(value)
s = self.make_serializer(secret_key, algorithm_name='HS384')
try:
s.loads(ts)
except idmod.BadSignature as e:
self.assertEqual(s.load_payload(e.payload), value)
else:
self.fail('Did not get algorithm mismatch')
class URLSafeSerializerMixin(object):
def test_is_base62(self):
allowed = frozenset(b'0123456789abcdefghijklmnopqrstuvwxyz' +
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ_-.')
objects = (['a', 'list'], 'a string', u'a unicode string \u2019',
{'a': 'dictionary'}, 42, 42.5)
s = self.make_serializer('Test')
for o in objects:
value = want_bytes(s.dumps(o))
self.assertTrue(set(value).issubset(set(allowed)))
self.assertNotEqual(o, value)
self.assertEqual(o, s.loads(value))
def test_invalid_base64_does_not_fail_load_payload(self):
s = idmod.URLSafeSerializer('aha!')
self.assertRaises(idmod.BadPayload, s.load_payload, b'kZ4m3du844lIN')
class PickleSerializerMixin(object):
def make_serializer(self, *args, **kwargs):
kwargs.setdefault('serializer', pickle)
return super(PickleSerializerMixin, self).make_serializer(*args, **kwargs)
class URLSafeSerializerTestCase(URLSafeSerializerMixin, SerializerTestCase):
serializer_class = idmod.URLSafeSerializer
class URLSafeTimedSerializerTestCase(URLSafeSerializerMixin, TimedSerializerTestCase):
serializer_class = idmod.URLSafeTimedSerializer
class PickleSerializerTestCase(PickleSerializerMixin, SerializerTestCase):
pass
class PickleTimedSerializerTestCase(PickleSerializerMixin, TimedSerializerTestCase):
pass
class PickleURLSafeSerializerTestCase(PickleSerializerMixin, URLSafeSerializerTestCase):
pass
class PickleURLSafeTimedSerializerTestCase(PickleSerializerMixin, URLSafeTimedSerializerTestCase):
pass
if __name__ == '__main__':
unittest.main()