jamlib 3.1.1__tar.gz → 3.2.0__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.1.1/src/jamlib.egg-info → jamlib-3.2.0}/PKG-INFO +5 -5
- {jamlib-3.1.1 → jamlib-3.2.0}/README.md +3 -3
- {jamlib-3.1.1 → jamlib-3.2.0}/pyproject.toml +2 -2
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/__base__.py +160 -39
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/__deprecated__.py +1 -1
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/__init__.py +2 -4
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/__base__.py +119 -2
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/instance.py +177 -17
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/sessions/__base__.py +5 -1
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/__init__.py +26 -21
- jamlib-3.2.0/src/jam/exceptions/jose.py +73 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/jwt.py +9 -2
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/flask/extensions.py +5 -2
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/litestar/middleware.py +4 -3
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/litestar/plugins.py +4 -1
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/starlette/backends.py +5 -2
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/instance.py +165 -14
- jamlib-3.2.0/src/jam/jose/__algorithms__.py +1263 -0
- jamlib-3.2.0/src/jam/jose/__base__.py +418 -0
- jamlib-3.2.0/src/jam/jose/__init__.py +113 -0
- jamlib-3.2.0/src/jam/jose/jwe.py +204 -0
- jamlib-3.2.0/src/jam/jose/jwk.py +527 -0
- jamlib-3.2.0/src/jam/jose/jws.py +211 -0
- jamlib-3.2.0/src/jam/jose/jwt.py +608 -0
- jamlib-3.2.0/src/jam/jose/lists/__base__.py +40 -0
- jamlib-3.2.0/src/jam/jose/lists/__init__.py +11 -0
- jamlib-3.2.0/src/jam/jose/lists/json.py +136 -0
- jamlib-3.2.0/src/jam/jose/lists/memory.py +111 -0
- jamlib-3.2.0/src/jam/jose/lists/redis.py +164 -0
- {jamlib-3.1.1/src/jam/jwt → jamlib-3.2.0/src/jam/jose}/utils.py +3 -2
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/__base__.py +2 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/__init__.py +1 -1
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/lists/__base__.py +3 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/lists/json.py +2 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/lists/redis.py +2 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/module.py +2 -0
- jamlib-3.2.0/src/jam/jwt/utils.py +36 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/v1.py +4 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/v2.py +4 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/v3.py +4 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/v4.py +4 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/sessions/__base__.py +5 -1
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/tests/clients.py +302 -28
- jamlib-3.2.0/src/jam/tests/fakers.py +187 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/config_maker.py +50 -4
- {jamlib-3.1.1 → jamlib-3.2.0/src/jamlib.egg-info}/PKG-INFO +5 -5
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jamlib.egg-info/SOURCES.txt +14 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jamlib.egg-info/requires.txt +1 -1
- jamlib-3.1.1/src/jam/tests/fakers.py +0 -102
- {jamlib-3.1.1 → jamlib-3.2.0}/LICENSE.md +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/setup.cfg +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/__base_encoder__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/jwt/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/__base__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/github.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/google.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/oauth2/client.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/sessions/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/sessions/json.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/aio/sessions/redis.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/cli/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/cli/cli.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/cli/commands/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/cli/commands/keys.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/cli/commands/password.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/encoders.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/base.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/oauth2.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/paseto.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/plugins.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/exceptions/sessions.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/fastapi/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/flask/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/flask/objects.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/litestar/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/litestar/objects.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/starlette/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/ext/starlette/objects.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/__algorithms__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/__types__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/jwt/lists/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/logger.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/__base__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/builtin/github.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/builtin/google.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/oauth2/client.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/otp/__base__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/otp/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/otp/hotp.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/otp/totp.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/__base__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/paseto/utils.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/plugins/__base__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/plugins/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/py.typed +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/sessions/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/sessions/json.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/sessions/redis.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/tests/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/__init__.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/aes.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/await_maybe.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/basic_auth.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/ed.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/otp_keys.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/rsa.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/salt_hash.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/symmetric.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/version_check.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/xchacha20poly1305.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jam/utils/xor.py +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jamlib.egg-info/dependency_links.txt +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jamlib.egg-info/entry_points.txt +0 -0
- {jamlib-3.1.1 → jamlib-3.2.0}/src/jamlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jamlib
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Simple and universal library for authorization.
|
|
5
5
|
Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -30,7 +30,7 @@ Classifier: Framework :: FastAPI
|
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
32
|
License-File: LICENSE.md
|
|
33
|
-
Requires-Dist: cryptography>=
|
|
33
|
+
Requires-Dist: cryptography>=48.0.0
|
|
34
34
|
Provides-Extra: cli
|
|
35
35
|
Requires-Dist: click>=8.3.1; extra == "cli"
|
|
36
36
|
Provides-Extra: redis
|
|
@@ -77,7 +77,7 @@ from jam import Jam
|
|
|
77
77
|
|
|
78
78
|
jam = Jam(config="config.toml")
|
|
79
79
|
|
|
80
|
-
jwt = jam.
|
|
80
|
+
jwt = jam.jwt_encode(payload={"user": 1})
|
|
81
81
|
session_id = jam.session_create(session_key="username", data={"user": 1})
|
|
82
82
|
otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
|
|
83
83
|
```
|
|
@@ -85,7 +85,7 @@ otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
|
|
|
85
85
|
## Why Jam?
|
|
86
86
|
Jam is a library that provides the most popular AUTH* mechanisms right out of the box.
|
|
87
87
|
|
|
88
|
-
* [
|
|
88
|
+
* [JOSE](https://jam.makridenko.ru/usage/jose/)
|
|
89
89
|
* [PASETO](https://jam.makridenko.ru/usage/paseto/)
|
|
90
90
|
* [Server side sessions](https://jam.makridenko.ru/usage/sessions/)
|
|
91
91
|
* [OTP](https://jam.makridenko.ru/usage/otp/)
|
|
@@ -109,7 +109,7 @@ Here is a comparison with other libraries:
|
|
|
109
109
|
|
|
110
110
|
| Features / Library | **Jam** | [Authx](https://authx.yezz.me/) | [PyJWT](https://pyjwt.readthedocs.io) | [AuthLib](https://docs.authlib.org) | [OTP Auth](https://otp.authlib.org/) |
|
|
111
111
|
|-----------------------|--------|----------------------------------|---------------------------------------|-------------------------------------|--------------------------------------|
|
|
112
|
-
|
|
|
112
|
+
| JOSE | ✅ | ❌ only JWT | ❌ only JWT | ✅ | ❌ |
|
|
113
113
|
| JWT black/white lists | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
114
114
|
| PASETO | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
115
115
|
| Server side sessions | ✅ | ✅ | ❌ | ❌ | ❌ |
|
|
@@ -24,7 +24,7 @@ from jam import Jam
|
|
|
24
24
|
|
|
25
25
|
jam = Jam(config="config.toml")
|
|
26
26
|
|
|
27
|
-
jwt = jam.
|
|
27
|
+
jwt = jam.jwt_encode(payload={"user": 1})
|
|
28
28
|
session_id = jam.session_create(session_key="username", data={"user": 1})
|
|
29
29
|
otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
|
|
30
30
|
```
|
|
@@ -32,7 +32,7 @@ otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
|
|
|
32
32
|
## Why Jam?
|
|
33
33
|
Jam is a library that provides the most popular AUTH* mechanisms right out of the box.
|
|
34
34
|
|
|
35
|
-
* [
|
|
35
|
+
* [JOSE](https://jam.makridenko.ru/usage/jose/)
|
|
36
36
|
* [PASETO](https://jam.makridenko.ru/usage/paseto/)
|
|
37
37
|
* [Server side sessions](https://jam.makridenko.ru/usage/sessions/)
|
|
38
38
|
* [OTP](https://jam.makridenko.ru/usage/otp/)
|
|
@@ -56,7 +56,7 @@ Here is a comparison with other libraries:
|
|
|
56
56
|
|
|
57
57
|
| Features / Library | **Jam** | [Authx](https://authx.yezz.me/) | [PyJWT](https://pyjwt.readthedocs.io) | [AuthLib](https://docs.authlib.org) | [OTP Auth](https://otp.authlib.org/) |
|
|
58
58
|
|-----------------------|--------|----------------------------------|---------------------------------------|-------------------------------------|--------------------------------------|
|
|
59
|
-
|
|
|
59
|
+
| JOSE | ✅ | ❌ only JWT | ❌ only JWT | ✅ | ❌ |
|
|
60
60
|
| JWT black/white lists | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
61
61
|
| PASETO | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
62
62
|
| Server side sessions | ✅ | ✅ | ❌ | ❌ | ❌ |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "jamlib"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.2.0"
|
|
4
4
|
description = "Simple and universal library for authorization."
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Makridenko Adrian",email = "adrianmakridenko@duck.com"},
|
|
@@ -23,7 +23,7 @@ keywords = [
|
|
|
23
23
|
]
|
|
24
24
|
requires-python = ">=3.10"
|
|
25
25
|
dependencies = [
|
|
26
|
-
"cryptography>=
|
|
26
|
+
"cryptography>=48.0.0",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
classifiers = [
|
|
@@ -10,7 +10,7 @@ from typing import Any, Literal
|
|
|
10
10
|
from jam.__base_encoder__ import BaseEncoder
|
|
11
11
|
from jam.encoders import JsonEncoder
|
|
12
12
|
from jam.exceptions import JamConfigurationError
|
|
13
|
-
from jam.
|
|
13
|
+
from jam.jose.__base__ import BaseJWE, BaseJWS, BaseJWT
|
|
14
14
|
from jam.logger import BaseLogger, JamLogger
|
|
15
15
|
from jam.oauth2.__base__ import BaseOAuth2Client
|
|
16
16
|
from jam.otp.__base__ import BaseOTP, OTPConfig
|
|
@@ -23,7 +23,7 @@ from jam.utils.config_maker import __config_maker__, __module_loader__
|
|
|
23
23
|
class BaseJam(ABC):
|
|
24
24
|
"""Base jam instance."""
|
|
25
25
|
|
|
26
|
-
MODULES: dict[str, str] = {}
|
|
26
|
+
MODULES: dict[str, str | dict[str, str]] = {}
|
|
27
27
|
|
|
28
28
|
def __init__(
|
|
29
29
|
self,
|
|
@@ -64,6 +64,9 @@ class BaseJam(ABC):
|
|
|
64
64
|
self._plugins = []
|
|
65
65
|
|
|
66
66
|
self.jwt: BaseJWT | None = None
|
|
67
|
+
self.jws: BaseJWS | None = None
|
|
68
|
+
self.jwe: BaseJWE | None = None
|
|
69
|
+
self.jose: dict[str, Any] | None = None
|
|
67
70
|
self.session: BaseSessionModule | None = None
|
|
68
71
|
self.oauth2: dict[str, BaseOAuth2Client] | None = None
|
|
69
72
|
self.otp: OTPConfig | None = None
|
|
@@ -78,7 +81,7 @@ class BaseJam(ABC):
|
|
|
78
81
|
)
|
|
79
82
|
self._logger.debug(
|
|
80
83
|
"BaseJam initialization complete. Modules loaded:\n"
|
|
81
|
-
f" jwt={self.jwt is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}"
|
|
84
|
+
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}"
|
|
82
85
|
)
|
|
83
86
|
if os.getenv("JAM_ENABLE_PLUGINS", "0") == "1":
|
|
84
87
|
self._logger.warning("Experimental plugins are enabled!")
|
|
@@ -151,6 +154,7 @@ class BaseJam(ABC):
|
|
|
151
154
|
"""Build instance.
|
|
152
155
|
|
|
153
156
|
Load modules from configuration and initialize them.
|
|
157
|
+
Supports both flat modules (name -> path) and nested modules (name -> {subname -> path}).
|
|
154
158
|
|
|
155
159
|
Args:
|
|
156
160
|
config (dict[str, Any]): Configuration
|
|
@@ -163,24 +167,68 @@ class BaseJam(ABC):
|
|
|
163
167
|
self._logger.debug(f"Missing configuration for module {name}")
|
|
164
168
|
continue
|
|
165
169
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
170
|
+
if isinstance(path, dict):
|
|
171
|
+
subconfig = config.get(name, {})
|
|
172
|
+
if not isinstance(subconfig, dict):
|
|
173
|
+
subconfig = {}
|
|
174
|
+
|
|
175
|
+
for subname, subpath in path.items():
|
|
176
|
+
if subname not in subconfig:
|
|
177
|
+
self._logger.debug(
|
|
178
|
+
f"Missing configuration for module {name}.{subname}"
|
|
179
|
+
)
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
module_cls = __module_loader__(subpath)
|
|
184
|
+
self._logger.debug(
|
|
185
|
+
f"Loading module {name}.{subname} from {subpath}"
|
|
186
|
+
)
|
|
187
|
+
params = subconfig.get(subname, {})
|
|
188
|
+
self._logger.debug(
|
|
189
|
+
f"Module {name}.{subname} config params: {list(params.keys())}"
|
|
190
|
+
)
|
|
191
|
+
module_instance = module_cls(**params)
|
|
192
|
+
|
|
193
|
+
if self.jose is None:
|
|
194
|
+
self.jose = {}
|
|
195
|
+
self.jose[subname] = module_instance
|
|
196
|
+
|
|
197
|
+
if subname == "jwt":
|
|
198
|
+
self.jwt = module_instance
|
|
199
|
+
elif subname == "jws":
|
|
200
|
+
self.jws = module_instance
|
|
201
|
+
elif subname == "jwe":
|
|
202
|
+
self.jwe = module_instance
|
|
203
|
+
|
|
204
|
+
self._logger.debug(
|
|
205
|
+
f"Module {name}.{subname} initialized successfully"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
self._logger.error(
|
|
210
|
+
f"Failed to load module {name}.{subname} from {subpath}: {e}",
|
|
211
|
+
exc_info=True,
|
|
212
|
+
)
|
|
213
|
+
else:
|
|
214
|
+
try:
|
|
215
|
+
module_cls = __module_loader__(path)
|
|
216
|
+
self._logger.debug(f"Loading module {name} from {path}")
|
|
217
|
+
params = config.get(name, {})
|
|
218
|
+
self._logger.debug(
|
|
219
|
+
f"Module {name} config params: {list(params.keys())}"
|
|
220
|
+
)
|
|
221
|
+
module_instance = module_cls(**params)
|
|
222
|
+
self.__setattr__(name, module_instance)
|
|
223
|
+
self._logger.debug(
|
|
224
|
+
f"Module {name} initialized successfully"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
except Exception as e:
|
|
228
|
+
self._logger.error(
|
|
229
|
+
f"Failed to load module {name} from {path}: {e}",
|
|
230
|
+
exc_info=True,
|
|
231
|
+
)
|
|
184
232
|
|
|
185
233
|
def __otp(
|
|
186
234
|
self, type: Literal["totp", "hotp"] | None = None
|
|
@@ -235,47 +283,120 @@ class BaseJam(ABC):
|
|
|
235
283
|
return kwargs
|
|
236
284
|
|
|
237
285
|
@abstractmethod
|
|
238
|
-
def
|
|
239
|
-
self,
|
|
286
|
+
def jwt_encode(
|
|
287
|
+
self,
|
|
288
|
+
iss: str | None = None,
|
|
289
|
+
sub: str | None = None,
|
|
290
|
+
aud: str | None = None,
|
|
291
|
+
exp: int | None = None,
|
|
292
|
+
nbf: int | None = None,
|
|
293
|
+
jti: str | None = None,
|
|
294
|
+
*,
|
|
295
|
+
payload: dict[str, Any] | None = None,
|
|
296
|
+
header: dict[str, Any] | None = None,
|
|
297
|
+
) -> str:
|
|
298
|
+
"""Encode the JWT with the given expire, header, and payload.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
exp (int | None): The expiration time in seconds.
|
|
302
|
+
nbf (int | None): The not-before time in seconds.
|
|
303
|
+
iss (str | None): The issuer.
|
|
304
|
+
sub (str | None): The subject.
|
|
305
|
+
aud (str | None): The audience.
|
|
306
|
+
jti (str | None): The JWT ID. If none use the JTI fabric function.
|
|
307
|
+
header (dict[str, Any] | None): The header to include in the JWT.
|
|
308
|
+
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
str: The encoded JWT.
|
|
312
|
+
"""
|
|
313
|
+
raise NotImplementedError
|
|
314
|
+
|
|
315
|
+
@abstractmethod
|
|
316
|
+
def jwt_decode(
|
|
317
|
+
self,
|
|
318
|
+
token: str,
|
|
319
|
+
check_exp: bool = True,
|
|
320
|
+
check_list: bool = True,
|
|
321
|
+
check_nbf: bool = False,
|
|
322
|
+
include_headers: bool = False,
|
|
240
323
|
) -> dict[str, Any]:
|
|
241
|
-
"""
|
|
324
|
+
"""Verify and decode JWT token.
|
|
242
325
|
|
|
243
326
|
Args:
|
|
244
|
-
|
|
245
|
-
|
|
327
|
+
token (str): JWT token
|
|
328
|
+
check_exp (bool): Check expire
|
|
329
|
+
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
330
|
+
check_nbf (bool): Check not-before time
|
|
331
|
+
include_headers (bool): Include headers in the decoded payload
|
|
246
332
|
|
|
247
333
|
Returns:
|
|
248
|
-
dict[str, Any]:
|
|
334
|
+
dict[str, Any]: Decoded payload
|
|
335
|
+
|
|
249
336
|
"""
|
|
250
337
|
raise NotImplementedError
|
|
251
338
|
|
|
252
339
|
@abstractmethod
|
|
253
|
-
def
|
|
254
|
-
|
|
340
|
+
def jws_sign(
|
|
341
|
+
self,
|
|
342
|
+
data: dict[str, Any] | str,
|
|
343
|
+
header: dict[str, Any] | None = None,
|
|
344
|
+
) -> str:
|
|
345
|
+
"""Sign data using JWS.
|
|
255
346
|
|
|
256
347
|
Args:
|
|
257
|
-
|
|
348
|
+
data: Data to sign. If dict, will be JSON encoded.
|
|
349
|
+
header: JWS header.
|
|
258
350
|
|
|
259
351
|
Returns:
|
|
260
|
-
str:
|
|
352
|
+
str: JWS token.
|
|
353
|
+
"""
|
|
354
|
+
raise NotImplementedError
|
|
355
|
+
|
|
356
|
+
@abstractmethod
|
|
357
|
+
def jws_verify(self, token: str) -> dict[str, Any]:
|
|
358
|
+
"""Verify JWS token.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
token: JWS token.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
dict[str, Any]: Decoded payload.
|
|
261
365
|
|
|
366
|
+
Raises:
|
|
367
|
+
JamJWSVerificationError: If verification fails.
|
|
262
368
|
"""
|
|
263
369
|
raise NotImplementedError
|
|
264
370
|
|
|
265
371
|
@abstractmethod
|
|
266
|
-
def
|
|
267
|
-
self,
|
|
268
|
-
|
|
269
|
-
|
|
372
|
+
def jwe_encrypt(
|
|
373
|
+
self,
|
|
374
|
+
data: dict[str, Any] | str,
|
|
375
|
+
header: dict[str, Any] | None = None,
|
|
376
|
+
) -> str:
|
|
377
|
+
"""Encrypt data using JWE.
|
|
270
378
|
|
|
271
379
|
Args:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
380
|
+
data: Data to encrypt. If dict, will be JSON encoded.
|
|
381
|
+
header: JWE header.
|
|
275
382
|
|
|
276
383
|
Returns:
|
|
277
|
-
|
|
384
|
+
str: JWE token.
|
|
385
|
+
"""
|
|
386
|
+
raise NotImplementedError
|
|
387
|
+
|
|
388
|
+
@abstractmethod
|
|
389
|
+
def jwe_decrypt(self, token: str) -> bytes:
|
|
390
|
+
"""Decrypt JWE token.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
token: JWE token.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
bytes: Decrypted data.
|
|
278
397
|
|
|
398
|
+
Raises:
|
|
399
|
+
JamJWEDecryptionError: If decryption fails.
|
|
279
400
|
"""
|
|
280
401
|
raise NotImplementedError
|
|
281
402
|
|
|
@@ -7,10 +7,8 @@ Documentation: https://jam.makridenko.ru
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from jam.__base__ import BaseJam
|
|
10
|
-
from jam.__base_encoder__ import BaseEncoder
|
|
11
|
-
from jam.encoders import JsonEncoder
|
|
12
10
|
from jam.instance import Jam
|
|
13
11
|
|
|
14
12
|
|
|
15
|
-
__version__ = "3.
|
|
16
|
-
__all__ = ["Jam", "
|
|
13
|
+
__version__ = "3.2.0"
|
|
14
|
+
__all__ = ["Jam", "BaseJam"]
|
|
@@ -4,24 +4,35 @@ from abc import abstractmethod
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from jam.__base__ import BaseJam
|
|
7
|
+
from jam.__deprecated__ import deprecated
|
|
7
8
|
from jam.aio.oauth2.__base__ import BaseAsyncOAuth2Client
|
|
8
9
|
from jam.aio.sessions.__base__ import BaseAsyncSessionModule
|
|
10
|
+
from jam.jose.__base__ import BaseJWE, BaseJWS
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class BaseAsyncJam(BaseJam):
|
|
12
14
|
"""Base async jam instance."""
|
|
13
15
|
|
|
14
|
-
MODULES: dict[str, str] = {}
|
|
16
|
+
MODULES: dict[str, str | dict[str, str]] = {}
|
|
15
17
|
|
|
16
18
|
session: BaseAsyncSessionModule | None = None # type: ignore[override]
|
|
17
19
|
oauth2: dict[str, BaseAsyncOAuth2Client] | None = None # type: ignore[override]
|
|
20
|
+
jose: dict[str, Any] | None = None # type: ignore[override]
|
|
21
|
+
jws: BaseJWS | None = None # type: ignore[override]
|
|
22
|
+
jwe: BaseJWE | None = None # type: ignore[override]
|
|
18
23
|
|
|
19
24
|
@abstractmethod
|
|
25
|
+
@deprecated(
|
|
26
|
+
"This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
|
|
27
|
+
)
|
|
20
28
|
async def jwt_make_payload( # type: ignore[override]
|
|
21
29
|
self, exp: int | None, data: dict[str, Any]
|
|
22
30
|
) -> dict[str, Any]:
|
|
23
31
|
"""Make JWT-specific payload.
|
|
24
32
|
|
|
33
|
+
!!! Deprecated
|
|
34
|
+
This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
|
|
35
|
+
|
|
25
36
|
Args:
|
|
26
37
|
exp (int | None): Token expire, if None -> use default
|
|
27
38
|
data (dict[str, Any]): Data to payload
|
|
@@ -32,6 +43,7 @@ class BaseAsyncJam(BaseJam):
|
|
|
32
43
|
raise NotImplementedError
|
|
33
44
|
|
|
34
45
|
@abstractmethod
|
|
46
|
+
@deprecated("Use jam.jwt_encode")
|
|
35
47
|
async def jwt_create( # type: ignore[override]
|
|
36
48
|
self, payload: dict[str, Any]
|
|
37
49
|
) -> str:
|
|
@@ -45,9 +57,44 @@ class BaseAsyncJam(BaseJam):
|
|
|
45
57
|
"""
|
|
46
58
|
raise NotImplementedError
|
|
47
59
|
|
|
60
|
+
@abstractmethod
|
|
61
|
+
async def jwt_encode( # type: ignore[override]
|
|
62
|
+
self,
|
|
63
|
+
iss: str | None = None,
|
|
64
|
+
sub: str | None = None,
|
|
65
|
+
aud: str | None = None,
|
|
66
|
+
exp: int | None = None,
|
|
67
|
+
nbf: int | None = None,
|
|
68
|
+
jti: str | None = None,
|
|
69
|
+
*,
|
|
70
|
+
payload: dict[str, Any] | None = None,
|
|
71
|
+
header: dict[str, Any] | None = None,
|
|
72
|
+
) -> str:
|
|
73
|
+
"""Encode the JWT with the given expire, header, and payload.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
exp (int | None): The expiration time in seconds.
|
|
77
|
+
nbf (int | None): The not-before time in seconds.
|
|
78
|
+
iss (str | None): The issuer.
|
|
79
|
+
sub (str | None): The subject.
|
|
80
|
+
aud (str | None): The audience.
|
|
81
|
+
jti (str | None): The JWT ID. If none use the JTI fabric function.
|
|
82
|
+
header (dict[str, Any] | None): The header to include in the JWT.
|
|
83
|
+
payload (dict[str, Any] | None): The payload to include in the JWT.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
str: The encoded JWT.
|
|
87
|
+
"""
|
|
88
|
+
raise NotImplementedError
|
|
89
|
+
|
|
48
90
|
@abstractmethod
|
|
49
91
|
async def jwt_decode( # type: ignore[override]
|
|
50
|
-
self,
|
|
92
|
+
self,
|
|
93
|
+
token: str,
|
|
94
|
+
check_exp: bool = True,
|
|
95
|
+
check_list: bool = True,
|
|
96
|
+
check_nbf: bool = False,
|
|
97
|
+
include_headers: bool = False,
|
|
51
98
|
) -> dict[str, Any]:
|
|
52
99
|
"""Verify and decode JWT token.
|
|
53
100
|
|
|
@@ -55,6 +102,8 @@ class BaseAsyncJam(BaseJam):
|
|
|
55
102
|
token (str): JWT token
|
|
56
103
|
check_exp (bool): Check expire
|
|
57
104
|
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
105
|
+
check_nbf (bool): Check not-before time
|
|
106
|
+
include_headers (bool): Include headers in the decoded payload
|
|
58
107
|
|
|
59
108
|
Returns:
|
|
60
109
|
dict[str, Any]: Decoded payload
|
|
@@ -305,6 +354,74 @@ class BaseAsyncJam(BaseJam):
|
|
|
305
354
|
"""
|
|
306
355
|
raise NotImplementedError
|
|
307
356
|
|
|
357
|
+
@abstractmethod
|
|
358
|
+
async def jws_sign( # type: ignore[override]
|
|
359
|
+
self,
|
|
360
|
+
data: dict[str, Any] | str,
|
|
361
|
+
header: dict[str, Any] | None = None,
|
|
362
|
+
) -> str:
|
|
363
|
+
"""Sign data using JWS.
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
data: Data to sign. If dict, will be JSON encoded.
|
|
367
|
+
header: JWS header.
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
str: JWS token.
|
|
371
|
+
"""
|
|
372
|
+
raise NotImplementedError
|
|
373
|
+
|
|
374
|
+
@abstractmethod
|
|
375
|
+
async def jws_verify( # type: ignore[override]
|
|
376
|
+
self, token: str
|
|
377
|
+
) -> dict[str, Any]:
|
|
378
|
+
"""Verify JWS token.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
token: JWS token.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
dict[str, Any]: Decoded payload.
|
|
385
|
+
|
|
386
|
+
Raises:
|
|
387
|
+
JamJWSVerificationError: If verification fails.
|
|
388
|
+
"""
|
|
389
|
+
raise NotImplementedError
|
|
390
|
+
|
|
391
|
+
@abstractmethod
|
|
392
|
+
async def jwe_encrypt( # type: ignore[override]
|
|
393
|
+
self,
|
|
394
|
+
data: dict[str, Any] | str,
|
|
395
|
+
header: dict[str, Any] | None = None,
|
|
396
|
+
) -> str:
|
|
397
|
+
"""Encrypt data using JWE.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
data: Data to encrypt. If dict, will be JSON encoded.
|
|
401
|
+
header: JWE header.
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
str: JWE token.
|
|
405
|
+
"""
|
|
406
|
+
raise NotImplementedError
|
|
407
|
+
|
|
408
|
+
@abstractmethod
|
|
409
|
+
async def jwe_decrypt( # type: ignore[override]
|
|
410
|
+
self, token: str
|
|
411
|
+
) -> bytes:
|
|
412
|
+
"""Decrypt JWE token.
|
|
413
|
+
|
|
414
|
+
Args:
|
|
415
|
+
token: JWE token.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
bytes: Decrypted data.
|
|
419
|
+
|
|
420
|
+
Raises:
|
|
421
|
+
JamJWEDecryptionError: If decryption fails.
|
|
422
|
+
"""
|
|
423
|
+
raise NotImplementedError
|
|
424
|
+
|
|
308
425
|
@abstractmethod
|
|
309
426
|
async def paseto_decode( # type: ignore[override]
|
|
310
427
|
self, token: str, check_exp: bool = True, check_list: bool = True
|