pypomes-jwt 1.1.1__tar.gz → 1.1.3__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.1
3
+ Version: 1.1.3
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.8
15
+ Requires-Dist: pypomes-core>=1.9.9
16
16
  Requires-Dist: pypomes-db>=2.0.9
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "pypomes_jwt"
9
- version = "1.1.1"
9
+ version = "1.1.3"
10
10
  authors = [
11
11
  { name="GT Nunes", email="wisecoder01@gmail.com" }
12
12
  ]
@@ -21,7 +21,7 @@ classifiers = [
21
21
  dependencies = [
22
22
  "PyJWT>=2.10.1",
23
23
  "cryptography>=44.0.2",
24
- "pypomes_core>=1.9.8",
24
+ "pypomes_core>=1.9.9",
25
25
  "pypomes_db>=2.0.9"
26
26
  ]
27
27
 
@@ -6,9 +6,8 @@ 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, db_setup
9
+ from pypomes_db import DbEngine
10
10
  from secrets import token_bytes
11
- from sys import stderr
12
11
 
13
12
 
14
13
  # recommended: allow the encode and decode keys to be generated anew when app starts
@@ -57,29 +56,9 @@ class JwtDbConfig(Enum):
57
56
  Parameters for JWT databse connection.
58
57
  """
59
58
  ENGINE: str = DbEngine(env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE"))
60
- CLIENT: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_CLIENT") # for Oracle, only
61
- DRIVER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_DRIVER") # for SQLServer, only
62
- NAME: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_NAME")
63
- HOST: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_HOST")
64
- PORT: int = env_get_int(key=f"{APP_PREFIX}_JWT_DB_PORT")
65
- USER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_USER")
66
- PWD: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_PWD")
67
59
  TABLE: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE")
68
60
  COL_ACCOUNT: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ACCOUNT")
69
61
  COL_ALGORITHM: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ALGORITHM")
70
62
  COL_DECODER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_DECODER")
71
63
  COL_KID: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_KID")
72
64
  COL_TOKEN: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_TOKEN")
73
-
74
-
75
- # define and validate the database engine
76
- # noinspection PyTypeChecker
77
- if not db_setup(engine=DbEngine(JwtDbConfig.ENGINE),
78
- db_name=JwtDbConfig.NAME,
79
- db_user=JwtDbConfig.USER,
80
- db_pwd=JwtDbConfig.PWD,
81
- db_host=JwtDbConfig.HOST,
82
- db_port=JwtDbConfig.PORT,
83
- db_client=JwtDbConfig.CLIENT,
84
- db_driver=JwtDbConfig.DRIVER):
85
- stderr.write("Invalid database parameters\n")
@@ -75,8 +75,8 @@ def jwt_assert_account(account_id: str) -> bool:
75
75
 
76
76
  def jwt_set_account(account_id: str,
77
77
  claims: dict[str, Any],
78
- access_max_age: int = JwtConfig.ACCESS_MAX_AGE,
79
- refresh_max_age: int = JwtConfig.REFRESH_MAX_AGE,
78
+ access_max_age: int = JwtConfig.ACCESS_MAX_AGE.value,
79
+ refresh_max_age: int = JwtConfig.REFRESH_MAX_AGE.value,
80
80
  grace_interval: int = None,
81
81
  logger: Logger = None) -> None:
82
82
  """
@@ -177,16 +177,15 @@ def jwt_validate_token(errors: list[str] | None,
177
177
  elif token_kid and len(token_kid) > 1 and \
178
178
  token_kid[0:1] in ["A", "R"] and token_kid[1:].isdigit():
179
179
  # token was likely issued locally
180
- where_data: dict[str, Any] = {
181
- str(JwtDbConfig.COL_KID): int(token_kid[1:])
182
- }
180
+ where_data: dict[str, Any] = {JwtDbConfig.COL_KID.value: int(token_kid[1:])}
183
181
  if account_id:
184
- where_data[str(JwtDbConfig.COL_ACCOUNT)] = account_id
182
+ where_data[JwtDbConfig.COL_ACCOUNT.value] = account_id
185
183
  recs: list[tuple[str]] = db_select(errors=op_errors,
186
- sel_stmt=f"SELECT {JwtDbConfig.COL_ALGORITHM}, "
187
- f"{JwtDbConfig.COL_DECODER} "
188
- f"FROM {JwtDbConfig.TABLE}",
184
+ sel_stmt=f"SELECT {JwtDbConfig.COL_ALGORITHM.value}, "
185
+ f"{JwtDbConfig.COL_DECODER.value} "
186
+ f"FROM {JwtDbConfig.TABLE.value}",
189
187
  where_data=where_data,
188
+ engine=JwtDbConfig.ENGINE.value,
190
189
  logger=logger)
191
190
  if recs:
192
191
  token_alg = recs[0][0]
@@ -199,10 +198,8 @@ def jwt_validate_token(errors: list[str] | None,
199
198
  logger.error(msg="Token not in the database")
200
199
  op_errors.append("Invalid token")
201
200
  else:
202
- # noinspection PyTypeChecker
203
- token_alg = JwtConfig.DEFAULT_ALGORITHM
204
- # noinspection PyTypeChecker
205
- token_decoder = JwtConfig.DECODING_KEY
201
+ token_alg = JwtConfig.DEFAULT_ALGORITHM.value
202
+ token_decoder = JwtConfig.DECODING_KEY.value
206
203
 
207
204
  # validate the token
208
205
  if not op_errors:
@@ -282,11 +279,12 @@ def jwt_revoke_token(errors: list[str] | None,
282
279
  op_errors.append("Invalid token")
283
280
  else:
284
281
  db_delete(errors=op_errors,
285
- delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
282
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
286
283
  where_data={
287
- str(JwtDbConfig.COL_KID): int(token_kid[1:]),
288
- str(JwtDbConfig.COL_ACCOUNT): account_id
284
+ JwtDbConfig.COL_KID.value: int(token_kid[1:]),
285
+ JwtDbConfig.COL_ACCOUNT.value: account_id
289
286
  },
287
+ engine=JwtDbConfig.ENGINE.value,
290
288
  logger=logger)
291
289
  if op_errors:
292
290
  if logger:
@@ -452,15 +450,17 @@ def jwt_refresh_tokens(errors: list[str] | None,
452
450
  # start the database transaction
453
451
  db_conn: Any = db_connect(errors=op_errors,
454
452
  autocommit=False,
453
+ engine=JwtDbConfig.ENGINE.value,
455
454
  logger=logger)
456
455
  if db_conn:
457
456
  # delete current refresh token
458
457
  db_delete(errors=op_errors,
459
- delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
458
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
460
459
  where_data={
461
- str(JwtDbConfig.COL_KID): int(token_kid[1:]),
462
- str(JwtDbConfig.COL_ACCOUNT): account_id
460
+ JwtDbConfig.COL_KID.value: int(token_kid[1:]),
461
+ JwtDbConfig.COL_ACCOUNT.value: account_id
463
462
  },
463
+ engine=JwtDbConfig.ENGINE.value,
464
464
  connection=db_conn,
465
465
  committable=False,
466
466
  logger=logger)
@@ -139,8 +139,9 @@ class JwtRegistry:
139
139
 
140
140
  # remove from database
141
141
  db_delete(errors=None,
142
- delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
143
- where_data={str(JwtDbConfig.COL_ACCOUNT): account_id},
142
+ delete_stmt=f"DELETE FROM {JwtDbConfig.value}",
143
+ where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
144
+ engine=JwtDbConfig.ENGINE.value,
144
145
  logger=logger)
145
146
  if logger:
146
147
  if account_data:
@@ -214,8 +215,8 @@ class JwtRegistry:
214
215
  tz=timezone.utc).isoformat()
215
216
  # may raise an exception
216
217
  return jwt.encode(payload=current_claims,
217
- key=JwtConfig.ENCODING_KEY,
218
- algorithm=JwtConfig.DEFAULT_ALGORITHM,
218
+ key=JwtConfig.ENCODING_KEY.value,
219
+ algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
219
220
  headers={"kid": nature})
220
221
 
221
222
  def issue_tokens(self,
@@ -275,13 +276,14 @@ class JwtRegistry:
275
276
  tz=timezone.utc).isoformat()
276
277
  # may raise an exception
277
278
  refresh_token: str = jwt.encode(payload=current_claims,
278
- key=JwtConfig.ENCODING_KEY,
279
- algorithm=JwtConfig.DEFAULT_ALGORITHM,
279
+ key=JwtConfig.ENCODING_KEY.value,
280
+ algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
280
281
  headers={"kid": "R0"})
281
282
 
282
283
  # make sure to have a database connection
283
284
  curr_conn: Any = db_conn or db_connect(errors=errors,
284
285
  autocommit=False,
286
+ engine=JwtDbConfig.ENGINE.value,
285
287
  logger=logger)
286
288
  if curr_conn:
287
289
  # persist the candidate token (may raise an exception)
@@ -291,14 +293,15 @@ class JwtRegistry:
291
293
  logger=logger)
292
294
  # issue the definitive refresh token
293
295
  refresh_token = jwt.encode(payload=current_claims,
294
- key=JwtConfig.ENCODING_KEY,
295
- algorithm=JwtConfig.DEFAULT_ALGORITHM,
296
+ key=JwtConfig.ENCODING_KEY.value,
297
+ algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
296
298
  headers={"kid": f"R{token_id}"})
297
299
  # persist it
298
300
  db_update(errors=errors,
299
- update_stmt=f"UPDATE {JwtDbConfig.TABLE}",
300
- update_data={str(JwtDbConfig.COL_TOKEN): refresh_token},
301
- where_data={str(JwtDbConfig.COL_KID): token_id},
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,
302
305
  connection=curr_conn,
303
306
  committable=False,
304
307
  logger=logger)
@@ -320,8 +323,8 @@ class JwtRegistry:
320
323
  current_claims["exp"] = just_now + account_data.get("access-max-age")
321
324
  # may raise an exception
322
325
  access_token: str = jwt.encode(payload=current_claims,
323
- key=JwtConfig.ENCODING_KEY,
324
- algorithm=JwtConfig.DEFAULT_ALGORITHM,
326
+ key=JwtConfig.ENCODING_KEY.value,
327
+ algorithm=JwtConfig.DEFAULT_ALGORITHM.value,
325
328
  headers={"kid": f"A{token_id}"})
326
329
  # return the token data
327
330
  return {
@@ -379,9 +382,10 @@ def _jwt_persist_token(account_id: str,
379
382
  # noinspection PyTypeChecker
380
383
  recs: list[tuple[int, str, str, str]] = \
381
384
  db_select(errors=errors,
382
- sel_stmt=f"SELECT {JwtDbConfig.COL_KID}, {JwtDbConfig.COL_TOKEN} "
383
- f"FROM {JwtDbConfig.TABLE}",
384
- where_data={str(JwtDbConfig.COL_ACCOUNT): account_id},
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,
385
389
  connection=db_conn,
386
390
  committable=False,
387
391
  logger=logger)
@@ -422,8 +426,9 @@ def _jwt_persist_token(account_id: str,
422
426
  # remove expired tokens from persistence
423
427
  if expired:
424
428
  db_delete(errors=errors,
425
- delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
426
- where_data={str(JwtDbConfig.COL_KID): expired},
429
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
430
+ where_data={JwtDbConfig.COL_KID.value: expired},
431
+ engine=JwtDbConfig.ENGINE.value,
427
432
  connection=db_conn,
428
433
  committable=False,
429
434
  logger=logger)
@@ -433,12 +438,12 @@ def _jwt_persist_token(account_id: str,
433
438
  logger.debug(msg=f"{len(expired)} tokens of account "
434
439
  f"'{account_id}' removed from storage")
435
440
 
436
- # noinspection PyTypeChecker
437
- if 0 < JwtConfig.ACCOUNT_LIMIT <= len(recs) - len(expired):
441
+ if 0 < JwtConfig.ACCOUNT_LIMIT.value <= len(recs) - len(expired):
438
442
  # delete the oldest token to make way for the new one
439
443
  db_delete(errors=errors,
440
- delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
441
- where_data={str(JwtDbConfig.COL_KID): oldest_id},
444
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE.value}",
445
+ where_data={JwtDbConfig.COL_KID.value: oldest_id},
446
+ engine=JwtDbConfig.ENGINE.value,
442
447
  connection=db_conn,
443
448
  committable=False,
444
449
  logger=logger)
@@ -448,15 +453,15 @@ def _jwt_persist_token(account_id: str,
448
453
  logger.debug(msg="Oldest active token of account "
449
454
  f"'{account_id}' removed from storage")
450
455
  # persist token
451
- # noinspection PyTypeChecker
452
456
  db_insert(errors=errors,
453
- insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE}",
457
+ insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE.value}",
454
458
  insert_data={
455
- str(JwtDbConfig.COL_ACCOUNT): account_id,
456
- str(JwtDbConfig.COL_TOKEN): jwt_token,
457
- str(JwtDbConfig.COL_ALGORITHM): JwtConfig.DEFAULT_ALGORITHM,
458
- str(JwtDbConfig.COL_DECODER): urlsafe_b64encode(s=JwtConfig.DECODING_KEY).decode()
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()
459
463
  },
464
+ engine=JwtDbConfig.ENGINE.value,
460
465
  connection=db_conn,
461
466
  committable=False,
462
467
  logger=logger)
@@ -467,14 +472,15 @@ def _jwt_persist_token(account_id: str,
467
472
  # HAZARD: JWT_DB_COL_TOKEN's column type might prevent it for being used in a WHERE clause
468
473
  where_clause: str | None = None
469
474
  if existing_ids:
470
- where_clause = f"{JwtDbConfig.COL_KID} NOT IN {existing_ids}"
475
+ where_clause = f"{JwtDbConfig.COL_KID.value} NOT IN {existing_ids}"
471
476
  where_clause = where_clause.replace("[", "(", 1).replace("]", ")", 1)
472
477
  reply: list[tuple[int]] = db_select(errors=errors,
473
- sel_stmt=f"SELECT {JwtDbConfig.COL_KID} "
474
- f"FROM {JwtDbConfig.TABLE}",
478
+ sel_stmt=f"SELECT {JwtDbConfig.COL_KID.value} "
479
+ f"FROM {JwtDbConfig.TABLE.value}",
475
480
  where_clause=where_clause,
476
- where_data={str(JwtDbConfig.COL_ACCOUNT): account_id},
481
+ where_data={JwtDbConfig.COL_ACCOUNT.value: account_id},
477
482
  require_count=1,
483
+ engine=JwtDbConfig.ENGINE.value,
478
484
  connection=db_conn,
479
485
  committable=False,
480
486
  logger=logger)
File without changes
File without changes
File without changes