pypomes-jwt 1.1.3__tar.gz → 1.1.5__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.

Potentially problematic release.


This version of pypomes-jwt might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypomes_jwt
3
- Version: 1.1.3
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>=1.9.9
16
- Requires-Dist: pypomes-db>=2.0.9
15
+ Requires-Dist: pypomes-core>=2.0.4
16
+ Requires-Dist: pypomes-db>=2.1.1
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "pypomes_jwt"
9
- version = "1.1.3"
9
+ version = "1.1.5"
10
10
  authors = [
11
11
  { name="GT Nunes", email="wisecoder01@gmail.com" }
12
12
  ]
@@ -21,8 +21,8 @@ classifiers = [
21
21
  dependencies = [
22
22
  "PyJWT>=2.10.1",
23
23
  "cryptography>=44.0.2",
24
- "pypomes_core>=1.9.9",
25
- "pypomes_db>=2.0.9"
24
+ "pypomes_core>=2.0.4",
25
+ "pypomes_db>=2.1.1"
26
26
  ]
27
27
 
28
28
  [project.urls]
@@ -1,4 +1,4 @@
1
- from .jwt_configuration import (
1
+ from .jwt_config import (
2
2
  JwtConfig, JwtDbConfig
3
3
  )
4
4
  from .jwt_pomes import (
@@ -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(Enum):
53
+ class JwtDbConfig(StrEnum):
55
54
  """
56
55
  Parameters for JWT databse connection.
57
56
  """
58
- ENGINE: str = DbEngine(env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE"))
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")
@@ -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, db_rollback, db_select, db_delete
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 .jwt_configuration import JwtConfig, JwtDbConfig
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.value: int(token_kid[1:])}
181
+ where_data: dict[str, Any] = {JwtDbConfig.COL_KID: int(token_kid[1:])}
181
182
  if account_id:
182
- where_data[JwtDbConfig.COL_ACCOUNT.value] = account_id
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.value}, "
185
- f"{JwtDbConfig.COL_DECODER.value} "
186
- f"FROM {JwtDbConfig.TABLE.value}",
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.value,
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.value}",
283
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
283
284
  where_data={
284
- JwtDbConfig.COL_KID.value: int(token_kid[1:]),
285
- JwtDbConfig.COL_ACCOUNT.value: account_id
285
+ JwtDbConfig.COL_KID: int(token_kid[1:]),
286
+ JwtDbConfig.COL_ACCOUNT: account_id
286
287
  },
287
- engine=JwtDbConfig.ENGINE.value,
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.value,
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.value}",
459
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
459
460
  where_data={
460
- JwtDbConfig.COL_KID.value: int(token_kid[1:]),
461
- JwtDbConfig.COL_ACCOUNT.value: account_id
461
+ JwtDbConfig.COL_KID: int(token_kid[1:]),
462
+ JwtDbConfig.COL_ACCOUNT: account_id
462
463
  },
463
- engine=JwtDbConfig.ENGINE.value,
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 to
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
  {
@@ -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 .jwt_configuration import JwtConfig, JwtDbConfig
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.value}",
143
- where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
144
- engine=JwtDbConfig.ENGINE.value,
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
- current_claims["valid-until"] = datetime.fromtimestamp(timestamp=current_claims["exp"],
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
- current_claims["valid-from"] = datetime.fromtimestamp(timestamp=current_claims["nbf"],
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.value,
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.value}",
302
- update_data={JwtDbConfig.COL_TOKEN.value: refresh_token},
303
- where_data={JwtDbConfig.COL_KID.value: token_id},
304
- engine=JwtDbConfig.ENGINE.value,
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.value}, {JwtDbConfig.COL_TOKEN.value} "
386
- f"FROM {JwtDbConfig.TABLE.value}",
387
- where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
388
- engine=JwtDbConfig.ENGINE.value,
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.value}",
430
- where_data={JwtDbConfig.COL_KID.value: expired},
431
- engine=JwtDbConfig.ENGINE.value,
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.value}",
445
- where_data={JwtDbConfig.COL_KID.value: oldest_id},
446
- engine=JwtDbConfig.ENGINE.value,
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.value}",
445
+ insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE}",
458
446
  insert_data={
459
- JwtDbConfig.COL_ACCOUNT.value: account_id,
460
- JwtDbConfig.COL_TOKEN.value: jwt_token,
461
- JwtDbConfig.COL_ALGORITHM.value: JwtConfig.DEFAULT_ALGORITHM.value,
462
- JwtDbConfig.COL_DECODER.value: urlsafe_b64encode(s=JwtConfig.DECODING_KEY.value).decode()
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.value,
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.value} NOT IN {existing_ids}"
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.value} "
479
- f"FROM {JwtDbConfig.TABLE.value}",
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.value: account_id},
469
+ where_data={JwtDbConfig.COL_ACCOUNT: account_id},
482
470
  require_count=1,
483
- engine=JwtDbConfig.ENGINE.value,
471
+ engine=DbEngine(JwtDbConfig.ENGINE),
484
472
  connection=db_conn,
485
473
  committable=False,
486
474
  logger=logger)
File without changes
File without changes
File without changes