jamlib 3.2.0b3__tar.gz → 3.2.0.post0__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.
Files changed (126) hide show
  1. {jamlib-3.2.0b3/src/jamlib.egg-info → jamlib-3.2.0.post0}/PKG-INFO +5 -5
  2. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/README.md +3 -3
  3. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/pyproject.toml +2 -2
  4. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__base__.py +54 -6
  5. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__init__.py +2 -4
  6. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/__base__.py +19 -5
  7. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/instance.py +26 -9
  8. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/__base__.py +5 -1
  9. jamlib-3.2.0.post0/src/jam/exceptions/jose.py +73 -0
  10. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/flask/extensions.py +2 -0
  11. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/plugins.py +3 -0
  12. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/starlette/backends.py +2 -0
  13. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/instance.py +8 -3
  14. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/__algorithms__.py +156 -54
  15. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/__base__.py +116 -36
  16. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jwe.py +11 -6
  17. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jwk.py +31 -10
  18. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jws.py +20 -1
  19. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/jwt.py +143 -79
  20. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/redis.py +4 -1
  21. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/logger.py +8 -1
  22. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v1.py +4 -0
  23. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v2.py +4 -0
  24. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v3.py +4 -0
  25. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/v4.py +4 -0
  26. jamlib-3.2.0.post0/src/jam/plugins/__base__.py +58 -0
  27. jamlib-3.2.0.post0/src/jam/plugins/__init__.py +10 -0
  28. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/__base__.py +5 -1
  29. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/tests/clients.py +271 -53
  30. jamlib-3.2.0.post0/src/jam/tests/fakers.py +187 -0
  31. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/config_maker.py +15 -0
  32. jamlib-3.2.0.post0/src/jam/utils/version_check.py +18 -0
  33. {jamlib-3.2.0b3 → jamlib-3.2.0.post0/src/jamlib.egg-info}/PKG-INFO +5 -5
  34. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/SOURCES.txt +3 -0
  35. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/requires.txt +1 -1
  36. jamlib-3.2.0b3/src/jam/exceptions/jose.py +0 -23
  37. jamlib-3.2.0b3/src/jam/tests/fakers.py +0 -102
  38. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/LICENSE.md +0 -0
  39. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/setup.cfg +0 -0
  40. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__base_encoder__.py +0 -0
  41. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/__deprecated__.py +0 -0
  42. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/__init__.py +0 -0
  43. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/jwt/__init__.py +0 -0
  44. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/__base__.py +0 -0
  45. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/__init__.py +0 -0
  46. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
  47. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/github.py +0 -0
  48. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
  49. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/google.py +0 -0
  50. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
  51. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/oauth2/client.py +0 -0
  52. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/__init__.py +0 -0
  53. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/json.py +0 -0
  54. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/aio/sessions/redis.py +0 -0
  55. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/__init__.py +0 -0
  56. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/cli.py +0 -0
  57. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/commands/__init__.py +0 -0
  58. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/commands/keys.py +0 -0
  59. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/cli/commands/password.py +0 -0
  60. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/encoders.py +0 -0
  61. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/__init__.py +0 -0
  62. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/base.py +0 -0
  63. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/jwt.py +0 -0
  64. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/oauth2.py +0 -0
  65. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/paseto.py +0 -0
  66. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/plugins.py +0 -0
  67. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/exceptions/sessions.py +0 -0
  68. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/__init__.py +0 -0
  69. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/fastapi/__init__.py +0 -0
  70. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/flask/__init__.py +0 -0
  71. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/flask/objects.py +0 -0
  72. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/__init__.py +0 -0
  73. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/middleware.py +0 -0
  74. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/litestar/objects.py +0 -0
  75. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/starlette/__init__.py +0 -0
  76. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/ext/starlette/objects.py +0 -0
  77. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/__init__.py +0 -0
  78. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/__base__.py +0 -0
  79. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/__init__.py +0 -0
  80. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/json.py +0 -0
  81. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/lists/memory.py +0 -0
  82. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jose/utils.py +0 -0
  83. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__algorithms__.py +0 -0
  84. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__base__.py +0 -0
  85. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__init__.py +0 -0
  86. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/__types__.py +0 -0
  87. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/__base__.py +0 -0
  88. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/__init__.py +0 -0
  89. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/json.py +0 -0
  90. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/lists/redis.py +0 -0
  91. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/module.py +0 -0
  92. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/jwt/utils.py +0 -0
  93. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/__base__.py +0 -0
  94. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/__init__.py +0 -0
  95. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/__init__.py +0 -0
  96. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/github.py +0 -0
  97. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/gitlab.py +0 -0
  98. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/google.py +0 -0
  99. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/builtin/yandex.py +0 -0
  100. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/oauth2/client.py +0 -0
  101. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/__base__.py +0 -0
  102. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/__init__.py +0 -0
  103. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/hotp.py +0 -0
  104. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/otp/totp.py +0 -0
  105. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/__base__.py +0 -0
  106. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/__init__.py +0 -0
  107. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/paseto/utils.py +0 -0
  108. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/py.typed +0 -0
  109. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/__init__.py +0 -0
  110. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/json.py +0 -0
  111. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/sessions/redis.py +0 -0
  112. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/tests/__init__.py +0 -0
  113. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/__init__.py +0 -0
  114. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/aes.py +0 -0
  115. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/await_maybe.py +0 -0
  116. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/basic_auth.py +0 -0
  117. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/ed.py +0 -0
  118. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/otp_keys.py +0 -0
  119. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/rsa.py +0 -0
  120. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/salt_hash.py +0 -0
  121. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/symmetric.py +0 -0
  122. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/xchacha20poly1305.py +0 -0
  123. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jam/utils/xor.py +0 -0
  124. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/dependency_links.txt +0 -0
  125. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/src/jamlib.egg-info/entry_points.txt +0 -0
  126. {jamlib-3.2.0b3 → jamlib-3.2.0.post0}/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.2.0b3
3
+ Version: 3.2.0.post0
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>=46.0.5
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.jwt_create({"user": 1})
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
- * [JWT](https://jam.makridenko.ru/usage/jwt/)
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
- | JWT | ✅ | | | ✅ | ❌ |
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.jwt_create({"user": 1})
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
- * [JWT](https://jam.makridenko.ru/usage/jwt/)
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
- | JWT | ✅ | | | ✅ | ❌ |
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.2.0b3"
3
+ version = "3.2.0.post0"
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>=46.0.5",
26
+ "cryptography>=48.0.0",
27
27
  ]
28
28
 
29
29
  classifiers = [
@@ -1,16 +1,21 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from abc import ABC, abstractmethod
4
6
  import gc
7
+ import os
5
8
  from typing import Any, Literal
6
9
 
7
- from jam.encoders import BaseEncoder, JsonEncoder
10
+ from jam.__base_encoder__ import BaseEncoder
11
+ from jam.encoders import JsonEncoder
8
12
  from jam.exceptions import JamConfigurationError
9
13
  from jam.jose.__base__ import BaseJWE, BaseJWS, BaseJWT
10
14
  from jam.logger import BaseLogger, JamLogger
11
15
  from jam.oauth2.__base__ import BaseOAuth2Client
12
16
  from jam.otp.__base__ import BaseOTP, OTPConfig
13
17
  from jam.paseto.__base__ import BasePASETO
18
+ from jam.plugins.__base__ import BasePlugin
14
19
  from jam.sessions.__base__ import BaseSessionModule
15
20
  from jam.utils.config_maker import __config_maker__, __module_loader__
16
21
 
@@ -30,15 +35,17 @@ class BaseJam(ABC):
30
35
  "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
31
36
  ] = "INFO",
32
37
  serializer: BaseEncoder | type[BaseEncoder] = JsonEncoder,
38
+ plugins: list[type[BasePlugin]] = [],
33
39
  ) -> None:
34
40
  """Initialize instance.
35
41
 
36
42
  Args:
37
- config (Union[str, dict[str, Any]]): Configuration
38
- pointer (str): Pointer
39
- logger (BaseLogger): Logger
40
- log_level (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]): Log level
41
- serializer (Union[BaseEncoder, type[BaseBrowser]]): Serializer
43
+ config (Union[str, dict[str, Any]]): Configuration
44
+ pointer (str): Pointer
45
+ logger (BaseLogger): Logger
46
+ log_level (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]): Log level
47
+ serializer (Union[BaseEncoder, type[BaseBrowser]]): Serializer
48
+ plugins (list[type[BasePlugin]]): List of plugins
42
49
 
43
50
  Returns:
44
51
  None
@@ -54,6 +61,8 @@ class BaseJam(ABC):
54
61
 
55
62
  self._logger = logger(log_level)
56
63
  self._serializer = serializer
64
+ self._plugins = []
65
+
57
66
  self.jwt: BaseJWT | None = None
58
67
  self.jws: BaseJWS | None = None
59
68
  self.jwe: BaseJWE | None = None
@@ -74,6 +83,9 @@ class BaseJam(ABC):
74
83
  "BaseJam initialization complete. Modules loaded:\n"
75
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}"
76
85
  )
86
+ if os.getenv("JAM_ENABLE_PLUGINS", "0") == "1":
87
+ self._logger.warning("Experimental plugins are enabled!")
88
+ self.__setup_plugins(plugins)
77
89
  gc.collect()
78
90
 
79
91
  def __build_main_config(
@@ -236,6 +248,40 @@ class BaseJam(ABC):
236
248
  case _:
237
249
  raise JamConfigurationError(message="Unknown OTP type.")
238
250
 
251
+ def __setup_plugins(self, plugins: list[type[BasePlugin]]) -> None:
252
+ """Setup plugins."""
253
+ for plugin in plugins:
254
+ self._logger.debug(f"Setup plugin: {plugin.name}")
255
+ from jam.utils.version_check import __is_compatible__
256
+
257
+ if not __is_compatible__(None, plugin.jam_requires):
258
+ continue
259
+
260
+ _plugin = plugin(self)
261
+ _plugin.setup()
262
+ self._plugins.append(_plugin)
263
+
264
+ def emit(self, event: str, **kwargs) -> Any:
265
+ """Emit event.
266
+
267
+ Args:
268
+ event (str): Event name,
269
+ **kwargs: Event data
270
+ """
271
+ for plugin in self._plugins:
272
+ handler = getattr(plugin, f"on_{event}", None)
273
+
274
+ if handler:
275
+ try:
276
+ result = handler(**kwargs)
277
+ if isinstance(result, dict):
278
+ kwargs.update(result)
279
+
280
+ except Exception as e:
281
+ self._logger.error(f"Plugin:{plugin.name} | error: {e}")
282
+
283
+ return kwargs
284
+
239
285
  @abstractmethod
240
286
  def jwt_encode(
241
287
  self,
@@ -244,6 +290,7 @@ class BaseJam(ABC):
244
290
  aud: str | None = None,
245
291
  exp: int | None = None,
246
292
  nbf: int | None = None,
293
+ jti: str | None = None,
247
294
  *,
248
295
  payload: dict[str, Any] | None = None,
249
296
  header: dict[str, Any] | None = None,
@@ -256,6 +303,7 @@ class BaseJam(ABC):
256
303
  iss (str | None): The issuer.
257
304
  sub (str | None): The subject.
258
305
  aud (str | None): The audience.
306
+ jti (str | None): The JWT ID. If none use the JTI fabric function.
259
307
  header (dict[str, Any] | None): The header to include in the JWT.
260
308
  payload (dict[str, Any] | None): The payload to include in the JWT.
261
309
 
@@ -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.2.0b3"
16
- __all__ = ["Jam", "JsonEncoder", "BaseJam", "BaseEncoder"]
13
+ __version__ = "3.2.0"
14
+ __all__ = ["Jam", "BaseJam"]
@@ -4,6 +4,7 @@ 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
9
10
  from jam.jose.__base__ import BaseJWE, BaseJWS
@@ -21,11 +22,17 @@ class BaseAsyncJam(BaseJam):
21
22
  jwe: BaseJWE | None = None # type: ignore[override]
22
23
 
23
24
  @abstractmethod
25
+ @deprecated(
26
+ "This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
27
+ )
24
28
  async def jwt_make_payload( # type: ignore[override]
25
29
  self, exp: int | None, data: dict[str, Any]
26
30
  ) -> dict[str, Any]:
27
31
  """Make JWT-specific payload.
28
32
 
33
+ !!! Deprecated
34
+ This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
35
+
29
36
  Args:
30
37
  exp (int | None): Token expire, if None -> use default
31
38
  data (dict[str, Any]): Data to payload
@@ -36,6 +43,7 @@ class BaseAsyncJam(BaseJam):
36
43
  raise NotImplementedError
37
44
 
38
45
  @abstractmethod
46
+ @deprecated("Use jam.jwt_encode")
39
47
  async def jwt_create( # type: ignore[override]
40
48
  self, payload: dict[str, Any]
41
49
  ) -> str:
@@ -50,13 +58,14 @@ class BaseAsyncJam(BaseJam):
50
58
  raise NotImplementedError
51
59
 
52
60
  @abstractmethod
53
- async def jwt_encode(
61
+ async def jwt_encode( # type: ignore[override]
54
62
  self,
55
63
  iss: str | None = None,
56
64
  sub: str | None = None,
57
65
  aud: str | None = None,
58
66
  exp: int | None = None,
59
67
  nbf: int | None = None,
68
+ jti: str | None = None,
60
69
  *,
61
70
  payload: dict[str, Any] | None = None,
62
71
  header: dict[str, Any] | None = None,
@@ -69,6 +78,7 @@ class BaseAsyncJam(BaseJam):
69
78
  iss (str | None): The issuer.
70
79
  sub (str | None): The subject.
71
80
  aud (str | None): The audience.
81
+ jti (str | None): The JWT ID. If none use the JTI fabric function.
72
82
  header (dict[str, Any] | None): The header to include in the JWT.
73
83
  payload (dict[str, Any] | None): The payload to include in the JWT.
74
84
 
@@ -345,7 +355,7 @@ class BaseAsyncJam(BaseJam):
345
355
  raise NotImplementedError
346
356
 
347
357
  @abstractmethod
348
- async def jws_sign(
358
+ async def jws_sign( # type: ignore[override]
349
359
  self,
350
360
  data: dict[str, Any] | str,
351
361
  header: dict[str, Any] | None = None,
@@ -362,7 +372,9 @@ class BaseAsyncJam(BaseJam):
362
372
  raise NotImplementedError
363
373
 
364
374
  @abstractmethod
365
- async def jws_verify(self, token: str) -> dict[str, Any]:
375
+ async def jws_verify( # type: ignore[override]
376
+ self, token: str
377
+ ) -> dict[str, Any]:
366
378
  """Verify JWS token.
367
379
 
368
380
  Args:
@@ -377,7 +389,7 @@ class BaseAsyncJam(BaseJam):
377
389
  raise NotImplementedError
378
390
 
379
391
  @abstractmethod
380
- async def jwe_encrypt(
392
+ async def jwe_encrypt( # type: ignore[override]
381
393
  self,
382
394
  data: dict[str, Any] | str,
383
395
  header: dict[str, Any] | None = None,
@@ -394,7 +406,9 @@ class BaseAsyncJam(BaseJam):
394
406
  raise NotImplementedError
395
407
 
396
408
  @abstractmethod
397
- async def jwe_decrypt(self, token: str) -> bytes:
409
+ async def jwe_decrypt( # type: ignore[override]
410
+ self, token: str
411
+ ) -> bytes:
398
412
  """Decrypt JWE token.
399
413
 
400
414
  Args:
@@ -1,10 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- import datetime
4
3
  import time
5
4
  from typing import Any
6
5
  import uuid
7
6
 
7
+ from jam.__deprecated__ import deprecated
8
8
  from jam.aio.__base__ import BaseAsyncJam
9
9
  from jam.exceptions import (
10
10
  JamConfigurationError,
@@ -30,11 +30,17 @@ class Jam(BaseAsyncJam):
30
30
  "otp": "jam.otp.__base__.OTPConfig",
31
31
  }
32
32
 
33
+ @deprecated(
34
+ "This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
35
+ )
33
36
  async def jwt_make_payload(
34
37
  self, exp: int | None, data: dict[str, Any]
35
38
  ) -> dict[str, Any]:
36
39
  """Make JWT-specific payload.
37
40
 
41
+ !!! Deprecated
42
+ This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
43
+
38
44
  Args:
39
45
  exp (int | None): Token expire
40
46
  data (dict[str, Any]): Data to payload
@@ -42,17 +48,22 @@ class Jam(BaseAsyncJam):
42
48
  Returns:
43
49
  dict[str, Any]: Payload
44
50
  """
51
+ now = time.time()
45
52
  payload = {
46
- "iat": datetime.datetime.now().timestamp(),
47
- "exp": (datetime.datetime.now().timestamp() + exp) if exp else None,
53
+ "iat": now,
54
+ "exp": (now + exp) if exp else None,
48
55
  "jti": str(uuid.uuid4()),
49
56
  }
50
57
  payload = payload | data
51
58
  return payload
52
59
 
60
+ @deprecated("Use jam.jwt_encode")
53
61
  async def jwt_create(self, payload: dict[str, Any]) -> str:
54
62
  """Create JWT token.
55
63
 
64
+ !!! Deprecated
65
+ Use Jam.jwt_encode
66
+
56
67
  Args:
57
68
  payload (dict[str, Any]): Data payload
58
69
 
@@ -81,6 +92,7 @@ class Jam(BaseAsyncJam):
81
92
  aud: str | None = None,
82
93
  exp: int | None = None,
83
94
  nbf: int | None = None,
95
+ jti: str | None = None,
84
96
  *,
85
97
  payload: dict[str, Any] | None = None,
86
98
  header: dict[str, Any] | None = None,
@@ -93,6 +105,7 @@ class Jam(BaseAsyncJam):
93
105
  iss (str | None): The issuer.
94
106
  sub (str | None): The subject.
95
107
  aud (str | None): The audience.
108
+ jti (str | None): The JWT ID. If none use the JTI fabric function.
96
109
  header (dict[str, Any] | None): The header to include in the JWT.
97
110
  payload (dict[str, Any] | None): The payload to include in the JWT.
98
111
 
@@ -100,12 +113,15 @@ class Jam(BaseAsyncJam):
100
113
  str: The encoded JWT.
101
114
  """
102
115
  assert self.jwt is not None
116
+ if not jti:
117
+ jti = self.jwt.jti
103
118
  token = self.jwt.encode(
104
119
  iss=iss,
105
120
  sub=sub,
106
121
  aud=aud,
107
122
  exp=exp,
108
123
  nbf=nbf,
124
+ jti=jti,
109
125
  payload=payload,
110
126
  header=header,
111
127
  )
@@ -239,7 +255,10 @@ class Jam(BaseAsyncJam):
239
255
  """
240
256
  assert self.jwe is not None
241
257
  self._logger.debug(f"Encrypting data with JWE, header: {header}")
242
- token = self.jwe.encrypt(data, header)
258
+ token = self.jwe.encrypt(
259
+ self._serializer.dumps(data) if isinstance(data, dict) else data,
260
+ header,
261
+ )
243
262
  self._logger.debug(f"JWE token created, length: {len(token)}")
244
263
  return token
245
264
 
@@ -364,8 +383,8 @@ class Jam(BaseAsyncJam):
364
383
  async def otp_uri(
365
384
  self,
366
385
  secret: str,
367
- name: str | None = None,
368
- issuer: str | None = None,
386
+ name: str,
387
+ issuer: str,
369
388
  counter: int | None = None,
370
389
  ) -> str:
371
390
  """Generates an otpauth:// URI for Google Authenticator.
@@ -383,9 +402,7 @@ class Jam(BaseAsyncJam):
383
402
  assert self._otp is not None
384
403
  return self._otp(
385
404
  secret=secret, digits=self.otp.digits, digest=self.otp.digest
386
- ).provisioning_uri(
387
- name=name or "", issuer=issuer or "", counter=counter
388
- )
405
+ ).provisioning_uri(name=name, issuer=issuer, counter=counter)
389
406
 
390
407
  async def otp_verify_code(
391
408
  self,
@@ -7,9 +7,11 @@ from uuid import uuid4
7
7
 
8
8
  from cryptography.fernet import Fernet
9
9
 
10
- from jam.encoders import BaseEncoder, JsonEncoder
10
+ from jam.__base_encoder__ import BaseEncoder
11
+ from jam.encoders import JsonEncoder
11
12
  from jam.exceptions import JamSessionEmptyAESKey
12
13
  from jam.logger import BaseLogger
14
+ from jam.utils.config_maker import __key_loader__
13
15
 
14
16
 
15
17
  class BaseAsyncSessionModule(ABC):
@@ -32,6 +34,8 @@ class BaseAsyncSessionModule(ABC):
32
34
  raise JamSessionEmptyAESKey
33
35
  if is_session_crypt:
34
36
  assert session_aes_secret is not None
37
+ if isinstance(session_aes_secret, str):
38
+ session_aes_secret = __key_loader__(session_aes_secret)
35
39
  self._code_session_key = Fernet(session_aes_secret)
36
40
 
37
41
  def __encode_session_id__(self, data: str) -> str:
@@ -0,0 +1,73 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from .base import JamConfigurationError, JamValidationError
4
+
5
+
6
+ class JamJWSVerificationError(JamValidationError):
7
+ default_message = "JWS signature verification failed."
8
+ default_code = "jws.verification_error"
9
+
10
+
11
+ class JamJWSValidationError(JamValidationError):
12
+ default_message = "JWS validation failed."
13
+ default_code = "jws.validation_error"
14
+
15
+
16
+ class JamJWSInvalidFormatError(JamValidationError):
17
+ default_message = "Invalid JWS format."
18
+ default_code = "jws.invalid_format"
19
+
20
+
21
+ class JamJWSSigningError(JamValidationError):
22
+ default_message = "JWS signing failed."
23
+ default_code = "jws.signing_error"
24
+
25
+
26
+ class JamJWKValidationError(JamValidationError):
27
+ default_message = "JWK validation failed."
28
+ default_code = "jwk.validation_error"
29
+
30
+
31
+ class JamJWKInvalidKeyTypeError(JamValidationError):
32
+ default_message = "Unsupported JWK key type."
33
+ default_code = "jwk.invalid_key_type"
34
+
35
+
36
+ class JamJWKMissingParameterError(JamValidationError):
37
+ default_message = "Missing required JWK parameter."
38
+ default_code = "jwk.missing_parameter"
39
+
40
+
41
+ class JamJWEEncryptionError(JamValidationError):
42
+ default_message = "JWE encryption failed."
43
+ default_code = "jwe.encryption_error"
44
+
45
+
46
+ class JamJWEDecryptionError(JamValidationError):
47
+ default_message = "JWE decryption failed."
48
+ default_code = "jwe.decryption_error"
49
+
50
+
51
+ class JamJWEInvalidFormatError(JamValidationError):
52
+ default_message = "Invalid JWE format."
53
+ default_code = "jwe.invalid_format"
54
+
55
+
56
+ class JamInvalidKeyTypeError(JamConfigurationError):
57
+ default_message = "Invalid key type."
58
+ default_code = "jose.invalid_key_type"
59
+
60
+
61
+ class JamAlgorithmError(JamConfigurationError):
62
+ default_message = "Algorithm error."
63
+ default_code = "jose.algorithm_error"
64
+
65
+
66
+ class JamInvalidPaddingError(JamValidationError):
67
+ default_message = "Invalid padding."
68
+ default_code = "jose.invalid_padding"
69
+
70
+
71
+ class JamRedisListConfigurationError(JamConfigurationError):
72
+ default_message = "Redis list configuration error."
73
+ default_code = "jose.redis_list_configuration_error"
@@ -89,6 +89,8 @@ class BaseAuthExtension(BaseExtension):
89
89
  _config: dict[str, Any] | None = (
90
90
  __config_maker__(config, pointer) if config else None
91
91
  )
92
+ if _config and _config.get("jose", None) and self.MODULE == create_jwt:
93
+ _config = _config["jose"]
92
94
 
93
95
  params = _config.pop(self._CONFIG_KEY) if _config else kwargs
94
96
  super().__init__(app=app, **params)
@@ -76,6 +76,9 @@ class BasePlugin(InitPlugin):
76
76
  __config_maker__(config, pointer) if config else None
77
77
  )
78
78
 
79
+ # FIXME: Make config wrapper
80
+ if _config and _config.get("jose", None) and self.MODULE == create_jwt:
81
+ _config = _config["jose"]
79
82
  params = _config.pop(self._CONFIG_KEY) if _config else kwargs
80
83
  self._setup_config(params)
81
84
  self._middleware = None
@@ -81,6 +81,8 @@ class BaseBackend(AuthenticationBackend):
81
81
  try:
82
82
  if config:
83
83
  config_ = __config_maker__(config, pointer)[self._CONFIG_KEY]
84
+ if config_.get("jose", None) and self.MODULE == create_jwt:
85
+ config_ = config_["jose"]
84
86
  self._auth = self.MODULE(**config_)
85
87
  else:
86
88
  self._auth = self.MODULE(**kwargs)
@@ -1,6 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- import datetime
4
3
  import time
5
4
  from typing import Any
6
5
  import uuid
@@ -49,9 +48,10 @@ class Jam(BaseJam):
49
48
  Returns:
50
49
  dict[str, Any]: Payload
51
50
  """
51
+ now = time.time()
52
52
  payload = {
53
- "iat": datetime.datetime.now().timestamp(),
54
- "exp": (datetime.datetime.now().timestamp() + exp) if exp else None,
53
+ "iat": now,
54
+ "exp": (now + exp) if exp else None,
55
55
  "jti": str(uuid.uuid4()),
56
56
  }
57
57
  payload = payload | data
@@ -92,6 +92,7 @@ class Jam(BaseJam):
92
92
  aud: str | None = None,
93
93
  exp: int | None = None,
94
94
  nbf: int | None = None,
95
+ jti: str | None = None,
95
96
  *,
96
97
  payload: dict[str, Any] | None = None,
97
98
  header: dict[str, Any] | None = None,
@@ -104,6 +105,7 @@ class Jam(BaseJam):
104
105
  iss (str | None): The issuer.
105
106
  sub (str | None): The subject.
106
107
  aud (str | None): The audience.
108
+ jti (str | None): The JWT ID. If none use the JTI fabric function.
107
109
  header (dict[str, Any] | None): The header to include in the JWT.
108
110
  payload (dict[str, Any] | None): The payload to include in the JWT.
109
111
 
@@ -111,12 +113,15 @@ class Jam(BaseJam):
111
113
  str: The encoded JWT.
112
114
  """
113
115
  assert self.jwt is not None
116
+ if not jti:
117
+ jti = self.jwt.jti
114
118
  token = self.jwt.encode(
115
119
  iss=iss,
116
120
  sub=sub,
117
121
  aud=aud,
118
122
  exp=exp,
119
123
  nbf=nbf,
124
+ jti=jti,
120
125
  payload=payload,
121
126
  header=header,
122
127
  )