Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-jwcrypto for openSUSE:Factory
checked in at 2021-08-11 11:47:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jwcrypto (Old)
and /work/SRC/openSUSE:Factory/.python-jwcrypto.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jwcrypto"
Wed Aug 11 11:47:01 2021 rev:11 rq:910436 version:1.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jwcrypto/python-jwcrypto.changes
2021-07-10 22:53:31.640210115 +0200
+++
/work/SRC/openSUSE:Factory/.python-jwcrypto.new.1899/python-jwcrypto.changes
2021-08-11 11:47:09.861750310 +0200
@@ -1,0 +2,13 @@
+Thu Aug 5 19:05:35 UTC 2021 - Michael Str??der <[email protected]>
+
+- update to 1.0
+ * Create SECURITY.md
+ * Allow empty payloads in JWS tokens
+ * Add tests to check empty payload support
+ * Drop python2 compatibility
+ * Fix python3 pylint issues
+ * Add explicit support to check 'typ' in JWT
+ * Drop support for importing old MutableMapping
+ * Disable annoying pep8 naming checks
+
+-------------------------------------------------------------------
Old:
----
jwcrypto-0.9.1.tar.gz
New:
----
jwcrypto-1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jwcrypto.spec ++++++
--- /var/tmp/diff_new_pack.efevCa/_old 2021-08-11 11:47:11.973747770 +0200
+++ /var/tmp/diff_new_pack.efevCa/_new 2021-08-11 11:47:11.973747770 +0200
@@ -18,8 +18,10 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
+%define skip_python2 1
+
Name: python-jwcrypto
-Version: 0.9.1
+Version: 1.0
Release: 0
Summary: Python module package implementing JOSE Web standards
License: LGPL-3.0-only
@@ -62,6 +64,6 @@
%files %{python_files}
%{python_sitelib}/*
%license LICENSE
-%doc README.md
+%doc README.md SECURITY.md
%changelog
++++++ jwcrypto-0.9.1.tar.gz -> jwcrypto-1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/.github/workflows/build.yml
new/jwcrypto-1.0/.github/workflows/build.yml
--- old/jwcrypto-0.9.1/.github/workflows/build.yml 2021-06-09
20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/.github/workflows/build.yml 2021-08-02
10:49:08.000000000 +0200
@@ -14,7 +14,6 @@
"fail-fast": false,
"matrix": {
"name": [
- "python-27",
"python-36",
"python-37",
"python-38",
@@ -22,16 +21,10 @@
"doc",
"sphinx",
"lint",
- "pep8py3",
+ "pep8",
],
"include": [
{
- "name": "python-27",
- "python": "2.7",
- "toxenv": "py27",
- "arch": "x64",
- },
- {
"name": "python-36",
"python": "3.6",
"toxenv": "py36",
@@ -74,9 +67,9 @@
"arch": "x64",
},
{
- "name": "pep8py3",
+ "name": "pep8",
"python": "3.9",
- "toxenv": "pep8py3",
+ "toxenv": "pep8",
"arch": "x64",
},
],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/.github/workflows/codeql-analysis.yml
new/jwcrypto-1.0/.github/workflows/codeql-analysis.yml
--- old/jwcrypto-0.9.1/.github/workflows/codeql-analysis.yml 2021-06-09
20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/.github/workflows/codeql-analysis.yml 2021-08-02
10:49:08.000000000 +0200
@@ -17,6 +17,9 @@
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
+ paths-ignore:
+ - '**/*.md'
+ - '**/*.txt'
schedule:
- cron: '31 10 * * 5'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/Makefile new/jwcrypto-1.0/Makefile
--- old/jwcrypto-0.9.1/Makefile 2021-06-01 16:52:31.000000000 +0200
+++ new/jwcrypto-1.0/Makefile 2021-08-02 10:49:08.000000000 +0200
@@ -7,8 +7,7 @@
pep8:
# Check style consistency
- tox -e pep8py2
- tox -e pep8py3
+ tox -e pep8
clean:
rm -fr build dist *.egg-info
@@ -25,7 +24,6 @@
test:
rm -f .coverage
- tox -e py27
tox -e py36 --skip-missing-interpreter
tox -e py37 --skip-missing-interpreter
tox -e py38 --skip-missing-interpreter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/PKG-INFO new/jwcrypto-1.0/PKG-INFO
--- old/jwcrypto-0.9.1/PKG-INFO 2021-06-09 20:43:44.513565800 +0200
+++ new/jwcrypto-1.0/PKG-INFO 2021-08-02 10:49:25.848379100 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: jwcrypto
-Version: 0.9.1
+Version: 1.0
Summary: Implementation of JOSE Web standards
Home-page: https://github.com/latchset/jwcrypto
Maintainer: JWCrypto Project Contributors
@@ -8,7 +8,6 @@
License: LGPLv3+
Description: UNKNOWN
Platform: UNKNOWN
-Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/README.md new/jwcrypto-1.0/README.md
--- old/jwcrypto-0.9.1/README.md 2021-06-09 20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/README.md 2021-08-02 10:49:08.000000000 +0200
@@ -2,6 +2,7 @@
[](https://github.com/latchset/jwcrypto/releases)
[](https://github.com/latchset/jwcrypto/actions/workflows/build.yml)
[](https://github.com/latchset/jwcrypto/actions/workflows/ppc64le.yml)
+[](https://github.com/latchset/jwcrypto/actions/workflows/codeql-analysis.yml)
JWCrypto
========
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/SECURITY.md
new/jwcrypto-1.0/SECURITY.md
--- old/jwcrypto-0.9.1/SECURITY.md 1970-01-01 01:00:00.000000000 +0100
+++ new/jwcrypto-1.0/SECURITY.md 2021-08-02 10:49:08.000000000 +0200
@@ -0,0 +1,16 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 0.8 + | :white_check_mark: |
+| < 0.8 | :x: |
+
+## Reporting a Vulnerability
+
+Please contact [email protected] if you have found a security vulnerability
+
+Expect a response within 2 business days (not on week ends or holidays).
+
+If the vulnerbaility is confirmed and accepted you will be given instruction
on any embargo or disclosure timeline via email.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/docs/source/conf.py
new/jwcrypto-1.0/docs/source/conf.py
--- old/jwcrypto-0.9.1/docs/source/conf.py 2021-06-09 20:43:19.000000000
+0200
+++ new/jwcrypto-1.0/docs/source/conf.py 2021-08-02 10:49:08.000000000
+0200
@@ -53,9 +53,9 @@
# built documents.
#
# The short X.Y version.
-version = '0.9'
+version = '1.0'
# The full version, including alpha/beta/rc tags.
-release = '0.9.1'
+release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/docs/source/index.rst
new/jwcrypto-1.0/docs/source/index.rst
--- old/jwcrypto-0.9.1/docs/source/index.rst 2015-07-10 18:38:15.000000000
+0200
+++ new/jwcrypto-1.0/docs/source/index.rst 2021-08-02 10:49:08.000000000
+0200
@@ -10,8 +10,7 @@
Encryption (JOSE) Web Standards as they are being developed in the
JOSE_ IETF Working Group and related technology.
-JWCrypto is Python2 and Python3 compatible and uses the Cryptography_
-package for all the crypto functions.
+JWCrypto uses the Cryptography_ package for all the crypto functions.
.. _JOSE: https://datatracker.ietf.org/wg/jose/charter/
.. _Cryptography: https://cryptography.io/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/common.py
new/jwcrypto-1.0/jwcrypto/common.py
--- old/jwcrypto-0.9.1/jwcrypto/common.py 2021-02-08 21:02:01.000000000
+0100
+++ new/jwcrypto-1.0/jwcrypto/common.py 2021-08-02 10:49:08.000000000 +0200
@@ -4,10 +4,7 @@
import json
from base64 import urlsafe_b64decode, urlsafe_b64encode
from collections import namedtuple
-try:
- from collections.abc import MutableMapping
-except ImportError:
- from collections import MutableMapping
+from collections.abc import MutableMapping
# Padding stripping versions as described in
# RFC 7515 Appendix C
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/jwa.py
new/jwcrypto-1.0/jwcrypto/jwa.py
--- old/jwcrypto-0.9.1/jwcrypto/jwa.py 2021-02-08 21:02:01.000000000 +0100
+++ new/jwcrypto-1.0/jwcrypto/jwa.py 2021-08-02 10:49:08.000000000 +0200
@@ -1,8 +1,8 @@
# Copyright (C) 2016 JWCrypto Project Contributors - see LICENSE file
-import abc
import os
import struct
+from abc import ABCMeta, abstractmethod
from binascii import hexlify, unhexlify
from cryptography.exceptions import InvalidSignature
@@ -17,8 +17,6 @@
from cryptography.hazmat.primitives.keywrap import aes_key_unwrap, aes_key_wrap
from cryptography.hazmat.primitives.padding import PKCS7
-import six
-
from jwcrypto.common import InvalidCEKeyLength
from jwcrypto.common import InvalidJWAAlgorithm
from jwcrypto.common import InvalidJWEKeyLength
@@ -31,33 +29,32 @@
# Implements RFC 7518 - JSON Web Algorithms (JWA)
[email protected]_metaclass(abc.ABCMeta)
-class JWAAlgorithm(object):
+class JWAAlgorithm(metaclass=ABCMeta):
- @abc.abstractproperty
+ @property
+ @abstractmethod
def name(self):
"""The algorithm Name"""
- pass
- @abc.abstractproperty
+ @property
+ @abstractmethod
def description(self):
"""A short description"""
- pass
- @abc.abstractproperty
+ @property
+ @abstractmethod
def keysize(self):
"""The actual/recommended/minimum key size"""
- pass
- @abc.abstractproperty
+ @property
+ @abstractmethod
def algorithm_usage_location(self):
"""One of 'alg', 'enc' or 'JWK'"""
- pass
- @abc.abstractproperty
+ @property
+ @abstractmethod
def algorithm_use(self):
"""One of 'sig', 'kex', 'enc'"""
- pass
def _bitsize(x):
@@ -1104,21 +1101,21 @@
try:
return cls.instantiate_alg(name, use='sig')
except KeyError:
- raise InvalidJWAAlgorithm(
- '%s is not a valid Signign algorithm name' % name)
+ raise InvalidJWAAlgorithm('%s is not a valid Signign algorithm'
+ ' name' % name) from None
@classmethod
def keymgmt_alg(cls, name):
try:
return cls.instantiate_alg(name, use='kex')
except KeyError:
- raise InvalidJWAAlgorithm(
- '%s is not a valid Key Management algorithm name' % name)
+ raise InvalidJWAAlgorithm('%s is not a valid Key Management'
+ ' algorithm name' % name) from None
@classmethod
def encryption_alg(cls, name):
try:
return cls.instantiate_alg(name, use='enc')
except KeyError:
- raise InvalidJWAAlgorithm(
- '%s is not a valid Encryption algorithm name' % name)
+ raise InvalidJWAAlgorithm('%s is not a valid Encryption'
+ ' algorithm name' % name) from None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/jwe.py
new/jwcrypto-1.0/jwcrypto/jwe.py
--- old/jwcrypto-0.9.1/jwcrypto/jwe.py 2021-02-08 21:02:01.000000000 +0100
+++ new/jwcrypto-1.0/jwcrypto/jwe.py 2021-08-02 10:49:08.000000000 +0200
@@ -477,10 +477,10 @@
if 'header' in djwe:
o['header'] = json_encode(djwe['header'])
- except ValueError:
+ except ValueError as e:
c = raw_jwe.split('.')
if len(c) != 5:
- raise InvalidJWEData()
+ raise InvalidJWEData() from e
p = base64url_decode(c[0])
o['protected'] = p.decode('utf-8')
ekey = base64url_decode(c[1])
@@ -493,7 +493,7 @@
self.objects = o
except Exception as e: # pylint: disable=broad-except
- raise InvalidJWEData('Invalid format', repr(e))
+ raise InvalidJWEData('Invalid format', repr(e)) from e
if key:
self.decrypt(key)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/jwk.py
new/jwcrypto-1.0/jwcrypto/jwk.py
--- old/jwcrypto-0.9.1/jwcrypto/jwk.py 2021-06-09 20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/jwcrypto/jwk.py 2021-08-02 10:49:08.000000000 +0200
@@ -13,8 +13,6 @@
from deprecated import deprecated
-from six import iteritems
-
from jwcrypto.common import JWException
from jwcrypto.common import base64url_decode, base64url_encode
from jwcrypto.common import json_decode, json_encode
@@ -263,8 +261,6 @@
on the key type or other constraints.
"""
- pass
-
class JWK(dict):
"""JSON Web Key object
@@ -318,8 +314,8 @@
try:
kty = kwargs['kty']
gen = getattr(obj, '_generate_%s' % kty)
- except (KeyError, AttributeError):
- raise InvalidJWKType(kty)
+ except (KeyError, AttributeError) as e:
+ raise InvalidJWKType(kty) from e
gen(kwargs)
return obj
@@ -328,8 +324,8 @@
try:
kty = params.pop('generate')
gen = getattr(self, '_generate_%s' % kty)
- except (KeyError, AttributeError):
- raise InvalidJWKType(kty)
+ except (KeyError, AttributeError) as e:
+ raise InvalidJWKType(kty) from e
gen(params)
@@ -341,8 +337,8 @@
try:
from jwcrypto.jwa import JWA
alg = JWA.instantiate_alg(params['alg'])
- except KeyError:
- raise ValueError("Invalid 'alg' parameter")
+ except KeyError as e:
+ raise ValueError("Invalid 'alg' parameter") from e
size = alg.keysize
return size
@@ -451,13 +447,13 @@
raise InvalidJWKValue('Must specify "crv" for OKP key generation')
try:
key = _OKP_CURVES_TABLE[params['crv']].privkey.generate()
- except KeyError:
+ except KeyError as e:
raise InvalidJWKValue('"%s" is not a supported curve for the '
- 'OKP key type' % params['crv'])
+ 'OKP key type' % params['crv']) from e
self._import_pyca_pri_okp(key, **params)
def _okp_curve_from_pyca_key(self, key):
- for name, val in iteritems(_OKP_CURVES_TABLE):
+ for name, val in _OKP_CURVES_TABLE.items():
if isinstance(key, (val.pubkey, val.privkey)):
return name
raise InvalidJWKValue('Invalid OKP Key object %r' % key)
@@ -509,7 +505,7 @@
while name in names:
names.remove(name)
- for name, val in iteritems(JWKValuesRegistry[kty]):
+ for name, val in JWKValuesRegistry[kty].items():
if val.required and name not in newkey:
raise InvalidJWKValue('Missing required value %s' % name)
if val.type == ParmType.unsupported and name in newkey:
@@ -518,18 +514,18 @@
# Check that the value is base64url encoded
try:
base64url_decode(newkey[name])
- except Exception: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
raise InvalidJWKValue(
'"%s" is not base64url encoded' % name
- )
+ ) from e
if val.type == ParmType.b64u and name in newkey:
# Check that the value is Base64urlUInt encoded
try:
self._decode_int(newkey[name])
- except Exception: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
raise InvalidJWKValue(
'"%s" is not Base64urlUInt encoded' % name
- )
+ ) from e
# Unknown key parameters are allowed
for name in names:
@@ -581,7 +577,7 @@
try:
jkey = json_decode(key)
except Exception as e: # pylint: disable=broad-except
- raise InvalidJWKValue(e)
+ raise InvalidJWKValue from e
obj.import_key(**jkey)
return obj
@@ -761,8 +757,8 @@
crv = self.get('crv')
try:
pubkey = _OKP_CURVES_TABLE[crv].pubkey
- except KeyError:
- raise InvalidJWKValue('Unknown curve "%s"' % crv)
+ except KeyError as e:
+ raise InvalidJWKValue('Unknown curve "%s"' % crv) from e
x = base64url_decode(self.get('x'))
return pubkey.from_public_bytes(x)
@@ -771,8 +767,8 @@
crv = self.get('crv')
try:
privkey = _OKP_CURVES_TABLE[crv].privkey
- except KeyError:
- raise InvalidJWKValue('Unknown curve "%s"' % crv)
+ except KeyError as e:
+ raise InvalidJWKValue('Unknown curve "%s"' % crv) from e
d = base64url_decode(self.get('d'))
return privkey.from_private_bytes(d)
@@ -883,6 +879,7 @@
data, backend=default_backend())
key = cert.public_key()
except ValueError:
+ # pylint: disable=raise-missing-from
raise e
self.import_from_pyca(key)
@@ -950,7 +947,7 @@
"""
t = {'kty': self.get('kty')}
- for name, val in iteritems(JWKValuesRegistry[t['kty']]):
+ for name, val in JWKValuesRegistry[t['kty']].items():
if val.required:
t[name] = self.get(name)
digest = hashes.Hash(hashalg, backend=default_backend())
@@ -980,17 +977,17 @@
# is used to indicate a 'None' key
if v == b'' and kty != 'oct' and item != 'k':
raise ValueError
- except Exception: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
raise InvalidJWKValue(
'"%s" is not base64url encoded' % item
- )
+ ) from e
elif JWKValuesRegistry[kty][item].type == ParmType.b64u:
try:
self._decode_int(value)
- except Exception: # pylint: disable=broad-except
+ except Exception as e: # pylint: disable=broad-except
raise InvalidJWKValue(
'"%s" is not Base64urlUInt encoded' % item
- )
+ ) from e
super(JWK, self).__setitem__(item, value)
return
@@ -1013,7 +1010,7 @@
super(JWK, self).__setitem__(item, value)
def update(self, *args, **kwargs):
- for k, v in iteritems(dict(*args, **kwargs)):
+ for k, v in dict(*args, **kwargs).items():
self.__setitem__(k, v)
def setdefault(self, key, default=None):
@@ -1055,7 +1052,7 @@
return self.get(item)
raise KeyError
except KeyError:
- raise AttributeError
+ raise AttributeError(item) from None
def __setattr__(self, item, value):
try:
@@ -1066,7 +1063,7 @@
self.__setitem__(item, value)
super(JWK, self).__setattr__(item, value)
except KeyError:
- raise AttributeError
+ raise AttributeError(item) from None
@classmethod
def from_password(cls, password):
@@ -1079,7 +1076,7 @@
try:
params['k'] = base64url_encode(password.encode('utf8'))
except Exception as e: # pylint: disable=broad-except
- raise InvalidJWKValue(e)
+ raise InvalidJWKValue from e
obj.import_key(**params)
return obj
@@ -1130,7 +1127,7 @@
super(JWKSet, self).__setitem__(key, val)
def update(self, *args, **kwargs):
- for k, v in iteritems(dict(*args, **kwargs)):
+ for k, v in dict(*args, **kwargs).items():
self.__setitem__(k, v)
def setdefault(self, key, default=None):
@@ -1151,7 +1148,7 @@
a JSON object
"""
exp_dict = dict()
- for k, v in iteritems(self):
+ for k, v in self.items():
if k == 'keys':
keys = list()
for jwk in v:
@@ -1169,13 +1166,13 @@
"""
try:
jwkset = json_decode(keyset)
- except Exception: # pylint: disable=broad-except
- raise InvalidJWKValue()
+ except Exception as e: # pylint: disable=broad-except
+ raise InvalidJWKValue from e
if 'keys' not in jwkset:
- raise InvalidJWKValue()
+ raise InvalidJWKValue
- for k, v in iteritems(jwkset):
+ for k, v in jwkset.items():
if k == 'keys':
for jwk in v:
self['keys'].add(JWK(**jwk))
@@ -1203,7 +1200,7 @@
def __repr__(self):
repr_dict = dict()
- for k, v in iteritems(self):
+ for k, v in self.items():
if k == 'keys':
keys = list()
for jwk in v:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/jws.py
new/jwcrypto-1.0/jwcrypto/jws.py
--- old/jwcrypto-0.9.1/jwcrypto/jws.py 2021-02-08 21:02:01.000000000 +0100
+++ new/jwcrypto-1.0/jwcrypto/jws.py 2021-08-02 10:49:08.000000000 +0200
@@ -163,7 +163,7 @@
sigin = b'.'.join([self.protected.encode('utf-8'), payload])
self.engine.verify(self.key, sigin, signature)
except Exception as e: # pylint: disable=broad-except
- raise InvalidJWSSignature('Verification failed', repr(e))
+ raise InvalidJWSSignature('Verification failed') from e
return True
@@ -180,8 +180,7 @@
:param header_registry: Optional additions to the header registry
"""
self.objects = dict()
- if payload:
- self.objects['payload'] = payload
+ self.objects['payload'] = payload
self.verifylog = None
self._allowed_algs = None
self.header_registry = JWSEHeaderRegistry(JWSHeaderRegistry)
@@ -400,7 +399,8 @@
except ValueError:
c = raw_jws.split('.')
if len(c) != 3:
- raise InvalidJWSObject('Unrecognized representation')
+ raise InvalidJWSObject('Unrecognized'
+ ' representation') from None
p = base64url_decode(str(c[0]))
if len(p) > 0:
o['protected'] = p.decode('utf-8')
@@ -411,7 +411,7 @@
self.objects = o
except Exception as e: # pylint: disable=broad-except
- raise InvalidJWSObject('Invalid format', repr(e))
+ raise InvalidJWSObject('Invalid format') from e
if key:
self.verify(key, alg)
@@ -427,8 +427,7 @@
:param protected: The Protected Header (optional)
:param header: The Unprotected Header (optional)
- :raises InvalidJWSObject: if no payload has been set on the object,
- or invalid headers are provided.
+ :raises InvalidJWSObject: if invalid headers are provided.
:raises ValueError: if the key is not a :class:`JWK` object.
:raises ValueError: if the algorithm is missing or is not provided
by one of the headers.
@@ -436,9 +435,6 @@
unknown or otherwise not yet implemented.
"""
- if not self.objects.get('payload', None):
- raise InvalidJWSObject('Missing Payload')
-
b64 = True
p = dict()
@@ -481,7 +477,8 @@
raise ValueError('"alg" not specified')
c = JWSCore(
- alg, key, protected, self.objects['payload'], self.allowed_algs
+ alg, key, protected, self.objects.get('payload'),
+ self.allowed_algs
)
sig = c.sign()
@@ -539,7 +536,7 @@
else:
raise InvalidJWSOperation("Can't use compact encoding "
"without protected header")
- if self.objects.get('payload', False):
+ if self.objects.get('payload'):
if self.objects.get('b64', True):
payload = base64url_encode(self.objects['payload'])
else:
@@ -558,11 +555,11 @@
else:
obj = self.objects
sig = dict()
- if self.objects.get('payload', False):
- if self.objects.get('b64', True):
- sig['payload'] = base64url_encode(self.objects['payload'])
- else:
- sig['payload'] = self.objects['payload']
+ payload = self.objects.get('payload', '')
+ if self.objects.get('b64', True):
+ sig['payload'] = base64url_encode(payload)
+ else:
+ sig['payload'] = payload
if 'signature' in obj:
if not obj.get('valid', False):
raise InvalidJWSSignature("No valid signature found")
@@ -590,11 +587,9 @@
@property
def payload(self):
- if 'payload' not in self.objects:
- raise InvalidJWSOperation("Payload not available")
if not self.is_valid:
raise InvalidJWSOperation("Payload not verified")
- return self.objects['payload']
+ return self.objects.get('payload')
def detach_payload(self):
self.objects.pop('payload', None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/jwt.py
new/jwcrypto-1.0/jwcrypto/jwt.py
--- old/jwcrypto-0.9.1/jwcrypto/jwt.py 2021-06-09 20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/jwcrypto/jwt.py 2021-08-02 10:49:08.000000000 +0200
@@ -3,8 +3,6 @@
import time
import uuid
-from six import string_types
-
from jwcrypto.common import JWException, json_decode, json_encode
from jwcrypto.jwe import JWE
from jwcrypto.jwk import JWK, JWKSet
@@ -306,17 +304,17 @@
def _check_string_claim(self, name, claims):
if name not in claims:
return
- if not isinstance(claims[name], string_types):
+ if not isinstance(claims[name], str):
raise JWTInvalidClaimFormat("Claim %s is not a StringOrURI type")
def _check_array_or_string_claim(self, name, claims):
if name not in claims:
return
if isinstance(claims[name], list):
- if any(not isinstance(claim, string_types) for claim in claims):
+ if any(not isinstance(claim, str) for claim in claims):
raise JWTInvalidClaimFormat(
"Claim %s contains non StringOrURI types" % (name, ))
- elif not isinstance(claims[name], string_types):
+ elif not isinstance(claims[name], str):
raise JWTInvalidClaimFormat(
"Claim %s is not a StringOrURI type" % (name, ))
@@ -325,9 +323,9 @@
return
try:
int(claims[name])
- except ValueError:
+ except ValueError as e:
raise JWTInvalidClaimFormat(
- "Claim %s is not an integer" % (name, ))
+ "Claim %s is not an integer" % (name, )) from e
def _check_exp(self, claim, limit, leeway):
if claim < limit - leeway:
@@ -347,6 +345,7 @@
self._check_integer_claim('nbf', claims)
self._check_integer_claim('iat', claims)
self._check_string_claim('jti', claims)
+ self._check_string_claim('typ', claims)
if self._check_claims is None:
if 'exp' in claims:
@@ -363,10 +362,11 @@
claims = json_decode(self.claims)
if not isinstance(claims, dict):
raise ValueError()
- except ValueError:
+ except ValueError as e:
if self._check_claims is not None:
- raise JWTInvalidClaimFormat(
- "Claims check requested but claims is not a json dict")
+ raise JWTInvalidClaimFormat("Claims check requested "
+ "but claims is not a json "
+ "dict") from e
return
self._check_default_claims(claims)
@@ -407,12 +407,28 @@
else:
self._check_nbf(claims[name], time.time(), self._leeway)
+ elif name == 'typ':
+ if value is not None:
+ if self.norm_typ(value) != self.norm_typ(claims[name]):
+ raise JWTInvalidClaimValue("Invalid '%s' value. '%s'"
+ " does not normalize to "
+ "'%s'" % (name,
+ claims[name],
+ value))
+
else:
if value is not None and value != claims[name]:
raise JWTInvalidClaimValue(
"Invalid '%s' value. Expected '%s' got '%s'" % (
name, value, claims[name]))
+ def norm_typ(self, val):
+ lc = val.lower()
+ if '/' in lc:
+ return lc
+ else:
+ return 'application/' + lc
+
def make_signed_token(self, key):
"""Signs the payload.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto/tests.py
new/jwcrypto-1.0/jwcrypto/tests.py
--- old/jwcrypto-0.9.1/jwcrypto/tests.py 2021-06-09 20:43:19.000000000
+0200
+++ new/jwcrypto-1.0/jwcrypto/tests.py 2021-08-02 10:49:08.000000000 +0200
@@ -934,6 +934,21 @@
jws_verify.verify(key.public())
self.assertEqual(jws_verify.payload, payload)
+ def test_jws_issue_224(self):
+ key = jwk.JWK().generate(kty='oct')
+
+ # Test Empty payload is supported for creating and verifying signatures
+ s = jws.JWS(payload='')
+ s.add_signature(key, None, json_encode({"alg": "HS256"}))
+ o1 = s.serialize(compact=True)
+ self.assertTrue('..' in o1)
+ o2 = json_decode(s.serialize())
+ self.assertEqual(o2['payload'], '')
+
+ t = jws.JWS()
+ t.deserialize(o1)
+ t.verify(key)
+
E_A1_plaintext = \
[84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
@@ -1492,6 +1507,38 @@
check_claims={"iss": "test", "exp": None,
"string_claim": "test"})
+ def test_claims_typ(self):
+ key = jwk.JWK().generate(kty='oct')
+ claims = '{"typ":"application/test"}'
+ string_header = '{"alg":"HS256"}'
+ t = jwt.JWT(string_header, claims)
+ t.make_signed_token(key)
+ token = t.serialize()
+
+ # Same typ w/o application prefix
+ jwt.JWT(jwt=token, key=key, check_claims={"typ": "test"})
+ self.assertRaises(jwt.JWTInvalidClaimValue, jwt.JWT, jwt=token,
+ key=key, check_claims={"typ": "wrong"})
+
+ # Same typ w/ application prefix
+ jwt.JWT(jwt=token, key=key, check_claims={"typ": "application/test"})
+ self.assertRaises(jwt.JWTInvalidClaimValue, jwt.JWT, jwt=token,
+ key=key, check_claims={"typ": "application/wrong"})
+
+ # check that a '/' in the name makes it not be matched with
+ # 'application/' prefix
+ claims = '{"typ":"diffmime/test"}'
+ t = jwt.JWT(string_header, claims)
+ t.make_signed_token(key)
+ token = t.serialize()
+ self.assertRaises(jwt.JWTInvalidClaimValue, jwt.JWT, jwt=token,
+ key=key, check_claims={"typ": "application/test"})
+ self.assertRaises(jwt.JWTInvalidClaimValue, jwt.JWT, jwt=token,
+ key=key, check_claims={"typ": "test"})
+
+ # finally make sure it doesn't raise if not checked.
+ jwt.JWT(jwt=token, key=key)
+
def test_empty_claims(self):
key = jwk.JWK().generate(kty='oct')
@@ -1505,12 +1552,12 @@
c.deserialize(token, key)
self.assertEqual('{}', c.claims)
- # empty string is not valid
+ # empty string is also valid
t = jwt.JWT('{"alg":"HS256"}', '')
- self.assertEqual('', t.claims)
- self.assertRaises(jws.InvalidJWSObject, t.make_signed_token, key)
+ t.make_signed_token(key)
+ token = t.serialize()
- # but a space is fine
+ # also a space is fine
t = jwt.JWT('{"alg":"HS256"}', ' ')
self.assertEqual(' ', t.claims)
t.make_signed_token(key)
@@ -1640,8 +1687,8 @@
def test_no_default_rsa_1_5(self):
s = jws.JWS('test')
- with self.assertRaisesRegexp(jws.InvalidJWSOperation,
- 'Algorithm not allowed'):
+ with self.assertRaisesRegex(jws.InvalidJWSOperation,
+ 'Algorithm not allowed'):
s.add_signature(A2_key, alg="RSA1_5")
def test_pbes2_hs256_aeskw(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto.egg-info/PKG-INFO
new/jwcrypto-1.0/jwcrypto.egg-info/PKG-INFO
--- old/jwcrypto-0.9.1/jwcrypto.egg-info/PKG-INFO 2021-06-09
20:43:44.000000000 +0200
+++ new/jwcrypto-1.0/jwcrypto.egg-info/PKG-INFO 2021-08-02 10:49:25.000000000
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.2
Name: jwcrypto
-Version: 0.9.1
+Version: 1.0
Summary: Implementation of JOSE Web standards
Home-page: https://github.com/latchset/jwcrypto
Maintainer: JWCrypto Project Contributors
@@ -8,7 +8,6 @@
License: LGPLv3+
Description: UNKNOWN
Platform: UNKNOWN
-Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto.egg-info/SOURCES.txt
new/jwcrypto-1.0/jwcrypto.egg-info/SOURCES.txt
--- old/jwcrypto-0.9.1/jwcrypto.egg-info/SOURCES.txt 2021-06-09
20:43:44.000000000 +0200
+++ new/jwcrypto-1.0/jwcrypto.egg-info/SOURCES.txt 2021-08-02
10:49:25.000000000 +0200
@@ -4,6 +4,7 @@
MANIFEST.in
Makefile
README.md
+SECURITY.md
setup.cfg
setup.py
tox.ini
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/jwcrypto.egg-info/requires.txt
new/jwcrypto-1.0/jwcrypto.egg-info/requires.txt
--- old/jwcrypto-0.9.1/jwcrypto.egg-info/requires.txt 2021-06-09
20:43:44.000000000 +0200
+++ new/jwcrypto-1.0/jwcrypto.egg-info/requires.txt 2021-08-02
10:49:25.000000000 +0200
@@ -1,3 +1,2 @@
cryptography>=2.3
deprecated
-six
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/setup.py new/jwcrypto-1.0/setup.py
--- old/jwcrypto-0.9.1/setup.py 2021-06-09 20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/setup.py 2021-08-02 10:49:08.000000000 +0200
@@ -6,7 +6,7 @@
setup(
name = 'jwcrypto',
- version = '0.9.1',
+ version = '1.0',
license = 'LGPLv3+',
maintainer = 'JWCrypto Project Contributors',
maintainer_email = '[email protected]',
@@ -14,7 +14,6 @@
packages = ['jwcrypto'],
description = 'Implementation of JOSE Web standards',
classifiers = [
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
@@ -27,6 +26,5 @@
install_requires = [
'cryptography >= 2.3',
'deprecated',
- 'six',
],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jwcrypto-0.9.1/tox.ini new/jwcrypto-1.0/tox.ini
--- old/jwcrypto-0.9.1/tox.ini 2021-06-09 20:43:19.000000000 +0200
+++ new/jwcrypto-1.0/tox.ini 2021-08-02 10:49:08.000000000 +0200
@@ -1,5 +1,5 @@
[tox]
-envlist = lint,py27,py36,py37,py38,py39,pep8py2,pep8py3,doc,sphinx
+envlist = lint,py36,py37,py38,py39,pep8,doc,sphinx
skip_missing_interpreters = true
[testenv]
@@ -15,37 +15,28 @@
{envpython} -m coverage report -m
[testenv:lint]
-basepython = python2.7
+basepython = python3.9
deps =
pylint
#sitepackages = True
commands =
{envpython} -m pylint -d c,r,i,W0613 -r n -f colorized --notes=
--disable=star-args ./jwcrypto
-[testenv:pep8py2]
-basepython = python2.7
-deps =
- flake8
- flake8-import-order
- pep8-naming
-commands =
- {envpython} -m flake8 {posargs} jwcrypto
-
-[testenv:pep8py3]
+[testenv:pep8]
basepython = python3
deps =
flake8
flake8-import-order
pep8-naming
commands =
- {envpython} -m flake8 {posargs} jwcrypto
+ {envpython} -m flake8 {posargs} --ignore=N802,N818 jwcrypto
[testenv:doc]
deps =
doc8
docutils
markdown
-basepython = python2.7
+basepython = python3
commands =
doc8 --allow-long-titles README.md
markdown_py README.md -f {toxworkdir}/README.md.html