pypomes-jwt 1.0.9__tar.gz → 1.1.1__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.0.9
3
+ Version: 1.1.1
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.4
16
- Requires-Dist: pypomes-db>=2.0.8
15
+ Requires-Dist: pypomes-core>=1.9.8
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.0.9"
9
+ version = "1.1.1"
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.4",
25
- "pypomes_db>=2.0.8"
24
+ "pypomes_core>=1.9.8",
25
+ "pypomes_db>=2.0.9"
26
26
  ]
27
27
 
28
28
  [project.urls]
@@ -1,5 +1,5 @@
1
- from .jwt_constants import (
2
- JwtParam, JwtDbParam
1
+ from .jwt_configuration import (
2
+ JwtConfig, JwtDbConfig
3
3
  )
4
4
  from .jwt_pomes import (
5
5
  jwt_needed, jwt_verify_request,
@@ -10,7 +10,7 @@ from .jwt_pomes import (
10
10
 
11
11
  __all__ = [
12
12
  # jwt_constants
13
- "JwtParam", "JwtDbParam",
13
+ "JwtConfig", "JwtDbConfig",
14
14
  # jwt_pomes
15
15
  "jwt_needed", "jwt_verify_request",
16
16
  "jwt_assert_account", "jwt_set_account", "jwt_remove_account",
@@ -0,0 +1,85 @@
1
+ from cryptography.hazmat.primitives import serialization
2
+ from cryptography.hazmat.primitives.asymmetric import rsa
3
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
4
+ from enum import Enum
5
+ from pypomes_core import (
6
+ APP_PREFIX,
7
+ env_get_str, env_get_bytes, env_get_int
8
+ )
9
+ from pypomes_db import DbEngine, db_setup
10
+ from secrets import token_bytes
11
+ from sys import stderr
12
+
13
+
14
+ # recommended: allow the encode and decode keys to be generated anew when app starts
15
+ _encoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_ENCODING_KEY",
16
+ encoding="base64url")
17
+ _decoding_key: bytes
18
+ # one of HS256, HS512, RS256, RS512
19
+ _default_algorithm: str = env_get_str(key=f"{APP_PREFIX}_JWT_DEFAULT_ALGORITHM",
20
+ def_value="RS256")
21
+ if _default_algorithm in ["HS256", "HS512"]:
22
+ if not _encoding_key:
23
+ _encoding_key = token_bytes(nbytes=32)
24
+ _decoding_key = _encoding_key
25
+ else:
26
+ _decoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_DECODING_KEY")
27
+ if not _encoding_key or not _decoding_key:
28
+ __priv_key: RSAPrivateKey = rsa.generate_private_key(public_exponent=65537,
29
+ key_size=2048)
30
+ _encoding_key = __priv_key.private_bytes(encoding=serialization.Encoding.PEM,
31
+ format=serialization.PrivateFormat.PKCS8,
32
+ encryption_algorithm=serialization.NoEncryption())
33
+ __pub_key: RSAPublicKey = __priv_key.public_key()
34
+ _decoding_key = __pub_key.public_bytes(encoding=serialization.Encoding.PEM,
35
+ format=serialization.PublicFormat.SubjectPublicKeyInfo)
36
+
37
+
38
+ class JwtConfig(Enum):
39
+ """
40
+ Parameters for JWT token issuance.
41
+ """
42
+ # recommended: between 5 min and 1 hour (set to 5 min)
43
+ ACCESS_MAX_AGE: int = env_get_int(key=f"{APP_PREFIX}_JWT_ACCESS_MAX_AGE",
44
+ def_value=300)
45
+ ACCOUNT_LIMIT: int = env_get_int(key=f"{APP_PREFIX}_JWT_ACCOUNT_LIMIT",
46
+ def_value=5)
47
+ ENCODING_KEY: bytes = _encoding_key
48
+ DECODING_KEY: bytes = _decoding_key
49
+ DEFAULT_ALGORITHM: str = _default_algorithm
50
+ # recommended: at least 2 hours (set to 24 hours)
51
+ REFRESH_MAX_AGE: int = env_get_int(key=f"{APP_PREFIX}_JWT_REFRESH_MAX_AGE",
52
+ def_value=86400)
53
+
54
+
55
+ class JwtDbConfig(Enum):
56
+ """
57
+ Parameters for JWT databse connection.
58
+ """
59
+ 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
+ TABLE: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE")
68
+ COL_ACCOUNT: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ACCOUNT")
69
+ COL_ALGORITHM: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ALGORITHM")
70
+ COL_DECODER: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_DECODER")
71
+ COL_KID: str = env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_KID")
72
+ 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")
@@ -9,9 +9,7 @@ from pypomes_db import (
9
9
  )
10
10
  from typing import Any
11
11
 
12
- from .jwt_constants import (
13
- JwtParam, JwtDbParam, _JWT_CONFIG, _JWT_DATABASE
14
- )
12
+ from .jwt_configuration import JwtConfig, JwtDbConfig
15
13
  from .jwt_registry import JwtRegistry
16
14
 
17
15
  # the JWT registry
@@ -77,8 +75,8 @@ def jwt_assert_account(account_id: str) -> bool:
77
75
 
78
76
  def jwt_set_account(account_id: str,
79
77
  claims: dict[str, Any],
80
- access_max_age: int = _JWT_CONFIG[JwtParam.ACCESS_MAX_AGE],
81
- refresh_max_age: int = _JWT_CONFIG[JwtParam.REFRESH_MAX_AGE],
78
+ access_max_age: int = JwtConfig.ACCESS_MAX_AGE,
79
+ refresh_max_age: int = JwtConfig.REFRESH_MAX_AGE,
82
80
  grace_interval: int = None,
83
81
  logger: Logger = None) -> None:
84
82
  """
@@ -180,14 +178,14 @@ def jwt_validate_token(errors: list[str] | None,
180
178
  token_kid[0:1] in ["A", "R"] and token_kid[1:].isdigit():
181
179
  # token was likely issued locally
182
180
  where_data: dict[str, Any] = {
183
- _JWT_DATABASE[JwtDbParam.COL_KID]: int(token_kid[1:])
181
+ str(JwtDbConfig.COL_KID): int(token_kid[1:])
184
182
  }
185
183
  if account_id:
186
- where_data[_JWT_DATABASE[JwtDbParam.COL_ACCOUNT]] = account_id
184
+ where_data[str(JwtDbConfig.COL_ACCOUNT)] = account_id
187
185
  recs: list[tuple[str]] = db_select(errors=op_errors,
188
- sel_stmt=f"SELECT {_JWT_DATABASE[JwtDbParam.COL_ALGORITHM]}, "
189
- f"{_JWT_DATABASE[JwtDbParam.COL_DECODER]} "
190
- f"FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
186
+ sel_stmt=f"SELECT {JwtDbConfig.COL_ALGORITHM}, "
187
+ f"{JwtDbConfig.COL_DECODER} "
188
+ f"FROM {JwtDbConfig.TABLE}",
191
189
  where_data=where_data,
192
190
  logger=logger)
193
191
  if recs:
@@ -201,8 +199,10 @@ def jwt_validate_token(errors: list[str] | None,
201
199
  logger.error(msg="Token not in the database")
202
200
  op_errors.append("Invalid token")
203
201
  else:
204
- token_alg = _JWT_CONFIG[JwtParam.DEFAULT_ALGORITHM]
205
- token_decoder = _JWT_CONFIG[JwtParam.DECODING_KEY]
202
+ # noinspection PyTypeChecker
203
+ token_alg = JwtConfig.DEFAULT_ALGORITHM
204
+ # noinspection PyTypeChecker
205
+ token_decoder = JwtConfig.DECODING_KEY
206
206
 
207
207
  # validate the token
208
208
  if not op_errors:
@@ -282,10 +282,10 @@ def jwt_revoke_token(errors: list[str] | None,
282
282
  op_errors.append("Invalid token")
283
283
  else:
284
284
  db_delete(errors=op_errors,
285
- delete_stmt=f"DELETE FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
285
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
286
286
  where_data={
287
- _JWT_DATABASE[JwtDbParam.COL_KID]: int(token_kid[1:]),
288
- _JWT_DATABASE[JwtDbParam.COL_ACCOUNT]: account_id
287
+ str(JwtDbConfig.COL_KID): int(token_kid[1:]),
288
+ str(JwtDbConfig.COL_ACCOUNT): account_id
289
289
  },
290
290
  logger=logger)
291
291
  if op_errors:
@@ -456,10 +456,10 @@ def jwt_refresh_tokens(errors: list[str] | None,
456
456
  if db_conn:
457
457
  # delete current refresh token
458
458
  db_delete(errors=op_errors,
459
- delete_stmt=f"DELETE FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
459
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
460
460
  where_data={
461
- _JWT_DATABASE[JwtDbParam.COL_KID]: int(token_kid[1:]),
462
- _JWT_DATABASE[JwtDbParam.COL_ACCOUNT]: account_id
461
+ str(JwtDbConfig.COL_KID): int(token_kid[1:]),
462
+ str(JwtDbConfig.COL_ACCOUNT): account_id
463
463
  },
464
464
  connection=db_conn,
465
465
  committable=False,
@@ -12,9 +12,7 @@ from pypomes_db import (
12
12
  from threading import Lock
13
13
  from typing import Any
14
14
 
15
- from .jwt_constants import (
16
- JwtParam, JwtDbParam, _JWT_CONFIG, _JWT_DATABASE
17
- )
15
+ from .jwt_configuration import JwtConfig, JwtDbConfig
18
16
 
19
17
 
20
18
  class JwtRegistry:
@@ -141,8 +139,8 @@ class JwtRegistry:
141
139
 
142
140
  # remove from database
143
141
  db_delete(errors=None,
144
- delete_stmt=f"DELETE FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
145
- where_data={_JWT_DATABASE[JwtDbParam.COL_ACCOUNT]: account_id},
142
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
143
+ where_data={str(JwtDbConfig.COL_ACCOUNT): account_id},
146
144
  logger=logger)
147
145
  if logger:
148
146
  if account_data:
@@ -216,8 +214,8 @@ class JwtRegistry:
216
214
  tz=timezone.utc).isoformat()
217
215
  # may raise an exception
218
216
  return jwt.encode(payload=current_claims,
219
- key=_JWT_CONFIG[JwtParam.ENCODING_KEY],
220
- algorithm=_JWT_CONFIG[JwtParam.DEFAULT_ALGORITHM],
217
+ key=JwtConfig.ENCODING_KEY,
218
+ algorithm=JwtConfig.DEFAULT_ALGORITHM,
221
219
  headers={"kid": nature})
222
220
 
223
221
  def issue_tokens(self,
@@ -277,8 +275,8 @@ class JwtRegistry:
277
275
  tz=timezone.utc).isoformat()
278
276
  # may raise an exception
279
277
  refresh_token: str = jwt.encode(payload=current_claims,
280
- key=_JWT_CONFIG[JwtParam.ENCODING_KEY],
281
- algorithm=_JWT_CONFIG[JwtParam.DEFAULT_ALGORITHM],
278
+ key=JwtConfig.ENCODING_KEY,
279
+ algorithm=JwtConfig.DEFAULT_ALGORITHM,
282
280
  headers={"kid": "R0"})
283
281
 
284
282
  # make sure to have a database connection
@@ -293,14 +291,14 @@ class JwtRegistry:
293
291
  logger=logger)
294
292
  # issue the definitive refresh token
295
293
  refresh_token = jwt.encode(payload=current_claims,
296
- key=_JWT_CONFIG[JwtParam.ENCODING_KEY],
297
- algorithm=_JWT_CONFIG[JwtParam.DEFAULT_ALGORITHM],
294
+ key=JwtConfig.ENCODING_KEY,
295
+ algorithm=JwtConfig.DEFAULT_ALGORITHM,
298
296
  headers={"kid": f"R{token_id}"})
299
297
  # persist it
300
298
  db_update(errors=errors,
301
- update_stmt=f"UPDATE {_JWT_DATABASE[JwtDbParam.TABLE]}",
302
- update_data={_JWT_DATABASE[JwtDbParam.COL_TOKEN]: refresh_token},
303
- where_data={_JWT_DATABASE[JwtDbParam.COL_KID]: token_id},
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},
304
302
  connection=curr_conn,
305
303
  committable=False,
306
304
  logger=logger)
@@ -322,8 +320,8 @@ class JwtRegistry:
322
320
  current_claims["exp"] = just_now + account_data.get("access-max-age")
323
321
  # may raise an exception
324
322
  access_token: str = jwt.encode(payload=current_claims,
325
- key=_JWT_CONFIG[JwtParam.ENCODING_KEY],
326
- algorithm=_JWT_CONFIG[JwtParam.DEFAULT_ALGORITHM],
323
+ key=JwtConfig.ENCODING_KEY,
324
+ algorithm=JwtConfig.DEFAULT_ALGORITHM,
327
325
  headers={"kid": f"A{token_id}"})
328
326
  # return the token data
329
327
  return {
@@ -381,9 +379,9 @@ def _jwt_persist_token(account_id: str,
381
379
  # noinspection PyTypeChecker
382
380
  recs: list[tuple[int, str, str, str]] = \
383
381
  db_select(errors=errors,
384
- sel_stmt=f"SELECT {_JWT_DATABASE[JwtDbParam.COL_KID]}, {_JWT_DATABASE[JwtDbParam.COL_TOKEN]} "
385
- f"FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
386
- where_data={_JWT_DATABASE[JwtDbParam.COL_ACCOUNT]: account_id},
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},
387
385
  connection=db_conn,
388
386
  committable=False,
389
387
  logger=logger)
@@ -424,8 +422,8 @@ def _jwt_persist_token(account_id: str,
424
422
  # remove expired tokens from persistence
425
423
  if expired:
426
424
  db_delete(errors=errors,
427
- delete_stmt=f"DELETE FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
428
- where_data={_JWT_DATABASE[JwtDbParam.COL_KID]: expired},
425
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
426
+ where_data={str(JwtDbConfig.COL_KID): expired},
429
427
  connection=db_conn,
430
428
  committable=False,
431
429
  logger=logger)
@@ -435,11 +433,12 @@ def _jwt_persist_token(account_id: str,
435
433
  logger.debug(msg=f"{len(expired)} tokens of account "
436
434
  f"'{account_id}' removed from storage")
437
435
 
438
- if 0 < _JWT_CONFIG[JwtParam.ACCOUNT_LIMIT] <= len(recs) - len(expired):
436
+ # noinspection PyTypeChecker
437
+ if 0 < JwtConfig.ACCOUNT_LIMIT <= len(recs) - len(expired):
439
438
  # delete the oldest token to make way for the new one
440
439
  db_delete(errors=errors,
441
- delete_stmt=f"DELETE FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
442
- where_data={_JWT_DATABASE[JwtDbParam.COL_KID]: oldest_id},
440
+ delete_stmt=f"DELETE FROM {JwtDbConfig.TABLE}",
441
+ where_data={str(JwtDbConfig.COL_KID): oldest_id},
443
442
  connection=db_conn,
444
443
  committable=False,
445
444
  logger=logger)
@@ -449,13 +448,14 @@ def _jwt_persist_token(account_id: str,
449
448
  logger.debug(msg="Oldest active token of account "
450
449
  f"'{account_id}' removed from storage")
451
450
  # persist token
451
+ # noinspection PyTypeChecker
452
452
  db_insert(errors=errors,
453
- insert_stmt=f"INSERT INTO {_JWT_DATABASE[JwtDbParam.TABLE]}",
453
+ insert_stmt=f"INSERT INTO {JwtDbConfig.TABLE}",
454
454
  insert_data={
455
- _JWT_DATABASE[JwtDbParam.COL_ACCOUNT]: account_id,
456
- _JWT_DATABASE[JwtDbParam.COL_TOKEN]: jwt_token,
457
- _JWT_DATABASE[JwtDbParam.COL_ALGORITHM]: _JWT_CONFIG[JwtParam.DEFAULT_ALGORITHM],
458
- _JWT_DATABASE[JwtDbParam.COL_DECODER]: urlsafe_b64encode(_JWT_CONFIG[JwtParam.DECODING_KEY]).decode()
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
459
  },
460
460
  connection=db_conn,
461
461
  committable=False,
@@ -467,13 +467,13 @@ def _jwt_persist_token(account_id: str,
467
467
  # HAZARD: JWT_DB_COL_TOKEN's column type might prevent it for being used in a WHERE clause
468
468
  where_clause: str | None = None
469
469
  if existing_ids:
470
- where_clause = f"{_JWT_DATABASE[JwtDbParam.COL_KID]} NOT IN {existing_ids}"
470
+ where_clause = f"{JwtDbConfig.COL_KID} NOT IN {existing_ids}"
471
471
  where_clause = where_clause.replace("[", "(", 1).replace("]", ")", 1)
472
472
  reply: list[tuple[int]] = db_select(errors=errors,
473
- sel_stmt=f"SELECT {_JWT_DATABASE[JwtDbParam.COL_KID]} "
474
- f"FROM {_JWT_DATABASE[JwtDbParam.TABLE]}",
473
+ sel_stmt=f"SELECT {JwtDbConfig.COL_KID} "
474
+ f"FROM {JwtDbConfig.TABLE}",
475
475
  where_clause=where_clause,
476
- where_data={_JWT_DATABASE[JwtDbParam.COL_ACCOUNT]: account_id},
476
+ where_data={str(JwtDbConfig.COL_ACCOUNT): account_id},
477
477
  require_count=1,
478
478
  connection=db_conn,
479
479
  committable=False,
@@ -1,116 +0,0 @@
1
- from cryptography.hazmat.primitives import serialization
2
- from cryptography.hazmat.primitives.asymmetric import rsa
3
- from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
4
- from enum import StrEnum
5
- from pypomes_core import (
6
- APP_PREFIX,
7
- env_get_str, env_get_bytes, env_get_int
8
- )
9
- from pypomes_db import DbEngine, db_setup
10
- from secrets import token_bytes
11
- from sys import stderr
12
- from typing import Any, Final
13
-
14
-
15
- class JwtParam(StrEnum):
16
- """
17
- Parameters for JWT provider access.
18
- """
19
- ACCESS_MAX_AGE = "access-max-age"
20
- ACCOUNT_LIMIT = "account-limit"
21
- DECODING_KEY = "decoding-key"
22
- DEFAULT_ALGORITHM = "default-algorithm"
23
- ENCODING_KEY = "encoding-key"
24
- REFRESH_MAX_AGE = "refresh-max-age"
25
-
26
- def __str__(self) -> str: # noqa: D105
27
- # noinspection PyTypeChecker
28
- return self.value
29
-
30
-
31
- class JwtDbParam(StrEnum):
32
- """
33
- Parameters for JWT databse connection.
34
- """
35
- CLIENT = "client"
36
- DRIVER = "driver"
37
- ENGINE = "engine"
38
- NAME = "name"
39
- HOST = "host"
40
- PORT = "port"
41
- USER = "user"
42
- PWD = "pwd"
43
- TABLE = "table"
44
- COL_ACCOUNT = "col-account"
45
- COL_ALGORITHM = "col-algorithm"
46
- COL_DECODER = "col-decoder"
47
- COL_KID = "col-kid"
48
- COL_TOKEN = "col-token"
49
-
50
- def __str__(self) -> str: # noqa: D105
51
- # noinspection PyTypeChecker
52
- return self.value
53
-
54
-
55
- # recommended: allow the encode and decode keys to be generated anew when app starts
56
- __encoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_ENCODING_KEY",
57
- encoding="base64url")
58
- __decoding_key: bytes
59
- # one of HS256, HS512, RS256, RS512
60
- __default_algorithm: str = env_get_str(key=f"{APP_PREFIX}_JWT_DEFAULT_ALGORITHM",
61
- def_value="RS256")
62
- if __default_algorithm in ["HS256", "HS512"]:
63
- if not __encoding_key:
64
- __encoding_key = token_bytes(nbytes=32)
65
- __decoding_key = __encoding_key
66
- else:
67
- __decoding_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_DECODING_KEY")
68
- if not __encoding_key or not __decoding_key:
69
- __priv_key: RSAPrivateKey = rsa.generate_private_key(public_exponent=65537,
70
- key_size=2048)
71
- __encoding_key = __priv_key.private_bytes(encoding=serialization.Encoding.PEM,
72
- format=serialization.PrivateFormat.PKCS8,
73
- encryption_algorithm=serialization.NoEncryption())
74
- __pub_key: RSAPublicKey = __priv_key.public_key()
75
- __decoding_key = __pub_key.public_bytes(encoding=serialization.Encoding.PEM,
76
- format=serialization.PublicFormat.SubjectPublicKeyInfo)
77
-
78
- _JWT_CONFIG: Final[dict[JwtParam, Any]] = {
79
- # recommended: between 5 min and 1 hour (set to 5 min)
80
- JwtParam.ACCESS_MAX_AGE: env_get_int(key=f"{APP_PREFIX}_JWT_ACCESS_MAX_AGE",
81
- def_value=300),
82
- JwtParam.ACCOUNT_LIMIT: env_get_int(key=f"{APP_PREFIX}_JWT_ACCOUNT_LIMIT"),
83
- JwtParam.DECODING_KEY: __decoding_key,
84
- JwtParam.DEFAULT_ALGORITHM: __default_algorithm,
85
- JwtParam.ENCODING_KEY: __encoding_key,
86
- # recommended: at least 2 hours (set to 24 hours)
87
- JwtParam.REFRESH_MAX_AGE: env_get_int(key=f"{APP_PREFIX}_JWT_REFRESH_MAX_AGE",
88
- def_value=86400)
89
- }
90
- _JWT_DATABASE: Final[JwtDbParam, Any] = {
91
- JwtDbParam.ENGINE: DbEngine(env_get_str(key=f"{APP_PREFIX}_JWT_DB_ENGINE")),
92
- JwtDbParam.CLIENT: env_get_str(key=f"{APP_PREFIX}_JWT_DB_CLIENT"), # for Oracle, only
93
- JwtDbParam.DRIVER: env_get_str(key=f"{APP_PREFIX}_JWT_DB_DRIVER"), # for SQLServer, only
94
- JwtDbParam.NAME: env_get_str(key=f"{APP_PREFIX}_JWT_DB_NAME"),
95
- JwtDbParam.HOST: env_get_str(key=f"{APP_PREFIX}_JWT_DB_HOST"),
96
- JwtDbParam.PORT: env_get_int(key=f"{APP_PREFIX}_JWT_DB_PORT"),
97
- JwtDbParam.USER: env_get_str(key=f"{APP_PREFIX}_JWT_DB_USER"),
98
- JwtDbParam.PWD: env_get_str(key=f"{APP_PREFIX}_JWT_DB_PWD"),
99
- JwtDbParam.TABLE: env_get_str(key=f"{APP_PREFIX}_JWT_DB_TABLE"),
100
- JwtDbParam.COL_ACCOUNT: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ACCOUNT"),
101
- JwtDbParam.COL_ALGORITHM: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_ALGORITHM"),
102
- JwtDbParam.COL_DECODER: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_DECODER"),
103
- JwtDbParam.COL_KID: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_KID"),
104
- JwtDbParam.COL_TOKEN: env_get_str(key=f"{APP_PREFIX}_JWT_DB_COL_TOKEN")
105
- }
106
-
107
- # define and validate the database engine
108
- if not db_setup(engine=_JWT_DATABASE[JwtDbParam.ENGINE],
109
- db_name=_JWT_DATABASE[JwtDbParam.NAME],
110
- db_user=_JWT_DATABASE[JwtDbParam.USER],
111
- db_pwd=_JWT_DATABASE[JwtDbParam.PWD],
112
- db_host=_JWT_DATABASE[JwtDbParam.HOST],
113
- db_port=_JWT_DATABASE[JwtDbParam.PORT],
114
- db_client=_JWT_DATABASE[JwtDbParam.CLIENT],
115
- db_driver=_JWT_DATABASE[JwtDbParam.DRIVER]):
116
- stderr.write("Invalid database parameters\n")
File without changes
File without changes
File without changes