jamlib 3.0.0a10__py3-none-any.whl
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.
- jam/__base__.py +451 -0
- jam/__base_encoder__.py +20 -0
- jam/__deprecated__.py +27 -0
- jam/__init__.py +17 -0
- jam/aio/__init__.py +10 -0
- jam/aio/instance.py +371 -0
- jam/aio/jwt/__init__.py +1 -0
- jam/aio/jwt/lists/__init__.py +1 -0
- jam/aio/jwt/lists/json.py +88 -0
- jam/aio/jwt/lists/redis.py +88 -0
- jam/aio/jwt/tools.py +88 -0
- jam/aio/oauth2/__init__.py +61 -0
- jam/aio/oauth2/builtin/__init__.py +3 -0
- jam/aio/oauth2/builtin/github.py +28 -0
- jam/aio/oauth2/builtin/gitlab.py +28 -0
- jam/aio/oauth2/builtin/google.py +28 -0
- jam/aio/oauth2/builtin/yandex.py +31 -0
- jam/aio/oauth2/client.py +151 -0
- jam/aio/sessions/__init__.py +87 -0
- jam/aio/sessions/json.py +85 -0
- jam/aio/sessions/redis.py +243 -0
- jam/encoders.py +47 -0
- jam/exceptions/__init__.py +19 -0
- jam/exceptions/jwt.py +39 -0
- jam/exceptions/oauth2.py +11 -0
- jam/exceptions/sessions.py +11 -0
- jam/ext/__init__.py +3 -0
- jam/ext/fastapi/__init__.py +11 -0
- jam/ext/flask/__init__.py +11 -0
- jam/ext/flask/extensions.py +161 -0
- jam/ext/litestar/__init__.py +13 -0
- jam/ext/litestar/middlewares.py +113 -0
- jam/ext/litestar/plugins.py +121 -0
- jam/ext/litestar/value.py +28 -0
- jam/ext/starlette/__init__.py +12 -0
- jam/ext/starlette/auth_backends.py +134 -0
- jam/ext/starlette/value.py +18 -0
- jam/instance.py +367 -0
- jam/jwt/__algorithms__.py +466 -0
- jam/jwt/__base__.py +38 -0
- jam/jwt/__init__.py +61 -0
- jam/jwt/__types__.py +15 -0
- jam/jwt/lists/__abc_list_repo__.py +27 -0
- jam/jwt/lists/__init__.py +11 -0
- jam/jwt/lists/json.py +110 -0
- jam/jwt/lists/redis.py +103 -0
- jam/jwt/module.py +228 -0
- jam/jwt/utils.py +32 -0
- jam/logger.py +76 -0
- jam/modules.py +29 -0
- jam/oauth2/__base__.py +113 -0
- jam/oauth2/__init__.py +69 -0
- jam/oauth2/builtin/__init__.py +3 -0
- jam/oauth2/builtin/github.py +28 -0
- jam/oauth2/builtin/gitlab.py +28 -0
- jam/oauth2/builtin/google.py +28 -0
- jam/oauth2/builtin/yandex.py +31 -0
- jam/oauth2/client.py +149 -0
- jam/otp/__base__.py +109 -0
- jam/otp/__init__.py +35 -0
- jam/otp/hotp.py +36 -0
- jam/otp/totp.py +73 -0
- jam/paseto/__base__.py +162 -0
- jam/paseto/__init__.py +57 -0
- jam/paseto/utils.py +99 -0
- jam/paseto/v1.py +314 -0
- jam/paseto/v2.py +235 -0
- jam/paseto/v3.py +361 -0
- jam/paseto/v4.py +276 -0
- jam/sessions/__base__.py +202 -0
- jam/sessions/__init__.py +89 -0
- jam/sessions/json.py +192 -0
- jam/sessions/redis.py +247 -0
- jam/tests/__init__.py +5 -0
- jam/tests/clients.py +914 -0
- jam/tests/fakers.py +39 -0
- jam/utils/__init__.py +35 -0
- jam/utils/aes.py +8 -0
- jam/utils/await_maybe.py +22 -0
- jam/utils/basic_auth.py +47 -0
- jam/utils/config_maker.py +236 -0
- jam/utils/ed.py +50 -0
- jam/utils/otp_keys.py +48 -0
- jam/utils/rsa.py +46 -0
- jam/utils/salt_hash.py +114 -0
- jam/utils/symmetric.py +17 -0
- jam/utils/xchacha20poly1305.py +61 -0
- jam/utils/xor.py +35 -0
- jamlib-3.0.0a10.dist-info/METADATA +117 -0
- jamlib-3.0.0a10.dist-info/RECORD +93 -0
- jamlib-3.0.0a10.dist-info/WHEEL +5 -0
- jamlib-3.0.0a10.dist-info/licenses/LICENSE.md +173 -0
- jamlib-3.0.0a10.dist-info/top_level.txt +1 -0
jam/__base__.py
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
import gc
|
|
5
|
+
from typing import Any, Literal, Optional, Union
|
|
6
|
+
|
|
7
|
+
from jam.encoders import BaseEncoder, JsonEncoder
|
|
8
|
+
from jam.jwt.__base__ import BaseJWT
|
|
9
|
+
from jam.logger import BaseLogger, JamLogger
|
|
10
|
+
from jam.oauth2.__base__ import BaseOAuth2Client
|
|
11
|
+
from jam.sessions.__base__ import BaseSessionModule
|
|
12
|
+
from jam.utils.config_maker import __config_maker__, __module_loader__
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseJam(ABC):
|
|
16
|
+
"""Base jam instance."""
|
|
17
|
+
|
|
18
|
+
MODULES: dict[str, str] = {}
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
config: Union[str, dict[str, Any]] = "pyproject.toml",
|
|
23
|
+
pointer: str = "jam",
|
|
24
|
+
*,
|
|
25
|
+
logger: type(BaseLogger) = JamLogger,
|
|
26
|
+
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO",
|
|
27
|
+
serializer: Union[BaseEncoder, type[BaseEncoder]] = JsonEncoder,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Initialize instance.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
config (Union[str, dict[str, Any]]): Configuration
|
|
33
|
+
pointer (str): Pointer
|
|
34
|
+
logger (BaseLogger): Logger
|
|
35
|
+
serializer (Union[BaseEncoder, type[BaseBrowser]]): Serializer
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
None
|
|
39
|
+
"""
|
|
40
|
+
config = __config_maker__(config, pointer)
|
|
41
|
+
main_config = self.__build_main_config(config, logger, log_level, serializer)
|
|
42
|
+
|
|
43
|
+
logger = main_config["logger"]
|
|
44
|
+
log_level = main_config["log_level"]
|
|
45
|
+
serializer = main_config["serializer"]
|
|
46
|
+
|
|
47
|
+
self.__logger = logger(log_level)
|
|
48
|
+
self._serializer = serializer
|
|
49
|
+
self.jwt: Optional[BaseJWT] = None
|
|
50
|
+
self.session: Optional[BaseSessionModule] = None
|
|
51
|
+
self.oauth2: Optional[BaseOAuth2Client] = None
|
|
52
|
+
|
|
53
|
+
self.__logger.debug(f"Initializing BaseJam with log_level={log_level}, serializer={serializer}")
|
|
54
|
+
self.__build_instance(config)
|
|
55
|
+
self.__logger.debug(f"BaseJam initialization complete. Modules loaded: jwt={self.jwt is not None}, session={self.session is not None}, oauth2={self.oauth2 is not None}")
|
|
56
|
+
gc.collect()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def __build_main_config(
|
|
60
|
+
self,
|
|
61
|
+
config: dict[str, Any],
|
|
62
|
+
default_logger: type[BaseLogger],
|
|
63
|
+
default_log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
64
|
+
default_serializer: Union[BaseEncoder, type[BaseEncoder]],
|
|
65
|
+
) -> dict[str, Any]:
|
|
66
|
+
"""Build main params from config like logger, loglevel, etc.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
config (dict[str, Any]): Configuration dictionary
|
|
70
|
+
default_logger (type[BaseLogger]): Default logger class
|
|
71
|
+
default_log_level (Literal): Default log level
|
|
72
|
+
default_serializer (Union[BaseEncoder, type[BaseEncoder]]): Default serializer
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
dict[str, Any]: Dictionary with logger, log_level, and serializer
|
|
76
|
+
"""
|
|
77
|
+
logger = default_logger
|
|
78
|
+
log_level = default_log_level
|
|
79
|
+
serializer = default_serializer
|
|
80
|
+
|
|
81
|
+
# Read logger from config
|
|
82
|
+
if "logger" in config:
|
|
83
|
+
logger_cfg = config["logger"]
|
|
84
|
+
if isinstance(logger_cfg, str):
|
|
85
|
+
logger = __module_loader__(logger_cfg)
|
|
86
|
+
elif isinstance(logger_cfg, type) and issubclass(logger_cfg, BaseLogger):
|
|
87
|
+
logger = logger_cfg
|
|
88
|
+
|
|
89
|
+
if "log_level" in config:
|
|
90
|
+
log_level_cfg = config["log_level"]
|
|
91
|
+
if isinstance(log_level_cfg, str) and log_level_cfg.upper() in (
|
|
92
|
+
"DEBUG",
|
|
93
|
+
"INFO",
|
|
94
|
+
"WARNING",
|
|
95
|
+
"ERROR",
|
|
96
|
+
"CRITICAL",
|
|
97
|
+
):
|
|
98
|
+
log_level = log_level_cfg.upper()
|
|
99
|
+
|
|
100
|
+
if "serializer" in config:
|
|
101
|
+
serializer_cfg = config["serializer"]
|
|
102
|
+
if isinstance(serializer_cfg, str):
|
|
103
|
+
serializer = __module_loader__(serializer_cfg)
|
|
104
|
+
elif isinstance(serializer_cfg, type) and issubclass(
|
|
105
|
+
serializer_cfg, BaseEncoder
|
|
106
|
+
):
|
|
107
|
+
serializer = serializer_cfg
|
|
108
|
+
elif isinstance(serializer_cfg, BaseEncoder):
|
|
109
|
+
serializer = serializer_cfg
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
"logger": logger,
|
|
113
|
+
"log_level": log_level,
|
|
114
|
+
"serializer": serializer,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def __build_instance(self, config: dict[str, Any]) -> None:
|
|
120
|
+
"""Build instance.
|
|
121
|
+
|
|
122
|
+
Load modules from configuration and initialize them.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
config (dict[str, Any]): Configuration
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
None
|
|
129
|
+
"""
|
|
130
|
+
for name, path in self.MODULES.items():
|
|
131
|
+
if name not in config:
|
|
132
|
+
self.__logger.debug(f"Missing configuration for module {name}")
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
module_cls = __module_loader__(path)
|
|
137
|
+
self.__logger.debug(f"Loading module {name} from {path}")
|
|
138
|
+
params = config.get(name, {})
|
|
139
|
+
self.__logger.debug(f"Module {name} config params: {list(params.keys())}")
|
|
140
|
+
params["logger"] = self.__logger
|
|
141
|
+
params["serializer"] = self._serializer
|
|
142
|
+
module_instance = module_cls(**params)
|
|
143
|
+
self.__setattr__(name, module_instance)
|
|
144
|
+
self.__logger.debug(f"Module {name} initialized successfully")
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
self.__logger.error(
|
|
148
|
+
f"Failed to load module {name} from {path}: {e}",
|
|
149
|
+
exc_info=True
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
@abstractmethod
|
|
153
|
+
def jwt_make_payload(
|
|
154
|
+
self, exp: Optional[int], data: dict[str, Any]
|
|
155
|
+
) -> dict[str, Any]:
|
|
156
|
+
"""Make JWT-specific payload.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
exp (int | None): Token expire, if None -> use default
|
|
160
|
+
data (dict[str, Any]): Data to payload
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
dict[str, Any]: Payload
|
|
164
|
+
"""
|
|
165
|
+
raise NotImplementedError
|
|
166
|
+
|
|
167
|
+
@abstractmethod
|
|
168
|
+
def jwt_create_token(self, payload: dict[str, Any]) -> str:
|
|
169
|
+
"""Create JWT token.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
payload (dict[str, Any]): Data payload
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
str: New token
|
|
176
|
+
|
|
177
|
+
Raises:
|
|
178
|
+
EmptySecretKey: If the HMAC algorithm is selected, but the secret key is None
|
|
179
|
+
EmtpyPrivateKey: If RSA algorithm is selected, but private key None
|
|
180
|
+
"""
|
|
181
|
+
raise NotImplementedError
|
|
182
|
+
|
|
183
|
+
@abstractmethod
|
|
184
|
+
def jwt_verify_token(
|
|
185
|
+
self, token: str, check_exp: bool = True, check_list: bool = True
|
|
186
|
+
) -> dict[str, Any]:
|
|
187
|
+
"""Verify and decode JWT token.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
token (str): JWT token
|
|
191
|
+
check_exp (bool): Check expire
|
|
192
|
+
check_list (bool): Check white/black list. Docs: https://jam.makridenko.ru/jwt/lists/what/
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
dict[str, Any]: Decoded payload
|
|
196
|
+
|
|
197
|
+
Raises:
|
|
198
|
+
ValueError: If the token is invalid.
|
|
199
|
+
EmptySecretKey: If the HMAC algorithm is selected, but the secret key is None.
|
|
200
|
+
EmtpyPublicKey: If RSA algorithm is selected, but public key None.
|
|
201
|
+
NotFoundSomeInPayload: If 'exp' not found in payload.
|
|
202
|
+
TokenLifeTimeExpired: If token has expired.
|
|
203
|
+
TokenNotInWhiteList: If the list type is white, but the token is not there
|
|
204
|
+
TokenInBlackList: If the list type is black and the token is there
|
|
205
|
+
"""
|
|
206
|
+
raise NotImplementedError
|
|
207
|
+
|
|
208
|
+
@abstractmethod
|
|
209
|
+
def session_create(self, session_key: str, data: dict[str, Any]) -> str:
|
|
210
|
+
"""Create new session.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
session_key (str): Key for session
|
|
214
|
+
data (dict[str, Any]): Session data
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
str: New session ID
|
|
218
|
+
"""
|
|
219
|
+
raise NotImplementedError
|
|
220
|
+
|
|
221
|
+
@abstractmethod
|
|
222
|
+
def session_get(self, session_id: str) -> Optional[dict[str, Any]]:
|
|
223
|
+
"""Get data from session.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
session_id (str): Session ID
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
dict[str, Any] | None: Session data if exist
|
|
230
|
+
"""
|
|
231
|
+
raise NotImplementedError
|
|
232
|
+
|
|
233
|
+
@abstractmethod
|
|
234
|
+
def session_delete(self, session_id: str) -> None:
|
|
235
|
+
"""Delete session.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
session_id (str): Session ID
|
|
239
|
+
"""
|
|
240
|
+
raise NotImplementedError
|
|
241
|
+
|
|
242
|
+
@abstractmethod
|
|
243
|
+
def session_update(self, session_id: str, data: dict[str, Any]) -> None:
|
|
244
|
+
"""Update session data.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
session_id (str): Session ID
|
|
248
|
+
data (dict[str, Any]): New data
|
|
249
|
+
"""
|
|
250
|
+
raise NotImplementedError
|
|
251
|
+
|
|
252
|
+
@abstractmethod
|
|
253
|
+
def session_clear(self, session_key: str) -> None:
|
|
254
|
+
"""Delete all sessions by key.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
session_key (str): Key of session
|
|
258
|
+
"""
|
|
259
|
+
raise NotImplementedError
|
|
260
|
+
|
|
261
|
+
@abstractmethod
|
|
262
|
+
def session_rework(self, old_session_id: str) -> str:
|
|
263
|
+
"""Rework session.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
old_session_id (str): Old session id
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
str: New session id
|
|
270
|
+
"""
|
|
271
|
+
raise NotImplementedError
|
|
272
|
+
|
|
273
|
+
@abstractmethod
|
|
274
|
+
def otp_code(
|
|
275
|
+
self, secret: Union[str, bytes], factor: Optional[int] = None
|
|
276
|
+
) -> str:
|
|
277
|
+
"""Generates an OTP.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
secret (str | bytes): User secret key.
|
|
281
|
+
factor (int | None, optional): Unixtime for TOTP(if none, use now time) / Counter for HOTP.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
str: OTP code (fixed-length string).
|
|
285
|
+
"""
|
|
286
|
+
raise NotImplementedError
|
|
287
|
+
|
|
288
|
+
@abstractmethod
|
|
289
|
+
def otp_uri(
|
|
290
|
+
self,
|
|
291
|
+
secret: str,
|
|
292
|
+
name: Optional[str] = None,
|
|
293
|
+
issuer: Optional[str] = None,
|
|
294
|
+
counter: Optional[int] = None,
|
|
295
|
+
) -> str:
|
|
296
|
+
"""Generates an otpauth:// URI for Google Authenticator.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
secret (str): User secret key.
|
|
300
|
+
name (str): Account name (e.g., email).
|
|
301
|
+
issuer (str): Service name (e.g., "GitHub").
|
|
302
|
+
counter (int | None, optional): Counter (for HOTP). Default is None.
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
str: A string of the form "otpauth://..."
|
|
306
|
+
"""
|
|
307
|
+
raise NotImplementedError
|
|
308
|
+
|
|
309
|
+
@abstractmethod
|
|
310
|
+
def otp_verify_code(
|
|
311
|
+
self,
|
|
312
|
+
secret: Union[str, bytes],
|
|
313
|
+
code: str,
|
|
314
|
+
factor: Optional[int] = None,
|
|
315
|
+
look_ahead: Optional[int] = 1,
|
|
316
|
+
) -> bool:
|
|
317
|
+
"""Checks the OTP code, taking into account the acceptable window.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
secret (str | bytes): User secret key.
|
|
321
|
+
code (str): The code entered.
|
|
322
|
+
factor (int | None, optional): Unixtime for TOTP(if none, use now time) / Counter for HOTP.
|
|
323
|
+
look_ahead (int, optional): Acceptable deviation in intervals (±window(totp) / ±look ahead(hotp)). Default is 1.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
bool: True if the code matches, otherwise False.
|
|
327
|
+
"""
|
|
328
|
+
raise NotImplementedError
|
|
329
|
+
|
|
330
|
+
@abstractmethod
|
|
331
|
+
def oauth2_get_authorized_url(
|
|
332
|
+
self, provider: str, scope: list[str], **extra_params: Any
|
|
333
|
+
) -> str:
|
|
334
|
+
"""Generate full OAuth2 authorization URL.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
provider (str): Provider name
|
|
338
|
+
scope (list[str]): Auth scope
|
|
339
|
+
extra_params (Any): Extra ath params
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
str: Authorization url
|
|
343
|
+
"""
|
|
344
|
+
raise NotImplementedError
|
|
345
|
+
|
|
346
|
+
@abstractmethod
|
|
347
|
+
def oauth2_fetch_token(
|
|
348
|
+
self,
|
|
349
|
+
provider: str,
|
|
350
|
+
code: str,
|
|
351
|
+
grant_type: str = "authorization_code",
|
|
352
|
+
**extra_params: Any,
|
|
353
|
+
) -> dict[str, Any]:
|
|
354
|
+
"""Exchange authorization code for access token.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
provider (str): Provider name
|
|
358
|
+
code (str): OAuth2 code
|
|
359
|
+
grant_type (str): Type of oauth2 grant
|
|
360
|
+
extra_params (Any): Extra auth params if needed
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
dict: OAuth2 token
|
|
364
|
+
"""
|
|
365
|
+
raise NotImplementedError
|
|
366
|
+
|
|
367
|
+
@abstractmethod
|
|
368
|
+
def oauth2_refresh_token(
|
|
369
|
+
self,
|
|
370
|
+
provider: str,
|
|
371
|
+
refresh_token: str,
|
|
372
|
+
grant_type: str = "refresh_token",
|
|
373
|
+
**extra_params: Any,
|
|
374
|
+
) -> dict[str, Any]:
|
|
375
|
+
"""Use refresh token to obtain a new access token.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
provider (str): Provider name
|
|
379
|
+
refresh_token (str): Refresh token
|
|
380
|
+
grant_type (str): Grant type
|
|
381
|
+
extra_params (Any): Extra auth params if needed
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
dict: Refresh token
|
|
385
|
+
"""
|
|
386
|
+
raise NotImplementedError
|
|
387
|
+
|
|
388
|
+
@abstractmethod
|
|
389
|
+
def oauth2_client_credentials_flow(
|
|
390
|
+
self,
|
|
391
|
+
provider: str,
|
|
392
|
+
scope: Optional[list[str]] = None,
|
|
393
|
+
**extra_params: Any,
|
|
394
|
+
) -> dict[str, Any]:
|
|
395
|
+
"""Obtain access token using client credentials flow (no user interaction).
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
provider (str): Provider name
|
|
399
|
+
scope (list[str] | None): Auth scope
|
|
400
|
+
extra_params (Any): Extra auth params if needed
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
dict: JSON with access token
|
|
404
|
+
"""
|
|
405
|
+
raise NotImplementedError
|
|
406
|
+
|
|
407
|
+
@abstractmethod
|
|
408
|
+
def paseto_make_payload(
|
|
409
|
+
self, exp: Optional[int] = None, **data: dict[str, Any]
|
|
410
|
+
) -> dict[str, Any]:
|
|
411
|
+
"""Generate payload for PASETO.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
exp (int | None): Custom expire if needed
|
|
415
|
+
data (dict[str, Any]): Data in payload
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
dict[str, Any]: New payload
|
|
419
|
+
"""
|
|
420
|
+
raise NotImplementedError
|
|
421
|
+
|
|
422
|
+
@abstractmethod
|
|
423
|
+
def paseto_create(
|
|
424
|
+
self,
|
|
425
|
+
payload: dict[str, Any],
|
|
426
|
+
footer: Optional[Union[dict[str, Any], str]],
|
|
427
|
+
) -> str:
|
|
428
|
+
"""Create new PASETO.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
payload (dict[str, Any]): Payload
|
|
432
|
+
footer (dict[str, Any] | str | None): Payload if needed
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
str: PASETO
|
|
436
|
+
"""
|
|
437
|
+
raise NotImplementedError
|
|
438
|
+
|
|
439
|
+
@abstractmethod
|
|
440
|
+
def paseto_decode( # mb refactoring this
|
|
441
|
+
self, token: str
|
|
442
|
+
) -> dict[str, Union[dict, Union[str, dict, None]]]:
|
|
443
|
+
"""Decode PASETO and return payload and footer.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
token (str): PASETO
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
dict: {`payload`: PAYLOAD, `footer`: FOOTER}
|
|
450
|
+
"""
|
|
451
|
+
raise NotImplementedError
|
jam/__base_encoder__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any, Union
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseEncoder(ABC):
|
|
8
|
+
"""Base encoder instance."""
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def dumps(cls, var: dict[str, Any]) -> bytes:
|
|
13
|
+
"""Dump dict."""
|
|
14
|
+
raise NotImplementedError
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def loads(cls, var: Union[str, bytes]) -> dict[str, Any]:
|
|
19
|
+
"""Load json."""
|
|
20
|
+
raise NotImplementedError
|
jam/__deprecated__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from typing import Optional
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def deprecated(replacement: Optional[str] = None):
|
|
9
|
+
"""Mark funcs are deprecated."""
|
|
10
|
+
|
|
11
|
+
def decorator(func):
|
|
12
|
+
msg = f"Function {func.__name__}() is deprecated."
|
|
13
|
+
if replacement:
|
|
14
|
+
msg += f" {replacement}"
|
|
15
|
+
|
|
16
|
+
@functools.wraps(func)
|
|
17
|
+
def wrapper(*args, **kwargs):
|
|
18
|
+
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
|
|
19
|
+
return func(*args, **kwargs)
|
|
20
|
+
|
|
21
|
+
wrapper.__deprecated__ = True
|
|
22
|
+
wrapper.__doc__ = (
|
|
23
|
+
func.__doc__ or ""
|
|
24
|
+
) + f"\n\n⚠️ Deprecated: {replacement or ''}".strip()
|
|
25
|
+
return wrapper
|
|
26
|
+
|
|
27
|
+
return decorator
|
jam/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
JAM - Universal auth* library
|
|
5
|
+
|
|
6
|
+
Source code: https://github.com/lyaguxafrog/jam
|
|
7
|
+
Documentation: https://jam.makridenko.ru
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from jam.__base_encoder__ import BaseEncoder
|
|
11
|
+
from jam.__base__ import BaseJam
|
|
12
|
+
from jam.encoders import JsonEncoder
|
|
13
|
+
from jam.instance import Jam
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
__version__ = "3.0.0a10"
|
|
17
|
+
__all__ = ["Jam", "JsonEncoder", "BaseJam", "BaseEncoder"]
|