jamlib 3.2.0b1__tar.gz → 3.2.0b3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jamlib-3.2.0b1/src/jamlib.egg-info → jamlib-3.2.0b3}/PKG-INFO +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/pyproject.toml +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/__base__.py +133 -21
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/__init__.py +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/__base__.py +69 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/instance.py +76 -2
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/flask/extensions.py +3 -2
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/litestar/middleware.py +4 -3
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/litestar/plugins.py +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/starlette/backends.py +3 -2
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/instance.py +79 -2
- jamlib-3.2.0b3/src/jam/jose/__init__.py +113 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/jwt.py +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/__init__.py +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/tests/clients.py +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/tests/fakers.py +1 -1
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/config_maker.py +35 -4
- {jamlib-3.2.0b1 → jamlib-3.2.0b3/src/jamlib.egg-info}/PKG-INFO +1 -1
- jamlib-3.2.0b1/src/jam/jose/__init__.py +0 -19
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/LICENSE.md +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/README.md +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/setup.cfg +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/__base_encoder__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/__deprecated__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/jwt/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/builtin/github.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/builtin/google.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/oauth2/client.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/sessions/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/sessions/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/sessions/json.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/aio/sessions/redis.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/cli/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/cli/cli.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/cli/commands/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/cli/commands/keys.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/cli/commands/password.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/encoders.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/base.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/jose.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/jwt.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/oauth2.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/paseto.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/plugins.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/exceptions/sessions.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/fastapi/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/flask/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/flask/objects.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/litestar/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/litestar/objects.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/starlette/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/ext/starlette/objects.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/__algorithms__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/jwe.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/jwk.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/jws.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/lists/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/lists/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/lists/json.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/lists/memory.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/lists/redis.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jose/utils.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/__algorithms__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/__types__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/lists/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/lists/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/lists/json.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/lists/redis.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/module.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/jwt/utils.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/logger.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/builtin/github.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/builtin/google.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/oauth2/client.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/otp/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/otp/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/otp/hotp.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/otp/totp.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/utils.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/v1.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/v2.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/v3.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/paseto/v4.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/py.typed +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/sessions/__base__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/sessions/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/sessions/json.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/sessions/redis.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/tests/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/__init__.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/aes.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/await_maybe.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/basic_auth.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/ed.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/otp_keys.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/rsa.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/salt_hash.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/symmetric.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/xchacha20poly1305.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jam/utils/xor.py +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jamlib.egg-info/SOURCES.txt +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jamlib.egg-info/dependency_links.txt +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jamlib.egg-info/entry_points.txt +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jamlib.egg-info/requires.txt +0 -0
- {jamlib-3.2.0b1 → jamlib-3.2.0b3}/src/jamlib.egg-info/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ from typing import Any, Literal
|
|
|
6
6
|
|
|
7
7
|
from jam.encoders import BaseEncoder, JsonEncoder
|
|
8
8
|
from jam.exceptions import JamConfigurationError
|
|
9
|
-
from jam.jose.__base__ import BaseJWT
|
|
9
|
+
from jam.jose.__base__ import BaseJWE, BaseJWS, BaseJWT
|
|
10
10
|
from jam.logger import BaseLogger, JamLogger
|
|
11
11
|
from jam.oauth2.__base__ import BaseOAuth2Client
|
|
12
12
|
from jam.otp.__base__ import BaseOTP, OTPConfig
|
|
@@ -18,7 +18,7 @@ from jam.utils.config_maker import __config_maker__, __module_loader__
|
|
|
18
18
|
class BaseJam(ABC):
|
|
19
19
|
"""Base jam instance."""
|
|
20
20
|
|
|
21
|
-
MODULES: dict[str, str] = {}
|
|
21
|
+
MODULES: dict[str, str | dict[str, str]] = {}
|
|
22
22
|
|
|
23
23
|
def __init__(
|
|
24
24
|
self,
|
|
@@ -55,6 +55,9 @@ class BaseJam(ABC):
|
|
|
55
55
|
self._logger = logger(log_level)
|
|
56
56
|
self._serializer = serializer
|
|
57
57
|
self.jwt: BaseJWT | None = None
|
|
58
|
+
self.jws: BaseJWS | None = None
|
|
59
|
+
self.jwe: BaseJWE | None = None
|
|
60
|
+
self.jose: dict[str, Any] | None = None
|
|
58
61
|
self.session: BaseSessionModule | None = None
|
|
59
62
|
self.oauth2: dict[str, BaseOAuth2Client] | None = None
|
|
60
63
|
self.otp: OTPConfig | None = None
|
|
@@ -69,7 +72,7 @@ class BaseJam(ABC):
|
|
|
69
72
|
)
|
|
70
73
|
self._logger.debug(
|
|
71
74
|
"BaseJam initialization complete. Modules loaded:\n"
|
|
72
|
-
f" jwt={self.jwt is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}"
|
|
75
|
+
f" jwt={self.jwt is not None}, jose={self.jose is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}"
|
|
73
76
|
)
|
|
74
77
|
gc.collect()
|
|
75
78
|
|
|
@@ -139,6 +142,7 @@ class BaseJam(ABC):
|
|
|
139
142
|
"""Build instance.
|
|
140
143
|
|
|
141
144
|
Load modules from configuration and initialize them.
|
|
145
|
+
Supports both flat modules (name -> path) and nested modules (name -> {subname -> path}).
|
|
142
146
|
|
|
143
147
|
Args:
|
|
144
148
|
config (dict[str, Any]): Configuration
|
|
@@ -151,24 +155,68 @@ class BaseJam(ABC):
|
|
|
151
155
|
self._logger.debug(f"Missing configuration for module {name}")
|
|
152
156
|
continue
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
158
|
+
if isinstance(path, dict):
|
|
159
|
+
subconfig = config.get(name, {})
|
|
160
|
+
if not isinstance(subconfig, dict):
|
|
161
|
+
subconfig = {}
|
|
162
|
+
|
|
163
|
+
for subname, subpath in path.items():
|
|
164
|
+
if subname not in subconfig:
|
|
165
|
+
self._logger.debug(
|
|
166
|
+
f"Missing configuration for module {name}.{subname}"
|
|
167
|
+
)
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
module_cls = __module_loader__(subpath)
|
|
172
|
+
self._logger.debug(
|
|
173
|
+
f"Loading module {name}.{subname} from {subpath}"
|
|
174
|
+
)
|
|
175
|
+
params = subconfig.get(subname, {})
|
|
176
|
+
self._logger.debug(
|
|
177
|
+
f"Module {name}.{subname} config params: {list(params.keys())}"
|
|
178
|
+
)
|
|
179
|
+
module_instance = module_cls(**params)
|
|
180
|
+
|
|
181
|
+
if self.jose is None:
|
|
182
|
+
self.jose = {}
|
|
183
|
+
self.jose[subname] = module_instance
|
|
184
|
+
|
|
185
|
+
if subname == "jwt":
|
|
186
|
+
self.jwt = module_instance
|
|
187
|
+
elif subname == "jws":
|
|
188
|
+
self.jws = module_instance
|
|
189
|
+
elif subname == "jwe":
|
|
190
|
+
self.jwe = module_instance
|
|
191
|
+
|
|
192
|
+
self._logger.debug(
|
|
193
|
+
f"Module {name}.{subname} initialized successfully"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
except Exception as e:
|
|
197
|
+
self._logger.error(
|
|
198
|
+
f"Failed to load module {name}.{subname} from {subpath}: {e}",
|
|
199
|
+
exc_info=True,
|
|
200
|
+
)
|
|
201
|
+
else:
|
|
202
|
+
try:
|
|
203
|
+
module_cls = __module_loader__(path)
|
|
204
|
+
self._logger.debug(f"Loading module {name} from {path}")
|
|
205
|
+
params = config.get(name, {})
|
|
206
|
+
self._logger.debug(
|
|
207
|
+
f"Module {name} config params: {list(params.keys())}"
|
|
208
|
+
)
|
|
209
|
+
module_instance = module_cls(**params)
|
|
210
|
+
self.__setattr__(name, module_instance)
|
|
211
|
+
self._logger.debug(
|
|
212
|
+
f"Module {name} initialized successfully"
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
except Exception as e:
|
|
216
|
+
self._logger.error(
|
|
217
|
+
f"Failed to load module {name} from {path}: {e}",
|
|
218
|
+
exc_info=True,
|
|
219
|
+
)
|
|
172
220
|
|
|
173
221
|
def __otp(
|
|
174
222
|
self, type: Literal["totp", "hotp"] | None = None
|
|
@@ -240,6 +288,70 @@ class BaseJam(ABC):
|
|
|
240
288
|
"""
|
|
241
289
|
raise NotImplementedError
|
|
242
290
|
|
|
291
|
+
@abstractmethod
|
|
292
|
+
def jws_sign(
|
|
293
|
+
self,
|
|
294
|
+
data: dict[str, Any] | str,
|
|
295
|
+
header: dict[str, Any] | None = None,
|
|
296
|
+
) -> str:
|
|
297
|
+
"""Sign data using JWS.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
data: Data to sign. If dict, will be JSON encoded.
|
|
301
|
+
header: JWS header.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
str: JWS token.
|
|
305
|
+
"""
|
|
306
|
+
raise NotImplementedError
|
|
307
|
+
|
|
308
|
+
@abstractmethod
|
|
309
|
+
def jws_verify(self, token: str) -> dict[str, Any]:
|
|
310
|
+
"""Verify JWS token.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
token: JWS token.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
dict[str, Any]: Decoded payload.
|
|
317
|
+
|
|
318
|
+
Raises:
|
|
319
|
+
JamJWSVerificationError: If verification fails.
|
|
320
|
+
"""
|
|
321
|
+
raise NotImplementedError
|
|
322
|
+
|
|
323
|
+
@abstractmethod
|
|
324
|
+
def jwe_encrypt(
|
|
325
|
+
self,
|
|
326
|
+
data: dict[str, Any] | str,
|
|
327
|
+
header: dict[str, Any] | None = None,
|
|
328
|
+
) -> str:
|
|
329
|
+
"""Encrypt data using JWE.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
data: Data to encrypt. If dict, will be JSON encoded.
|
|
333
|
+
header: JWE header.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
str: JWE token.
|
|
337
|
+
"""
|
|
338
|
+
raise NotImplementedError
|
|
339
|
+
|
|
340
|
+
@abstractmethod
|
|
341
|
+
def jwe_decrypt(self, token: str) -> bytes:
|
|
342
|
+
"""Decrypt JWE token.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
token: JWE token.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
bytes: Decrypted data.
|
|
349
|
+
|
|
350
|
+
Raises:
|
|
351
|
+
JamJWEDecryptionError: If decryption fails.
|
|
352
|
+
"""
|
|
353
|
+
raise NotImplementedError
|
|
354
|
+
|
|
243
355
|
@abstractmethod
|
|
244
356
|
def session_create(self, session_key: str, data: dict[str, Any]) -> str:
|
|
245
357
|
"""Create new session.
|
|
@@ -6,15 +6,19 @@ from typing import Any
|
|
|
6
6
|
from jam.__base__ import BaseJam
|
|
7
7
|
from jam.aio.oauth2.__base__ import BaseAsyncOAuth2Client
|
|
8
8
|
from jam.aio.sessions.__base__ import BaseAsyncSessionModule
|
|
9
|
+
from jam.jose.__base__ import BaseJWE, BaseJWS
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class BaseAsyncJam(BaseJam):
|
|
12
13
|
"""Base async jam instance."""
|
|
13
14
|
|
|
14
|
-
MODULES: dict[str, str] = {}
|
|
15
|
+
MODULES: dict[str, str | dict[str, str]] = {}
|
|
15
16
|
|
|
16
17
|
session: BaseAsyncSessionModule | None = None # type: ignore[override]
|
|
17
18
|
oauth2: dict[str, BaseAsyncOAuth2Client] | None = None # type: ignore[override]
|
|
19
|
+
jose: dict[str, Any] | None = None # type: ignore[override]
|
|
20
|
+
jws: BaseJWS | None = None # type: ignore[override]
|
|
21
|
+
jwe: BaseJWE | None = None # type: ignore[override]
|
|
18
22
|
|
|
19
23
|
@abstractmethod
|
|
20
24
|
async def jwt_make_payload( # type: ignore[override]
|
|
@@ -340,6 +344,70 @@ class BaseAsyncJam(BaseJam):
|
|
|
340
344
|
"""
|
|
341
345
|
raise NotImplementedError
|
|
342
346
|
|
|
347
|
+
@abstractmethod
|
|
348
|
+
async def jws_sign(
|
|
349
|
+
self,
|
|
350
|
+
data: dict[str, Any] | str,
|
|
351
|
+
header: dict[str, Any] | None = None,
|
|
352
|
+
) -> str:
|
|
353
|
+
"""Sign data using JWS.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
data: Data to sign. If dict, will be JSON encoded.
|
|
357
|
+
header: JWS header.
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
str: JWS token.
|
|
361
|
+
"""
|
|
362
|
+
raise NotImplementedError
|
|
363
|
+
|
|
364
|
+
@abstractmethod
|
|
365
|
+
async def jws_verify(self, token: str) -> dict[str, Any]:
|
|
366
|
+
"""Verify JWS token.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
token: JWS token.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
dict[str, Any]: Decoded payload.
|
|
373
|
+
|
|
374
|
+
Raises:
|
|
375
|
+
JamJWSVerificationError: If verification fails.
|
|
376
|
+
"""
|
|
377
|
+
raise NotImplementedError
|
|
378
|
+
|
|
379
|
+
@abstractmethod
|
|
380
|
+
async def jwe_encrypt(
|
|
381
|
+
self,
|
|
382
|
+
data: dict[str, Any] | str,
|
|
383
|
+
header: dict[str, Any] | None = None,
|
|
384
|
+
) -> str:
|
|
385
|
+
"""Encrypt data using JWE.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
data: Data to encrypt. If dict, will be JSON encoded.
|
|
389
|
+
header: JWE header.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
str: JWE token.
|
|
393
|
+
"""
|
|
394
|
+
raise NotImplementedError
|
|
395
|
+
|
|
396
|
+
@abstractmethod
|
|
397
|
+
async def jwe_decrypt(self, token: str) -> bytes:
|
|
398
|
+
"""Decrypt JWE token.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
token: JWE token.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
bytes: Decrypted data.
|
|
405
|
+
|
|
406
|
+
Raises:
|
|
407
|
+
JamJWEDecryptionError: If decryption fails.
|
|
408
|
+
"""
|
|
409
|
+
raise NotImplementedError
|
|
410
|
+
|
|
343
411
|
@abstractmethod
|
|
344
412
|
async def paseto_decode( # type: ignore[override]
|
|
345
413
|
self, token: str, check_exp: bool = True, check_list: bool = True
|
|
@@ -18,8 +18,12 @@ from jam.exceptions import (
|
|
|
18
18
|
class Jam(BaseAsyncJam):
|
|
19
19
|
"""Main async Jam instance."""
|
|
20
20
|
|
|
21
|
-
MODULES: dict[str, str] = {
|
|
22
|
-
"
|
|
21
|
+
MODULES: dict[str, str | dict[str, str]] = {
|
|
22
|
+
"jose": {
|
|
23
|
+
"jwt": "jam.jose.create_jwt_instance",
|
|
24
|
+
"jws": "jam.jose.create_jws_instance",
|
|
25
|
+
"jwe": "jam.jose.create_jwe_instance",
|
|
26
|
+
},
|
|
23
27
|
"session": "jam.aio.sessions.create_instance",
|
|
24
28
|
"oauth2": "jam.aio.oauth2.create_instance",
|
|
25
29
|
"paseto": "jam.paseto.create_instance",
|
|
@@ -184,6 +188,76 @@ class Jam(BaseAsyncJam):
|
|
|
184
188
|
return {"header": headers, "payload": payload}
|
|
185
189
|
return payload
|
|
186
190
|
|
|
191
|
+
async def jws_sign(
|
|
192
|
+
self,
|
|
193
|
+
data: dict[str, Any] | str,
|
|
194
|
+
header: dict[str, Any] | None = None,
|
|
195
|
+
) -> str:
|
|
196
|
+
"""Sign data using JWS.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
data: Data to sign. If dict, will be JSON encoded.
|
|
200
|
+
header: JWS header.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
str: JWS token.
|
|
204
|
+
"""
|
|
205
|
+
assert self.jws is not None
|
|
206
|
+
self._logger.debug(f"Signing data with JWS, header: {header}")
|
|
207
|
+
token = self.jws.sign(header or {}, data)
|
|
208
|
+
self._logger.debug(f"JWS token created, length: {len(token)}")
|
|
209
|
+
return token
|
|
210
|
+
|
|
211
|
+
async def jws_verify(self, token: str) -> dict[str, Any]:
|
|
212
|
+
"""Verify JWS token.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
token: JWS token.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
dict[str, Any]: Decoded payload.
|
|
219
|
+
"""
|
|
220
|
+
assert self.jws is not None
|
|
221
|
+
self._logger.debug(f"Verifying JWS token, length: {len(token)}")
|
|
222
|
+
result = self.jws.verify(token)
|
|
223
|
+
self._logger.debug("JWS token verified successfully")
|
|
224
|
+
return result
|
|
225
|
+
|
|
226
|
+
async def jwe_encrypt(
|
|
227
|
+
self,
|
|
228
|
+
data: dict[str, Any] | str,
|
|
229
|
+
header: dict[str, Any] | None = None,
|
|
230
|
+
) -> str:
|
|
231
|
+
"""Encrypt data using JWE.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
data: Data to encrypt. If dict, will be JSON encoded.
|
|
235
|
+
header: JWE header.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
str: JWE token.
|
|
239
|
+
"""
|
|
240
|
+
assert self.jwe is not None
|
|
241
|
+
self._logger.debug(f"Encrypting data with JWE, header: {header}")
|
|
242
|
+
token = self.jwe.encrypt(data, header)
|
|
243
|
+
self._logger.debug(f"JWE token created, length: {len(token)}")
|
|
244
|
+
return token
|
|
245
|
+
|
|
246
|
+
async def jwe_decrypt(self, token: str) -> bytes:
|
|
247
|
+
"""Decrypt JWE token.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
token: JWE token.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
bytes: Decrypted data.
|
|
254
|
+
"""
|
|
255
|
+
assert self.jwe is not None
|
|
256
|
+
self._logger.debug(f"Decrypting JWE token, length: {len(token)}")
|
|
257
|
+
result = self.jwe.decrypt(token)
|
|
258
|
+
self._logger.debug("JWE token decrypted successfully")
|
|
259
|
+
return result
|
|
260
|
+
|
|
187
261
|
async def session_create(
|
|
188
262
|
self, session_key: str, data: dict[str, Any]
|
|
189
263
|
) -> str:
|
|
@@ -5,7 +5,7 @@ from typing import Any
|
|
|
5
5
|
import flask
|
|
6
6
|
|
|
7
7
|
from jam.exceptions import JamFlaskPluginConfigError
|
|
8
|
-
from jam.
|
|
8
|
+
from jam.jose import create_instance as create_jwt
|
|
9
9
|
from jam.oauth2 import create_instance as create_oauth2
|
|
10
10
|
from jam.paseto import create_instance as create_paseto
|
|
11
11
|
from jam.sessions import create_instance as create_session
|
|
@@ -170,7 +170,8 @@ class JWTExtension(BaseAuthExtension):
|
|
|
170
170
|
if not token:
|
|
171
171
|
return None
|
|
172
172
|
try:
|
|
173
|
-
|
|
173
|
+
result = self._auth.decode(token)
|
|
174
|
+
payload = result.get("payload", result)
|
|
174
175
|
flask.g.payload = payload
|
|
175
176
|
return payload
|
|
176
177
|
except Exception:
|
|
@@ -11,7 +11,7 @@ from litestar.middleware import (
|
|
|
11
11
|
from jam.aio.sessions.__base__ import BaseAsyncSessionModule
|
|
12
12
|
from jam.exceptions import JamLitestarPluginConfigError, JamLitestarPluginError
|
|
13
13
|
from jam.ext.litestar.objects import BaseUser, Token
|
|
14
|
-
from jam.
|
|
14
|
+
from jam.jose.__base__ import BaseJWT as JWTClass
|
|
15
15
|
from jam.paseto import BasePASETO
|
|
16
16
|
|
|
17
17
|
|
|
@@ -46,7 +46,7 @@ class BaseMiddleware(AbstractAuthenticationMiddleware):
|
|
|
46
46
|
class JWTMiddleware(BaseMiddleware):
|
|
47
47
|
"""JWT Middleware for litestar."""
|
|
48
48
|
|
|
49
|
-
AUTH_MODULE:
|
|
49
|
+
AUTH_MODULE: JWTClass
|
|
50
50
|
LIST: bool = False
|
|
51
51
|
|
|
52
52
|
async def authenticate_request( # noqa
|
|
@@ -57,7 +57,8 @@ class JWTMiddleware(BaseMiddleware):
|
|
|
57
57
|
if not token:
|
|
58
58
|
return AuthenticationResult(user=None, auth=token_model)
|
|
59
59
|
try:
|
|
60
|
-
|
|
60
|
+
result = self.AUTH_MODULE.decode(token)
|
|
61
|
+
data = result.get("payload", result)
|
|
61
62
|
if self.AUTH_MODULE.list and self.LIST:
|
|
62
63
|
match self.AUTH_MODULE.list.__list_type__:
|
|
63
64
|
case "white":
|
|
@@ -16,7 +16,7 @@ from jam.ext.litestar.middleware import (
|
|
|
16
16
|
SessionMiddleware,
|
|
17
17
|
)
|
|
18
18
|
from jam.ext.litestar.objects import BaseUser
|
|
19
|
-
from jam.
|
|
19
|
+
from jam.jose import create_instance as create_jwt
|
|
20
20
|
from jam.oauth2 import create_instance as create_oauth2
|
|
21
21
|
from jam.paseto import create_instance as create_paseto
|
|
22
22
|
from jam.utils.config_maker import GENERIC_POINTER, __config_maker__
|
|
@@ -14,7 +14,7 @@ from starlette.requests import HTTPConnection
|
|
|
14
14
|
from jam.aio.sessions import create_instance as create_session
|
|
15
15
|
from jam.exceptions import JamStarlettePluginConfigError
|
|
16
16
|
from jam.ext.starlette.objects import BaseUser, SimpleUser
|
|
17
|
-
from jam.
|
|
17
|
+
from jam.jose import create_instance as create_jwt
|
|
18
18
|
from jam.paseto import create_instance as create_paseto
|
|
19
19
|
from jam.utils.config_maker import GENERIC_POINTER, __config_maker__
|
|
20
20
|
|
|
@@ -141,7 +141,8 @@ class JWTBackend(BaseBackend):
|
|
|
141
141
|
if self._auth.list.check(token):
|
|
142
142
|
return AuthCredentials(None), UnauthenticatedUser()
|
|
143
143
|
data = self._auth.decode(token)
|
|
144
|
-
|
|
144
|
+
payload = data.get("payload", data)
|
|
145
|
+
user = self._user.from_payload(payload)
|
|
145
146
|
return AuthCredentials(["authenticated"]), user
|
|
146
147
|
|
|
147
148
|
return AuthCredentials(None), UnauthenticatedUser()
|
|
@@ -19,8 +19,12 @@ from jam.exceptions import (
|
|
|
19
19
|
class Jam(BaseJam):
|
|
20
20
|
"""Main instance."""
|
|
21
21
|
|
|
22
|
-
MODULES: dict[str, str] = {
|
|
23
|
-
"
|
|
22
|
+
MODULES: dict[str, str | dict[str, str]] = {
|
|
23
|
+
"jose": {
|
|
24
|
+
"jwt": "jam.jose.create_jwt_instance",
|
|
25
|
+
"jws": "jam.jose.create_jws_instance",
|
|
26
|
+
"jwe": "jam.jose.create_jwe_instance",
|
|
27
|
+
},
|
|
24
28
|
"session": "jam.sessions.create_instance",
|
|
25
29
|
"oauth2": "jam.oauth2.create_instance",
|
|
26
30
|
"paseto": "jam.paseto.create_instance",
|
|
@@ -190,6 +194,79 @@ class Jam(BaseJam):
|
|
|
190
194
|
return data
|
|
191
195
|
return payload
|
|
192
196
|
|
|
197
|
+
def jws_sign(
|
|
198
|
+
self,
|
|
199
|
+
data: dict[str, Any] | str,
|
|
200
|
+
header: dict[str, Any] | None = None,
|
|
201
|
+
) -> str:
|
|
202
|
+
"""Sign data using JWS.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
data: Data to sign. If dict, will be JSON encoded.
|
|
206
|
+
header: JWS header.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
str: JWS token.
|
|
210
|
+
"""
|
|
211
|
+
assert self.jws is not None
|
|
212
|
+
self._logger.debug(f"Signing data with JWS, header: {header}")
|
|
213
|
+
token = self.jws.sign(header or {}, data)
|
|
214
|
+
self._logger.debug(f"JWS token created, length: {len(token)}")
|
|
215
|
+
return token
|
|
216
|
+
|
|
217
|
+
def jws_verify(self, token: str) -> dict[str, Any]:
|
|
218
|
+
"""Verify JWS token.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
token: JWS token.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
dict[str, Any]: Decoded payload.
|
|
225
|
+
"""
|
|
226
|
+
assert self.jws is not None
|
|
227
|
+
self._logger.debug(f"Verifying JWS token, length: {len(token)}")
|
|
228
|
+
result = self.jws.verify(token)
|
|
229
|
+
self._logger.debug("JWS token verified successfully")
|
|
230
|
+
return result
|
|
231
|
+
|
|
232
|
+
def jwe_encrypt(
|
|
233
|
+
self,
|
|
234
|
+
data: dict[str, Any] | str,
|
|
235
|
+
header: dict[str, Any] | None = None,
|
|
236
|
+
) -> str:
|
|
237
|
+
"""Encrypt data using JWE.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
data: Data to encrypt. If dict, will be JSON encoded.
|
|
241
|
+
header: JWE header.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
str: JWE token.
|
|
245
|
+
"""
|
|
246
|
+
assert self.jwe is not None
|
|
247
|
+
self._logger.debug(f"Encrypting data with JWE, header: {header}")
|
|
248
|
+
token = self.jwe.encrypt(
|
|
249
|
+
self._serializer.dumps(data) if isinstance(data, dict) else data,
|
|
250
|
+
header,
|
|
251
|
+
)
|
|
252
|
+
self._logger.debug(f"JWE token created, length: {len(token)}")
|
|
253
|
+
return token
|
|
254
|
+
|
|
255
|
+
def jwe_decrypt(self, token: str) -> bytes:
|
|
256
|
+
"""Decrypt JWE token.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
token: JWE token.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
bytes: Decrypted data.
|
|
263
|
+
"""
|
|
264
|
+
assert self.jwe is not None
|
|
265
|
+
self._logger.debug(f"Decrypting JWE token, length: {len(token)}")
|
|
266
|
+
result = self.jwe.decrypt(token)
|
|
267
|
+
self._logger.debug("JWE token decrypted successfully")
|
|
268
|
+
return result
|
|
269
|
+
|
|
193
270
|
def session_create(self, session_key: str, data: dict[str, Any]) -> str:
|
|
194
271
|
"""Create new session.
|
|
195
272
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""JOSE tools."""
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from jam.jose.jwk import JWK, JWKOct, JWKSet, JWKRSA, JWKEC
|
|
8
|
+
from jam.jose.jws import JWS
|
|
9
|
+
from jam.jose.jwe import JWE
|
|
10
|
+
from jam.jose.jwt import JWT
|
|
11
|
+
from jam.logger import BaseLogger, logger
|
|
12
|
+
from jam.encoders import BaseEncoder, JsonEncoder
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_jwt_instance(
|
|
16
|
+
alg: str,
|
|
17
|
+
secret: Any = None,
|
|
18
|
+
secret_key: Any = None,
|
|
19
|
+
password: str | bytes | None = None,
|
|
20
|
+
list: dict[str, Any] | None = None,
|
|
21
|
+
logger: BaseLogger = logger,
|
|
22
|
+
serializer: BaseEncoder | type[BaseEncoder] = JsonEncoder,
|
|
23
|
+
**kwargs: Any,
|
|
24
|
+
) -> JWT:
|
|
25
|
+
"""Create JWT instance."""
|
|
26
|
+
if secret is None and secret_key is not None:
|
|
27
|
+
secret = secret_key
|
|
28
|
+
elif secret is None:
|
|
29
|
+
raise ValueError("Either 'secret' or 'secret_key' must be provided")
|
|
30
|
+
|
|
31
|
+
key = secret
|
|
32
|
+
if isinstance(secret, JWK):
|
|
33
|
+
key = secret._to_keylike()
|
|
34
|
+
|
|
35
|
+
return JWT(
|
|
36
|
+
alg=alg,
|
|
37
|
+
secret_key=key,
|
|
38
|
+
password=password,
|
|
39
|
+
list=list,
|
|
40
|
+
serializer=serializer,
|
|
41
|
+
logger=logger,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def create_jws_instance(
|
|
46
|
+
alg: str,
|
|
47
|
+
key: Any = None,
|
|
48
|
+
password: bytes | None = None,
|
|
49
|
+
logger: BaseLogger = logger,
|
|
50
|
+
**kwargs: Any,
|
|
51
|
+
) -> JWS:
|
|
52
|
+
"""Create JWS instance."""
|
|
53
|
+
if key is None:
|
|
54
|
+
raise ValueError("'key' must be provided")
|
|
55
|
+
|
|
56
|
+
from jam.jose.jwk import JWK as JWKClass
|
|
57
|
+
|
|
58
|
+
if isinstance(key, JWKClass):
|
|
59
|
+
key = key._to_keylike()
|
|
60
|
+
|
|
61
|
+
return JWS(
|
|
62
|
+
alg=alg,
|
|
63
|
+
key=key,
|
|
64
|
+
password=password,
|
|
65
|
+
logger=logger,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_jwe_instance(
|
|
70
|
+
alg: str,
|
|
71
|
+
enc: str,
|
|
72
|
+
key: Any = None,
|
|
73
|
+
password: bytes | None = None,
|
|
74
|
+
serializer: BaseEncoder | type[BaseEncoder] = JsonEncoder,
|
|
75
|
+
logger: BaseLogger = logger,
|
|
76
|
+
**kwargs: Any,
|
|
77
|
+
) -> JWE:
|
|
78
|
+
"""Create JWE instance."""
|
|
79
|
+
if key is None:
|
|
80
|
+
raise ValueError("'key' must be provided")
|
|
81
|
+
|
|
82
|
+
from jam.jose.jwk import JWK as JWKClass
|
|
83
|
+
|
|
84
|
+
if isinstance(key, JWKClass):
|
|
85
|
+
key = key._to_keylike()
|
|
86
|
+
|
|
87
|
+
return JWE(
|
|
88
|
+
alg=alg,
|
|
89
|
+
enc=enc,
|
|
90
|
+
key=key,
|
|
91
|
+
password=password,
|
|
92
|
+
serializer=serializer,
|
|
93
|
+
logger=logger,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
create_instance = create_jwt_instance
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
__all__ = [
|
|
101
|
+
"JWK",
|
|
102
|
+
"JWKSet",
|
|
103
|
+
"JWS",
|
|
104
|
+
"JWE",
|
|
105
|
+
"JWT",
|
|
106
|
+
"JWKRSA",
|
|
107
|
+
"JWKEC",
|
|
108
|
+
"JWKOct",
|
|
109
|
+
"create_instance",
|
|
110
|
+
"create_jwt_instance",
|
|
111
|
+
"create_jws_instance",
|
|
112
|
+
"create_jwe_instance",
|
|
113
|
+
]
|
|
@@ -7,7 +7,7 @@ import uuid
|
|
|
7
7
|
|
|
8
8
|
from jam.aio import Jam as AioJam
|
|
9
9
|
from jam.instance import Jam
|
|
10
|
-
from jam.
|
|
10
|
+
from jam.jose.utils import __base64url_decode__ as base64url_decode
|
|
11
11
|
from jam.tests.fakers import (
|
|
12
12
|
fake_jwt_token,
|
|
13
13
|
fake_oauth2_token,
|
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
import sys
|
|
8
8
|
from typing import Any
|
|
9
|
+
import warnings
|
|
9
10
|
|
|
10
11
|
from jam.encoders import BaseEncoder, JsonEncoder
|
|
11
12
|
from jam.exceptions import JamConfigurationError
|
|
@@ -351,18 +352,48 @@ def __config_maker__(
|
|
|
351
352
|
ext = config.split(".")[-1].lower()
|
|
352
353
|
match ext:
|
|
353
354
|
case "yml" | "yaml":
|
|
354
|
-
|
|
355
|
+
result = __yaml_config_parser(
|
|
356
|
+
path=config, pointer=pointer
|
|
357
|
+
).copy()
|
|
355
358
|
case "toml":
|
|
356
|
-
|
|
359
|
+
result = __toml_config_parser(
|
|
360
|
+
path=config, pointer=pointer
|
|
361
|
+
).copy()
|
|
357
362
|
case "json":
|
|
358
|
-
|
|
363
|
+
result = __json_config_parser(path=config).copy()
|
|
359
364
|
case _:
|
|
360
365
|
raise JamConfigurationError(
|
|
361
366
|
message="YML/YAML, TOML or JSON configs only!",
|
|
362
367
|
error_code="configuration.invalid_config_type",
|
|
363
368
|
)
|
|
364
369
|
else:
|
|
365
|
-
|
|
370
|
+
result = config.copy()
|
|
371
|
+
|
|
372
|
+
result = __apply_jwt_config_migration__(result)
|
|
373
|
+
return result
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
# TODO: Delete this after deleting jam.jwt
|
|
377
|
+
def __apply_jwt_config_migration__(config: dict) -> dict:
|
|
378
|
+
"""Backward compatibility: copy jam.jwt -> jam.jose.jwt with deprecation warning.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
config: Parsed configuration dict
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
dict: Updated config with migration applied
|
|
385
|
+
"""
|
|
386
|
+
if "jwt" in config and "jose" not in config:
|
|
387
|
+
warnings.warn(
|
|
388
|
+
"[jam.jwt] is deprecated. Use [jam.jose.jwt] instead. See: https://jam.makridenko.ru/usage/jose",
|
|
389
|
+
DeprecationWarning,
|
|
390
|
+
stacklevel=2,
|
|
391
|
+
)
|
|
392
|
+
config["jose"] = {"jwt": config["jwt"]}
|
|
393
|
+
elif "jwt" in config and "jose" in config:
|
|
394
|
+
if "jwt" not in config.get("jose", {}):
|
|
395
|
+
config["jose"]["jwt"] = config["jwt"]
|
|
396
|
+
return config
|
|
366
397
|
|
|
367
398
|
|
|
368
399
|
def __module_loader__(path: str) -> Callable:
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
"""JOSE tools."""
|
|
4
|
-
|
|
5
|
-
from jam.jose.jwk import JWK, JWKOct, JWKSet, JWKRSA, JWKEC
|
|
6
|
-
from jam.jose.jws import JWS
|
|
7
|
-
from jam.jose.jwe import JWE
|
|
8
|
-
from jam.jose.jwt import JWT
|
|
9
|
-
|
|
10
|
-
__all__ = [
|
|
11
|
-
"JWK",
|
|
12
|
-
"JWKSet",
|
|
13
|
-
"JWS",
|
|
14
|
-
"JWE",
|
|
15
|
-
"JWT",
|
|
16
|
-
"JWKRSA",
|
|
17
|
-
"JWKEC",
|
|
18
|
-
"JWKOct",
|
|
19
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|