Encryptors 2.0__tar.gz → 2.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.
- {encryptors-2.0 → encryptors-2.1}/PKG-INFO +1 -1
- {encryptors-2.0 → encryptors-2.1}/setup.py +1 -1
- {encryptors-2.0 → encryptors-2.1}/src/Encryptors.egg-info/PKG-INFO +1 -1
- {encryptors-2.0 → encryptors-2.1}/src/Encryptors.egg-info/SOURCES.txt +5 -4
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/AuditLog.py +8 -7
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/DecryptedData.py +10 -9
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/ExternalHttp/Client.py +27 -32
- encryptors-2.1/src/Osdental/Grpc/Adapter/AuthGrpcAdapter.py +15 -0
- encryptors-2.1/src/Osdental/Grpc/Adapter/SharedGrpcAdapter.py +28 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Client/AuthGrpcClient.py +2 -2
- encryptors-2.0/src/Osdental/Grpc/Client/SharedResourcesGrpcClient.py → encryptors-2.1/src/Osdental/Grpc/Client/SharedGrpcClient.py +11 -1
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/Shared_pb2.py +2 -2
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/Shared_pb2_grpc.py +43 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Helpers/AuditLogHelper.py +3 -23
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Helpers/DecryptedHelper.py +7 -30
- encryptors-2.1/src/Osdental/Helpers/EncryptorHelper.py +24 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Messaging/AzureServiceBus.py +1 -1
- encryptors-2.1/src/Osdental/Models/Encryptor.py +12 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Models/Token.py +2 -2
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/RedisCache/Redis.py +15 -37
- encryptors-2.1/src/Osdental/ServicesBus/ServicesBus.py +21 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/App.py +0 -1
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Instance.py +8 -6
- encryptors-2.1/src/Osdental/Shared/Logger.py +3 -0
- encryptors-2.0/src/Osdental/Grpc/Adapter/SharedLegacyGrpcAdapter.py +0 -17
- encryptors-2.0/src/Osdental/Grpc/Adapter/SharedResourcesGrpcAdapter.py +0 -19
- encryptors-2.0/src/Osdental/Grpc/Client/SharedLegacyGrpcClient.py +0 -26
- encryptors-2.0/src/Osdental/ServicesBus/ServicesBus.py +0 -28
- encryptors-2.0/src/Osdental/Shared/Logger.py +0 -17
- {encryptors-2.0 → encryptors-2.1}/README.md +0 -0
- {encryptors-2.0 → encryptors-2.1}/setup.cfg +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Encryptors.egg-info/dependency_links.txt +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Encryptors.egg-info/entry_points.txt +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Encryptors.egg-info/requires.txt +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Encryptors.egg-info/top_level.txt +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/BlobStorage/Storage.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/BlobStorage/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Cli/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Database/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/Deprecated.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/Grpc.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/Retry.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/SqlDataNormalizer.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Decorators/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/Aes.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/Argon2.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/Bcrypt.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/Jwt.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/Rsa.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/Sha512.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Encryptor/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Exception/ControlledException.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Exception/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/ExternalHttp/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Adapter/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Base/GrpcClientBase.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Base/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Client/GrpcConnection.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Client/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Dtos/GrpcResponse.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Dtos/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/Auth_pb2.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/Auth_pb2_grpc.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/Common_pb2.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/Common_pb2_grpc.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/Generated/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Grpc/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Helpers/AuditQueueHelper.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Helpers/RequestHelper.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Helpers/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/InternalHttp/Request.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/InternalHttp/Response.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/InternalHttp/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Messaging/AuditServiceBus.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Messaging/Kafka.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Messaging/RabbitMQ.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Messaging/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Models/Legacy.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Models/Response.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Models/ShardResource.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Models/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/RedisCache/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/ServicesBus/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Config/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/Code.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/Constant.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/FileType.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/GrahpqlOperation.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/Message.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/Profile.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Enums/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/CaseConverter.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/CodeGenerator.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/DataUtils.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/DateUtils.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/FileMetaData.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/HashValidator.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/Mapper.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/PasswordGenerator.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/QueryGenerator.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/TextProcessor.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/Utils/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Shared/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Storage/AzureBlobStorage.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Storage/S3Storage.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/Storage/__init__.py +0 -0
- {encryptors-2.0 → encryptors-2.1}/src/Osdental/__init__.py +0 -0
|
@@ -30,15 +30,14 @@ src/Osdental/Exception/__init__.py
|
|
|
30
30
|
src/Osdental/ExternalHttp/Client.py
|
|
31
31
|
src/Osdental/ExternalHttp/__init__.py
|
|
32
32
|
src/Osdental/Grpc/__init__.py
|
|
33
|
-
src/Osdental/Grpc/Adapter/
|
|
34
|
-
src/Osdental/Grpc/Adapter/
|
|
33
|
+
src/Osdental/Grpc/Adapter/AuthGrpcAdapter.py
|
|
34
|
+
src/Osdental/Grpc/Adapter/SharedGrpcAdapter.py
|
|
35
35
|
src/Osdental/Grpc/Adapter/__init__.py
|
|
36
36
|
src/Osdental/Grpc/Base/GrpcClientBase.py
|
|
37
37
|
src/Osdental/Grpc/Base/__init__.py
|
|
38
38
|
src/Osdental/Grpc/Client/AuthGrpcClient.py
|
|
39
39
|
src/Osdental/Grpc/Client/GrpcConnection.py
|
|
40
|
-
src/Osdental/Grpc/Client/
|
|
41
|
-
src/Osdental/Grpc/Client/SharedResourcesGrpcClient.py
|
|
40
|
+
src/Osdental/Grpc/Client/SharedGrpcClient.py
|
|
42
41
|
src/Osdental/Grpc/Client/__init__.py
|
|
43
42
|
src/Osdental/Grpc/Dtos/GrpcResponse.py
|
|
44
43
|
src/Osdental/Grpc/Dtos/__init__.py
|
|
@@ -52,6 +51,7 @@ src/Osdental/Grpc/Generated/__init__.py
|
|
|
52
51
|
src/Osdental/Helpers/AuditLogHelper.py
|
|
53
52
|
src/Osdental/Helpers/AuditQueueHelper.py
|
|
54
53
|
src/Osdental/Helpers/DecryptedHelper.py
|
|
54
|
+
src/Osdental/Helpers/EncryptorHelper.py
|
|
55
55
|
src/Osdental/Helpers/RequestHelper.py
|
|
56
56
|
src/Osdental/Helpers/__init__.py
|
|
57
57
|
src/Osdental/InternalHttp/Request.py
|
|
@@ -62,6 +62,7 @@ src/Osdental/Messaging/AzureServiceBus.py
|
|
|
62
62
|
src/Osdental/Messaging/Kafka.py
|
|
63
63
|
src/Osdental/Messaging/RabbitMQ.py
|
|
64
64
|
src/Osdental/Messaging/__init__.py
|
|
65
|
+
src/Osdental/Models/Encryptor.py
|
|
65
66
|
src/Osdental/Models/Legacy.py
|
|
66
67
|
src/Osdental/Models/Response.py
|
|
67
68
|
src/Osdental/Models/ShardResource.py
|
|
@@ -3,6 +3,7 @@ import time
|
|
|
3
3
|
from functools import wraps
|
|
4
4
|
from opentelemetry import trace
|
|
5
5
|
from Osdental.Helpers.AuditLogHelper import AuditLogHelper
|
|
6
|
+
from Osdental.Helpers.EncryptorHelper import EncryptorHelper
|
|
6
7
|
from Osdental.Helpers.AuditQueueHelper import AuditQueueHelper
|
|
7
8
|
from Osdental.InternalHttp.Request import CustomRequest
|
|
8
9
|
from Osdental.Exception.ControlledException import OSDException
|
|
@@ -21,8 +22,8 @@ def handle_audit_and_exception(batch: int = 0):
|
|
|
21
22
|
operation_name = "UnknownOperation"
|
|
22
23
|
|
|
23
24
|
try:
|
|
24
|
-
# Load
|
|
25
|
-
|
|
25
|
+
# Load encryptor with cache
|
|
26
|
+
encryptor = await EncryptorHelper.get_cached_encryptors()
|
|
26
27
|
|
|
27
28
|
_, info = args[:2]
|
|
28
29
|
headers = info.context.get("headers") or {}
|
|
@@ -46,12 +47,12 @@ def handle_audit_and_exception(batch: int = 0):
|
|
|
46
47
|
if request:
|
|
47
48
|
AuditLogHelper.fire_and_forget(
|
|
48
49
|
AuditQueueHelper.send(
|
|
49
|
-
CustomRequest(request,
|
|
50
|
+
CustomRequest(request, encryptor.aes_user).send_to_service_bus()
|
|
50
51
|
)
|
|
51
52
|
)
|
|
52
53
|
|
|
53
54
|
except Exception as e:
|
|
54
|
-
logger.
|
|
55
|
+
logger.exception("Failed to prepare auditing")
|
|
55
56
|
|
|
56
57
|
# Perform the main logic inside span
|
|
57
58
|
with tracer.start_as_current_span(f"GraphQL.{operation_name}") as span:
|
|
@@ -63,7 +64,7 @@ def handle_audit_and_exception(batch: int = 0):
|
|
|
63
64
|
# decrypt data if needed
|
|
64
65
|
raw_data = response.get("data")
|
|
65
66
|
if raw_data:
|
|
66
|
-
decrypted = AuditLogHelper.try_decrypt_or_return_raw(raw_data,
|
|
67
|
+
decrypted = AuditLogHelper.try_decrypt_or_return_raw(raw_data, encryptor.private_key_2, encryptor.aes_auth)
|
|
67
68
|
else:
|
|
68
69
|
decrypted = None
|
|
69
70
|
|
|
@@ -81,7 +82,7 @@ def handle_audit_and_exception(batch: int = 0):
|
|
|
81
82
|
return response
|
|
82
83
|
|
|
83
84
|
except OSDException as ex:
|
|
84
|
-
logger.
|
|
85
|
+
logger.exception("Controlled error")
|
|
85
86
|
duration = (time.time() - start) * 1000
|
|
86
87
|
|
|
87
88
|
msg = str(ex) or getattr(ex, 'message', 'OSDException')
|
|
@@ -101,7 +102,7 @@ def handle_audit_and_exception(batch: int = 0):
|
|
|
101
102
|
return ex.get_response()
|
|
102
103
|
|
|
103
104
|
except Exception as e:
|
|
104
|
-
logger.
|
|
105
|
+
logger.exception("Unexpected error")
|
|
105
106
|
ex = OSDException(error=str(e), headers=headers)
|
|
106
107
|
duration = (time.time() - start) * 1000
|
|
107
108
|
|
|
@@ -2,6 +2,7 @@ import asyncio
|
|
|
2
2
|
from functools import wraps
|
|
3
3
|
from typing import Callable, Tuple, Optional, Union, Dict, Any
|
|
4
4
|
from graphql import GraphQLResolveInfo
|
|
5
|
+
from Osdental.Helpers.EncryptorHelper import EncryptorHelper
|
|
5
6
|
from Osdental.Helpers.DecryptedHelper import DecryptedHelper
|
|
6
7
|
from Osdental.Exception.ControlledException import ProfilePermissionDeniedException
|
|
7
8
|
from Osdental.Shared.Enums.Message import Message
|
|
@@ -10,7 +11,7 @@ from Osdental.Shared.Enums.Message import Message
|
|
|
10
11
|
def process_encrypted_data(mutate: bool = True, allowed_permissions: Optional[Union[str, Tuple[str, ...]]] = None):
|
|
11
12
|
"""
|
|
12
13
|
Decorator to:
|
|
13
|
-
- get cached
|
|
14
|
+
- get cached encryptor (fast & safe)
|
|
14
15
|
- decrypt and validate token (async)
|
|
15
16
|
- decrypt aes_data (CPU-bound small op)
|
|
16
17
|
- perform profile permission checks
|
|
@@ -21,8 +22,8 @@ def process_encrypted_data(mutate: bool = True, allowed_permissions: Optional[Un
|
|
|
21
22
|
|
|
22
23
|
@wraps(func)
|
|
23
24
|
async def wrapper(self, info: GraphQLResolveInfo = None, aes_data: str = None, **rest_kwargs):
|
|
24
|
-
# 1) Get
|
|
25
|
-
|
|
25
|
+
# 1) Get encryptor (fast cached path)
|
|
26
|
+
encryptor = await EncryptorHelper.get_cached_encryptors()
|
|
26
27
|
|
|
27
28
|
# 2) Extract context & headers safely
|
|
28
29
|
token_task = None
|
|
@@ -36,15 +37,15 @@ def process_encrypted_data(mutate: bool = True, allowed_permissions: Optional[Un
|
|
|
36
37
|
headers = info.context.get('headers', {}) or {}
|
|
37
38
|
|
|
38
39
|
# 3) Start tasks in parallel where possible
|
|
39
|
-
# decrypted_token requires
|
|
40
|
-
token_coro = DecryptedHelper.decrypted_token(info,
|
|
41
|
-
# decrypted_data requires
|
|
42
|
-
# we can start decrypting aes_data because aes decrypt only needs
|
|
40
|
+
# decrypted_token requires encryptor + info
|
|
41
|
+
token_coro = DecryptedHelper.decrypted_token(info, encryptor, mutate) if param_mask["token"] else None
|
|
42
|
+
# decrypted_data requires aes_auth and token (token not yet available)
|
|
43
|
+
# we can start decrypting aes_data because aes decrypt only needs aes_auth (from encryptor)
|
|
43
44
|
data_coro = None
|
|
44
45
|
if param_mask["data"] and aes_data is not None:
|
|
45
46
|
# decrypt is sync in our lib -> wrap in loop.run_in_executor to avoid blocking event loop if heavy
|
|
46
47
|
loop = asyncio.get_running_loop()
|
|
47
|
-
data_coro = loop.run_in_executor(None, DecryptedHelper.decrypted_data, aes_data,
|
|
48
|
+
data_coro = loop.run_in_executor(None, DecryptedHelper.decrypted_data, aes_data, encryptor.aes_auth, None)
|
|
48
49
|
|
|
49
50
|
# run token and data decrypt in parallel (token will run validate_token internally)
|
|
50
51
|
results = await asyncio.gather(*[c for c in (token_coro, data_coro) if c is not None], return_exceptions=True)
|
|
@@ -70,7 +71,7 @@ def process_encrypted_data(mutate: bool = True, allowed_permissions: Optional[Un
|
|
|
70
71
|
if token_result and data_result is None and aes_data is not None and param_mask["data"]:
|
|
71
72
|
# decrypt using executor to avoid blocking (sync operation)
|
|
72
73
|
loop = asyncio.get_running_loop()
|
|
73
|
-
data_result = await loop.run_in_executor(None, DecryptedHelper.decrypted_data, aes_data,
|
|
74
|
+
data_result = await loop.run_in_executor(None, DecryptedHelper.decrypted_data, aes_data, encryptor.aes_auth, token_result)
|
|
74
75
|
|
|
75
76
|
# If we have both token and data and we decrypted data before token (token finished later),
|
|
76
77
|
# ensure token id_external_enterprise override is applied:
|
|
@@ -4,12 +4,13 @@ import httpx
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from typing import Dict, Optional
|
|
6
6
|
from Osdental.Decorators.Retry import rest_retry
|
|
7
|
-
from Osdental.
|
|
7
|
+
from Osdental.Helpers.AuditLogHelper import AuditLogHelper
|
|
8
|
+
from Osdental.Helpers.AuditQueueHelper import AuditQueueHelper
|
|
8
9
|
from Osdental.Shared.Enums.Constant import Constant
|
|
9
10
|
from Osdental.Shared.Enums.App import App
|
|
10
11
|
from Osdental.Shared.Instance import Instance
|
|
11
12
|
|
|
12
|
-
#
|
|
13
|
+
# Limits attendance towards Service Bus (avoids saturation)
|
|
13
14
|
_SERVICE_BUS_SEMAPHORE = asyncio.Semaphore(100)
|
|
14
15
|
|
|
15
16
|
|
|
@@ -29,20 +30,6 @@ class APIClient(httpx.AsyncClient):
|
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
@staticmethod
|
|
33
|
-
def fire_and_forget(coro):
|
|
34
|
-
task = asyncio.create_task(coro)
|
|
35
|
-
|
|
36
|
-
def _callback(t: asyncio.Task):
|
|
37
|
-
try:
|
|
38
|
-
t.result()
|
|
39
|
-
except Exception as e:
|
|
40
|
-
logger.error(f"[APIClient] background task error: {e}")
|
|
41
|
-
|
|
42
|
-
task.add_done_callback(_callback)
|
|
43
|
-
return task
|
|
44
|
-
|
|
45
|
-
|
|
46
33
|
def _handle_response(self, response: httpx.Response):
|
|
47
34
|
response.raise_for_status()
|
|
48
35
|
|
|
@@ -66,19 +53,23 @@ class APIClient(httpx.AsyncClient):
|
|
|
66
53
|
):
|
|
67
54
|
headers = kwargs.get("headers", {})
|
|
68
55
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
56
|
+
AuditLogHelper.fire_and_forget(
|
|
57
|
+
AuditQueueHelper.send(
|
|
58
|
+
self.send_request_to_service_bus(
|
|
59
|
+
endpoint=url,
|
|
60
|
+
body=kwargs.get("body"),
|
|
61
|
+
headers=headers,
|
|
62
|
+
http_method=method
|
|
63
|
+
)
|
|
75
64
|
)
|
|
76
65
|
)
|
|
77
66
|
|
|
78
67
|
response = await self.request(method, url, *args, **kwargs)
|
|
79
68
|
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
AuditLogHelper.fire_and_forget(
|
|
70
|
+
AuditQueueHelper.send(
|
|
71
|
+
self.send_response_to_service_bus(response, headers)
|
|
72
|
+
)
|
|
82
73
|
)
|
|
83
74
|
|
|
84
75
|
return self._handle_response(response)
|
|
@@ -94,12 +85,14 @@ class APIClient(httpx.AsyncClient):
|
|
|
94
85
|
):
|
|
95
86
|
headers = headers or {}
|
|
96
87
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
88
|
+
AuditLogHelper.fire_and_forget(
|
|
89
|
+
AuditQueueHelper.send(
|
|
90
|
+
self.send_request_to_service_bus(
|
|
91
|
+
endpoint=url,
|
|
92
|
+
body=variables,
|
|
93
|
+
headers=headers,
|
|
94
|
+
http_method="POST"
|
|
95
|
+
)
|
|
103
96
|
)
|
|
104
97
|
)
|
|
105
98
|
|
|
@@ -109,8 +102,10 @@ class APIClient(httpx.AsyncClient):
|
|
|
109
102
|
headers=headers
|
|
110
103
|
)
|
|
111
104
|
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
AuditLogHelper.fire_and_forget(
|
|
106
|
+
AuditQueueHelper.send(
|
|
107
|
+
self.send_response_to_service_bus(response, headers)
|
|
108
|
+
)
|
|
114
109
|
)
|
|
115
110
|
|
|
116
111
|
return self._handle_response(response)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from Osdental.Grpc.Client.AuthGrpcClient import AuthGrpcClient
|
|
3
|
+
|
|
4
|
+
class AuthGrpcAdapter:
|
|
5
|
+
|
|
6
|
+
def __init__(self, client: AuthGrpcClient):
|
|
7
|
+
self.client = client
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def validate_auth_token(self, data: str) -> bool:
|
|
11
|
+
response = await self.client.call_validate_auth_token(data)
|
|
12
|
+
if response.status != 200:
|
|
13
|
+
raise ValueError(response.message)
|
|
14
|
+
|
|
15
|
+
return response.data
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from Osdental.Grpc.Client.SharedGrpcClient import SharedGrpcClient
|
|
3
|
+
from Osdental.Models.Encryptor import Encryptor
|
|
4
|
+
from Osdental.Models.ShardResource import ShardResource
|
|
5
|
+
|
|
6
|
+
class SharedGrpcAdapter:
|
|
7
|
+
|
|
8
|
+
def __init__(self, client: SharedGrpcClient):
|
|
9
|
+
self.client = client
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def get_shared_encryptions(self) -> Encryptor:
|
|
13
|
+
response = await self.client.call_get_shared_encryptions()
|
|
14
|
+
if response.status != 200:
|
|
15
|
+
raise ValueError(response.message)
|
|
16
|
+
|
|
17
|
+
data_dict = json.loads(response.data)
|
|
18
|
+
return Encryptor.model_validate(data_dict)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def get_shared_resources(self, id_external_enterprise: str, microservice_name: str) -> ShardResource:
|
|
22
|
+
response = await self.client.call_get_shared_resources(id_external_enterprise, microservice_name)
|
|
23
|
+
if response.status != 200:
|
|
24
|
+
raise ValueError(response.message)
|
|
25
|
+
|
|
26
|
+
data_dict = json.loads(response.data)
|
|
27
|
+
return ShardResource.model_validate(data_dict)
|
|
28
|
+
|
|
@@ -17,9 +17,9 @@ class AuthGrpcClient:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@grpc_retry
|
|
20
|
-
async def
|
|
20
|
+
async def call_validate_auth_token(self, data: str) -> GrpcResponse:
|
|
21
21
|
await self._ensure_stub()
|
|
22
|
-
request = Auth_pb2.AuthTokenRequest(data=
|
|
22
|
+
request = Auth_pb2.AuthTokenRequest(data=data)
|
|
23
23
|
response = await self.stub.ValidateAuthToken(request)
|
|
24
24
|
return GrpcResponse(
|
|
25
25
|
status=response.status,
|
|
@@ -2,7 +2,7 @@ from Osdental.Grpc.Client.GrpcConnection import GrpcConnection
|
|
|
2
2
|
from Osdental.Grpc.Generated import Shared_pb2_grpc, Shared_pb2
|
|
3
3
|
from Osdental.Grpc.Dtos.GrpcResponse import GrpcResponse
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class SharedGrpcClient:
|
|
6
6
|
|
|
7
7
|
def __init__(self, connection: GrpcConnection):
|
|
8
8
|
self.connection = connection
|
|
@@ -25,3 +25,13 @@ class SharedResourcesGrpcClient:
|
|
|
25
25
|
message=response.message,
|
|
26
26
|
data=response.data
|
|
27
27
|
)
|
|
28
|
+
|
|
29
|
+
async def call_get_shared_encryptions(self) -> GrpcResponse:
|
|
30
|
+
await self._ensure_stub()
|
|
31
|
+
request = Shared_pb2.EmptyRequest()
|
|
32
|
+
response = await self.stub.GetShardEncryptionData(request)
|
|
33
|
+
return GrpcResponse(
|
|
34
|
+
status=response.status,
|
|
35
|
+
message=response.message,
|
|
36
|
+
data=response.data
|
|
37
|
+
)
|
|
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cShared.proto\x12\nShardProto\"\x0e\n\x0c\x45mptyRequest\"H\n\x0eGetUserRequest\x12\x1c\n\x14idExternalEnterprise\x18\x01 \x01(\t\x12\x18\n\x10microserviceName\x18\x02 \x01(\t\"\x1c\n\x0cSetKeyPortal\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\">\n\x10GetTenantRequest\x12\x18\n\x10microserviceName\x18\x01 \x01(\t\x12\x10\n\x08idTenant\x18\x02 \x01(\t\">\n\rShardResponse\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t2\
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cShared.proto\x12\nShardProto\"\x0e\n\x0c\x45mptyRequest\"H\n\x0eGetUserRequest\x12\x1c\n\x14idExternalEnterprise\x18\x01 \x01(\t\x12\x18\n\x10microserviceName\x18\x02 \x01(\t\"\x1c\n\x0cSetKeyPortal\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\t\">\n\x10GetTenantRequest\x12\x18\n\x10microserviceName\x18\x01 \x01(\t\x12\x10\n\x08idTenant\x18\x02 \x01(\t\">\n\rShardResponse\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t2\xa1\x03\n\rShardResource\x12X\n\x1fGetShardResourcesByMicroservice\x12\x1a.ShardProto.GetUserRequest\x1a\x19.ShardProto.ShardResponse\x12\x45\n\x0eGetShardLegacy\x12\x18.ShardProto.SetKeyPortal\x1a\x19.ShardProto.ShardResponse\x12J\n\x13GetShardSqlSecurity\x12\x18.ShardProto.EmptyRequest\x1a\x19.ShardProto.ShardResponse\x12T\n\x19GetShardResourcesByTenant\x12\x1c.ShardProto.GetTenantRequest\x1a\x19.ShardProto.ShardResponse\x12M\n\x16GetShardEncryptionData\x12\x18.ShardProto.EmptyRequest\x1a\x19.ShardProto.ShardResponseb\x06proto3')
|
|
28
28
|
|
|
29
29
|
_globals = globals()
|
|
30
30
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -42,5 +42,5 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
42
42
|
_globals['_SHARDRESPONSE']._serialized_start=212
|
|
43
43
|
_globals['_SHARDRESPONSE']._serialized_end=274
|
|
44
44
|
_globals['_SHARDRESOURCE']._serialized_start=277
|
|
45
|
-
_globals['_SHARDRESOURCE']._serialized_end=
|
|
45
|
+
_globals['_SHARDRESOURCE']._serialized_end=694
|
|
46
46
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -54,6 +54,11 @@ class ShardResourceStub(object):
|
|
|
54
54
|
request_serializer=Shared__pb2.GetTenantRequest.SerializeToString,
|
|
55
55
|
response_deserializer=Shared__pb2.ShardResponse.FromString,
|
|
56
56
|
_registered_method=True)
|
|
57
|
+
self.GetShardEncryptionData = channel.unary_unary(
|
|
58
|
+
'/ShardProto.ShardResource/GetShardEncryptionData',
|
|
59
|
+
request_serializer=Shared__pb2.EmptyRequest.SerializeToString,
|
|
60
|
+
response_deserializer=Shared__pb2.ShardResponse.FromString,
|
|
61
|
+
_registered_method=True)
|
|
57
62
|
|
|
58
63
|
|
|
59
64
|
class ShardResourceServicer(object):
|
|
@@ -83,6 +88,12 @@ class ShardResourceServicer(object):
|
|
|
83
88
|
context.set_details('Method not implemented!')
|
|
84
89
|
raise NotImplementedError('Method not implemented!')
|
|
85
90
|
|
|
91
|
+
def GetShardEncryptionData(self, request, context):
|
|
92
|
+
"""Missing associated documentation comment in .proto file."""
|
|
93
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
94
|
+
context.set_details('Method not implemented!')
|
|
95
|
+
raise NotImplementedError('Method not implemented!')
|
|
96
|
+
|
|
86
97
|
|
|
87
98
|
def add_ShardResourceServicer_to_server(servicer, server):
|
|
88
99
|
rpc_method_handlers = {
|
|
@@ -106,6 +117,11 @@ def add_ShardResourceServicer_to_server(servicer, server):
|
|
|
106
117
|
request_deserializer=Shared__pb2.GetTenantRequest.FromString,
|
|
107
118
|
response_serializer=Shared__pb2.ShardResponse.SerializeToString,
|
|
108
119
|
),
|
|
120
|
+
'GetShardEncryptionData': grpc.unary_unary_rpc_method_handler(
|
|
121
|
+
servicer.GetShardEncryptionData,
|
|
122
|
+
request_deserializer=Shared__pb2.EmptyRequest.FromString,
|
|
123
|
+
response_serializer=Shared__pb2.ShardResponse.SerializeToString,
|
|
124
|
+
),
|
|
109
125
|
}
|
|
110
126
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
111
127
|
'ShardProto.ShardResource', rpc_method_handlers)
|
|
@@ -224,3 +240,30 @@ class ShardResource(object):
|
|
|
224
240
|
timeout,
|
|
225
241
|
metadata,
|
|
226
242
|
_registered_method=True)
|
|
243
|
+
|
|
244
|
+
@staticmethod
|
|
245
|
+
def GetShardEncryptionData(request,
|
|
246
|
+
target,
|
|
247
|
+
options=(),
|
|
248
|
+
channel_credentials=None,
|
|
249
|
+
call_credentials=None,
|
|
250
|
+
insecure=False,
|
|
251
|
+
compression=None,
|
|
252
|
+
wait_for_ready=None,
|
|
253
|
+
timeout=None,
|
|
254
|
+
metadata=None):
|
|
255
|
+
return grpc.experimental.unary_unary(
|
|
256
|
+
request,
|
|
257
|
+
target,
|
|
258
|
+
'/ShardProto.ShardResource/GetShardEncryptionData',
|
|
259
|
+
Shared__pb2.EmptyRequest.SerializeToString,
|
|
260
|
+
Shared__pb2.ShardResponse.FromString,
|
|
261
|
+
options,
|
|
262
|
+
channel_credentials,
|
|
263
|
+
insecure,
|
|
264
|
+
call_credentials,
|
|
265
|
+
compression,
|
|
266
|
+
wait_for_ready,
|
|
267
|
+
timeout,
|
|
268
|
+
metadata,
|
|
269
|
+
_registered_method=True)
|
|
@@ -4,32 +4,12 @@ from typing import Dict, Any
|
|
|
4
4
|
from Osdental.InternalHttp.Response import CustomResponse
|
|
5
5
|
from Osdental.Encryptor.Rsa import RSAEncryptor
|
|
6
6
|
from Osdental.Shared.Logger import logger
|
|
7
|
-
from Osdental.Shared.Enums.App import App
|
|
8
7
|
from Osdental.Shared.Instance import Instance
|
|
9
8
|
from Osdental.Helpers.AuditQueueHelper import AuditQueueHelper
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class AuditLogHelper:
|
|
13
|
-
|
|
14
|
-
_GRPC_LEGACY_CACHE = {"value": None, "timestamp": 0}
|
|
15
|
-
_GRPC_LOCK = asyncio.Lock()
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
async def get_cached_legacy():
|
|
19
|
-
"""Cache the legacy for X seconds to avoid GRPC calls on every resolver."""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if AuditLogHelper._GRPC_LEGACY_CACHE["value"] is not None:
|
|
23
|
-
return AuditLogHelper._GRPC_LEGACY_CACHE["value"]
|
|
24
|
-
|
|
25
|
-
async with AuditLogHelper._GRPC_LOCK:
|
|
26
|
-
if AuditLogHelper._GRPC_LEGACY_CACHE["value"] is not None:
|
|
27
|
-
return AuditLogHelper._GRPC_LEGACY_CACHE["value"]
|
|
28
|
-
|
|
29
|
-
legacy = await Instance.grpc_shared_adapter.get_shared_legacies(App.LEGACY_NAME)
|
|
30
|
-
AuditLogHelper._GRPC_LEGACY_CACHE["value"] = legacy
|
|
31
|
-
return legacy
|
|
32
|
-
|
|
11
|
+
class AuditLogHelper:
|
|
12
|
+
|
|
33
13
|
@staticmethod
|
|
34
14
|
def fire_and_forget(coro):
|
|
35
15
|
"""Centralized task handler to avoid silent errors."""
|
|
@@ -39,7 +19,7 @@ class AuditLogHelper:
|
|
|
39
19
|
try:
|
|
40
20
|
t.result()
|
|
41
21
|
except Exception as e:
|
|
42
|
-
logger.
|
|
22
|
+
logger.exception("[fire_and_forget] Unhandled task error")
|
|
43
23
|
|
|
44
24
|
task.add_done_callback(_callback)
|
|
45
25
|
return task
|
|
@@ -5,11 +5,8 @@ from typing import Callable, Tuple, Optional, Union, Dict, Any
|
|
|
5
5
|
from graphql import GraphQLResolveInfo
|
|
6
6
|
from graphql import OperationType
|
|
7
7
|
from Osdental.Encryptor.Jwt import JWT
|
|
8
|
-
from Osdental.Exception.ControlledException import
|
|
9
|
-
|
|
10
|
-
InvalidFormatException, OSDException
|
|
11
|
-
)
|
|
12
|
-
from Osdental.Models.Legacy import Legacy
|
|
8
|
+
from Osdental.Exception.ControlledException import UnauthorizedException, InvalidFormatException
|
|
9
|
+
from Osdental.Models.Encryptor import Encryptor
|
|
13
10
|
from Osdental.Models.Token import AuthToken
|
|
14
11
|
from Osdental.Shared.Enums.Message import Message
|
|
15
12
|
from Osdental.Shared.Enums.Profile import Profile
|
|
@@ -19,23 +16,7 @@ from Osdental.Shared.Instance import Instance
|
|
|
19
16
|
|
|
20
17
|
class DecryptedHelper:
|
|
21
18
|
|
|
22
|
-
_GRPC_LEGACY_CACHE = {"value": None, "timestamp": 0}
|
|
23
|
-
_GRPC_LOCK = asyncio.Lock()
|
|
24
19
|
_PARAM_MASK_CACHE: Dict[Callable, Dict[str, bool]] = {}
|
|
25
|
-
|
|
26
|
-
@staticmethod
|
|
27
|
-
async def get_cached_legacy():
|
|
28
|
-
"""Cache the legacy for X seconds to avoid GRPC calls on every resolver."""
|
|
29
|
-
if DecryptedHelper._GRPC_LEGACY_CACHE["value"] is not None:
|
|
30
|
-
return DecryptedHelper._GRPC_LEGACY_CACHE["value"]
|
|
31
|
-
|
|
32
|
-
async with DecryptedHelper._GRPC_LOCK:
|
|
33
|
-
if DecryptedHelper._GRPC_LEGACY_CACHE["value"] is not None:
|
|
34
|
-
return DecryptedHelper._GRPC_LEGACY_CACHE["value"]
|
|
35
|
-
|
|
36
|
-
legacy = await Instance.grpc_shared_adapter.get_shared_legacies(App.LEGACY_NAME)
|
|
37
|
-
DecryptedHelper._GRPC_LEGACY_CACHE["value"] = legacy
|
|
38
|
-
return legacy
|
|
39
20
|
|
|
40
21
|
|
|
41
22
|
@staticmethod
|
|
@@ -50,17 +31,13 @@ class DecryptedHelper:
|
|
|
50
31
|
"id_external_enterprise": id_external_enterprise,
|
|
51
32
|
"id_tenant": id_tenant
|
|
52
33
|
}
|
|
53
|
-
|
|
54
|
-
if res.status != 200:
|
|
55
|
-
raise OSDException(error=res.message)
|
|
56
|
-
|
|
57
|
-
is_auth = res.data
|
|
34
|
+
is_auth = await Instance.grpc_auth_adapter.validate_auth_token(json.dumps(request))
|
|
58
35
|
if not is_auth:
|
|
59
36
|
raise UnauthorizedException(message=Message.PORTAL_ACCESS_RESTRICTED_MSG, error=Message.PORTAL_ACCESS_RESTRICTED_MSG)
|
|
60
37
|
|
|
61
38
|
|
|
62
39
|
@staticmethod
|
|
63
|
-
async def decrypted_token(info: GraphQLResolveInfo,
|
|
40
|
+
async def decrypted_token(info: GraphQLResolveInfo, encryptor: Encryptor, mutate: bool = True) -> Optional[AuthToken]:
|
|
64
41
|
"""
|
|
65
42
|
Decrypts and validates the context token (user_token).
|
|
66
43
|
Returns AuthToken or None if no token exists.
|
|
@@ -71,10 +48,10 @@ class DecryptedHelper:
|
|
|
71
48
|
if not user_token_encrypted:
|
|
72
49
|
return None
|
|
73
50
|
|
|
74
|
-
# decrypt user_token using
|
|
75
|
-
user_token = Instance.aes.decrypt(
|
|
51
|
+
# decrypt user_token using encryptor user key
|
|
52
|
+
user_token = Instance.aes.decrypt(encryptor.aes_user, user_token_encrypted)
|
|
76
53
|
payload = JWT.extract_payload(user_token, App.JWT_USER_KEY)
|
|
77
|
-
payload['
|
|
54
|
+
payload['encryptor'] = encryptor
|
|
78
55
|
payload['jwt_user_key'] = App.JWT_USER_KEY
|
|
79
56
|
|
|
80
57
|
access_token = info.context.get('access_token')
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from Osdental.Models.Encryptor import Encryptor
|
|
3
|
+
from Osdental.Shared.Instance import Instance
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class EncryptorHelper:
|
|
7
|
+
|
|
8
|
+
_GRPC_ENCRYPTOR_CACHE = {"value": None, "timestamp": 0}
|
|
9
|
+
_GRPC_LOCK = asyncio.Lock()
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
async def get_cached_encryptors() -> Encryptor:
|
|
13
|
+
"""Cache the encryptors for X seconds to avoid GRPC calls on every resolver."""
|
|
14
|
+
|
|
15
|
+
if EncryptorHelper._GRPC_ENCRYPTOR_CACHE["value"] is not None:
|
|
16
|
+
return EncryptorHelper._GRPC_ENCRYPTOR_CACHE["value"]
|
|
17
|
+
|
|
18
|
+
async with EncryptorHelper._GRPC_LOCK:
|
|
19
|
+
if EncryptorHelper._GRPC_ENCRYPTOR_CACHE["value"] is not None:
|
|
20
|
+
return EncryptorHelper._GRPC_ENCRYPTOR_CACHE["value"]
|
|
21
|
+
|
|
22
|
+
encryptor = await Instance.grpc_shared_adapter.get_shared_encryptions()
|
|
23
|
+
EncryptorHelper._GRPC_ENCRYPTOR_CACHE["value"] = encryptor
|
|
24
|
+
return encryptor
|
|
@@ -51,7 +51,7 @@ class AzureServiceBusQueue(IMessageQueue):
|
|
|
51
51
|
results.append(body)
|
|
52
52
|
await receiver.complete_message(msg)
|
|
53
53
|
except Exception as e:
|
|
54
|
-
logger.
|
|
54
|
+
logger.exception("Processing message failed")
|
|
55
55
|
await receiver.abandon_message(msg)
|
|
56
56
|
|
|
57
57
|
return results
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
|
|
3
|
+
class Encryptor(BaseModel):
|
|
4
|
+
public_key_1: str = Field(alias="PublicKey1")
|
|
5
|
+
public_key_2: str = Field(alias="PublicKey2")
|
|
6
|
+
private_key_1: str = Field(alias="SecretKey1")
|
|
7
|
+
private_key_2: str = Field(alias="SecretKey1")
|
|
8
|
+
aes_auth: str = Field(alias="AesAuth")
|
|
9
|
+
aes_user: str = Field(alias="AesUser")
|
|
10
|
+
|
|
11
|
+
class ConfigDict:
|
|
12
|
+
populate_by_name = True
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from pydantic import BaseModel, Field
|
|
2
2
|
from typing import Optional
|
|
3
|
-
from Osdental.Models.
|
|
3
|
+
from Osdental.Models.Encryptor import Encryptor
|
|
4
4
|
|
|
5
5
|
class AuthToken(BaseModel):
|
|
6
6
|
id_token: str = Field(alias="idToken")
|
|
@@ -19,7 +19,7 @@ class AuthToken(BaseModel):
|
|
|
19
19
|
base_id_external_enterprise: Optional[str] = None
|
|
20
20
|
mk_id_external_enterprise: Optional[str] = None
|
|
21
21
|
jwt_user_key: Optional[str] = None
|
|
22
|
-
|
|
22
|
+
encryptor: Optional[Encryptor] = None
|
|
23
23
|
|
|
24
24
|
class ConfigDict:
|
|
25
25
|
populate_by_name = True
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from typing import Dict, List, Optional
|
|
3
3
|
import redis.asyncio as redis
|
|
4
|
-
from Osdental.Exception.ControlledException import RedisException
|
|
5
|
-
from Osdental.Shared.Logger import logger
|
|
6
|
-
from Osdental.Shared.Enums.Message import Message
|
|
7
4
|
from Osdental.Shared.Enums.Constant import Constant
|
|
8
5
|
|
|
9
6
|
class RedisCacheAsync:
|
|
@@ -26,56 +23,37 @@ class RedisCacheAsync:
|
|
|
26
23
|
|
|
27
24
|
async def set_dict(self, key: str, value: Dict, ttl: Optional[int] = None):
|
|
28
25
|
"""Set a JSON value in the cache."""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
await self.client.expire(key, ttl)
|
|
34
|
-
except Exception as e:
|
|
35
|
-
logger.error(f'Redis set_dict error: {str(e)}')
|
|
36
|
-
raise RedisException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
|
|
26
|
+
json_value = json.dumps(value)
|
|
27
|
+
await self.client.set(key, json_value)
|
|
28
|
+
if ttl:
|
|
29
|
+
await self.client.expire(key, ttl)
|
|
37
30
|
|
|
38
31
|
|
|
39
32
|
async def set_str(self, key: str, value: str, ttl: Optional[int] = None):
|
|
40
33
|
"""Set a string value in the cache."""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
await self.client.expire(key, ttl)
|
|
45
|
-
except Exception as e:
|
|
46
|
-
logger.error(f'Redis set_str error: {str(e)}')
|
|
47
|
-
raise RedisException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
|
|
34
|
+
await self.client.set(key, value)
|
|
35
|
+
if ttl:
|
|
36
|
+
await self.client.expire(key, ttl)
|
|
48
37
|
|
|
49
38
|
|
|
50
39
|
async def get_dict(self, key: str) -> Optional[str]:
|
|
51
40
|
"""Get a JSON value from the cache and convert it back to a Python object."""
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
except Exception as e:
|
|
58
|
-
logger.error(f'Redis get_dict error: {str(e)}')
|
|
59
|
-
raise RedisException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
|
|
41
|
+
json_value = await self.client.get(key)
|
|
42
|
+
if json_value:
|
|
43
|
+
return json.loads(json_value)
|
|
44
|
+
|
|
45
|
+
return None
|
|
60
46
|
|
|
61
47
|
|
|
62
48
|
async def get_str(self, key: str) -> Optional[str]:
|
|
63
49
|
"""Get a string value from the cache."""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return value.decode(Constant.DEFAULT_ENCODING) if value else None
|
|
67
|
-
except Exception as e:
|
|
68
|
-
logger.error(f'Redis get_str error: {str(e)}')
|
|
69
|
-
raise RedisException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
|
|
50
|
+
value = await self.client.get(key)
|
|
51
|
+
return value.decode(Constant.DEFAULT_ENCODING) if value else None
|
|
70
52
|
|
|
71
53
|
|
|
72
54
|
async def delete(self, key: str) -> bool:
|
|
73
55
|
"""Delete a value from the cache."""
|
|
74
|
-
|
|
75
|
-
return await self.client.delete(key)
|
|
76
|
-
except Exception as e:
|
|
77
|
-
logger.error(f'Redis delete error: {str(e)}')
|
|
78
|
-
raise RedisException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
|
|
56
|
+
return await self.client.delete(key)
|
|
79
57
|
|
|
80
58
|
|
|
81
59
|
async def exists(self, key: str) -> bool:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Dict
|
|
3
|
+
from azure.servicebus.aio import ServiceBusClient
|
|
4
|
+
from azure.servicebus import ServiceBusMessage
|
|
5
|
+
from Osdental.Decorators.Deprecated import deprecated
|
|
6
|
+
|
|
7
|
+
@deprecated("Replaced class, use Osdental.Messaging.. and implement its port")
|
|
8
|
+
class ServicesBus:
|
|
9
|
+
|
|
10
|
+
def __init__(self, conn_str:str, queue_name:str):
|
|
11
|
+
self.conn_str = conn_str
|
|
12
|
+
self.queue_name = queue_name
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def send_message(self, message:Dict[str,str] | str) -> None:
|
|
16
|
+
"""Method to send a message to the Service Bus."""
|
|
17
|
+
data = json.dumps(message) if isinstance(message, dict) else message
|
|
18
|
+
async with ServiceBusClient.from_connection_string(self.conn_str) as servicebus_client:
|
|
19
|
+
async with servicebus_client.get_queue_sender(queue_name=self.queue_name) as sender:
|
|
20
|
+
message = ServiceBusMessage(data)
|
|
21
|
+
await sender.send_messages(message)
|
|
@@ -5,7 +5,6 @@ from dotenv import load_dotenv
|
|
|
5
5
|
load_dotenv(dotenv_path='.env', override=True)
|
|
6
6
|
|
|
7
7
|
class App(StrEnum):
|
|
8
|
-
LEGACY_NAME = os.getenv('LEGACY_NAME')
|
|
9
8
|
MICROSERVICE_NAME = os.getenv('MICROSERVICE_NAME')
|
|
10
9
|
JWT_USER_KEY = os.getenv('JWT_USER_KEY')
|
|
11
10
|
ENVIRONMENT = os.getenv('ENVIRONMENT')
|
|
@@ -2,9 +2,10 @@ import httpx
|
|
|
2
2
|
from Osdental.Encryptor.Aes import AES
|
|
3
3
|
from Osdental.Messaging.AuditServiceBus import AuditServiceBus
|
|
4
4
|
from Osdental.Grpc.Client.AuthGrpcClient import AuthGrpcClient
|
|
5
|
+
from Osdental.Grpc.Adapter.AuthGrpcAdapter import AuthGrpcAdapter
|
|
5
6
|
from Osdental.Grpc.Client.GrpcConnection import GrpcConnection
|
|
6
|
-
from Osdental.Grpc.Client.
|
|
7
|
-
from Osdental.Grpc.Adapter.
|
|
7
|
+
from Osdental.Grpc.Client.SharedGrpcClient import SharedGrpcClient
|
|
8
|
+
from Osdental.Grpc.Adapter.SharedGrpcAdapter import SharedGrpcAdapter
|
|
8
9
|
from Osdental.Shared.Config import Config
|
|
9
10
|
|
|
10
11
|
class Instance:
|
|
@@ -12,13 +13,14 @@ class Instance:
|
|
|
12
13
|
# Service bus audit log
|
|
13
14
|
sb_audit = AuditServiceBus(Config.CONNECTION_STRING, Config.AUDIT_QUEUE)
|
|
14
15
|
# Grpc Security
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
grpc_auth_conn = GrpcConnection(Config.SECURITY_GRPC_HOST)
|
|
17
|
+
grpc_auth_client = AuthGrpcClient(grpc_auth_conn)
|
|
18
|
+
grpc_auth_adapter = AuthGrpcAdapter(grpc_auth_client)
|
|
17
19
|
|
|
18
20
|
# Grpc Shared Resources
|
|
19
21
|
grpc_shared_conn = GrpcConnection(Config.SHARED_GRPC_HOST)
|
|
20
|
-
grpc_shared_client =
|
|
21
|
-
grpc_shared_adapter =
|
|
22
|
+
grpc_shared_client = SharedGrpcClient(grpc_shared_conn)
|
|
23
|
+
grpc_shared_adapter = SharedGrpcAdapter(grpc_shared_client)
|
|
22
24
|
|
|
23
25
|
# AES Encryptor
|
|
24
26
|
aes = AES()
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from Osdental.Grpc.Client.SharedLegacyGrpcClient import SharedLegacyGrpcClient
|
|
3
|
-
from Osdental.Models.Legacy import Legacy
|
|
4
|
-
|
|
5
|
-
class SharedLegacyGrpcAdapter:
|
|
6
|
-
|
|
7
|
-
def __init__(self, client: SharedLegacyGrpcClient):
|
|
8
|
-
self.client = client
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
async def get_shared_legacies(self, data: str) -> Legacy:
|
|
12
|
-
response = await self.client.call_get_shared_legacies(data)
|
|
13
|
-
if response.status != 200:
|
|
14
|
-
raise ValueError(response.message)
|
|
15
|
-
|
|
16
|
-
data_dict = json.loads(response.data)
|
|
17
|
-
return Legacy(**data_dict)
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from Osdental.Grpc.Client.SharedResourcesGrpcClient import SharedResourcesGrpcClient
|
|
3
|
-
from Osdental.Exception.ControlledException import OSDException
|
|
4
|
-
from Osdental.Models.ShardResource import ShardResource
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class SharedResourcesGrpcAdapter:
|
|
8
|
-
|
|
9
|
-
def __init__(self, client: SharedResourcesGrpcClient):
|
|
10
|
-
self.client = client
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async def get_shared_resources(self, id_external_enterprise: str, microservice_name: str) -> ShardResource:
|
|
14
|
-
response = await self.client.call_get_shared_resources(id_external_enterprise, microservice_name)
|
|
15
|
-
if response.status != 200:
|
|
16
|
-
raise OSDException(message=response.message, error=response.message)
|
|
17
|
-
|
|
18
|
-
data_dict = json.loads(response.data)
|
|
19
|
-
return ShardResource(**data_dict)
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from Osdental.Grpc.Client.GrpcConnection import GrpcConnection
|
|
2
|
-
from Osdental.Grpc.Generated import Shared_pb2_grpc, Shared_pb2
|
|
3
|
-
from Osdental.Grpc.Dtos.GrpcResponse import GrpcResponse
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class SharedLegacyGrpcClient:
|
|
7
|
-
|
|
8
|
-
def __init__(self, connection: GrpcConnection):
|
|
9
|
-
self.connection = connection
|
|
10
|
-
self.stub = None
|
|
11
|
-
|
|
12
|
-
async def _ensure_stub(self):
|
|
13
|
-
if not self.stub:
|
|
14
|
-
channel = await self.connection.connect()
|
|
15
|
-
self.stub = Shared_pb2_grpc.ShardResourceStub(channel)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async def call_get_shared_legacies(self, data: str) -> GrpcResponse:
|
|
19
|
-
await self._ensure_stub()
|
|
20
|
-
request = Shared_pb2.SetKeyPortal(data=data)
|
|
21
|
-
response = await self.stub.GetShardLegacy(request)
|
|
22
|
-
return GrpcResponse(
|
|
23
|
-
status=response.status,
|
|
24
|
-
message=response.message,
|
|
25
|
-
data=response.data
|
|
26
|
-
)
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import Dict
|
|
3
|
-
from azure.servicebus.aio import ServiceBusClient
|
|
4
|
-
from azure.servicebus import ServiceBusMessage
|
|
5
|
-
from Osdental.Shared.Logger import logger
|
|
6
|
-
from Osdental.Shared.Enums.Message import Message
|
|
7
|
-
from Osdental.Decorators.Deprecated import deprecated
|
|
8
|
-
|
|
9
|
-
@deprecated("Replaced class, use Osdental.Messaging.. and implement its port")
|
|
10
|
-
class ServicesBus:
|
|
11
|
-
|
|
12
|
-
def __init__(self, conn_str:str, queue_name:str):
|
|
13
|
-
self.conn_str = conn_str
|
|
14
|
-
self.queue_name = queue_name
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
async def send_message(self, message:Dict[str,str] | str) -> None:
|
|
18
|
-
"""Method to send a message to the Service Bus."""
|
|
19
|
-
try:
|
|
20
|
-
data = json.dumps(message) if isinstance(message, dict) else message
|
|
21
|
-
async with ServiceBusClient.from_connection_string(self.conn_str) as servicebus_client:
|
|
22
|
-
async with servicebus_client.get_queue_sender(queue_name=self.queue_name) as sender:
|
|
23
|
-
message = ServiceBusMessage(data)
|
|
24
|
-
await sender.send_messages(message)
|
|
25
|
-
|
|
26
|
-
except Exception as e:
|
|
27
|
-
logger.error(f'Unexpected services bus error: {str(e)}')
|
|
28
|
-
raise ValueError(f'{Message.UNEXPECTED_ERROR_MSG}: {str(e)}')
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import colorlog
|
|
3
|
-
|
|
4
|
-
handler = colorlog.StreamHandler()
|
|
5
|
-
handler.setFormatter(colorlog.ColoredFormatter(
|
|
6
|
-
'%(log_color)s%(levelname)s:%(name)s:%(message)s',
|
|
7
|
-
log_colors={
|
|
8
|
-
'DEBUG': 'cyan',
|
|
9
|
-
'INFO': 'green',
|
|
10
|
-
'WARNING': 'yellow',
|
|
11
|
-
'ERROR': 'red',
|
|
12
|
-
'CRITICAL': 'bold_red',
|
|
13
|
-
}
|
|
14
|
-
))
|
|
15
|
-
logger = colorlog.getLogger('my_logger')
|
|
16
|
-
logger.addHandler(handler)
|
|
17
|
-
logger.setLevel(logging.DEBUG)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|