Encryptors 2.39__tar.gz → 2.41__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.
Files changed (90) hide show
  1. {encryptors-2.39 → encryptors-2.41}/PKG-INFO +1 -20
  2. {encryptors-2.39 → encryptors-2.41}/setup.py +2 -2
  3. {encryptors-2.39 → encryptors-2.41}/src/Encryptors.egg-info/PKG-INFO +1 -20
  4. {encryptors-2.39 → encryptors-2.41}/src/Encryptors.egg-info/SOURCES.txt +3 -0
  5. encryptors-2.41/src/Osdental/Decorators/PublicResolver.py +3 -0
  6. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Decorators/SecureResolver.py +9 -4
  7. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Encryptor/Jwt.py +3 -3
  8. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Encryptor/Rsa.py +3 -3
  9. encryptors-2.41/src/Osdental/Graphql/Extensions/AuditExtension.py +189 -0
  10. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Helpers/AuditDispatcher.py +10 -1
  11. encryptors-2.41/src/Osdental/Helpers/ResponseDecryptor.py +15 -0
  12. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Models/Response.py +9 -1
  13. encryptors-2.41/src/Osdental/Shared/Utils/RsaUtils.py +30 -0
  14. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Storage/AzureBlobStorage.py +5 -1
  15. encryptors-2.41/src/Osdental/__init__.py +0 -0
  16. encryptors-2.39/README.md +0 -17
  17. encryptors-2.39/src/Osdental/Graphql/Extensions/AuditExtension.py +0 -120
  18. /encryptors-2.39/src/Osdental/Database/__init__.py → /encryptors-2.41/README.md +0 -0
  19. {encryptors-2.39 → encryptors-2.41}/setup.cfg +0 -0
  20. {encryptors-2.39 → encryptors-2.41}/src/Encryptors.egg-info/dependency_links.txt +0 -0
  21. {encryptors-2.39 → encryptors-2.41}/src/Encryptors.egg-info/entry_points.txt +0 -0
  22. {encryptors-2.39 → encryptors-2.41}/src/Encryptors.egg-info/requires.txt +0 -0
  23. {encryptors-2.39 → encryptors-2.41}/src/Encryptors.egg-info/top_level.txt +0 -0
  24. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Cli/__init__.py +0 -0
  25. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Database/BaseRepository.py +0 -0
  26. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Database/Connection.py +0 -0
  27. {encryptors-2.39/src/Osdental/Decorators → encryptors-2.41/src/Osdental/Database}/__init__.py +0 -0
  28. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Decorators/Grpc.py +0 -0
  29. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Decorators/Retry.py +0 -0
  30. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Decorators/SqlDataNormalizer.py +0 -0
  31. {encryptors-2.39/src/Osdental/Encryptor → encryptors-2.41/src/Osdental/Decorators}/__init__.py +0 -0
  32. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Encryptor/Aes.py +0 -0
  33. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Encryptor/Argon2.py +0 -0
  34. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Encryptor/Bcrypt.py +0 -0
  35. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Encryptor/Sha512.py +0 -0
  36. {encryptors-2.39/src/Osdental/Exception → encryptors-2.41/src/Osdental/Encryptor}/__init__.py +0 -0
  37. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Exception/ControlledException.py +0 -0
  38. {encryptors-2.39/src/Osdental/Graphql/Extensions → encryptors-2.41/src/Osdental/Exception}/__init__.py +0 -0
  39. {encryptors-2.39/src/Osdental/Graphql/_Helpers → encryptors-2.41/src/Osdental/Graphql/Extensions}/__init__.py +0 -0
  40. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Graphql/Models/__init__.py +0 -0
  41. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Graphql/_Exceptions/__init__.py +0 -0
  42. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_AuditHelper.py +0 -0
  43. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_ExtractAuthToken.py +0 -0
  44. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_TenantPolicy.py +0 -0
  45. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_TokenService.py +0 -0
  46. {encryptors-2.39/src/Osdental/Graphql → encryptors-2.41/src/Osdental/Graphql/_Helpers}/__init__.py +0 -0
  47. {encryptors-2.39/src/Osdental/Helpers → encryptors-2.41/src/Osdental/Graphql}/__init__.py +0 -0
  48. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Helpers/KeyVaultService.py +0 -0
  49. {encryptors-2.39/src/Osdental/Http → encryptors-2.41/src/Osdental/Helpers}/__init__.py +0 -0
  50. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Http/APIClient.py +0 -0
  51. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Http/_Exceptions.py +0 -0
  52. {encryptors-2.39/src/Osdental/Models → encryptors-2.41/src/Osdental/Http}/__init__.py +0 -0
  53. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Messaging/AzureServiceBus.py +0 -0
  54. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Messaging/Kafka.py +0 -0
  55. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Messaging/RabbitMQ.py +0 -0
  56. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Messaging/__init__.py +0 -0
  57. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Models/AuditConfig.py +0 -0
  58. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Models/Token.py +0 -0
  59. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Models/_Audit.py +0 -0
  60. {encryptors-2.39/src/Osdental/RedisCache → encryptors-2.41/src/Osdental/Models}/__init__.py +0 -0
  61. {encryptors-2.39 → encryptors-2.41}/src/Osdental/RedisCache/Redis.py +0 -0
  62. {encryptors-2.39/src/Osdental/Rest/Context → encryptors-2.41/src/Osdental/RedisCache}/__init__.py +0 -0
  63. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Rest/Context/RequestContext.py +0 -0
  64. {encryptors-2.39/src/Osdental/Rest/Middlewares → encryptors-2.41/src/Osdental/Rest/Context}/__init__.py +0 -0
  65. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Rest/Middlewares/RequestContextMiddleware.py +0 -0
  66. {encryptors-2.39/src/Osdental/Rest → encryptors-2.41/src/Osdental/Rest/Middlewares}/__init__.py +0 -0
  67. {encryptors-2.39/src/Osdental/Shared/Enums → encryptors-2.41/src/Osdental/Rest}/__init__.py +0 -0
  68. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Enums/Code.py +0 -0
  69. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Enums/Constant.py +0 -0
  70. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Enums/FileType.py +0 -0
  71. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Enums/GrahpqlOperation.py +0 -0
  72. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Enums/Message.py +0 -0
  73. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Enums/Profile.py +0 -0
  74. {encryptors-2.39/src/Osdental/Shared/Utils → encryptors-2.41/src/Osdental/Shared/Enums}/__init__.py +0 -0
  75. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Logger.py +0 -0
  76. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/CaseConverter.py +0 -0
  77. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/CodeGenerator.py +0 -0
  78. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/DataNormalizer.py +0 -0
  79. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/DataUtils.py +0 -0
  80. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/DateUtils.py +0 -0
  81. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/FileMetaData.py +0 -0
  82. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/HashValidator.py +0 -0
  83. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/Mapper.py +0 -0
  84. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/PasswordGenerator.py +0 -0
  85. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/QueryGenerator.py +0 -0
  86. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Shared/Utils/TextProcessor.py +0 -0
  87. {encryptors-2.39/src/Osdental/Shared → encryptors-2.41/src/Osdental/Shared/Utils}/__init__.py +0 -0
  88. {encryptors-2.39/src/Osdental → encryptors-2.41/src/Osdental/Shared}/__init__.py +0 -0
  89. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Storage/S3Storage.py +0 -0
  90. {encryptors-2.39 → encryptors-2.41}/src/Osdental/Storage/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Encryptors
3
- Version: 2.39
3
+ Version: 2.41
4
4
  Summary: End-to-end algorithm library
5
5
  Author: OSDental LLC
6
6
  Author-email: support@osdental.ai
@@ -59,26 +59,7 @@ Requires-Dist: gunicorn==23.0.0
59
59
  Dynamic: author
60
60
  Dynamic: author-email
61
61
  Dynamic: classifier
62
- Dynamic: description
63
62
  Dynamic: description-content-type
64
63
  Dynamic: requires-dist
65
64
  Dynamic: requires-python
66
65
  Dynamic: summary
67
-
68
- # osdental-library
69
-
70
- `osdental-library` is a versatile and easy-to-use library for handling common tasks related to **encryption**, **hashing**, and **JWT token management**. Ideal for projects that require a secure and efficient approach to handling sensitive data.
71
-
72
- ## Features
73
-
74
- - Generation and validation of **hashes** using modern algorithms.
75
- - Encryption and decryption of data using secure keys.
76
- - Creation and verification of **JWT tokens** for authentication and authorization.
77
- - Implementations that are easy to integrate into any Python project.
78
-
79
- ## Installation
80
-
81
- You can easily install `osdental-library` using `pip`:
82
-
83
- ```bash
84
- pip install osdental-library
@@ -1,8 +1,8 @@
1
1
  from setuptools import setup, find_packages
2
-
2
+ # ANDERSON ESTO YA SE SUBIO Y ESTA ESTABLE, AUN TE QUEDA PENDIENTE LA AUDITORIA CON RSA Y AES DE ACCESSTOKEN
3
3
  setup(
4
4
  name="Encryptors",
5
- version="2.39",
5
+ version="2.41",
6
6
  author="OSDental LLC",
7
7
  author_email="support@osdental.ai",
8
8
  description="End-to-end algorithm library",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Encryptors
3
- Version: 2.39
3
+ Version: 2.41
4
4
  Summary: End-to-end algorithm library
5
5
  Author: OSDental LLC
6
6
  Author-email: support@osdental.ai
@@ -59,26 +59,7 @@ Requires-Dist: gunicorn==23.0.0
59
59
  Dynamic: author
60
60
  Dynamic: author-email
61
61
  Dynamic: classifier
62
- Dynamic: description
63
62
  Dynamic: description-content-type
64
63
  Dynamic: requires-dist
65
64
  Dynamic: requires-python
66
65
  Dynamic: summary
67
-
68
- # osdental-library
69
-
70
- `osdental-library` is a versatile and easy-to-use library for handling common tasks related to **encryption**, **hashing**, and **JWT token management**. Ideal for projects that require a secure and efficient approach to handling sensitive data.
71
-
72
- ## Features
73
-
74
- - Generation and validation of **hashes** using modern algorithms.
75
- - Encryption and decryption of data using secure keys.
76
- - Creation and verification of **JWT tokens** for authentication and authorization.
77
- - Implementations that are easy to integrate into any Python project.
78
-
79
- ## Installation
80
-
81
- You can easily install `osdental-library` using `pip`:
82
-
83
- ```bash
84
- pip install osdental-library
@@ -12,6 +12,7 @@ src/Osdental/Database/BaseRepository.py
12
12
  src/Osdental/Database/Connection.py
13
13
  src/Osdental/Database/__init__.py
14
14
  src/Osdental/Decorators/Grpc.py
15
+ src/Osdental/Decorators/PublicResolver.py
15
16
  src/Osdental/Decorators/Retry.py
16
17
  src/Osdental/Decorators/SecureResolver.py
17
18
  src/Osdental/Decorators/SqlDataNormalizer.py
@@ -37,6 +38,7 @@ src/Osdental/Graphql/_Helpers/_TokenService.py
37
38
  src/Osdental/Graphql/_Helpers/__init__.py
38
39
  src/Osdental/Helpers/AuditDispatcher.py
39
40
  src/Osdental/Helpers/KeyVaultService.py
41
+ src/Osdental/Helpers/ResponseDecryptor.py
40
42
  src/Osdental/Helpers/__init__.py
41
43
  src/Osdental/Http/APIClient.py
42
44
  src/Osdental/Http/_Exceptions.py
@@ -76,6 +78,7 @@ src/Osdental/Shared/Utils/HashValidator.py
76
78
  src/Osdental/Shared/Utils/Mapper.py
77
79
  src/Osdental/Shared/Utils/PasswordGenerator.py
78
80
  src/Osdental/Shared/Utils/QueryGenerator.py
81
+ src/Osdental/Shared/Utils/RsaUtils.py
79
82
  src/Osdental/Shared/Utils/TextProcessor.py
80
83
  src/Osdental/Shared/Utils/__init__.py
81
84
  src/Osdental/Storage/AzureBlobStorage.py
@@ -0,0 +1,3 @@
1
+ def public_resolver(resolver):
2
+ setattr(resolver, "_is_public", True)
3
+ return resolver
@@ -8,12 +8,13 @@ from Osdental.Shared.Enums.Profile import Profile
8
8
  from Osdental.Exception.ControlledException import OSDException, AccessDeniedException
9
9
  from Osdental.Encryptor.Aes import AES
10
10
  from Osdental.Graphql.Models import BaseGraphQLContext
11
+ from Osdental.Shared.Logger import logger
11
12
 
12
13
  def secure_resolver(action = None):
13
14
  def decorator(func: Callable):
14
15
 
15
16
  signature = inspect.signature(func)
16
- accepts_data = "data" in signature.parameters
17
+ params = signature.parameters
17
18
 
18
19
  @wraps(func)
19
20
  async def wrapper(obj: Any, context: BaseGraphQLContext, **kwargs: Dict[str, Any]):
@@ -26,19 +27,23 @@ def secure_resolver(action = None):
26
27
  if Profile(token.abbreviation) not in action.allowed_roles:
27
28
  raise AccessDeniedException(error="The user's profile is not allowed to perform this action.")
28
29
 
29
- if accepts_data and payload:
30
+ if "token" in params:
31
+ kwargs["token"] = token
32
+
33
+ if "data" in params:
30
34
  kwargs["data"] = payload
31
35
 
32
- result: Response = await func(obj, context, **kwargs)
36
+ result: Response = await func(obj, **kwargs)
33
37
 
34
38
  context.audit_plain_response = copy.deepcopy(result)
35
39
 
36
- if result.data is not None:
40
+ if result.data is not None and result.encryption_type == "AES" and result.key is None:
37
41
  result.data = AES.encrypt(aes_auth, result.data)
38
42
 
39
43
  return result.send()
40
44
 
41
45
  except (Exception, OSDException) as e:
46
+ logger.exception(f"An error has occurred: {str(e)}")
42
47
  result = Response(
43
48
  status=getattr(e, "status_code", "DB_ERROR_UNEXPECTED"),
44
49
  message=getattr(e, "message", "Could not process request."),
@@ -1,5 +1,5 @@
1
1
  import jwt
2
- from typing import Dict
2
+ from typing import Dict, Any
3
3
  from cryptography.hazmat.primitives import serialization
4
4
  from cryptography.hazmat.backends import default_backend
5
5
  from Osdental.Exception.ControlledException import JWTokenException
@@ -11,7 +11,7 @@ class JWT:
11
11
 
12
12
  @staticmethod
13
13
  def generate_token(
14
- payload: Dict[str, str], jwt_secret_key: str, algorithm="HS256"
14
+ payload: Dict[str, Any], jwt_secret_key: str, algorithm="HS256"
15
15
  ) -> str:
16
16
  try:
17
17
  token = jwt.encode(payload, jwt_secret_key, algorithm=algorithm)
@@ -22,7 +22,7 @@ class JWT:
22
22
  raise JWTokenException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
23
23
 
24
24
  @staticmethod
25
- def extract_payload(jwt_token: str, jwt_secret_key: str) -> Dict[str, str]:
25
+ def extract_payload(jwt_token: str, jwt_secret_key: str) -> Dict[str, Any]:
26
26
  try:
27
27
  payload = jwt.decode(jwt_token, jwt_secret_key, algorithms=["HS256"])
28
28
  return payload
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from base64 import b64decode, b64encode
3
- from typing import Dict
3
+ from typing import Dict, Any
4
4
  from cryptography.hazmat.primitives import serialization
5
5
  from cryptography.hazmat.primitives.asymmetric import padding
6
6
  from cryptography.hazmat.primitives import hashes
@@ -12,7 +12,7 @@ from Osdental.Shared.Enums.Constant import Constant
12
12
  class RSAEncryptor:
13
13
 
14
14
  @staticmethod
15
- def encrypt(data:str | Dict[str,str], public_key_rsa:str) -> str:
15
+ def encrypt(data: str | Dict[str, Any], public_key_rsa: str) -> str:
16
16
  try:
17
17
  if isinstance(data, dict):
18
18
  data = json.dumps(data)
@@ -36,7 +36,7 @@ class RSAEncryptor:
36
36
 
37
37
 
38
38
  @staticmethod
39
- def decrypt(data:str, private_key_rsa:str, silent:bool = False) -> str:
39
+ def decrypt(data: str, private_key_rsa: str, silent: bool = False) -> str:
40
40
  try:
41
41
  encrypted_bytes = b64decode(data)
42
42
  private_key = serialization.load_pem_private_key(private_key_rsa.encode(Constant.DEFAULT_ENCODING), password=None)
@@ -0,0 +1,189 @@
1
+ import json
2
+ from graphql.pyutils import is_awaitable
3
+ from ariadne.types import Extension
4
+ from Osdental.Shared.Logger import logger
5
+ from Osdental.Encryptor.Aes import AES
6
+ from Osdental.Graphql._Helpers._TenantPolicy import TenantPolicy
7
+ from Osdental.Rest.Context.RequestContext import (
8
+ current_context,
9
+ RequestContext
10
+ )
11
+ from Osdental.Graphql.Models import BaseGraphQLContext
12
+ from Osdental.Shared.Enums.Constant import Constant
13
+
14
+ class AuditExtension(Extension):
15
+
16
+ def request_started(self, context):
17
+ request = context.request
18
+ self._ctx_token = current_context.set(
19
+ RequestContext(
20
+ request=request,
21
+ request_id=request.headers.get("x-request-id"),
22
+ user=None
23
+ )
24
+ )
25
+
26
+ self.errors = None
27
+ self.request_payload = None
28
+ self.result = None
29
+
30
+ def _should_skip(self, body) -> bool:
31
+ query = body.get("query", "") or ""
32
+ return "__schema" in query or "__type(" in query
33
+
34
+ async def resolve(self, next_, root, info, **kwargs):
35
+
36
+ context: BaseGraphQLContext = info.context
37
+ request = context.request
38
+
39
+ # cache body
40
+ if not hasattr(context, "_cached_body"):
41
+ context._cached_body = await request.json()
42
+
43
+ body = context._cached_body
44
+
45
+ # skip introspection
46
+ if self._should_skip(body):
47
+ result = next_(root, info, **kwargs)
48
+ if is_awaitable(result):
49
+ result = await result
50
+ return result
51
+
52
+ is_root = root is None
53
+
54
+ # SOLO ROOT
55
+ if is_root:
56
+
57
+ # identificar resolver público
58
+ resolver_fn = getattr(next_, "__wrapped__", next_)
59
+ is_public = getattr(resolver_fn, "_is_public", False)
60
+
61
+ # inicializar auth UNA SOLA VEZ
62
+ if not hasattr(context, "_auth_initialized"):
63
+ context._auth_initialized = True
64
+
65
+ headers = request.headers
66
+ container = context.container
67
+ token_service = container.token_service
68
+
69
+ aes_auth = request.app.state.aes_auth
70
+ aes_user = request.app.state.aes_user
71
+
72
+ if not aes_auth or not aes_user:
73
+ aes_auth = None
74
+ aes_user = None
75
+
76
+ original_token = None
77
+ if not is_public and headers.get("authorization"):
78
+ try:
79
+ original_token = await token_service.authenticate(headers, aes_user)
80
+ except Exception:
81
+ original_token = None
82
+
83
+ context._original_token = original_token
84
+ context.token = original_token
85
+ context.aes_auth = aes_auth
86
+
87
+ # VALIDACIÓN SOLO ROOT
88
+ original_token = getattr(context, "_original_token", None)
89
+
90
+ if not is_public and not original_token:
91
+ raise ValueError("Authorization required")
92
+
93
+ # payload
94
+ variables = body.get("variables") or {}
95
+
96
+ encrypted_payload = (
97
+ kwargs.get("data")
98
+ or variables.get("data")
99
+ )
100
+
101
+ decrypted_payload = None
102
+
103
+ if encrypted_payload is not None:
104
+ if isinstance(encrypted_payload, dict):
105
+ decrypted_payload = encrypted_payload
106
+
107
+ elif isinstance(encrypted_payload, str):
108
+ try:
109
+ decrypted_payload = json.loads(encrypted_payload)
110
+ except Exception:
111
+ if context.aes_auth:
112
+ try:
113
+ decrypted_payload = AES.decrypt(context.aes_auth, encrypted_payload)
114
+ try:
115
+ decrypted_payload = json.loads(decrypted_payload)
116
+ except Exception:
117
+ pass
118
+ except Exception:
119
+ decrypted_payload = None
120
+
121
+ if decrypted_payload is not None:
122
+ context.decrypted_payload = decrypted_payload
123
+
124
+ if not is_public:
125
+ token = TenantPolicy.resolve(
126
+ token=context._original_token,
127
+ headers=request.headers,
128
+ decrypted_payload=decrypted_payload,
129
+ operation_type=info.operation.operation.value
130
+ )
131
+ context.token = token
132
+
133
+ # auditoría request payload
134
+ if not self.request_payload:
135
+ token = context.token
136
+
137
+ self.request = request
138
+ self.request_payload = {
139
+ "operation_type": info.operation.operation.value,
140
+ "operation_name": body.get("operationName", "UnknownOperation"),
141
+ "query": body.get("query"),
142
+ "variables": decrypted_payload,
143
+ "user": token.user_full_name if token else "Public"
144
+ }
145
+
146
+ # SIEMPRE ejecutar resolver (root + fields)
147
+ result = next_(root, info, **kwargs)
148
+
149
+ if is_awaitable(result):
150
+ result = await result
151
+
152
+ # SOLO ROOT captura resultado final
153
+ if is_root and self.result is None:
154
+ self.result = result
155
+
156
+ if not getattr(context, "audit_plain_response", None):
157
+ context.audit_plain_response = result
158
+
159
+ return result
160
+
161
+ def has_errors(self, errors, context):
162
+ self.errors = errors
163
+
164
+ def request_finished(self, context):
165
+
166
+ if not self.request_payload:
167
+ return
168
+
169
+ query = self.request_payload.get("query", "")
170
+
171
+ if "__schema" in query or "__type" in query:
172
+ return
173
+
174
+ final_result = context.audit_plain_response or self.result
175
+
176
+ if final_result is None:
177
+ return
178
+
179
+ dispatcher = context.request.app.state.audit_dispatcher
180
+
181
+ try:
182
+ dispatcher.dispatch(
183
+ request=self.request,
184
+ request_payload=self.request_payload,
185
+ result=final_result,
186
+ audit_type=Constant.MESSAGE_LOG_INTERNAL
187
+ )
188
+ except Exception as e:
189
+ logger(f"[AUDIT ERROR]: {str(e)}")
@@ -4,6 +4,7 @@ from fastapi import Request
4
4
  from Osdental.Models.AuditConfig import AuditConfig
5
5
  from Osdental.Messaging import IMessageQueue
6
6
  from Osdental.Graphql._Helpers._AuditHelper import AuditHelper
7
+ from Osdental.Helpers.ResponseDecryptor import decryptor_data, VALID_TYPES
7
8
  from Osdental.Models._Audit import Audit
8
9
  from Osdental.Models.Response import Response
9
10
  from Osdental.Shared.Enums.Constant import Constant
@@ -74,7 +75,7 @@ class AuditDispatcher:
74
75
  async def _process(self, payload: Dict[str, Any]):
75
76
  request = payload["request"]
76
77
  request_payload = payload["request_payload"]
77
- result = payload["result"]
78
+ result: Response = payload["result"]
78
79
  audit_type = payload["audit_type"]
79
80
 
80
81
  operation_name = request_payload.get("operation_name")
@@ -96,6 +97,11 @@ class AuditDispatcher:
96
97
  message = result.message
97
98
  data = result.data
98
99
  error = result.error if result.error else message
100
+
101
+ # Obtencion de campos adicionales cuando es otro tipo de encriptacion o clave
102
+ encryption_type = result.encryption_type
103
+ key = result.key
104
+
99
105
 
100
106
  if audit_type == Constant.MESSAGE_LOG_INTERNAL:
101
107
 
@@ -121,6 +127,9 @@ class AuditDispatcher:
121
127
  audit_message = request_audit_payload | payload
122
128
 
123
129
  else:
130
+ if encryption_type in VALID_TYPES and key is not None:
131
+ data = decryptor_data(encryption_type, key, data)
132
+
124
133
  payload = AuditHelper.build_final_payload(
125
134
  _type="RESPONSE",
126
135
  status_code=status_code,
@@ -0,0 +1,15 @@
1
+ from typing import Dict, Any
2
+ from Osdental.Encryptor.Aes import AES
3
+ from Osdental.Encryptor.Rsa import RSAEncryptor
4
+
5
+ VALID_TYPES = {"RSA", "AES"}
6
+
7
+ def decryptor_data(encryption_type: str, key: str, data: Dict[str, Any] | str) -> Any:
8
+
9
+ match encryption_type:
10
+
11
+ case "AES":
12
+ return AES.decrypt(key, data)
13
+
14
+ case "RSA":
15
+ return RSAEncryptor.decrypt(data, key)
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, field, asdict
2
- from typing import Optional, Any
2
+ from typing import Optional, Any, Literal
3
3
  from Osdental.Shared.Enums.Code import Code
4
4
  from Osdental.Shared.Enums.Message import Message
5
5
 
@@ -9,6 +9,8 @@ class Response:
9
9
  message: str = field(default=Message.PROCESS_SUCCESS_MSG)
10
10
  data: Optional[Any] = None
11
11
  error: Optional[str] = None
12
+ encryption_type: Literal["AES", "RSA", "NORMAL"] = "AES"
13
+ key: Optional[str] = None
12
14
 
13
15
  def send(self):
14
16
  response = asdict(self)
@@ -16,4 +18,10 @@ class Response:
16
18
  if response["error"] is None:
17
19
  response.pop("error")
18
20
 
21
+ if response["encryption_type"]:
22
+ response.pop("encryption_type")
23
+
24
+ if response["key"]:
25
+ response.pop("key")
26
+
19
27
  return response
@@ -0,0 +1,30 @@
1
+
2
+ def normalize_rsa_keys(key_str: str, is_private: bool = True) -> str:
3
+ """
4
+ Normaliza una llave RSA (privada o pública) para que sea compatible con cryptography.
5
+ Si is_private=True, normaliza la llave privada; si False, normaliza la llave pública.
6
+ """
7
+
8
+ # Determinar encabezados correctos
9
+ if is_private:
10
+ header = "-----BEGIN RSA PRIVATE KEY-----"
11
+ footer = "-----END RSA PRIVATE KEY-----"
12
+ invalid_texts = ["-----BEGINRSAPRIVATEKEY-----", "-----ENDRSAPRIVATEKEY-----",
13
+ "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----"]
14
+ else:
15
+ header = "-----BEGIN PUBLIC KEY-----"
16
+ footer = "-----END PUBLIC KEY-----"
17
+ invalid_texts = ["-----BEGINPUBLICKEY-----", "-----ENDPUBLICKEY-----",
18
+ "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----"]
19
+
20
+ # Limpiar encabezados inválidos y espacios
21
+ for text in invalid_texts:
22
+ key_str = key_str.replace(text, "")
23
+ key_str = key_str.replace("\r", "").replace(" ", "").replace("\n", "")
24
+
25
+ # Dividir en líneas de 64 caracteres
26
+ lines = [key_str[i:i+64] for i in range(0, len(key_str), 64)]
27
+
28
+ # Reconstruir PEM válido
29
+ pem = f"{header}\n" + "\n".join(lines) + f"\n{footer}\n"
30
+ return pem
@@ -80,4 +80,8 @@ class AzureBlobStorage(IStorageService):
80
80
  return {
81
81
  "uploadUrl": url,
82
82
  "blobName": filename
83
- }
83
+ }
84
+
85
+ async def close(self):
86
+ await self._client.close()
87
+ await self._credential.close()
File without changes
encryptors-2.39/README.md DELETED
@@ -1,17 +0,0 @@
1
- # osdental-library
2
-
3
- `osdental-library` is a versatile and easy-to-use library for handling common tasks related to **encryption**, **hashing**, and **JWT token management**. Ideal for projects that require a secure and efficient approach to handling sensitive data.
4
-
5
- ## Features
6
-
7
- - Generation and validation of **hashes** using modern algorithms.
8
- - Encryption and decryption of data using secure keys.
9
- - Creation and verification of **JWT tokens** for authentication and authorization.
10
- - Implementations that are easy to integrate into any Python project.
11
-
12
- ## Installation
13
-
14
- You can easily install `osdental-library` using `pip`:
15
-
16
- ```bash
17
- pip install osdental-library
@@ -1,120 +0,0 @@
1
- import json
2
- from graphql.pyutils import is_awaitable
3
- from ariadne.types import Extension
4
- from Osdental.Encryptor.Aes import AES
5
- from Osdental.Graphql._Helpers._TenantPolicy import TenantPolicy
6
- from Osdental.Rest.Context.RequestContext import (
7
- current_context,
8
- RequestContext
9
- )
10
- from Osdental.Graphql.Models import BaseGraphQLContext
11
- from Osdental.Graphql._Exceptions import AESKeyNotFound
12
- from Osdental.Shared.Enums.Constant import Constant
13
-
14
- class AuditExtension(Extension):
15
-
16
- def request_started(self, context):
17
- request = context.request
18
- self._ctx_token = current_context.set(
19
- RequestContext(
20
- request=request,
21
- request_id=request.headers.get("x-request-id"),
22
- user=None
23
- )
24
- )
25
-
26
- self.errors = None
27
- self.request_payload = None
28
- self.result = None
29
-
30
- async def resolve(self, next_, root, info, **kwargs):
31
-
32
- if not self.request_payload:
33
- context: BaseGraphQLContext = info.context
34
-
35
- request = context.request
36
- self.request = request
37
-
38
- body = await request.json()
39
- headers = request.headers
40
-
41
- container = context.container
42
- token_service = container.token_service
43
-
44
- aes_auth = request.app.state.aes_auth
45
- aes_user = request.app.state.aes_user
46
-
47
- if not aes_auth:
48
- raise AESKeyNotFound("AES user key is missing.", "aes_auth")
49
-
50
- if not aes_user:
51
- raise AESKeyNotFound("AES authorization key is missing.", "aes_user")
52
-
53
- original_token = await token_service.authenticate(headers, aes_user)
54
-
55
- variables = body.get("variables") or {}
56
- encrypted_payload = variables.get("data")
57
-
58
- decrypted_payload = None
59
-
60
- if encrypted_payload:
61
- try:
62
- decrypted_payload = AES.decrypt(aes_auth, encrypted_payload)
63
-
64
- try:
65
- decrypted_payload = json.loads(decrypted_payload)
66
- except Exception:
67
- pass
68
-
69
- except Exception:
70
- decrypted_payload = None
71
-
72
- token = TenantPolicy.resolve(
73
- token=original_token,
74
- headers=request.headers,
75
- decrypted_payload=decrypted_payload,
76
- operation_type=info.operation.operation.value
77
- )
78
-
79
- self.request_payload = {
80
- "operation_type": info.operation.operation.value,
81
- "operation_name": body.get("operationName", "UnknownOperation"),
82
- "query": body.get("query"),
83
- "variables": decrypted_payload,
84
- "user": token.user_full_name
85
- }
86
-
87
- context.decrypted_payload = decrypted_payload
88
- context.token = token
89
- context.aes_auth = aes_auth
90
-
91
- result = next_(root, info, **kwargs)
92
-
93
- if is_awaitable(result):
94
- result = await result
95
-
96
- if root is None:
97
- self.result = result
98
-
99
- return result
100
-
101
- def has_errors(self, errors, context):
102
- self.errors = errors
103
-
104
- def request_finished(self, context):
105
- if not self.request_payload: return
106
-
107
- query = self.request_payload.get("query", "")
108
-
109
- if "__schema" in query or "__type" in query: return
110
-
111
- if not hasattr(context, "audit_plain_response"): return
112
-
113
- dispatcher = context.request.app.state.audit_dispatcher
114
-
115
- dispatcher.dispatch(
116
- request=self.request,
117
- request_payload=self.request_payload,
118
- result=context.audit_plain_response,
119
- audit_type=Constant.MESSAGE_LOG_INTERNAL
120
- )
File without changes