Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/jwt/api_jwk.py: 25%
92 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from __future__ import annotations
3import json
4import time
6from .algorithms import get_default_algorithms
7from .exceptions import InvalidKeyError, PyJWKError, PyJWKSetError
10class PyJWK:
11 def __init__(self, jwk_data, algorithm=None):
12 self._algorithms = get_default_algorithms()
13 self._jwk_data = jwk_data
15 kty = self._jwk_data.get("kty", None)
16 if not kty:
17 raise InvalidKeyError(f"kty is not found: {self._jwk_data}")
19 if not algorithm and isinstance(self._jwk_data, dict):
20 algorithm = self._jwk_data.get("alg", None)
22 if not algorithm:
23 # Determine alg with kty (and crv).
24 crv = self._jwk_data.get("crv", None)
25 if kty == "EC":
26 if crv == "P-256" or not crv:
27 algorithm = "ES256"
28 elif crv == "P-384":
29 algorithm = "ES384"
30 elif crv == "P-521":
31 algorithm = "ES512"
32 elif crv == "secp256k1":
33 algorithm = "ES256K"
34 else:
35 raise InvalidKeyError(f"Unsupported crv: {crv}")
36 elif kty == "RSA":
37 algorithm = "RS256"
38 elif kty == "oct":
39 algorithm = "HS256"
40 elif kty == "OKP":
41 if not crv:
42 raise InvalidKeyError(f"crv is not found: {self._jwk_data}")
43 if crv == "Ed25519":
44 algorithm = "EdDSA"
45 else:
46 raise InvalidKeyError(f"Unsupported crv: {crv}")
47 else:
48 raise InvalidKeyError(f"Unsupported kty: {kty}")
50 self.Algorithm = self._algorithms.get(algorithm)
52 if not self.Algorithm:
53 raise PyJWKError(f"Unable to find a algorithm for key: {self._jwk_data}")
55 self.key = self.Algorithm.from_jwk(self._jwk_data)
57 @staticmethod
58 def from_dict(obj, algorithm=None):
59 return PyJWK(obj, algorithm)
61 @staticmethod
62 def from_json(data, algorithm=None):
63 obj = json.loads(data)
64 return PyJWK.from_dict(obj, algorithm)
66 @property
67 def key_type(self):
68 return self._jwk_data.get("kty", None)
70 @property
71 def key_id(self):
72 return self._jwk_data.get("kid", None)
74 @property
75 def public_key_use(self):
76 return self._jwk_data.get("use", None)
79class PyJWKSet:
80 def __init__(self, keys: list[dict]) -> None:
81 self.keys = []
83 if not keys:
84 raise PyJWKSetError("The JWK Set did not contain any keys")
86 if not isinstance(keys, list):
87 raise PyJWKSetError("Invalid JWK Set value")
89 for key in keys:
90 try:
91 self.keys.append(PyJWK(key))
92 except PyJWKError:
93 # skip unusable keys
94 continue
96 if len(self.keys) == 0:
97 raise PyJWKSetError("The JWK Set did not contain any usable keys")
99 @staticmethod
100 def from_dict(obj):
101 keys = obj.get("keys", [])
102 return PyJWKSet(keys)
104 @staticmethod
105 def from_json(data):
106 obj = json.loads(data)
107 return PyJWKSet.from_dict(obj)
109 def __getitem__(self, kid):
110 for key in self.keys:
111 if key.key_id == kid:
112 return key
113 raise KeyError(f"keyset has no key for kid: {kid}")
116class PyJWTSetWithTimestamp:
117 def __init__(self, jwk_set: PyJWKSet):
118 self.jwk_set = jwk_set
119 self.timestamp = time.monotonic()
121 def get_jwk_set(self):
122 return self.jwk_set
124 def get_timestamp(self):
125 return self.timestamp