pypomes-jwt 1.1.3__py3-none-any.whl → 1.1.5__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.
Potentially problematic release.
This version of pypomes-jwt might be problematic. Click here for more details.
- pypomes_jwt/__init__.py +1 -1
- pypomes_jwt/{jwt_configuration.py → jwt_config.py} +3 -4
- pypomes_jwt/jwt_pomes.py +20 -19
- pypomes_jwt/jwt_registry.py +33 -45
- {pypomes_jwt-1.1.3.dist-info → pypomes_jwt-1.1.5.dist-info}/METADATA +3 -3
- pypomes_jwt-1.1.5.dist-info/RECORD +8 -0
- pypomes_jwt-1.1.3.dist-info/RECORD +0 -8
- {pypomes_jwt-1.1.3.dist-info → pypomes_jwt-1.1.5.dist-info}/WHEEL +0 -0
- {pypomes_jwt-1.1.3.dist-info → pypomes_jwt-1.1.5.dist-info}/licenses/LICENSE +0 -0
pypomes_jwt/__init__.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from cryptography.hazmat.primitives import serialization
|
|
2
2
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
3
3
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
|
|
4
|
-
from enum import Enum
|
|
4
|
+
from enum import Enum, StrEnum
|
|
5
5
|
from pypomes_core import (
|
|
6
6
|
APP_PREFIX,
|
|
7
7
|
env_get_str, env_get_bytes, env_get_int
|
|
8
8
|
)
|
|
9
|
-
from pypomes_db import DbEngine
|
|
10
9
|
from secrets import token_bytes
|
|
11
10
|
|
|
12
11
|
|
|
@@ -51,11 +50,11 @@ class JwtConfig(Enum):
|
|
|
51
50
|
def_value=86400)
|
|
52
51
|
|
|
53
52
|
|
|
54
|
-
class JwtDbConfig(
|
|
53
|
+
class JwtDbConfig(StrEnum):
|
|
55
54
|
"""
|
|
56
55
|
Parameters for JWT databse connection.
|
|
57
56
|
"""
|
|
58
|
-
ENGINE: str =
|
|
57
|
+
ENGINE: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE")
|
|
59
58
|
TABLE: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE")
|
|
60
59
|
COL_ACCOUNT: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ACCOUNT")
|
|
61
60
|
COL_ALGORITHM: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ALGORITHM")
|
pypomes_jwt/jwt_pomes.py
CHANGED
|
@@ -5,11 +5,12 @@ from flask import Request, Response, request
|
|
|
5
5
|
from logging import Logger
|
|
6
6
|
from pypomes_core import exc_format
|
|
7
7
|
from pypomes_db import (
|
|
8
|
-
db_connect, db_commit,
|
|
8
|
+
DbEngine, db_connect, db_commit,
|
|
9
|
+
db_rollback, db_select, db_delete
|
|
9
10
|
)
|
|
10
11
|
from typing import Any
|
|
11
12
|
|
|
12
|
-
from .
|
|
13
|
+
from .jwt_config import JwtConfig, JwtDbConfig
|
|
13
14
|
from .jwt_registry import JwtRegistry
|
|
14
15
|
|
|
15
16
|
# the JWT registry
|
|
@@ -177,15 +178,15 @@ def jwt_validate_token(errors: list[str] | None,
|
|
|
177
178
|
elif token_kid and len(token_kid) > 1 and \
|
|
178
179
|
token_kid[0:1] in ["A", "R"] and token_kid[1:].isdigit():
|
|
179
180
|
# token was likely issued locally
|
|
180
|
-
where_data: dict[str, Any] = {JwtDbConfig.COL_KID
|
|
181
|
+
where_data: dict[str, Any] = {JwtDbConfig.COL_KID: int(token_kid[1:])}
|
|
181
182
|
if account_id:
|
|
182
|
-
where_data[JwtDbConfig.COL_ACCOUNT
|
|
183
|
+
where_data[JwtDbConfig.COL_ACCOUNT] = account_id
|
|
183
184
|
recs: list[tuple[str]] = db_select(errors=op_errors,
|
|
184
|
-
sel_stmt=f"SELECT {JwtDbConfig.COL_ALGORITHM
|
|
185
|
-
f"{JwtDbConfig.COL_DECODER
|
|
186
|
-
f"FROM {JwtDbConfig.TABLE
|
|
185
|
+
sel_stmt=f"SELECT {JwtDbConfig.COL_ALGORITHM}, "
|
|
186
|
+
f"{JwtDbConfig.COL_DECODER} "
|
|
187
|
+
f"FROM {JwtDbConfig.TABLE}",
|
|
187
188
|
where_data=where_data,
|
|
188
|
-
engine=JwtDbConfig.ENGINE
|
|
189
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
189
190
|
logger=logger)
|
|
190
191
|
if recs:
|
|
191
192
|
token_alg = recs[0][0]
|
|
@@ -279,12 +280,12 @@ def jwt_revoke_token(errors: list[str] | None,
|
|
|
279
280
|
op_errors.append("Invalid token")
|
|
280
281
|
else:
|
|
281
282
|
db_delete(errors=op_errors,
|
|
282
|
-
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE
|
|
283
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
|
|
283
284
|
where_data={
|
|
284
|
-
JwtDbConfig.COL_KID
|
|
285
|
-
JwtDbConfig.COL_ACCOUNT
|
|
285
|
+
JwtDbConfig.COL_KID: int(token_kid[1:]),
|
|
286
|
+
JwtDbConfig.COL_ACCOUNT: account_id
|
|
286
287
|
},
|
|
287
|
-
engine=JwtDbConfig.ENGINE
|
|
288
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
288
289
|
logger=logger)
|
|
289
290
|
if op_errors:
|
|
290
291
|
if logger:
|
|
@@ -450,17 +451,17 @@ def jwt_refresh_tokens(errors: list[str] | None,
|
|
|
450
451
|
# start the database transaction
|
|
451
452
|
db_conn: Any = db_connect(errors=op_errors,
|
|
452
453
|
autocommit=False,
|
|
453
|
-
engine=JwtDbConfig.ENGINE
|
|
454
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
454
455
|
logger=logger)
|
|
455
456
|
if db_conn:
|
|
456
457
|
# delete current refresh token
|
|
457
458
|
db_delete(errors=op_errors,
|
|
458
|
-
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE
|
|
459
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
|
|
459
460
|
where_data={
|
|
460
|
-
JwtDbConfig.COL_KID
|
|
461
|
-
JwtDbConfig.COL_ACCOUNT
|
|
461
|
+
JwtDbConfig.COL_KID: int(token_kid[1:]),
|
|
462
|
+
JwtDbConfig.COL_ACCOUNT: account_id
|
|
462
463
|
},
|
|
463
|
-
engine=JwtDbConfig.ENGINE
|
|
464
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
464
465
|
connection=db_conn,
|
|
465
466
|
committable=False,
|
|
466
467
|
logger=logger)
|
|
@@ -510,8 +511,8 @@ def jwt_get_claims(errors: list[str] | None,
|
|
|
510
511
|
"""
|
|
511
512
|
Retrieve and return the claims set of a JWT *token*.
|
|
512
513
|
|
|
513
|
-
Any well-constructed JWT token may be provided in *token*, as this operation is not restricted
|
|
514
|
-
locally issued tokens. Note that neither the token's signature nor its expiration is verified.
|
|
514
|
+
Any well-constructed JWT token may be provided in *token*, as this operation is not restricted
|
|
515
|
+
to locally issued tokens. Note that neither the token's signature nor its expiration is verified.
|
|
515
516
|
|
|
516
517
|
Structure of the returned data, for locally issued tokens:
|
|
517
518
|
{
|
pypomes_jwt/jwt_registry.py
CHANGED
|
@@ -6,13 +6,13 @@ from datetime import datetime, timezone
|
|
|
6
6
|
from logging import Logger
|
|
7
7
|
from pypomes_core import str_random
|
|
8
8
|
from pypomes_db import (
|
|
9
|
-
db_connect, db_commit, db_rollback,
|
|
9
|
+
DbEngine, db_connect, db_commit, db_rollback,
|
|
10
10
|
db_select, db_insert, db_update, db_delete
|
|
11
11
|
)
|
|
12
12
|
from threading import Lock
|
|
13
13
|
from typing import Any
|
|
14
14
|
|
|
15
|
-
from .
|
|
15
|
+
from .jwt_config import JwtConfig, JwtDbConfig
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class JwtRegistry:
|
|
@@ -139,9 +139,9 @@ class JwtRegistry:
|
|
|
139
139
|
|
|
140
140
|
# remove from database
|
|
141
141
|
db_delete(errors=None,
|
|
142
|
-
delete_stmt=f"DELETE FROM {JwtDbConfig
|
|
143
|
-
where_data={JwtDbConfig.COL_ACCOUNT
|
|
144
|
-
engine=JwtDbConfig.ENGINE
|
|
142
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig}",
|
|
143
|
+
where_data={JwtDbConfig.COL_ACCOUNT: account_id},
|
|
144
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
145
145
|
logger=logger)
|
|
146
146
|
if logger:
|
|
147
147
|
if account_data:
|
|
@@ -205,14 +205,8 @@ class JwtRegistry:
|
|
|
205
205
|
current_claims["iat"] = just_now
|
|
206
206
|
if grace_interval:
|
|
207
207
|
current_claims["nbf"] = just_now + grace_interval
|
|
208
|
-
current_claims["valid-from"] = datetime.fromtimestamp(timestamp=current_claims["nbf"],
|
|
209
|
-
tz=timezone.utc).isoformat()
|
|
210
|
-
else:
|
|
211
|
-
current_claims["valid-from"] = datetime.fromtimestamp(timestamp=current_claims["iat"],
|
|
212
|
-
tz=timezone.utc).isoformat()
|
|
213
208
|
current_claims["exp"] = just_now + duration
|
|
214
|
-
|
|
215
|
-
tz=timezone.utc).isoformat()
|
|
209
|
+
|
|
216
210
|
# may raise an exception
|
|
217
211
|
return jwt.encode(payload=current_claims,
|
|
218
212
|
key=JwtConfig.ENCODING_KEY.value,
|
|
@@ -265,15 +259,9 @@ class JwtRegistry:
|
|
|
265
259
|
grace_interval = account_data.get("grace-interval")
|
|
266
260
|
if grace_interval:
|
|
267
261
|
current_claims["nbf"] = just_now + grace_interval
|
|
268
|
-
|
|
269
|
-
tz=timezone.utc).isoformat()
|
|
270
|
-
else:
|
|
271
|
-
current_claims["valid-from"] = datetime.fromtimestamp(timestamp=current_claims["iat"],
|
|
272
|
-
tz=timezone.utc).isoformat()
|
|
262
|
+
|
|
273
263
|
# issue a candidate refresh token first, and persist it
|
|
274
264
|
current_claims["exp"] = just_now + account_data.get("refresh-max-age")
|
|
275
|
-
current_claims["valid-until"] = datetime.fromtimestamp(timestamp=current_claims["exp"],
|
|
276
|
-
tz=timezone.utc).isoformat()
|
|
277
265
|
# may raise an exception
|
|
278
266
|
refresh_token: str = jwt.encode(payload=current_claims,
|
|
279
267
|
key=JwtConfig.ENCODING_KEY.value,
|
|
@@ -283,7 +271,7 @@ class JwtRegistry:
|
|
|
283
271
|
# make sure to have a database connection
|
|
284
272
|
curr_conn: Any = db_conn or db_connect(errors=errors,
|
|
285
273
|
autocommit=False,
|
|
286
|
-
engine=JwtDbConfig.ENGINE
|
|
274
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
287
275
|
logger=logger)
|
|
288
276
|
if curr_conn:
|
|
289
277
|
# persist the candidate token (may raise an exception)
|
|
@@ -298,10 +286,10 @@ class JwtRegistry:
|
|
|
298
286
|
headers={"kid": f"R{token_id}"})
|
|
299
287
|
# persist it
|
|
300
288
|
db_update(errors=errors,
|
|
301
|
-
update_stmt=f"UPDATE {JwtDbConfig.TABLE
|
|
302
|
-
update_data={JwtDbConfig.COL_TOKEN
|
|
303
|
-
where_data={JwtDbConfig.COL_KID
|
|
304
|
-
engine=JwtDbConfig.ENGINE
|
|
289
|
+
update_stmt=f"UPDATE {JwtDbConfig.TABLE}",
|
|
290
|
+
update_data={JwtDbConfig.COL_TOKEN: refresh_token},
|
|
291
|
+
where_data={JwtDbConfig.COL_KID: token_id},
|
|
292
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
305
293
|
connection=curr_conn,
|
|
306
294
|
committable=False,
|
|
307
295
|
logger=logger)
|
|
@@ -382,10 +370,10 @@ def _jwt_persist_token(account_id: str,
|
|
|
382
370
|
# noinspection PyTypeChecker
|
|
383
371
|
recs: list[tuple[int, str, str, str]] = \
|
|
384
372
|
db_select(errors=errors,
|
|
385
|
-
sel_stmt=f"SELECT {JwtDbConfig.COL_KID
|
|
386
|
-
f"FROM {JwtDbConfig.TABLE
|
|
387
|
-
where_data={JwtDbConfig.COL_ACCOUNT
|
|
388
|
-
engine=JwtDbConfig.ENGINE
|
|
373
|
+
sel_stmt=f"SELECT {JwtDbConfig.COL_KID}, {JwtDbConfig.COL_TOKEN} "
|
|
374
|
+
f"FROM {JwtDbConfig.TABLE}",
|
|
375
|
+
where_data={JwtDbConfig.COL_ACCOUNT: account_id},
|
|
376
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
389
377
|
connection=db_conn,
|
|
390
378
|
committable=False,
|
|
391
379
|
logger=logger)
|
|
@@ -426,9 +414,9 @@ def _jwt_persist_token(account_id: str,
|
|
|
426
414
|
# remove expired tokens from persistence
|
|
427
415
|
if expired:
|
|
428
416
|
db_delete(errors=errors,
|
|
429
|
-
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE
|
|
430
|
-
where_data={JwtDbConfig.COL_KID
|
|
431
|
-
engine=JwtDbConfig.ENGINE
|
|
417
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
|
|
418
|
+
where_data={JwtDbConfig.COL_KID: expired},
|
|
419
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
432
420
|
connection=db_conn,
|
|
433
421
|
committable=False,
|
|
434
422
|
logger=logger)
|
|
@@ -441,9 +429,9 @@ def _jwt_persist_token(account_id: str,
|
|
|
441
429
|
if 0 < JwtConfig.ACCOUNT_LIMIT.value <= len(recs) - len(expired):
|
|
442
430
|
# delete the oldest token to make way for the new one
|
|
443
431
|
db_delete(errors=errors,
|
|
444
|
-
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE
|
|
445
|
-
where_data={JwtDbConfig.COL_KID
|
|
446
|
-
engine=JwtDbConfig.ENGINE
|
|
432
|
+
delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
|
|
433
|
+
where_data={JwtDbConfig.COL_KID: oldest_id},
|
|
434
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
447
435
|
connection=db_conn,
|
|
448
436
|
committable=False,
|
|
449
437
|
logger=logger)
|
|
@@ -454,14 +442,14 @@ def _jwt_persist_token(account_id: str,
|
|
|
454
442
|
f"'{account_id}' removed from storage")
|
|
455
443
|
# persist token
|
|
456
444
|
db_insert(errors=errors,
|
|
457
|
-
insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE
|
|
445
|
+
insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE}",
|
|
458
446
|
insert_data={
|
|
459
|
-
JwtDbConfig.COL_ACCOUNT
|
|
460
|
-
JwtDbConfig.COL_TOKEN
|
|
461
|
-
JwtDbConfig.COL_ALGORITHM
|
|
462
|
-
JwtDbConfig.COL_DECODER
|
|
447
|
+
JwtDbConfig.COL_ACCOUNT: account_id,
|
|
448
|
+
JwtDbConfig.COL_TOKEN: jwt_token,
|
|
449
|
+
JwtDbConfig.COL_ALGORITHM: JwtConfig.DEFAULT_ALGORITHM.value,
|
|
450
|
+
JwtDbConfig.COL_DECODER: urlsafe_b64encode(s=JwtConfig.DECODING_KEY.value).decode()
|
|
463
451
|
},
|
|
464
|
-
engine=JwtDbConfig.ENGINE
|
|
452
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
465
453
|
connection=db_conn,
|
|
466
454
|
committable=False,
|
|
467
455
|
logger=logger)
|
|
@@ -472,15 +460,15 @@ def _jwt_persist_token(account_id: str,
|
|
|
472
460
|
# HAZARD: JWT_DB_COL_TOKEN's column type might prevent it for being used in a WHERE clause
|
|
473
461
|
where_clause: str | None = None
|
|
474
462
|
if existing_ids:
|
|
475
|
-
where_clause = f"{JwtDbConfig.COL_KID
|
|
463
|
+
where_clause = f"{JwtDbConfig.COL_KID} NOT IN {existing_ids}"
|
|
476
464
|
where_clause = where_clause.replace("[", "(", 1).replace("]", ")", 1)
|
|
477
465
|
reply: list[tuple[int]] = db_select(errors=errors,
|
|
478
|
-
sel_stmt=f"SELECT {JwtDbConfig.COL_KID
|
|
479
|
-
f"FROM {JwtDbConfig.TABLE
|
|
466
|
+
sel_stmt=f"SELECT {JwtDbConfig.COL_KID} "
|
|
467
|
+
f"FROM {JwtDbConfig.TABLE}",
|
|
480
468
|
where_clause=where_clause,
|
|
481
|
-
where_data={JwtDbConfig.COL_ACCOUNT
|
|
469
|
+
where_data={JwtDbConfig.COL_ACCOUNT: account_id},
|
|
482
470
|
require_count=1,
|
|
483
|
-
engine=JwtDbConfig.ENGINE
|
|
471
|
+
engine=DbEngine(JwtDbConfig.ENGINE),
|
|
484
472
|
connection=db_conn,
|
|
485
473
|
committable=False,
|
|
486
474
|
logger=logger)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_jwt
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.5
|
|
4
4
|
Summary: A collection of Python pomes, penyeach (JWT module)
|
|
5
5
|
Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-JWT
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-JWT/issues
|
|
@@ -12,5 +12,5 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Requires-Dist: cryptography>=44.0.2
|
|
14
14
|
Requires-Dist: pyjwt>=2.10.1
|
|
15
|
-
Requires-Dist: pypomes-core>=
|
|
16
|
-
Requires-Dist: pypomes-db>=2.
|
|
15
|
+
Requires-Dist: pypomes-core>=2.0.4
|
|
16
|
+
Requires-Dist: pypomes-db>=2.1.1
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pypomes_jwt/__init__.py,sha256=NZzjWKnhjxNuoE32V6soKo9sG5ypmt25V0mBAh3rAIs,793
|
|
2
|
+
pypomes_jwt/jwt_config.py,sha256=mtihd58_O00FuFXcNBKsabftG6UHu3Cj24i6cZXoskc,3096
|
|
3
|
+
pypomes_jwt/jwt_pomes.py,sha256=5B5xYA6Z3zJvYwYTZoqD1sH1mraSwdYQVKEvVx2fCSY,23517
|
|
4
|
+
pypomes_jwt/jwt_registry.py,sha256=gMnximiWagh7OkoXEM6msvdXdrXIqosolbyajTIbhTs,22372
|
|
5
|
+
pypomes_jwt-1.1.5.dist-info/METADATA,sha256=tzzNQQ4bebsCN_N7qgDkuoI0D82IMKCnNsubQn_Vw_k,632
|
|
6
|
+
pypomes_jwt-1.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
+
pypomes_jwt-1.1.5.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
8
|
+
pypomes_jwt-1.1.5.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
pypomes_jwt/__init__.py,sha256=g4tjg7gt5_vwiHM_6-T6Ji4XYJ5py9RuzGmF2Z-qlXI,800
|
|
2
|
-
pypomes_jwt/jwt_configuration.py,sha256=mqTPblkfb4RXAzUe28T2gCk1auCYVY7gIlz2iFK4JSg,3127
|
|
3
|
-
pypomes_jwt/jwt_pomes.py,sha256=OkkzKc87eviEovAPIlGJlFlMIKooSivTB9LvX2137mg,23559
|
|
4
|
-
pypomes_jwt/jwt_registry.py,sha256=NEIYE15j4MnKaGVKp42WjriBzekvDZVTHFXP08EOcXA,23687
|
|
5
|
-
pypomes_jwt-1.1.3.dist-info/METADATA,sha256=dm8aTZMrvDbHxcpLvp07PDw1F_pZSef6DLeXnoVPqbo,632
|
|
6
|
-
pypomes_jwt-1.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
pypomes_jwt-1.1.3.dist-info/licenses/LICENSE,sha256=NdakochSXm_H_-DSL_x2JlRCkYikj3snYYvTwgR5d_c,1086
|
|
8
|
-
pypomes_jwt-1.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|