Encryptors 2.40__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 (88) hide show
  1. {encryptors-2.40 → encryptors-2.41}/PKG-INFO +1 -1
  2. {encryptors-2.40 → encryptors-2.41}/setup.py +2 -2
  3. {encryptors-2.40 → encryptors-2.41}/src/Encryptors.egg-info/PKG-INFO +1 -1
  4. {encryptors-2.40 → encryptors-2.41}/src/Encryptors.egg-info/SOURCES.txt +2 -0
  5. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Decorators/SecureResolver.py +1 -1
  6. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/Jwt.py +3 -3
  7. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/Rsa.py +3 -3
  8. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/Extensions/AuditExtension.py +11 -12
  9. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Helpers/AuditDispatcher.py +10 -1
  10. encryptors-2.41/src/Osdental/Helpers/ResponseDecryptor.py +15 -0
  11. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Models/Response.py +9 -1
  12. encryptors-2.41/src/Osdental/Shared/Utils/RsaUtils.py +30 -0
  13. {encryptors-2.40 → encryptors-2.41}/README.md +0 -0
  14. {encryptors-2.40 → encryptors-2.41}/setup.cfg +0 -0
  15. {encryptors-2.40 → encryptors-2.41}/src/Encryptors.egg-info/dependency_links.txt +0 -0
  16. {encryptors-2.40 → encryptors-2.41}/src/Encryptors.egg-info/entry_points.txt +0 -0
  17. {encryptors-2.40 → encryptors-2.41}/src/Encryptors.egg-info/requires.txt +0 -0
  18. {encryptors-2.40 → encryptors-2.41}/src/Encryptors.egg-info/top_level.txt +0 -0
  19. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Cli/__init__.py +0 -0
  20. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Database/BaseRepository.py +0 -0
  21. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Database/Connection.py +0 -0
  22. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Database/__init__.py +0 -0
  23. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Decorators/Grpc.py +0 -0
  24. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Decorators/PublicResolver.py +0 -0
  25. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Decorators/Retry.py +0 -0
  26. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Decorators/SqlDataNormalizer.py +0 -0
  27. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Decorators/__init__.py +0 -0
  28. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/Aes.py +0 -0
  29. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/Argon2.py +0 -0
  30. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/Bcrypt.py +0 -0
  31. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/Sha512.py +0 -0
  32. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Encryptor/__init__.py +0 -0
  33. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Exception/ControlledException.py +0 -0
  34. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Exception/__init__.py +0 -0
  35. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/Extensions/__init__.py +0 -0
  36. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/Models/__init__.py +0 -0
  37. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/_Exceptions/__init__.py +0 -0
  38. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_AuditHelper.py +0 -0
  39. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_ExtractAuthToken.py +0 -0
  40. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_TenantPolicy.py +0 -0
  41. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/_TokenService.py +0 -0
  42. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/_Helpers/__init__.py +0 -0
  43. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Graphql/__init__.py +0 -0
  44. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Helpers/KeyVaultService.py +0 -0
  45. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Helpers/__init__.py +0 -0
  46. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Http/APIClient.py +0 -0
  47. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Http/_Exceptions.py +0 -0
  48. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Http/__init__.py +0 -0
  49. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Messaging/AzureServiceBus.py +0 -0
  50. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Messaging/Kafka.py +0 -0
  51. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Messaging/RabbitMQ.py +0 -0
  52. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Messaging/__init__.py +0 -0
  53. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Models/AuditConfig.py +0 -0
  54. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Models/Token.py +0 -0
  55. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Models/_Audit.py +0 -0
  56. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Models/__init__.py +0 -0
  57. {encryptors-2.40 → encryptors-2.41}/src/Osdental/RedisCache/Redis.py +0 -0
  58. {encryptors-2.40 → encryptors-2.41}/src/Osdental/RedisCache/__init__.py +0 -0
  59. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Rest/Context/RequestContext.py +0 -0
  60. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Rest/Context/__init__.py +0 -0
  61. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Rest/Middlewares/RequestContextMiddleware.py +0 -0
  62. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Rest/Middlewares/__init__.py +0 -0
  63. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Rest/__init__.py +0 -0
  64. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/Code.py +0 -0
  65. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/Constant.py +0 -0
  66. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/FileType.py +0 -0
  67. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/GrahpqlOperation.py +0 -0
  68. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/Message.py +0 -0
  69. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/Profile.py +0 -0
  70. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Enums/__init__.py +0 -0
  71. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Logger.py +0 -0
  72. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/CaseConverter.py +0 -0
  73. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/CodeGenerator.py +0 -0
  74. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/DataNormalizer.py +0 -0
  75. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/DataUtils.py +0 -0
  76. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/DateUtils.py +0 -0
  77. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/FileMetaData.py +0 -0
  78. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/HashValidator.py +0 -0
  79. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/Mapper.py +0 -0
  80. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/PasswordGenerator.py +0 -0
  81. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/QueryGenerator.py +0 -0
  82. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/TextProcessor.py +0 -0
  83. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/Utils/__init__.py +0 -0
  84. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Shared/__init__.py +0 -0
  85. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Storage/AzureBlobStorage.py +0 -0
  86. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Storage/S3Storage.py +0 -0
  87. {encryptors-2.40 → encryptors-2.41}/src/Osdental/Storage/__init__.py +0 -0
  88. {encryptors-2.40 → encryptors-2.41}/src/Osdental/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Encryptors
3
- Version: 2.40
3
+ Version: 2.41
4
4
  Summary: End-to-end algorithm library
5
5
  Author: OSDental LLC
6
6
  Author-email: support@osdental.ai
@@ -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.40",
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.40
3
+ Version: 2.41
4
4
  Summary: End-to-end algorithm library
5
5
  Author: OSDental LLC
6
6
  Author-email: support@osdental.ai
@@ -38,6 +38,7 @@ src/Osdental/Graphql/_Helpers/_TokenService.py
38
38
  src/Osdental/Graphql/_Helpers/__init__.py
39
39
  src/Osdental/Helpers/AuditDispatcher.py
40
40
  src/Osdental/Helpers/KeyVaultService.py
41
+ src/Osdental/Helpers/ResponseDecryptor.py
41
42
  src/Osdental/Helpers/__init__.py
42
43
  src/Osdental/Http/APIClient.py
43
44
  src/Osdental/Http/_Exceptions.py
@@ -77,6 +78,7 @@ src/Osdental/Shared/Utils/HashValidator.py
77
78
  src/Osdental/Shared/Utils/Mapper.py
78
79
  src/Osdental/Shared/Utils/PasswordGenerator.py
79
80
  src/Osdental/Shared/Utils/QueryGenerator.py
81
+ src/Osdental/Shared/Utils/RsaUtils.py
80
82
  src/Osdental/Shared/Utils/TextProcessor.py
81
83
  src/Osdental/Shared/Utils/__init__.py
82
84
  src/Osdental/Storage/AzureBlobStorage.py
@@ -37,7 +37,7 @@ def secure_resolver(action = None):
37
37
 
38
38
  context.audit_plain_response = copy.deepcopy(result)
39
39
 
40
- if result.data is not None:
40
+ if result.data is not None and result.encryption_type == "AES" and result.key is None:
41
41
  result.data = AES.encrypt(aes_auth, result.data)
42
42
 
43
43
  return result.send()
@@ -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)
@@ -29,37 +29,36 @@ class AuditExtension(Extension):
29
29
 
30
30
  def _should_skip(self, body) -> bool:
31
31
  query = body.get("query", "") or ""
32
- return "__schema" in query or "__type" in query
32
+ return "__schema" in query or "__type(" in query
33
33
 
34
34
  async def resolve(self, next_, root, info, **kwargs):
35
35
 
36
36
  context: BaseGraphQLContext = info.context
37
37
  request = context.request
38
38
 
39
- # 🔹 cache body
39
+ # cache body
40
40
  if not hasattr(context, "_cached_body"):
41
41
  context._cached_body = await request.json()
42
42
 
43
43
  body = context._cached_body
44
44
 
45
- # 🔹 skip introspection
45
+ # skip introspection
46
46
  if self._should_skip(body):
47
47
  result = next_(root, info, **kwargs)
48
48
  if is_awaitable(result):
49
49
  result = await result
50
50
  return result
51
51
 
52
- # 🔥 CLAVE
53
52
  is_root = root is None
54
53
 
55
- # 🔥 SOLO ROOT → TODO TU SISTEMA
54
+ # SOLO ROOT
56
55
  if is_root:
57
56
 
58
- # 🔹 identificar resolver público
57
+ # identificar resolver público
59
58
  resolver_fn = getattr(next_, "__wrapped__", next_)
60
59
  is_public = getattr(resolver_fn, "_is_public", False)
61
60
 
62
- # 🔹 inicializar auth UNA SOLA VEZ
61
+ # inicializar auth UNA SOLA VEZ
63
62
  if not hasattr(context, "_auth_initialized"):
64
63
  context._auth_initialized = True
65
64
 
@@ -85,13 +84,13 @@ class AuditExtension(Extension):
85
84
  context.token = original_token
86
85
  context.aes_auth = aes_auth
87
86
 
88
- # 🔐 VALIDACIÓN SOLO ROOT
87
+ # VALIDACIÓN SOLO ROOT
89
88
  original_token = getattr(context, "_original_token", None)
90
89
 
91
90
  if not is_public and not original_token:
92
91
  raise ValueError("Authorization required")
93
92
 
94
- # 🔹 payload
93
+ # payload
95
94
  variables = body.get("variables") or {}
96
95
 
97
96
  encrypted_payload = (
@@ -131,7 +130,7 @@ class AuditExtension(Extension):
131
130
  )
132
131
  context.token = token
133
132
 
134
- # 🔹 auditoría request
133
+ # auditoría request payload
135
134
  if not self.request_payload:
136
135
  token = context.token
137
136
 
@@ -144,13 +143,13 @@ class AuditExtension(Extension):
144
143
  "user": token.user_full_name if token else "Public"
145
144
  }
146
145
 
147
- # 🔥 SIEMPRE ejecutar resolver (root + fields)
146
+ # SIEMPRE ejecutar resolver (root + fields)
148
147
  result = next_(root, info, **kwargs)
149
148
 
150
149
  if is_awaitable(result):
151
150
  result = await result
152
151
 
153
- # 🔹 SOLO ROOT captura resultado final
152
+ # SOLO ROOT captura resultado final
154
153
  if is_root and self.result is None:
155
154
  self.result = result
156
155
 
@@ -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
File without changes
File without changes