maleo-foundation 0.1.69__tar.gz → 0.1.71__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. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/PKG-INFO +1 -1
  2. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/authentication.py +10 -5
  3. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/client/services/signature.py +17 -20
  4. maleo_foundation-0.1.71/maleo_foundation/client/services/token.py +62 -0
  5. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/middlewares/authentication.py +13 -1
  6. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/middlewares/base.py +3 -3
  7. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/loaders/__init__.py +2 -2
  8. maleo_foundation-0.1.71/maleo_foundation/utils/loaders/key/__init__.py +5 -0
  9. maleo_foundation-0.1.71/maleo_foundation/utils/loaders/key/rsa.py +93 -0
  10. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation.egg-info/PKG-INFO +1 -1
  11. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation.egg-info/SOURCES.txt +3 -2
  12. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/pyproject.toml +1 -1
  13. maleo_foundation-0.1.69/maleo_foundation/client/services/token.py +0 -34
  14. maleo_foundation-0.1.69/maleo_foundation/utils/loaders/key.py +0 -67
  15. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/README.md +0 -0
  16. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/__init__.py +0 -0
  17. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/client/__init__.py +0 -0
  18. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/client/manager.py +0 -0
  19. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/client/services/__init__.py +0 -0
  20. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/constants.py +0 -0
  21. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/enums.py +0 -0
  22. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/__init__.py +0 -0
  23. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/client.py +0 -0
  24. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/general.py +0 -0
  25. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/query.py +0 -0
  26. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/service.py +0 -0
  27. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/signature.py +0 -0
  28. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/expanded_types/token.py +0 -0
  29. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/extended_types.py +0 -0
  30. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/__init__.py +0 -0
  31. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/__init__.py +0 -0
  32. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/base.py +0 -0
  33. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/google/__init__.py +0 -0
  34. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/google/base.py +0 -0
  35. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/google/secret.py +0 -0
  36. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/google/storage.py +0 -0
  37. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/client/maleo.py +0 -0
  38. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/db.py +0 -0
  39. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/middleware.py +0 -0
  40. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/managers/service.py +0 -0
  41. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/middlewares/cors.py +0 -0
  42. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/__init__.py +0 -0
  43. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/responses.py +0 -0
  44. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/schemas/__init__.py +0 -0
  45. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/schemas/general.py +0 -0
  46. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/schemas/parameter.py +0 -0
  47. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/schemas/result.py +0 -0
  48. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/schemas/signature.py +0 -0
  49. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/schemas/token.py +0 -0
  50. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/table.py +0 -0
  51. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/__init__.py +0 -0
  52. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/general/__init__.py +0 -0
  53. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/general/signature.py +0 -0
  54. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/general/token.py +0 -0
  55. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/parameters/__init__.py +0 -0
  56. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/parameters/client.py +0 -0
  57. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/parameters/general.py +0 -0
  58. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/parameters/service.py +0 -0
  59. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/parameters/signature.py +0 -0
  60. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/parameters/token.py +0 -0
  61. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/__init__.py +0 -0
  62. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/client/__init__.py +0 -0
  63. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/client/controllers/__init__.py +0 -0
  64. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/client/controllers/http.py +0 -0
  65. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/client/service.py +0 -0
  66. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/service/__init__.py +0 -0
  67. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/service/controllers/__init__.py +0 -0
  68. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/service/controllers/rest.py +0 -0
  69. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/service/general.py +0 -0
  70. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/service/query.py +0 -0
  71. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/signature.py +0 -0
  72. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/models/transfers/results/token.py +0 -0
  73. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/types.py +0 -0
  74. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/__init__.py +0 -0
  75. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/controller.py +0 -0
  76. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/exceptions.py +0 -0
  77. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/extractor.py +0 -0
  78. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/formatter/__init__.py +0 -0
  79. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/formatter/case.py +0 -0
  80. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/loaders/json.py +0 -0
  81. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/loaders/yaml.py +0 -0
  82. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/logging.py +0 -0
  83. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/mergers.py +0 -0
  84. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation/utils/query.py +0 -0
  85. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation.egg-info/dependency_links.txt +0 -0
  86. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation.egg-info/requires.txt +0 -0
  87. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/maleo_foundation.egg-info/top_level.txt +0 -0
  88. {maleo_foundation-0.1.69 → maleo_foundation-0.1.71}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.1.69
3
+ Version: 0.1.71
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -1,7 +1,5 @@
1
- from starlette.authentication import (
2
- AuthCredentials,
3
- BaseUser
4
- )
1
+ from pydantic import BaseModel, Field
2
+ from starlette.authentication import AuthCredentials, BaseUser
5
3
  from typing import Optional, Sequence
6
4
  from maleo_foundation.models.transfers.general.token import BaseTokenGeneralTransfers
7
5
  from maleo_foundation.types import BaseTypes
@@ -46,4 +44,11 @@ class User(BaseUser):
46
44
 
47
45
  @property
48
46
  def identity(self) -> str:
49
- return self._email
47
+ return self._email
48
+
49
+ class Authentication(BaseModel):
50
+ credentials:Credentials = Field(..., description="Credentials's information")
51
+ user:User = Field(..., description="User's information")
52
+
53
+ class Config:
54
+ arbitrary_types_allowed=True
@@ -1,13 +1,14 @@
1
1
  from base64 import b64decode, b64encode
2
- from Crypto.PublicKey import RSA
3
2
  from Crypto.Hash import SHA256
4
3
  from Crypto.Signature import pkcs1_15
4
+ from maleo_foundation.enums import BaseEnums
5
+ from maleo_foundation.expanded_types.signature import BaseSignatureResultsTypes
6
+ from maleo_foundation.managers.client.base import ClientService
5
7
  from maleo_foundation.models.schemas.signature import BaseSignatureSchemas
6
8
  from maleo_foundation.models.transfers.parameters.signature import BaseSignatureParametersTransfers
7
9
  from maleo_foundation.models.transfers.results.signature import BaseSignatureResultsTransfers
8
- from maleo_foundation.expanded_types.signature import BaseSignatureResultsTypes
9
- from maleo_foundation.managers.client.base import ClientService
10
10
  from maleo_foundation.utils.exceptions import BaseExceptions
11
+ from maleo_foundation.utils.loaders.key.rsa import RSAKeyLoader
11
12
 
12
13
  class MaleoFoundationSignatureClientService(ClientService):
13
14
  def sign(self, parameters:BaseSignatureParametersTransfers.Sign) -> BaseSignatureResultsTypes.Sign:
@@ -18,14 +19,12 @@ class MaleoFoundationSignatureClientService(ClientService):
18
19
  )
19
20
  def _impl():
20
21
  try:
21
- #* Load RSA key using PyCryptodome's RSA.import_key
22
- private_key = RSA.import_key(extern_key=parameters.key, passphrase=parameters.password)
23
- #* Validate the key type
24
- if not private_key.has_private():
25
- message = "Invalid key type"
26
- description = "A private key must be used for RSA Verify"
27
- other = "Ensure the given key is of type private key"
28
- return BaseSignatureResultsTransfers.Fail(message=message, description=description, other=other)
22
+ private_key = RSAKeyLoader.load_with_pycryptodome(type=BaseEnums.KeyType.PRIVATE, extern_key=parameters.key, passphrase=parameters.password)
23
+ except TypeError:
24
+ message = "Invalid key type"
25
+ description = "A private key must be used for signing a message"
26
+ other = "Ensure the given key is of type private key"
27
+ return BaseSignatureResultsTransfers.Fail(message=message, description=description, other=other)
29
28
  except Exception as e:
30
29
  self._logger.error("Unexpected error occured while trying to import key:\n'%s'", str(e), exc_info=True)
31
30
  message = "Invalid key"
@@ -39,7 +38,7 @@ class MaleoFoundationSignatureClientService(ClientService):
39
38
  return BaseSignatureResultsTransfers.Sign(data=data)
40
39
  return _impl()
41
40
 
42
- def verify(self, parameters:BaseSignatureParametersTransfers.Verify) -> BaseSignatureResultsTypes.Verify:
41
+ def decode(self, parameters:BaseSignatureParametersTransfers.Verify) -> BaseSignatureResultsTypes.Verify:
43
42
  @BaseExceptions.service_exception_handler(
44
43
  operation="verify single signature",
45
44
  logger=self._logger,
@@ -47,14 +46,12 @@ class MaleoFoundationSignatureClientService(ClientService):
47
46
  )
48
47
  def _impl():
49
48
  try:
50
- #* Load RSA key using PyCryptodome's RSA.import_key
51
- public_key = RSA.import_key(parameters.key)
52
- #* Validate the key type
53
- if public_key.has_private():
54
- message = "Invalid key type"
55
- description = "A public key must be used for RSA Sign"
56
- other = "Ensure the given key is of type public key"
57
- return BaseSignatureResultsTransfers.Fail(message=message, description=description, other=other)
49
+ public_key = RSAKeyLoader.load_with_pycryptodome(type=BaseEnums.KeyType.PUBLIC, extern_key=parameters.key)
50
+ except TypeError:
51
+ message = "Invalid key type"
52
+ description = "A public key must be used for verifying a signature"
53
+ other = "Ensure the given key is of type public key"
54
+ return BaseSignatureResultsTransfers.Fail(message=message, description=description, other=other)
58
55
  except Exception as e:
59
56
  self._logger.error("Unexpected error occured while trying to import key:\n'%s'", str(e), exc_info=True)
60
57
  message = "Invalid key"
@@ -0,0 +1,62 @@
1
+ import jwt
2
+ from maleo_foundation.enums import BaseEnums
3
+ from maleo_foundation.expanded_types.token import BaseTokenResultsTypes
4
+ from maleo_foundation.managers.client.base import ClientService
5
+ from maleo_foundation.models.schemas.token import BaseTokenSchemas
6
+ from maleo_foundation.models.transfers.general.token import BaseTokenGeneralTransfers
7
+ from maleo_foundation.models.transfers.parameters.token import BaseTokenParametersTransfers
8
+ from maleo_foundation.models.transfers.results.token import BaseTokenResultsTransfers
9
+ from maleo_foundation.utils.exceptions import BaseExceptions
10
+ from maleo_foundation.utils.loaders.key.rsa import RSAKeyLoader
11
+
12
+ class MaleoFoundationTokenClientService(ClientService):
13
+ def encode(self, parameters:BaseTokenParametersTransfers.Encode) -> BaseTokenResultsTypes.Encode:
14
+ @BaseExceptions.service_exception_handler(
15
+ operation="encoding a payload into a token",
16
+ logger=self._logger,
17
+ fail_result_class=BaseTokenResultsTransfers.Fail
18
+ )
19
+ def _impl():
20
+ try:
21
+ private_key = RSAKeyLoader.load_with_pycryptodome(type=BaseEnums.KeyType.PRIVATE, extern_key=parameters.key, passphrase=parameters.password)
22
+ except TypeError:
23
+ message = "Invalid key type"
24
+ description = "A private key must be used for payload encoding"
25
+ other = "Ensure the given key is of type private key"
26
+ return BaseTokenResultsTransfers.Fail(message=message, description=description, other=other)
27
+ except Exception as e:
28
+ self._logger.error("Unexpected error occured while trying to import key:\n'%s'", str(e), exc_info=True)
29
+ message = "Invalid key"
30
+ description = "Unexpected error occured while trying to import key"
31
+ other = "Ensure given key is valid"
32
+ return BaseTokenResultsTransfers.Fail(message=message, description=description, other=other)
33
+ payload = BaseTokenGeneralTransfers.EncodePayload.model_validate(parameters.payload.model_dump()).model_dump(mode="json")
34
+ token = jwt.encode(payload=payload, key=private_key.export_key(), algorithm="RS256")
35
+ data = BaseTokenSchemas.Token(token=token)
36
+ return BaseTokenResultsTransfers.Encode(data=data)
37
+ return _impl()
38
+
39
+ def decode(self, parameters:BaseTokenParametersTransfers.Decode) -> BaseTokenResultsTypes.Decode:
40
+ @BaseExceptions.service_exception_handler(
41
+ operation="decoding a token into a payload",
42
+ logger=self._logger,
43
+ fail_result_class=BaseTokenResultsTransfers.Fail
44
+ )
45
+ def _impl():
46
+ try:
47
+ public_key = RSAKeyLoader.load_with_pycryptodome(type=BaseEnums.KeyType.PUBLIC, extern_key=parameters.key)
48
+ except TypeError:
49
+ message = "Invalid key type"
50
+ description = "A public key must be used for token decoding"
51
+ other = "Ensure the given key is of type public key"
52
+ return BaseTokenResultsTransfers.Fail(message=message, description=description, other=other)
53
+ except Exception as e:
54
+ self._logger.error("Unexpected error occured while trying to import key:\n'%s'", str(e), exc_info=True)
55
+ message = "Invalid key"
56
+ description = "Unexpected error occured while trying to import key"
57
+ other = "Ensure given key is valid"
58
+ return BaseTokenResultsTransfers.Fail(message=message, description=description, other=other)
59
+ payload = jwt.decode(jwt=parameters.token, key=public_key.export_key(), algorithms=["RS256"])
60
+ data = BaseTokenGeneralTransfers.DecodePayload.model_validate(payload)
61
+ return BaseTokenResultsTransfers.Decode(data=data)
62
+ return _impl()
@@ -34,7 +34,19 @@ class Backend(AuthenticationBackend):
34
34
  if decode_token_result.data.exp_dt <= datetime.now(tz=timezone.utc):
35
35
  raise AuthenticationError("Expired Bearer token, request new or refresh token")
36
36
 
37
- return Credentials(token=token, payload=decode_token_result.data, scopes=["authenticated"]), User(authenticated=True, username=decode_token_result.data.u_u, email=decode_token_result.data.u_e)
37
+ payload = decode_token_result.data
38
+ return (
39
+ Credentials(
40
+ token=token,
41
+ payload=payload,
42
+ scopes=["authenticated", payload.sr]
43
+ ),
44
+ User(
45
+ authenticated=True,
46
+ username=payload.u_u,
47
+ email=payload.u_e
48
+ )
49
+ )
38
50
 
39
51
  def add_authentication_middleware(app:FastAPI, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager) -> None:
40
52
  """
@@ -148,8 +148,8 @@ class BaseMiddleware(BaseHTTPMiddleware):
148
148
  response = self._add_response_headers(request, response, request_timestamp, response_timestamp, process_time)
149
149
  log_func = getattr(self._logger, log_level)
150
150
  log_func(
151
- f"Request {authentication_info} | IP: {client_ip} | Method: {request.method} | URL: {request.url.path} | "
152
- f"Headers: {dict(request.headers)} - Response | Status: {response.status_code} | "
151
+ f"Request {authentication_info} | IP: {client_ip} | Host: {request.client.host} | Port: {request.client.port} | Method: {request.method} | URL: {request.url.path} | "
152
+ f"Headers: {dict(request.headers)} - Response | Status: {response.status_code}"
153
153
  )
154
154
  return response
155
155
 
@@ -179,7 +179,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
179
179
  )
180
180
 
181
181
  self._logger.error(
182
- f"Request {authentication_info} | IP: {client_ip} | Method: {request.method} | URL: {request.url.path} | "
182
+ f"Request {authentication_info} | IP: {client_ip} | Host: {request.client.host} | Port: {request.client.port} | Method: {request.method} | URL: {request.url.path} | "
183
183
  f"Headers: {dict(request.headers)} - Response | Status: 500 | Exception:\n{json.dumps(error_details, indent=4)}"
184
184
  )
185
185
 
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
  from .json import JSONLoader
3
- from .key import KeyLoader
3
+ from .key import BaseKeyLoaders
4
4
  from .yaml import YAMLLoader
5
5
 
6
6
  class BaseLoaders:
7
7
  Json = JSONLoader
8
- Key = KeyLoader
8
+ Key = BaseKeyLoaders
9
9
  Yaml = YAMLLoader
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+ from .rsa import RSAKeyLoader
3
+
4
+ class BaseKeyLoaders:
5
+ RSA = RSAKeyLoader
@@ -0,0 +1,93 @@
1
+ from cryptography.hazmat.primitives import serialization
2
+ from Crypto.PublicKey import RSA
3
+ from pathlib import Path
4
+ from typing import Optional, Union
5
+ from maleo_foundation.enums import BaseEnums
6
+ from maleo_foundation.types import BaseTypes
7
+
8
+ class RSAKeyLoader:
9
+ @staticmethod
10
+ def load_with_cryptography(
11
+ type:BaseEnums.KeyType,
12
+ data:Optional[Union[bytes, str]] = None,
13
+ path:Optional[Union[str, Path]] = None,
14
+ password:Optional[Union[bytes, str]] = None,
15
+ format:BaseEnums.KeyFormatType = BaseEnums.KeyFormatType.STRING,
16
+ ) -> Union[bytes, str]:
17
+ if not isinstance(type, BaseEnums.KeyType):
18
+ raise TypeError("Invalid key type")
19
+
20
+ if data is not None and path is not None:
21
+ raise ValueError("Only either data or path will be accepted as parameters")
22
+
23
+ if data is not None:
24
+ if isinstance(data, bytes):
25
+ key_data = data
26
+ elif isinstance(data, str):
27
+ key_data = data.encode()
28
+ else:
29
+ raise TypeError("Invalid data type")
30
+
31
+ if path is not None:
32
+ file_path = Path(path)
33
+
34
+ if not file_path.exists() or not file_path.is_file():
35
+ raise FileNotFoundError(f"Key file not found: {file_path}")
36
+
37
+ key_data = file_path.read_bytes()
38
+
39
+ if password is not None and not isinstance(password, (str, bytes)):
40
+ raise TypeError("Invalid passsword type")
41
+
42
+ if not isinstance(format, BaseEnums.KeyFormatType):
43
+ raise TypeError("Invalid key format type")
44
+
45
+ if type == BaseEnums.KeyType.PRIVATE:
46
+ private_key = serialization.load_pem_private_key(
47
+ key_data,
48
+ password=password.encode() if isinstance(password, str) else password,
49
+ )
50
+ private_key_bytes = private_key.private_bytes(
51
+ encoding=serialization.Encoding.PEM,
52
+ format=serialization.PrivateFormat.PKCS8,
53
+ encryption_algorithm=serialization.NoEncryption()
54
+ )
55
+ if format == BaseEnums.KeyFormatType.BYTES:
56
+ return private_key_bytes
57
+ elif format == BaseEnums.KeyFormatType.STRING:
58
+ return private_key_bytes.decode()
59
+
60
+ if type == BaseEnums.KeyType.PUBLIC:
61
+ public_key = serialization.load_pem_public_key(key_data)
62
+ public_key_bytes = public_key.public_bytes(
63
+ encoding=serialization.Encoding.PEM,
64
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
65
+ )
66
+ if format == BaseEnums.KeyFormatType.BYTES:
67
+ return public_key_bytes
68
+ elif format == BaseEnums.KeyFormatType.STRING:
69
+ return public_key_bytes.decode()
70
+
71
+ @staticmethod
72
+ def load_with_pycryptodome(
73
+ type:BaseEnums.KeyType,
74
+ extern_key:Union[bytes, str],
75
+ passphrase:BaseTypes.OptionalString = None,
76
+ ) -> RSA.RsaKey:
77
+ if not isinstance(type, BaseEnums.KeyType):
78
+ raise TypeError("Invalid key type")
79
+
80
+ if not isinstance(extern_key, (str, bytes)):
81
+ raise TypeError("Invalid external key type")
82
+
83
+ if type == BaseEnums.KeyType.PRIVATE:
84
+ private_key = RSA.import_key(extern_key=extern_key, passphrase=passphrase)
85
+ if not private_key.has_private():
86
+ raise TypeError("Invalid chosen key type, the private key did not has private inside it")
87
+ return private_key
88
+
89
+ if type == BaseEnums.KeyType.PUBLIC:
90
+ public_key = RSA.import_key(extern_key=extern_key)
91
+ if public_key.has_private():
92
+ raise TypeError("Invalid chosen key type, the public key did has private inside it")
93
+ return public_key
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.1.69
3
+ Version: 0.1.71
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -79,5 +79,6 @@ maleo_foundation/utils/formatter/__init__.py
79
79
  maleo_foundation/utils/formatter/case.py
80
80
  maleo_foundation/utils/loaders/__init__.py
81
81
  maleo_foundation/utils/loaders/json.py
82
- maleo_foundation/utils/loaders/key.py
83
- maleo_foundation/utils/loaders/yaml.py
82
+ maleo_foundation/utils/loaders/yaml.py
83
+ maleo_foundation/utils/loaders/key/__init__.py
84
+ maleo_foundation/utils/loaders/key/rsa.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maleo_foundation"
7
- version = "0.1.69"
7
+ version = "0.1.71"
8
8
  description = "Foundation package for Maleo"
9
9
  authors = [
10
10
  { name = "Agra Bima Yuda", email = "agra@nexmedis.com" }
@@ -1,34 +0,0 @@
1
- import jwt
2
- from maleo_foundation.models.schemas.token import BaseTokenSchemas
3
- from maleo_foundation.models.transfers.general.token import BaseTokenGeneralTransfers
4
- from maleo_foundation.models.transfers.parameters.token import BaseTokenParametersTransfers
5
- from maleo_foundation.models.transfers.results.token import BaseTokenResultsTransfers
6
- from maleo_foundation.expanded_types.token import BaseTokenResultsTypes
7
- from maleo_foundation.managers.client.base import ClientService
8
- from maleo_foundation.utils.exceptions import BaseExceptions
9
-
10
- class MaleoFoundationTokenClientService(ClientService):
11
- def encode(self, parameters:BaseTokenParametersTransfers.Encode) -> BaseTokenResultsTypes.Encode:
12
- @BaseExceptions.service_exception_handler(
13
- operation="encoding a payload into a token",
14
- logger=self._logger,
15
- fail_result_class=BaseTokenResultsTransfers.Fail
16
- )
17
- def _impl():
18
- payload = BaseTokenGeneralTransfers.EncodePayload.model_validate(parameters.payload.model_dump()).model_dump(mode="json")
19
- token = jwt.encode(payload=payload, key=parameters.key, algorithm="RS256")
20
- data = BaseTokenSchemas.Token(token=token)
21
- return BaseTokenResultsTransfers.Encode(data=data)
22
- return _impl()
23
-
24
- def decode(self, parameters:BaseTokenParametersTransfers.Decode) -> BaseTokenResultsTypes.Decode:
25
- @BaseExceptions.service_exception_handler(
26
- operation="decoding a token into a payload",
27
- logger=self._logger,
28
- fail_result_class=BaseTokenResultsTransfers.Fail
29
- )
30
- def _impl():
31
- payload = jwt.decode(jwt=parameters.token, key=parameters.key, algorithms=["RS256"])
32
- data = BaseTokenGeneralTransfers.DecodePayload.model_validate(payload)
33
- return BaseTokenResultsTransfers.Decode(data=data)
34
- return _impl()
@@ -1,67 +0,0 @@
1
- from cryptography.hazmat.primitives import serialization
2
- from pathlib import Path
3
- from typing import Optional, Union
4
- from maleo_foundation.enums import BaseEnums
5
-
6
- class KeyLoader:
7
- @staticmethod
8
- def load_rsa(
9
- type:BaseEnums.KeyType,
10
- path: Union[str, Path],
11
- password:Optional[Union[str, bytes]] = None,
12
- format:BaseEnums.KeyFormatType = BaseEnums.KeyFormatType.STRING,
13
- ) -> Union[bytes, str]:
14
- """
15
- Load an RSA private or public key strictly from a file.
16
-
17
- Args:
18
- path (str | Path): Path to the PEM file.
19
- password (str | bytes | None): Password for encrypted private keys (optional).
20
-
21
- Returns:
22
- rsa.RSAPrivateKey | rsa.RSAPublicKey
23
- """
24
- if not isinstance(type, BaseEnums.KeyType):
25
- raise TypeError("Invalid key type")
26
-
27
- file_path = Path(path)
28
-
29
- if not file_path.is_file():
30
- raise FileNotFoundError(f"Key file not found: {file_path}")
31
-
32
- if password is not None and not isinstance(password, (str, bytes)):
33
- raise TypeError("Invalid passsword type")
34
-
35
- if not isinstance(format, BaseEnums.KeyFormatType):
36
- raise TypeError("Invalid key format type")
37
-
38
- key_data = file_path.read_bytes()
39
-
40
- if type == BaseEnums.KeyType.PRIVATE:
41
- private_key = serialization.load_pem_private_key(
42
- key_data,
43
- password=password.encode() if isinstance(password, str) else password,
44
- )
45
- private_key_bytes = private_key.private_bytes(
46
- encoding=serialization.Encoding.PEM,
47
- format=serialization.PrivateFormat.PKCS8,
48
- encryption_algorithm=serialization.NoEncryption()
49
- )
50
- if format == BaseEnums.KeyFormatType.BYTES:
51
- return private_key_bytes
52
- elif format == BaseEnums.KeyFormatType.STRING:
53
- return private_key_bytes.decode()
54
-
55
- elif type == BaseEnums.KeyType.PUBLIC:
56
- public_key = serialization.load_pem_public_key(key_data)
57
- public_key_bytes = public_key.public_bytes(
58
- encoding=serialization.Encoding.PEM,
59
- format=serialization.PublicFormat.SubjectPublicKeyInfo
60
- )
61
- if format == BaseEnums.KeyFormatType.BYTES:
62
- return public_key_bytes
63
- elif format == BaseEnums.KeyFormatType.STRING:
64
- return public_key_bytes.decode()
65
-
66
- else:
67
- raise ValueError(f"Unsupported key type: {type}")