mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 15:56:07 -07:00
Bump pyjwt from 2.8.0 to 2.9.0 (#2374)
* Bump pyjwt from 2.8.0 to 2.9.0 Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.8.0 to 2.9.0. - [Release notes](https://github.com/jpadilla/pyjwt/releases) - [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst) - [Commits](https://github.com/jpadilla/pyjwt/compare/2.8.0...2.9.0) --- updated-dependencies: - dependency-name: pyjwt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update pyjwt==2.9.0 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
43cb027592
commit
da501df846
8 changed files with 102 additions and 87 deletions
|
@ -27,7 +27,7 @@ from .exceptions import (
|
||||||
)
|
)
|
||||||
from .jwks_client import PyJWKClient
|
from .jwks_client import PyJWKClient
|
||||||
|
|
||||||
__version__ = "2.8.0"
|
__version__ = "2.9.0"
|
||||||
|
|
||||||
__title__ = "PyJWT"
|
__title__ = "PyJWT"
|
||||||
__description__ = "JSON Web Token implementation in Python"
|
__description__ = "JSON Web Token implementation in Python"
|
||||||
|
|
|
@ -3,9 +3,8 @@ from __future__ import annotations
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import json
|
import json
|
||||||
import sys
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import TYPE_CHECKING, Any, ClassVar, NoReturn, Union, cast, overload
|
from typing import TYPE_CHECKING, Any, ClassVar, Literal, NoReturn, cast, overload
|
||||||
|
|
||||||
from .exceptions import InvalidKeyError
|
from .exceptions import InvalidKeyError
|
||||||
from .types import HashlibHash, JWKDict
|
from .types import HashlibHash, JWKDict
|
||||||
|
@ -21,14 +20,8 @@ from .utils import (
|
||||||
to_base64url_uint,
|
to_base64url_uint,
|
||||||
)
|
)
|
||||||
|
|
||||||
if sys.version_info >= (3, 8):
|
|
||||||
from typing import Literal
|
|
||||||
else:
|
|
||||||
from typing_extensions import Literal
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cryptography.exceptions import InvalidSignature
|
from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from cryptography.hazmat.primitives.asymmetric import padding
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
@ -194,18 +187,16 @@ class Algorithm(ABC):
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def to_jwk(key_obj, as_dict: Literal[True]) -> JWKDict:
|
def to_jwk(key_obj, as_dict: Literal[True]) -> JWKDict: ... # pragma: no cover
|
||||||
... # pragma: no cover
|
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def to_jwk(key_obj, as_dict: Literal[False] = False) -> str:
|
def to_jwk(key_obj, as_dict: Literal[False] = False) -> str: ... # pragma: no cover
|
||||||
... # pragma: no cover
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def to_jwk(key_obj, as_dict: bool = False) -> Union[JWKDict, str]:
|
def to_jwk(key_obj, as_dict: bool = False) -> JWKDict | str:
|
||||||
"""
|
"""
|
||||||
Serializes a given key into a JWK
|
Serializes a given key into a JWK
|
||||||
"""
|
"""
|
||||||
|
@ -274,16 +265,18 @@ class HMACAlgorithm(Algorithm):
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key_obj: str | bytes, as_dict: Literal[True]) -> JWKDict:
|
def to_jwk(
|
||||||
... # pragma: no cover
|
key_obj: str | bytes, as_dict: Literal[True]
|
||||||
|
) -> JWKDict: ... # pragma: no cover
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key_obj: str | bytes, as_dict: Literal[False] = False) -> str:
|
def to_jwk(
|
||||||
... # pragma: no cover
|
key_obj: str | bytes, as_dict: Literal[False] = False
|
||||||
|
) -> str: ... # pragma: no cover
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key_obj: str | bytes, as_dict: bool = False) -> Union[JWKDict, str]:
|
def to_jwk(key_obj: str | bytes, as_dict: bool = False) -> JWKDict | str:
|
||||||
jwk = {
|
jwk = {
|
||||||
"k": base64url_encode(force_bytes(key_obj)).decode(),
|
"k": base64url_encode(force_bytes(key_obj)).decode(),
|
||||||
"kty": "oct",
|
"kty": "oct",
|
||||||
|
@ -350,22 +343,25 @@ if has_crypto:
|
||||||
RSAPrivateKey, load_pem_private_key(key_bytes, password=None)
|
RSAPrivateKey, load_pem_private_key(key_bytes, password=None)
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
try:
|
||||||
return cast(RSAPublicKey, load_pem_public_key(key_bytes))
|
return cast(RSAPublicKey, load_pem_public_key(key_bytes))
|
||||||
|
except (ValueError, UnsupportedAlgorithm):
|
||||||
|
raise InvalidKeyError("Could not parse the provided public key.")
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
|
||||||
def to_jwk(key_obj: AllowedRSAKeys, as_dict: Literal[True]) -> JWKDict:
|
|
||||||
... # pragma: no cover
|
|
||||||
|
|
||||||
@overload
|
|
||||||
@staticmethod
|
|
||||||
def to_jwk(key_obj: AllowedRSAKeys, as_dict: Literal[False] = False) -> str:
|
|
||||||
... # pragma: no cover
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(
|
def to_jwk(
|
||||||
key_obj: AllowedRSAKeys, as_dict: bool = False
|
key_obj: AllowedRSAKeys, as_dict: Literal[True]
|
||||||
) -> Union[JWKDict, str]:
|
) -> JWKDict: ... # pragma: no cover
|
||||||
|
|
||||||
|
@overload
|
||||||
|
@staticmethod
|
||||||
|
def to_jwk(
|
||||||
|
key_obj: AllowedRSAKeys, as_dict: Literal[False] = False
|
||||||
|
) -> str: ... # pragma: no cover
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_jwk(key_obj: AllowedRSAKeys, as_dict: bool = False) -> JWKDict | str:
|
||||||
obj: dict[str, Any] | None = None
|
obj: dict[str, Any] | None = None
|
||||||
|
|
||||||
if hasattr(key_obj, "private_numbers"):
|
if hasattr(key_obj, "private_numbers"):
|
||||||
|
@ -533,7 +529,7 @@ if has_crypto:
|
||||||
|
|
||||||
return der_to_raw_signature(der_sig, key.curve)
|
return der_to_raw_signature(der_sig, key.curve)
|
||||||
|
|
||||||
def verify(self, msg: bytes, key: "AllowedECKeys", sig: bytes) -> bool:
|
def verify(self, msg: bytes, key: AllowedECKeys, sig: bytes) -> bool:
|
||||||
try:
|
try:
|
||||||
der_sig = raw_to_der_signature(sig, key.curve)
|
der_sig = raw_to_der_signature(sig, key.curve)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -552,18 +548,18 @@ if has_crypto:
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key_obj: AllowedECKeys, as_dict: Literal[True]) -> JWKDict:
|
def to_jwk(
|
||||||
... # pragma: no cover
|
key_obj: AllowedECKeys, as_dict: Literal[True]
|
||||||
|
) -> JWKDict: ... # pragma: no cover
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key_obj: AllowedECKeys, as_dict: Literal[False] = False) -> str:
|
def to_jwk(
|
||||||
... # pragma: no cover
|
key_obj: AllowedECKeys, as_dict: Literal[False] = False
|
||||||
|
) -> str: ... # pragma: no cover
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(
|
def to_jwk(key_obj: AllowedECKeys, as_dict: bool = False) -> JWKDict | str:
|
||||||
key_obj: AllowedECKeys, as_dict: bool = False
|
|
||||||
) -> Union[JWKDict, str]:
|
|
||||||
if isinstance(key_obj, EllipticCurvePrivateKey):
|
if isinstance(key_obj, EllipticCurvePrivateKey):
|
||||||
public_numbers = key_obj.public_key().public_numbers()
|
public_numbers = key_obj.public_key().public_numbers()
|
||||||
elif isinstance(key_obj, EllipticCurvePublicKey):
|
elif isinstance(key_obj, EllipticCurvePublicKey):
|
||||||
|
@ -771,16 +767,18 @@ if has_crypto:
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key: AllowedOKPKeys, as_dict: Literal[True]) -> JWKDict:
|
def to_jwk(
|
||||||
... # pragma: no cover
|
key: AllowedOKPKeys, as_dict: Literal[True]
|
||||||
|
) -> JWKDict: ... # pragma: no cover
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key: AllowedOKPKeys, as_dict: Literal[False] = False) -> str:
|
def to_jwk(
|
||||||
... # pragma: no cover
|
key: AllowedOKPKeys, as_dict: Literal[False] = False
|
||||||
|
) -> str: ... # pragma: no cover
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_jwk(key: AllowedOKPKeys, as_dict: bool = False) -> Union[JWKDict, str]:
|
def to_jwk(key: AllowedOKPKeys, as_dict: bool = False) -> JWKDict | str:
|
||||||
if isinstance(key, (Ed25519PublicKey, Ed448PublicKey)):
|
if isinstance(key, (Ed25519PublicKey, Ed448PublicKey)):
|
||||||
x = key.public_bytes(
|
x = key.public_bytes(
|
||||||
encoding=Encoding.Raw,
|
encoding=Encoding.Raw,
|
||||||
|
|
|
@ -5,7 +5,13 @@ import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from .algorithms import get_default_algorithms, has_crypto, requires_cryptography
|
from .algorithms import get_default_algorithms, has_crypto, requires_cryptography
|
||||||
from .exceptions import InvalidKeyError, PyJWKError, PyJWKSetError, PyJWTError
|
from .exceptions import (
|
||||||
|
InvalidKeyError,
|
||||||
|
MissingCryptographyError,
|
||||||
|
PyJWKError,
|
||||||
|
PyJWKSetError,
|
||||||
|
PyJWTError,
|
||||||
|
)
|
||||||
from .types import JWKDict
|
from .types import JWKDict
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,21 +56,25 @@ class PyJWK:
|
||||||
raise InvalidKeyError(f"Unsupported kty: {kty}")
|
raise InvalidKeyError(f"Unsupported kty: {kty}")
|
||||||
|
|
||||||
if not has_crypto and algorithm in requires_cryptography:
|
if not has_crypto and algorithm in requires_cryptography:
|
||||||
raise PyJWKError(f"{algorithm} requires 'cryptography' to be installed.")
|
raise MissingCryptographyError(
|
||||||
|
f"{algorithm} requires 'cryptography' to be installed."
|
||||||
|
)
|
||||||
|
|
||||||
self.Algorithm = self._algorithms.get(algorithm)
|
self.algorithm_name = algorithm
|
||||||
|
|
||||||
if not self.Algorithm:
|
if algorithm in self._algorithms:
|
||||||
|
self.Algorithm = self._algorithms[algorithm]
|
||||||
|
else:
|
||||||
raise PyJWKError(f"Unable to find an algorithm for key: {self._jwk_data}")
|
raise PyJWKError(f"Unable to find an algorithm for key: {self._jwk_data}")
|
||||||
|
|
||||||
self.key = self.Algorithm.from_jwk(self._jwk_data)
|
self.key = self.Algorithm.from_jwk(self._jwk_data)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(obj: JWKDict, algorithm: str | None = None) -> "PyJWK":
|
def from_dict(obj: JWKDict, algorithm: str | None = None) -> PyJWK:
|
||||||
return PyJWK(obj, algorithm)
|
return PyJWK(obj, algorithm)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_json(data: str, algorithm: None = None) -> "PyJWK":
|
def from_json(data: str, algorithm: None = None) -> PyJWK:
|
||||||
obj = json.loads(data)
|
obj = json.loads(data)
|
||||||
return PyJWK.from_dict(obj, algorithm)
|
return PyJWK.from_dict(obj, algorithm)
|
||||||
|
|
||||||
|
@ -94,7 +104,9 @@ class PyJWKSet:
|
||||||
for key in keys:
|
for key in keys:
|
||||||
try:
|
try:
|
||||||
self.keys.append(PyJWK(key))
|
self.keys.append(PyJWK(key))
|
||||||
except PyJWTError:
|
except PyJWTError as error:
|
||||||
|
if isinstance(error, MissingCryptographyError):
|
||||||
|
raise error
|
||||||
# skip unusable keys
|
# skip unusable keys
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -104,16 +116,16 @@ class PyJWKSet:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(obj: dict[str, Any]) -> "PyJWKSet":
|
def from_dict(obj: dict[str, Any]) -> PyJWKSet:
|
||||||
keys = obj.get("keys", [])
|
keys = obj.get("keys", [])
|
||||||
return PyJWKSet(keys)
|
return PyJWKSet(keys)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_json(data: str) -> "PyJWKSet":
|
def from_json(data: str) -> PyJWKSet:
|
||||||
obj = json.loads(data)
|
obj = json.loads(data)
|
||||||
return PyJWKSet.from_dict(obj)
|
return PyJWKSet.from_dict(obj)
|
||||||
|
|
||||||
def __getitem__(self, kid: str) -> "PyJWK":
|
def __getitem__(self, kid: str) -> PyJWK:
|
||||||
for key in self.keys:
|
for key in self.keys:
|
||||||
if key.key_id == kid:
|
if key.key_id == kid:
|
||||||
return key
|
return key
|
||||||
|
|
|
@ -11,6 +11,7 @@ from .algorithms import (
|
||||||
has_crypto,
|
has_crypto,
|
||||||
requires_cryptography,
|
requires_cryptography,
|
||||||
)
|
)
|
||||||
|
from .api_jwk import PyJWK
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
DecodeError,
|
DecodeError,
|
||||||
InvalidAlgorithmError,
|
InvalidAlgorithmError,
|
||||||
|
@ -172,7 +173,7 @@ class PyJWS:
|
||||||
def decode_complete(
|
def decode_complete(
|
||||||
self,
|
self,
|
||||||
jwt: str | bytes,
|
jwt: str | bytes,
|
||||||
key: AllowedPublicKeys | str | bytes = "",
|
key: AllowedPublicKeys | PyJWK | str | bytes = "",
|
||||||
algorithms: list[str] | None = None,
|
algorithms: list[str] | None = None,
|
||||||
options: dict[str, Any] | None = None,
|
options: dict[str, Any] | None = None,
|
||||||
detached_payload: bytes | None = None,
|
detached_payload: bytes | None = None,
|
||||||
|
@ -190,7 +191,7 @@ class PyJWS:
|
||||||
merged_options = {**self.options, **options}
|
merged_options = {**self.options, **options}
|
||||||
verify_signature = merged_options["verify_signature"]
|
verify_signature = merged_options["verify_signature"]
|
||||||
|
|
||||||
if verify_signature and not algorithms:
|
if verify_signature and not algorithms and not isinstance(key, PyJWK):
|
||||||
raise DecodeError(
|
raise DecodeError(
|
||||||
'It is required that you pass in a value for the "algorithms" argument when calling decode().'
|
'It is required that you pass in a value for the "algorithms" argument when calling decode().'
|
||||||
)
|
)
|
||||||
|
@ -217,7 +218,7 @@ class PyJWS:
|
||||||
def decode(
|
def decode(
|
||||||
self,
|
self,
|
||||||
jwt: str | bytes,
|
jwt: str | bytes,
|
||||||
key: AllowedPublicKeys | str | bytes = "",
|
key: AllowedPublicKeys | PyJWK | str | bytes = "",
|
||||||
algorithms: list[str] | None = None,
|
algorithms: list[str] | None = None,
|
||||||
options: dict[str, Any] | None = None,
|
options: dict[str, Any] | None = None,
|
||||||
detached_payload: bytes | None = None,
|
detached_payload: bytes | None = None,
|
||||||
|
@ -289,9 +290,11 @@ class PyJWS:
|
||||||
signing_input: bytes,
|
signing_input: bytes,
|
||||||
header: dict[str, Any],
|
header: dict[str, Any],
|
||||||
signature: bytes,
|
signature: bytes,
|
||||||
key: AllowedPublicKeys | str | bytes = "",
|
key: AllowedPublicKeys | PyJWK | str | bytes = "",
|
||||||
algorithms: list[str] | None = None,
|
algorithms: list[str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if algorithms is None and isinstance(key, PyJWK):
|
||||||
|
algorithms = [key.algorithm_name]
|
||||||
try:
|
try:
|
||||||
alg = header["alg"]
|
alg = header["alg"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -300,6 +303,10 @@ class PyJWS:
|
||||||
if not alg or (algorithms is not None and alg not in algorithms):
|
if not alg or (algorithms is not None and alg not in algorithms):
|
||||||
raise InvalidAlgorithmError("The specified alg value is not allowed")
|
raise InvalidAlgorithmError("The specified alg value is not allowed")
|
||||||
|
|
||||||
|
if isinstance(key, PyJWK):
|
||||||
|
alg_obj = key.Algorithm
|
||||||
|
prepared_key = key.key
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
alg_obj = self.get_algorithm_by_name(alg)
|
alg_obj = self.get_algorithm_by_name(alg)
|
||||||
except NotImplementedError as e:
|
except NotImplementedError as e:
|
||||||
|
|
|
@ -5,7 +5,7 @@ import warnings
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any, List
|
||||||
|
|
||||||
from . import api_jws
|
from . import api_jws
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
|
@ -21,6 +21,7 @@ from .warnings import RemovedInPyjwt3Warning
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .algorithms import AllowedPrivateKeys, AllowedPublicKeys
|
from .algorithms import AllowedPrivateKeys, AllowedPublicKeys
|
||||||
|
from .api_jwk import PyJWK
|
||||||
|
|
||||||
|
|
||||||
class PyJWT:
|
class PyJWT:
|
||||||
|
@ -100,7 +101,7 @@ class PyJWT:
|
||||||
def decode_complete(
|
def decode_complete(
|
||||||
self,
|
self,
|
||||||
jwt: str | bytes,
|
jwt: str | bytes,
|
||||||
key: AllowedPublicKeys | str | bytes = "",
|
key: AllowedPublicKeys | PyJWK | str | bytes = "",
|
||||||
algorithms: list[str] | None = None,
|
algorithms: list[str] | None = None,
|
||||||
options: dict[str, Any] | None = None,
|
options: dict[str, Any] | None = None,
|
||||||
# deprecated arg, remove in pyjwt3
|
# deprecated arg, remove in pyjwt3
|
||||||
|
@ -110,7 +111,7 @@ class PyJWT:
|
||||||
# passthrough arguments to _validate_claims
|
# passthrough arguments to _validate_claims
|
||||||
# consider putting in options
|
# consider putting in options
|
||||||
audience: str | Iterable[str] | None = None,
|
audience: str | Iterable[str] | None = None,
|
||||||
issuer: str | None = None,
|
issuer: str | List[str] | None = None,
|
||||||
leeway: float | timedelta = 0,
|
leeway: float | timedelta = 0,
|
||||||
# kwargs
|
# kwargs
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
|
@ -185,7 +186,7 @@ class PyJWT:
|
||||||
def decode(
|
def decode(
|
||||||
self,
|
self,
|
||||||
jwt: str | bytes,
|
jwt: str | bytes,
|
||||||
key: AllowedPublicKeys | str | bytes = "",
|
key: AllowedPublicKeys | PyJWK | str | bytes = "",
|
||||||
algorithms: list[str] | None = None,
|
algorithms: list[str] | None = None,
|
||||||
options: dict[str, Any] | None = None,
|
options: dict[str, Any] | None = None,
|
||||||
# deprecated arg, remove in pyjwt3
|
# deprecated arg, remove in pyjwt3
|
||||||
|
@ -195,7 +196,7 @@ class PyJWT:
|
||||||
# passthrough arguments to _validate_claims
|
# passthrough arguments to _validate_claims
|
||||||
# consider putting in options
|
# consider putting in options
|
||||||
audience: str | Iterable[str] | None = None,
|
audience: str | Iterable[str] | None = None,
|
||||||
issuer: str | None = None,
|
issuer: str | List[str] | None = None,
|
||||||
leeway: float | timedelta = 0,
|
leeway: float | timedelta = 0,
|
||||||
# kwargs
|
# kwargs
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
|
@ -300,7 +301,7 @@ class PyJWT:
|
||||||
try:
|
try:
|
||||||
exp = int(payload["exp"])
|
exp = int(payload["exp"])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise DecodeError("Expiration Time claim (exp) must be an" " integer.")
|
raise DecodeError("Expiration Time claim (exp) must be an integer.")
|
||||||
|
|
||||||
if exp <= (now - leeway):
|
if exp <= (now - leeway):
|
||||||
raise ExpiredSignatureError("Signature has expired")
|
raise ExpiredSignatureError("Signature has expired")
|
||||||
|
@ -362,6 +363,10 @@ class PyJWT:
|
||||||
if "iss" not in payload:
|
if "iss" not in payload:
|
||||||
raise MissingRequiredClaimError("iss")
|
raise MissingRequiredClaimError("iss")
|
||||||
|
|
||||||
|
if isinstance(issuer, list):
|
||||||
|
if payload["iss"] not in issuer:
|
||||||
|
raise InvalidIssuerError("Invalid issuer")
|
||||||
|
else:
|
||||||
if payload["iss"] != issuer:
|
if payload["iss"] != issuer:
|
||||||
raise InvalidIssuerError("Invalid issuer")
|
raise InvalidIssuerError("Invalid issuer")
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,10 @@ class PyJWKError(PyJWTError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MissingCryptographyError(PyJWKError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PyJWKSetError(PyJWTError):
|
class PyJWKSetError(PyJWTError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -131,26 +131,15 @@ def is_pem_format(key: bytes) -> bool:
|
||||||
|
|
||||||
|
|
||||||
# Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46
|
# Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46
|
||||||
_CERT_SUFFIX = b"-cert-v01@openssh.com"
|
_SSH_KEY_FORMATS = (
|
||||||
_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)")
|
|
||||||
_SSH_KEY_FORMATS = [
|
|
||||||
b"ssh-ed25519",
|
b"ssh-ed25519",
|
||||||
b"ssh-rsa",
|
b"ssh-rsa",
|
||||||
b"ssh-dss",
|
b"ssh-dss",
|
||||||
b"ecdsa-sha2-nistp256",
|
b"ecdsa-sha2-nistp256",
|
||||||
b"ecdsa-sha2-nistp384",
|
b"ecdsa-sha2-nistp384",
|
||||||
b"ecdsa-sha2-nistp521",
|
b"ecdsa-sha2-nistp521",
|
||||||
]
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_ssh_key(key: bytes) -> bool:
|
def is_ssh_key(key: bytes) -> bool:
|
||||||
if any(string_value in key for string_value in _SSH_KEY_FORMATS):
|
return key.startswith(_SSH_KEY_FORMATS)
|
||||||
return True
|
|
||||||
|
|
||||||
ssh_pubkey_match = _SSH_PUBKEY_RC.match(key)
|
|
||||||
if ssh_pubkey_match:
|
|
||||||
key_type = ssh_pubkey_match.group(1)
|
|
||||||
if _CERT_SUFFIX == key_type[-len(_CERT_SUFFIX) :]:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ platformdirs==4.2.2
|
||||||
plexapi==4.15.15
|
plexapi==4.15.15
|
||||||
portend==3.2.0
|
portend==3.2.0
|
||||||
profilehooks==1.12.0
|
profilehooks==1.12.0
|
||||||
PyJWT==2.8.0
|
PyJWT==2.9.0
|
||||||
pyparsing==3.1.2
|
pyparsing==3.1.2
|
||||||
python-dateutil==2.9.0.post0
|
python-dateutil==2.9.0.post0
|
||||||
python-twitter==3.5
|
python-twitter==3.5
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue