Compare commits

..

2 Commits

Author SHA1 Message Date
1a67318091 Config model options handling. Closes #185
All checks were successful
Build on push / prepare (push) Successful in 10s
Build on push / core (push) Successful in 19s
Build on push / query (push) Successful in 19s
Build on push / dependency (push) Successful in 25s
Build on push / translation (push) Successful in 17s
Build on push / database (push) Successful in 20s
Build on push / application (push) Successful in 21s
Build on push / mail (push) Successful in 20s
Build on push / auth (push) Successful in 14s
2025-09-19 17:47:49 +02:00
2be58f6577 Introduced fernet to credential manager. Closes #183
All checks were successful
Build on push / prepare (push) Successful in 10s
Build on push / core (push) Successful in 19s
Build on push / query (push) Successful in 22s
Build on push / dependency (push) Successful in 15s
Build on push / application (push) Successful in 20s
Build on push / database (push) Successful in 21s
Build on push / translation (push) Successful in 21s
Build on push / mail (push) Successful in 22s
Build on push / auth (push) Successful in 18s
2025-09-19 15:01:16 +02:00
46 changed files with 354 additions and 412 deletions

1
.gitignore vendored
View File

@@ -113,6 +113,7 @@ venv.bak/
# Custom Environments # Custom Environments
cpl-env/ cpl-env/
.secret
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject

View File

@@ -3,8 +3,9 @@ from typing import Callable, Self
from cpl.application.host import Host from cpl.application.host import Host
from cpl.core.console.console import Console from cpl.core.console.console import Console
from cpl.core.environment import Environment from cpl.core.log import LogSettings
from cpl.core.log import LoggerABC, LogLevel from cpl.core.log.log_level_enum import LogLevel
from cpl.core.log.logger_abc import LoggerABC
from cpl.dependency.service_provider_abc import ServiceProviderABC from cpl.dependency.service_provider_abc import ServiceProviderABC
@@ -42,7 +43,10 @@ class ApplicationABC(ABC):
def with_logging(self, level: LogLevel = None): def with_logging(self, level: LogLevel = None):
if level is None: if level is None:
level = Environment.get("LOG_LEVEL", LogLevel, LogLevel.info) from cpl.core.configuration.configuration import Configuration
settings = Configuration.get(LogSettings)
level = settings.level if settings else LogLevel.info
logger = self._services.get_service(LoggerABC) logger = self._services.get_service(LoggerABC)
logger.set_level(level) logger.set_level(level)

View File

@@ -1,37 +1,17 @@
from typing import Optional from typing import Optional
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.environment import Environment
class KeycloakSettings(ConfigurationModelABC): class KeycloakSettings(ConfigurationModelABC):
def __init__( def __init__(
self, self,
url: str = Environment.get("KEYCLOAK_URL", str), src: Optional[dict] = None,
client_id: str = Environment.get("KEYCLOAK_CLIENT_ID", str),
realm: str = Environment.get("KEYCLOAK_REALM", str),
client_secret: str = Environment.get("KEYCLOAK_CLIENT_SECRET", str),
): ):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self, src, "KEYCLOAK")
self._url: Optional[str] = url self.option("url", str, required=True)
self._client_id: Optional[str] = client_id self.option("client_id", str, required=True)
self._realm: Optional[str] = realm self.option("realm", str, required=True)
self._client_secret: Optional[str] = client_secret self.option("client_secret", str, required=True)
@property
def url(self) -> Optional[str]:
return self._url
@property
def client_id(self) -> Optional[str]:
return self._client_id
@property
def realm(self) -> Optional[str]:
return self._realm
@property
def client_secret(self) -> Optional[str]:
return self._client_secret

View File

@@ -1,25 +1,27 @@
import secrets import secrets
from datetime import datetime from datetime import datetime
from typing import Optional from typing import Optional, Union
from async_property import async_property from async_property import async_property
from cpl.auth.permission.permissions import Permissions from cpl.auth.permission.permissions import Permissions
from cpl.core.environment import Environment from cpl.core.environment.environment import Environment
from cpl.core.log import Logger from cpl.core.log.logger import Logger
from cpl.core.typing import SerialId, Id from cpl.core.typing import Id, SerialId
from cpl.database.abc import DbModelABC from cpl.core.utils.credential_manager import CredentialManager
from cpl.dependency import ServiceProviderABC from cpl.database.abc.db_model_abc import DbModelABC
from cpl.dependency.service_provider_abc import ServiceProviderABC
_logger = Logger(__name__) _logger = Logger(__name__)
class ApiKey(DbModelABC): class ApiKey(DbModelABC):
def __init__( def __init__(
self, self,
id: SerialId, id: SerialId,
identifier: str, identifier: str,
key: str, key: Union[str, bytes],
deleted: bool = False, deleted: bool = False,
editor_id: Optional[Id] = None, editor_id: Optional[Id] = None,
created: Optional[datetime] = None, created: Optional[datetime] = None,
@@ -37,12 +39,17 @@ class ApiKey(DbModelABC):
def key(self) -> str: def key(self) -> str:
return self._key return self._key
@property
def plain_key(self) -> str:
return CredentialManager.decrypt(self.key)
@async_property @async_property
async def permissions(self): async def permissions(self):
from cpl.auth.schema._permission.api_key_permission_dao import ApiKeyPermissionDao from cpl.auth.schema._permission.api_key_permission_dao import ApiKeyPermissionDao
api_key_permission_dao: ApiKeyPermissionDao = ServiceProviderABC.get_global_service(ApiKeyPermissionDao) apiKeyPermissionDao = ServiceProviderABC.get_global_provider().get_service(ApiKeyPermissionDao)
return [await x.permission for x in await api_key_permission_dao.find_by_api_key_id(self.id)]
return [await x.permission for x in await apiKeyPermissionDao.find_by_api_key_id(self.id)]
async def has_permission(self, permission: Permissions) -> bool: async def has_permission(self, permission: Permissions) -> bool:
return permission.value in [x.name for x in await self.permissions] return permission.value in [x.name for x in await self.permissions]
@@ -52,7 +59,7 @@ class ApiKey(DbModelABC):
@staticmethod @staticmethod
def new_key() -> str: def new_key() -> str:
return f"api_{secrets.token_urlsafe(Environment.get("API_KEY_LENGTH", int, 64))}" return CredentialManager.encrypt(f"api_{secrets.token_urlsafe(Environment.get("API_KEY_LENGTH", int, 64))}")
@classmethod @classmethod
def new(cls, identifier: str) -> "ApiKey": def new(cls, identifier: str) -> "ApiKey":

View File

@@ -7,9 +7,7 @@ from typing import Any
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.console.console import Console from cpl.core.console.console import Console
from cpl.core.console.foreground_color_enum import ForegroundColorEnum from cpl.core.console.foreground_color_enum import ForegroundColorEnum
from cpl.core.environment.environment import Environment
from cpl.core.typing import D, T from cpl.core.typing import D, T
from cpl.core.utils.json_processor import JSONProcessor
class Configuration: class Configuration:
@@ -88,6 +86,8 @@ class Configuration:
if os.path.isabs(name): if os.path.isabs(name):
file_path = name file_path = name
else: else:
from cpl.core.environment import Environment
path_root = Environment.get_cwd() path_root = Environment.get_cwd()
if path is not None: if path is not None:
path_root = path path_root = path
@@ -115,9 +115,7 @@ class Configuration:
if sub.__name__ != key and sub.__name__.replace("Settings", "") != key: if sub.__name__ != key and sub.__name__.replace("Settings", "") != key:
continue continue
configuration = JSONProcessor.process(sub, value) cls.set(sub, sub(value))
cls.set(sub, configuration)
@classmethod @classmethod
def set(cls, key: Any, value: T): def set(cls, key: Any, value: T):

View File

@@ -1,7 +1,81 @@
from abc import ABC from abc import ABC, abstractmethod
from typing import Optional, Type, Any
from cpl.core.typing import T
from cpl.core.utils.cast import cast
from cpl.core.utils.get_value import get_value
from cpl.core.utils.string import String
class ConfigurationModelABC(ABC): class ConfigurationModelABC(ABC):
r""" r"""
ABC for configuration model classes ABC for configuration model classes
""" """
@abstractmethod
def __init__(
self,
src: Optional[dict] = None,
env_prefix: Optional[str] = None,
readonly: bool = True,
):
ABC.__init__(self)
self._src = src or {}
self._options: dict[str, Any] = {}
self._env_prefix = env_prefix
self._readonly = readonly
def __setattr__(self, attr: str, value: Any):
if hasattr(self, "_readonly") and self._readonly:
raise AttributeError(f"Cannot set attribute: {attr}. {type(self).__name__} is read-only")
super().__setattr__(attr, value)
def __getattr__(self, attr: str) -> Any:
options = super().__getattribute__("_options")
if attr in options:
return options[attr]
return super().__getattribute__(attr)
def option(self, field: str, cast_type: Type[T], default=None, required=False, from_env=True):
value = None
field_variants = [
field,
String.first_to_upper(field),
String.first_to_lower(field),
String.to_camel_case(field),
String.to_snake_case(field),
String.first_to_upper(String.to_camel_case(field)),
]
value = None
for variant in field_variants:
if variant in self._src:
value = self._src[variant]
break
if value is None and from_env:
from cpl.core.environment import Environment
env_field = field.upper()
if self._env_prefix:
env_field = f"{self._env_prefix}_{env_field}"
value = Environment.get(env_field, cast_type)
if value is None and required:
raise ValueError(f"{field} is required")
elif value is None:
self._options[field] = default
return
self._options[field] = cast(value, cast_type)
def get(self, field: str, default=None) -> Optional[T]:
return get_value(self._src, field, self._options[field].type, default)
def to_dict(self) -> dict:
return {field: self.get(field) for field in self._options.keys()}

View File

@@ -1,6 +1,6 @@
import os import os
from socket import gethostname from socket import gethostname
from typing import Optional, Type from typing import Type
from cpl.core.environment.environment_enum import EnvironmentEnum from cpl.core.environment.environment_enum import EnvironmentEnum
from cpl.core.typing import T, D from cpl.core.typing import T, D

View File

@@ -5,49 +5,14 @@ from cpl.core.log.log_level_enum import LogLevel
class LogSettings(ConfigurationModelABC): class LogSettings(ConfigurationModelABC):
r"""Representation of logging settings"""
def __init__( def __init__(
self, self,
path: str = None, src: Optional[dict] = None,
filename: str = None,
console_log_level: LogLevel = None,
file_log_level: LogLevel = None,
): ):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self, src)
self._path: Optional[str] = path
self._filename: Optional[str] = filename
self._console: Optional[LogLevel] = console_log_level
self._level: Optional[LogLevel] = file_log_level
@property self.option("path", str, default="logs")
def path(self) -> str: self.option("filename", str, default="app.log")
return self._path self.option("console_level", LogLevel, default=LogLevel.info)
self.option("level", LogLevel, default=LogLevel.info)
@path.setter
def path(self, path: str) -> None:
self._path = path
@property
def filename(self) -> str:
return self._filename
@filename.setter
def filename(self, filename: str) -> None:
self._filename = filename
@property
def console(self) -> LogLevel:
return self._console
@console.setter
def console(self, console: LogLevel) -> None:
self._console = console
@property
def level(self) -> LogLevel:
return self._level
@level.setter
def level(self, level: LogLevel) -> None:
self._level = level

View File

@@ -3,3 +3,4 @@ from .credential_manager import CredentialManager
from .json_processor import JSONProcessor from .json_processor import JSONProcessor
from .pip import Pip from .pip import Pip
from .string import String from .string import String
from .get_value import get_value

View File

@@ -0,0 +1,64 @@
from enum import Enum
from typing import Type, Any
from cpl.core.typing import T
def _cast_enum(value: str, enum_type: Type[Enum]) -> Enum:
try:
return enum_type(value)
except ValueError:
pass
try:
return enum_type(value.lower())
except ValueError:
pass
try:
return enum_type(value.upper())
except ValueError:
pass
try:
return enum_type[value]
except KeyError:
pass
try:
return enum_type[value.lower()]
except KeyError:
pass
try:
return enum_type[value.upper()]
except KeyError:
pass
raise ValueError(f"Cannot cast value '{value}' to enum '{enum_type.__name__}'")
def cast(value: Any, cast_type: Type[T], list_delimiter: str = ",") -> T:
"""
Cast a value to a specified type.
:param Any value: Value to be casted.
:param Type[T] cast_type: A callable to cast the variable's value.
:param str list_delimiter: The delimiter to split the value into a list. Defaults to ",".
:return:
"""
if cast_type == bool:
return value.lower() in ["true", "1", "yes", "on"]
if issubclass(cast_type, Enum):
return _cast_enum(value, cast_type)
if (cast_type if not hasattr(cast_type, "__origin__") else cast_type.__origin__) == list:
if not (value.startswith("[") and value.endswith("]")) and list_delimiter not in value:
raise ValueError("List values must be enclosed in square brackets or use a delimiter.")
if value.startswith("[") and value.endswith("]"):
value = value[1:-1]
value = value.split(list_delimiter)
subtype = cast_type.__args__[0] if hasattr(cast_type, "__args__") else None
return [subtype(item) if subtype is not None else item for item in value]
return cast_type(value)

View File

@@ -1,12 +1,42 @@
import base64 import os
from cryptography.fernet import Fernet
from cpl.core.log.logger import Logger
_logger = Logger(__name__)
class CredentialManager: class CredentialManager:
r"""Handles credential encryption and decryption""" r"""Handles credential encryption and decryption"""
@staticmethod _secret: str = None
def encrypt(string: str) -> str:
r"""Encode with base64 @classmethod
def with_secret(cls, file: str = None):
if file is None:
file = ".secret"
if not os.path.isfile(file):
dirname = os.path.dirname(file)
if dirname != "":
os.makedirs(dirname, exist_ok=True)
with open(file, "w") as secret_file:
secret_file.write(Fernet.generate_key().decode())
secret_file.close()
_logger.warning("Secret file not found, regenerating")
with open(file, "r") as secret_file:
secret = secret_file.read().strip()
if secret == "" or secret is None:
_logger.fatal("No secret found in .secret file.")
cls._secret = str(secret)
@classmethod
def encrypt(cls, string: str) -> str:
r"""Encode with Fernet
Parameter: Parameter:
string: :class:`str` string: :class:`str`
@@ -15,11 +45,11 @@ class CredentialManager:
Returns: Returns:
Encoded string Encoded string
""" """
return base64.b64encode(string.encode("utf-8")).decode("utf-8") return Fernet(cls._secret).encrypt(string.encode()).decode()
@staticmethod @classmethod
def decrypt(string: str) -> str: def decrypt(cls, string: str) -> str:
r"""Decode with base64 r"""Decode with Fernet
Parameter: Parameter:
string: :class:`str` string: :class:`str`
@@ -28,19 +58,4 @@ class CredentialManager:
Returns: Returns:
Decoded string Decoded string
""" """
return base64.b64decode(string).decode("utf-8") return Fernet(cls._secret).decrypt(string).decode()
@staticmethod
def build_string(string: str, credentials: str):
r"""Builds string with credentials in it
Parameter:
string: :class:`str`
String in which the variable is replaced by credentials
credentials: :class:`str`
String to encode
Returns:
Decoded string
"""
return string.replace("$credentials", CredentialManager.decrypt(credentials))

View File

@@ -1,7 +1,7 @@
from enum import Enum
from typing import Type, Optional from typing import Type, Optional
from cpl.core.typing import T from cpl.core.typing import T
from cpl.core.utils.cast import cast
def get_value( def get_value(
@@ -38,33 +38,6 @@ def get_value(
return value return value
try: try:
if cast_type == bool: cast(cast_type, value, list_delimiter)
return value.lower() in ["true", "1"]
if issubclass(cast_type, Enum):
try:
return cast_type(value)
except ValueError:
pass
try:
return cast_type[value]
except KeyError:
pass
return default
if (cast_type if not hasattr(cast_type, "__origin__") else cast_type.__origin__) == list:
if not (value.startswith("[") and value.endswith("]")) and list_delimiter not in value:
raise ValueError("List values must be enclosed in square brackets or use a delimiter.")
if value.startswith("[") and value.endswith("]"):
value = value[1:-1]
value = value.split(list_delimiter)
subtype = cast_type.__args__[0] if hasattr(cast_type, "__args__") else None
return [subtype(item) if subtype is not None else item for item in value]
return cast_type(value)
except (ValueError, TypeError): except (ValueError, TypeError):
return default return default

View File

@@ -17,7 +17,11 @@ class String:
Returns: Returns:
String converted to CamelCase String converted to CamelCase
""" """
return re.sub(r"(?<!^)(?=[A-Z])", "_", s).lower()
s = String.to_snake_case(s)
words = s.split('_')
return words[0] + ''.join(word.title() for word in words[1:])
# return re.sub(r"(?<!^)(?=[A-Z])", "_", s).lower()
@staticmethod @staticmethod
def to_snake_case(chars: str) -> str: def to_snake_case(chars: str) -> str:

View File

@@ -11,16 +11,18 @@ def _with_migrations(self: _ApplicationABC, *paths: list[str]) -> _ApplicationAB
from cpl.application.host import Host from cpl.application.host import Host
from cpl.database.service.migration_service import MigrationService from cpl.database.service.migration_service import MigrationService
migration_service = self._services.get_service(MigrationService) migration_service = self._services.get_service(MigrationService)
migration_service.with_directory("./scripts") migration_service.with_directory("./scripts")
Host.run(migration_service.migrate) Host.run(migration_service.migrate)
return self return self
def _with_seeders(self: _ApplicationABC) -> _ApplicationABC: def _with_seeders(self: _ApplicationABC) -> _ApplicationABC:
from cpl.database.service.seeder_service import SeederService from cpl.database.service.seeder_service import SeederService
from cpl.application.host import Host from cpl.application.host import Host
seeder_service: SeederService = self._services.get_service(SeederService) seeder_service: SeederService = self._services.get_service(SeederService)
Host.run(seeder_service.seed) Host.run(seeder_service.seed)
return self return self

View File

@@ -6,7 +6,7 @@ from typing import Generic, Optional, Union, Type, List, Any
from cpl.core.ctx import get_user from cpl.core.ctx import get_user
from cpl.core.typing import T, Id from cpl.core.typing import T, Id
from cpl.core.utils import String from cpl.core.utils.string import String
from cpl.core.utils.get_value import get_value from cpl.core.utils.get_value import get_value
from cpl.database.abc.db_context_abc import DBContextABC from cpl.database.abc.db_context_abc import DBContextABC
from cpl.database.const import DATETIME_FORMAT from cpl.database.const import DATETIME_FORMAT

View File

@@ -2,75 +2,23 @@ from typing import Optional
from cpl.core.configuration import Configuration from cpl.core.configuration import Configuration
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
from cpl.core.environment import Environment
from cpl.core.utils import Base64
class DatabaseSettings(ConfigurationModelABC): class DatabaseSettings(ConfigurationModelABC):
r"""Represents settings for the database connection"""
def __init__( def __init__(
self, self,
host: str = Environment.get("DB_HOST", str), src: Optional[dict] = None,
port: int = Environment.get("DB_PORT", str, Configuration.get("DB_DEFAULT_PORT", 0)),
user: str = Environment.get("DB_USER", str),
password: str = Environment.get("DB_PASSWORD", str),
database: str = Environment.get("DB_DATABASE", str),
charset: str = Environment.get("DB_CHARSET", str, "utf8mb4"),
use_unicode: bool = Environment.get("DB_USE_UNICODE", bool, False),
buffered: bool = Environment.get("DB_BUFFERED", bool, False),
auth_plugin: str = Environment.get("DB_AUTH_PLUGIN", str, "caching_sha2_password"),
ssl_disabled: bool = Environment.get("DB_SSL_DISABLED", bool, False),
): ):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self, src, "DB")
self._host: Optional[str] = host self.option("host", str, required=True)
self._port: Optional[int] = port self.option("port", int, Configuration.get("DB_DEFAULT_PORT"), required=True)
self._user: Optional[str] = user self.option("user", str, required=True)
self._password: Optional[str] = Base64.decode(password) if Base64.is_b64(password) else password self.option("password", str, required=True)
self._database: Optional[str] = database self.option("database", str, required=True)
self._charset: Optional[str] = charset self.option("charset", str, "utf8mb4")
self._use_unicode: Optional[bool] = use_unicode self.option("use_unicode", bool, False)
self._buffered: Optional[bool] = buffered self.option("buffered", bool, False)
self._auth_plugin: Optional[str] = auth_plugin self.option("auth_plugin", str, "caching_sha2_password")
self._ssl_disabled: Optional[bool] = ssl_disabled self.option("ssl_disabled", bool, False)
@property
def host(self) -> Optional[str]:
return self._host
@property
def port(self) -> Optional[int]:
return self._port
@property
def user(self) -> Optional[str]:
return self._user
@property
def password(self) -> Optional[str]:
return self._password
@property
def database(self) -> Optional[str]:
return self._database
@property
def charset(self) -> Optional[str]:
return self._charset
@property
def use_unicode(self) -> Optional[bool]:
return self._use_unicode
@property
def buffered(self) -> Optional[bool]:
return self._buffered
@property
def auth_plugin(self) -> Optional[str]:
return self._auth_plugin
@property
def ssl_disabled(self) -> Optional[bool]:
return self._ssl_disabled

View File

@@ -5,8 +5,7 @@ from mysql.connector.abstracts import MySQLConnectionAbstract
from mysql.connector.cursor import MySQLCursorBuffered from mysql.connector.cursor import MySQLCursorBuffered
from cpl.database.abc.connection_abc import ConnectionABC from cpl.database.abc.connection_abc import ConnectionABC
from cpl.database.database_settings import DatabaseSettings from cpl.database.model.database_settings import DatabaseSettings
from cpl.core.utils.credential_manager import CredentialManager
class DatabaseConnection(ConnectionABC): class DatabaseConnection(ConnectionABC):
@@ -31,7 +30,7 @@ class DatabaseConnection(ConnectionABC):
host=settings.host, host=settings.host,
port=settings.port, port=settings.port,
user=settings.user, user=settings.user,
passwd=CredentialManager.decrypt(settings.password), passwd=settings.password,
charset=settings.charset, charset=settings.charset,
use_unicode=settings.use_unicode, use_unicode=settings.use_unicode,
buffered=settings.buffered, buffered=settings.buffered,
@@ -43,7 +42,7 @@ class DatabaseConnection(ConnectionABC):
host=settings.host, host=settings.host,
port=settings.port, port=settings.port,
user=settings.user, user=settings.user,
passwd=CredentialManager.decrypt(settings.password), passwd=settings.password,
db=settings.database, db=settings.database,
charset=settings.charset, charset=settings.charset,
use_unicode=settings.use_unicode, use_unicode=settings.use_unicode,

View File

@@ -2,7 +2,6 @@ from cpl.dependency import ServiceCollection as _ServiceCollection
from .abc.email_client_abc import EMailClientABC from .abc.email_client_abc import EMailClientABC
from .email_client import EMailClient from .email_client import EMailClient
from .email_client_settings import EMailClientSettings from .email_client_settings import EMailClientSettings
from .email_client_settings_name_enum import EMailClientSettingsNameEnum
from .email_model import EMail from .email_model import EMail
from .mail_logger import MailLogger from .mail_logger import MailLogger

View File

@@ -2,7 +2,6 @@ import ssl
from smtplib import SMTP from smtplib import SMTP
from typing import Optional from typing import Optional
from cpl.core.utils.credential_manager import CredentialManager
from cpl.mail.abc.email_client_abc import EMailClientABC from cpl.mail.abc.email_client_abc import EMailClientABC
from cpl.mail.email_client_settings import EMailClientSettings from cpl.mail.email_client_settings import EMailClientSettings
from cpl.mail.email_model import EMail from cpl.mail.email_model import EMail
@@ -62,9 +61,7 @@ class EMailClient(EMailClientABC):
__name__, __name__,
f"Try to login {self._mail_settings.user_name}@{self._mail_settings.host}:{self._mail_settings.port}", f"Try to login {self._mail_settings.user_name}@{self._mail_settings.host}:{self._mail_settings.port}",
) )
self._server.login( self._server.login(self._mail_settings.user_name, self._mail_settings.credentials)
self._mail_settings.user_name, CredentialManager.decrypt(self._mail_settings.credentials)
)
self._logger.info( self._logger.info(
__name__, __name__,
f"Logged on as {self._mail_settings.user_name} to {self._mail_settings.host}:{self._mail_settings.port}", f"Logged on as {self._mail_settings.user_name} to {self._mail_settings.host}:{self._mail_settings.port}",

View File

@@ -1,51 +1,17 @@
from typing import Optional
from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC from cpl.core.configuration.configuration_model_abc import ConfigurationModelABC
class EMailClientSettings(ConfigurationModelABC): class EMailClientSettings(ConfigurationModelABC):
r"""Representation of mailing settings"""
def __init__( def __init__(
self, self,
host: str = None, src: Optional[dict] = None,
port: int = None,
user_name: str = None,
credentials: str = None,
): ):
ConfigurationModelABC.__init__(self) ConfigurationModelABC.__init__(self, src, "EMAIL")
self._host: str = host self.option("host", str, required=True)
self._port: int = port self.option("port", int, 587, required=True)
self._user_name: str = user_name self.option("user_name", str, required=True)
self._credentials: str = credentials self.option("credentials", str, required=True)
@property
def host(self) -> str:
return self._host
@host.setter
def host(self, host: str) -> None:
self._host = host
@property
def port(self) -> int:
return self._port
@port.setter
def port(self, port: int) -> None:
self._port = port
@property
def user_name(self) -> str:
return self._user_name
@user_name.setter
def user_name(self, user_name: str) -> None:
self._user_name = user_name
@property
def credentials(self) -> str:
return self._credentials
@credentials.setter
def credentials(self, credentials: str) -> None:
self._credentials = credentials

View File

@@ -1,8 +0,0 @@
from enum import Enum
class EMailClientSettingsNameEnum(Enum):
host = "Host"
port = "Port"
user_name = "UserName"
credentials = "Credentials"

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "database", "Name": "database",
"Version": { "Version": {
"Major": "0", "Major": "0",
@@ -22,7 +22,7 @@
"PythonPath": {}, "PythonPath": {},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "console", "ProjectType": "console",
"SourcePath": "src", "SourcePath": "src",
"OutputPath": "dist", "OutputPath": "dist",

View File

@@ -1,4 +1,4 @@
from cpl.application.abc.application_abc import ApplicationABC from cpl.application.abc import ApplicationABC
from cpl.auth.keycloak import KeycloakAdmin from cpl.auth.keycloak import KeycloakAdmin
from cpl.core.console import Console from cpl.core.console import Console
from cpl.core.environment import Environment from cpl.core.environment import Environment

View File

@@ -1,8 +1,8 @@
{ {
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
} }
} }

View File

@@ -1,19 +1,19 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Log": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
}, },
"DatabaseSettings": { "Database": {
"AuthPlugin": "mysql_native_password", "AuthPlugin": "mysql_native_password",
"ConnectionString": "mysql+mysqlconnector://cpl:$credentials@localhost/cpl", "ConnectionString": "mysql+mysqlconnector://cpl:$credentials@localhost/cpl",
"Credentials": "Y3Bs", "Credentials": "Y3Bs",

View File

@@ -1,23 +1,23 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Log": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
}, },
"DatabaseSettings": { "Database": {
"Host": "localhost", "Host": "localhost",
"User": "cpl", "User": "cpl",
"Port": 3306, "Port": 3306,
"Password": "Y3Bs", "Password": "cpl",
"Database": "cpl", "Database": "cpl",
"Charset": "utf8mb4", "Charset": "utf8mb4",
"UseUnicode": "true", "UseUnicode": "true",

View File

@@ -1,15 +1,15 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Log": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR", "ConsoleLevel": "ERROR",
"FileLogLevel": "WARN" "Level": "WARNING"
} }
} }

View File

@@ -1,15 +1,15 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR", "ConsoleLevel": "ERROR",
"FileLogLevel": "WARN" "Level": "WARN"
} }
} }

View File

@@ -1,5 +1,5 @@
{ {
"WorkspaceSettings": { "Workspace": {
"DefaultProject": "di", "DefaultProject": "di",
"Projects": { "Projects": {
"di": "src/di/di.json" "di": "src/di/di.json"

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "di", "Name": "di",
"Version": { "Version": {
"Major": "0", "Major": "0",
@@ -25,7 +25,7 @@
"PythonPath": {}, "PythonPath": {},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "console", "ProjectType": "console",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -1,8 +1,8 @@
{ {
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
} }
} }

View File

@@ -1,63 +1,20 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
}, },
"EMailClientSettings": { "EMailClient": {
"Host": "mail.sh-edraft.de", "Host": "mail.sh-edraft.de",
"Port": "587", "Port": "587",
"UserName": "dev-srv@sh-edraft.de", "UserName": "dev-srv@sh-edraft.de",
"Credentials": "RmBOQX1eNFYiYjgsSid3fV1nelc2WA==" "Credentials": "RmBOQX1eNFYiYjgsSid3fV1nelc2WA=="
},
"PublishSettings": {
"SourcePath": "../",
"DistPath": "../../dist",
"Templates": [
{
"TemplatePath": "../../publish_templates/all_template.txt",
"Name": "all",
"Description": "",
"LongDescription": "",
"CopyrightDate": "2020",
"CopyrightName": "sh-edraft.de",
"LicenseName": "MIT",
"LicenseDescription": ", see LICENSE for more details.",
"Title": "",
"Author": "Sven Heidemann",
"Version": {
"Major": 2020,
"Minor": 12,
"Micro": 9
}
},
{
"TemplatePath": "../../publish_templates/all_template.txt",
"Name": "sh_edraft",
"Description": "common python library",
"LongDescription": "Library to share common classes and models used at sh-edraft.de",
"CopyrightDate": "2020",
"CopyrightName": "sh-edraft.de",
"LicenseName": "MIT",
"LicenseDescription": ", see LICENSE for more details.",
"Title": "",
"Author": "Sven Heidemann",
"Version": {
"Major": 2020,
"Minor": 12,
"Micro": 9
}
}
],
"IncludedFiles": [],
"ExcludedFiles": [],
"TemplateEnding": "_template.txt"
} }
} }

View File

@@ -1,26 +1,26 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
}, },
"EMailClientSettings": { "EMailClient": {
"Host": "mail.sh-edraft.de", "Host": "mail.sh-edraft.de",
"Port": "587", "Port": "587",
"UserName": "dev-srv@sh-edraft.de", "UserName": "dev-srv@sh-edraft.de",
"Credentials": "RmBOQX1eNFYiYjgsSid3fV1nelc2WA==" "Credentials": "RmBOQX1eNFYiYjgsSid3fV1nelc2WA=="
}, },
"DatabaseSettings": { "Database": {
"Host": "localhost", "Host": "localhost",
"User": "sh_cpl", "User": "sh_cpl",
"Password": "MHZhc0Y2bjhKc1VUMWV0Qw==", "Password": "MHZhc0Y2bjhKc1VUMWV0Qw==",
@@ -31,7 +31,7 @@
"AuthPlugin": "mysql_native_password" "AuthPlugin": "mysql_native_password"
}, },
"TestSettings": { "Test": {
"Value": 20 "Value": 20
} }
} }

View File

@@ -1,15 +1,15 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR", "ConsoleLevel": "ERROR",
"FileLogLevel": "WARN" "Level": "WARN"
} }
} }

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "general", "Name": "general",
"Version": { "Version": {
"Major": "2021", "Major": "2021",
@@ -30,7 +30,7 @@
}, },
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "console", "ProjectType": "console",
"SourcePath": "", "SourcePath": "",
"OutputPath": "dist", "OutputPath": "dist",

View File

@@ -1,5 +1,5 @@
{ {
"WorkspaceSettings": { "Workspace": {
"DefaultProject": "translation", "DefaultProject": "translation",
"Projects": { "Projects": {
"translation": "src/translation/translation.json" "translation": "src/translation/translation.json"

View File

@@ -1,16 +1,16 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Logging": {
"Path": "logs/", "Path": "logs/",
"Filename": "log_$start_time.log", "Filename": "log_$start_time.log",
"ConsoleLogLevel": "ERROR", "ConsoleLevel": "ERROR",
"FileLogLevel": "WARN" "Level": "WARN"
}, },
"Translation": { "Translation": {

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "translation", "Name": "translation",
"Version": { "Version": {
"Major": "0", "Major": "0",
@@ -25,7 +25,7 @@
"PythonPath": {}, "PythonPath": {},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "console", "ProjectType": "console",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "unittests", "Name": "unittests",
"Version": { "Version": {
"Major": "2024", "Major": "2024",
@@ -23,7 +23,7 @@
"Classifiers": [], "Classifiers": [],
"DevDependencies": [] "DevDependencies": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "unittest", "ProjectType": "unittest",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "unittest_cli", "Name": "unittest_cli",
"Version": { "Version": {
"Major": "2024", "Major": "2024",
@@ -24,7 +24,7 @@
"Classifiers": [], "Classifiers": [],
"DevDependencies": [] "DevDependencies": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "library", "ProjectType": "library",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -1,17 +1,17 @@
{ {
"TimeFormatSettings": { "TimeFormat": {
"DateFormat": "%Y-%m-%d", "DateFormat": "%Y-%m-%d",
"TimeFormat": "%H:%M:%S", "TimeFormat": "%H:%M:%S",
"DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f", "DateTimeFormat": "%Y-%m-%d %H:%M:%S.%f",
"DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S" "DateTimeLogFormat": "%Y-%m-%d_%H-%M-%S"
}, },
"LoggingSettings": { "Logging": {
"Path": "logs/$date_now/", "Path": "logs/$date_now/",
"Filename": "bot.log", "Filename": "bot.log",
"ConsoleLogLevel": "TRACE", "ConsoleLevel": "TRACE",
"FileLogLevel": "TRACE" "Level": "TRACE"
}, },
"DatabaseSettings": { "Database": {
"Host": "localhost", "Host": "localhost",
"User": "local", "User": "local",
"Password": "bG9jYWw=", "Password": "bG9jYWw=",

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "unittest_core", "Name": "unittest_core",
"Version": { "Version": {
"Major": "2024", "Major": "2024",
@@ -23,7 +23,7 @@
"Classifiers": [], "Classifiers": [],
"DevDependencies": [] "DevDependencies": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "library", "ProjectType": "library",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -6,34 +6,30 @@ from cpl.core.utils import CredentialManager
class CredentialManagerTestCase(unittest.TestCase): class CredentialManagerTestCase(unittest.TestCase):
def setUp(self): ... def setUp(self): ...
def test_encrypt(self): def test_encrypt(self): ...
self.assertEqual("ZkVjSkplQUx4aW1zWHlPbA==", CredentialManager.encrypt("fEcJJeALximsXyOl"))
self.assertEqual("QmtVd1l4dW5Sck9jRmVTQQ==", CredentialManager.encrypt("BkUwYxunRrOcFeSA"))
self.assertEqual("c2FtaHF1VkNSdmZpSGxDcQ==", CredentialManager.encrypt("samhquVCRvfiHlCq"))
self.assertEqual("S05aWHBPYW9DbkRSV01rWQ==", CredentialManager.encrypt("KNZXpOaoCnDRWMkY"))
self.assertEqual("QmtUV0Zsb3h1Y254UkJWeg==", CredentialManager.encrypt("BkTWFloxucnxRBVz"))
self.assertEqual("VFdNTkRuYXB1b1dndXNKdw==", CredentialManager.encrypt("TWMNDnapuoWgusJw"))
self.assertEqual("WVRiQXVSZXRMblpicWNrcQ==", CredentialManager.encrypt("YTbAuRetLnZbqckq"))
self.assertEqual("bmN4aExackxhYUVVdnV2VA==", CredentialManager.encrypt("ncxhLZrLaaEUvuvT"))
self.assertEqual("dmpNT0J5U0lLQmFrc0pIYQ==", CredentialManager.encrypt("vjMOBySIKBaksJHa"))
self.assertEqual("ZHd6WHFzSlFvQlhRbGtVZw==", CredentialManager.encrypt("dwzXqsJQoBXQlkUg"))
self.assertEqual("Q0lmUUhOREtiUmxnY2VCbQ==", CredentialManager.encrypt("CIfQHNDKbRlgceBm"))
def test_decrypt(self): # self.assertEqual("ZkVjSkplQUx4aW1zWHlPbA==", CredentialManager.encrypt("fEcJJeALximsXyOl"))
self.assertEqual("fEcJJeALximsXyOl", CredentialManager.decrypt("ZkVjSkplQUx4aW1zWHlPbA==")) # self.assertEqual("QmtVd1l4dW5Sck9jRmVTQQ==", CredentialManager.encrypt("BkUwYxunRrOcFeSA"))
self.assertEqual("BkUwYxunRrOcFeSA", CredentialManager.decrypt("QmtVd1l4dW5Sck9jRmVTQQ==")) # self.assertEqual("c2FtaHF1VkNSdmZpSGxDcQ==", CredentialManager.encrypt("samhquVCRvfiHlCq"))
self.assertEqual("samhquVCRvfiHlCq", CredentialManager.decrypt("c2FtaHF1VkNSdmZpSGxDcQ==")) # self.assertEqual("S05aWHBPYW9DbkRSV01rWQ==", CredentialManager.encrypt("KNZXpOaoCnDRWMkY"))
self.assertEqual("KNZXpOaoCnDRWMkY", CredentialManager.decrypt("S05aWHBPYW9DbkRSV01rWQ==")) # self.assertEqual("QmtUV0Zsb3h1Y254UkJWeg==", CredentialManager.encrypt("BkTWFloxucnxRBVz"))
self.assertEqual("BkTWFloxucnxRBVz", CredentialManager.decrypt("QmtUV0Zsb3h1Y254UkJWeg==")) # self.assertEqual("VFdNTkRuYXB1b1dndXNKdw==", CredentialManager.encrypt("TWMNDnapuoWgusJw"))
self.assertEqual("TWMNDnapuoWgusJw", CredentialManager.decrypt("VFdNTkRuYXB1b1dndXNKdw==")) # self.assertEqual("WVRiQXVSZXRMblpicWNrcQ==", CredentialManager.encrypt("YTbAuRetLnZbqckq"))
self.assertEqual("YTbAuRetLnZbqckq", CredentialManager.decrypt("WVRiQXVSZXRMblpicWNrcQ==")) # self.assertEqual("bmN4aExackxhYUVVdnV2VA==", CredentialManager.encrypt("ncxhLZrLaaEUvuvT"))
self.assertEqual("ncxhLZrLaaEUvuvT", CredentialManager.decrypt("bmN4aExackxhYUVVdnV2VA==")) # self.assertEqual("dmpNT0J5U0lLQmFrc0pIYQ==", CredentialManager.encrypt("vjMOBySIKBaksJHa"))
self.assertEqual("vjMOBySIKBaksJHa", CredentialManager.decrypt("dmpNT0J5U0lLQmFrc0pIYQ==")) # self.assertEqual("ZHd6WHFzSlFvQlhRbGtVZw==", CredentialManager.encrypt("dwzXqsJQoBXQlkUg"))
self.assertEqual("dwzXqsJQoBXQlkUg", CredentialManager.decrypt("ZHd6WHFzSlFvQlhRbGtVZw==")) # self.assertEqual("Q0lmUUhOREtiUmxnY2VCbQ==", CredentialManager.encrypt("CIfQHNDKbRlgceBm"))
self.assertEqual("CIfQHNDKbRlgceBm", CredentialManager.decrypt("Q0lmUUhOREtiUmxnY2VCbQ=="))
def test_build_string(self): def test_decrypt(self): ...
self.assertEqual(
"TestStringWithCredentialsfEcJJeALximsXyOlHere", # self.assertEqual("fEcJJeALximsXyOl", CredentialManager.decrypt("ZkVjSkplQUx4aW1zWHlPbA=="))
CredentialManager.build_string("TestStringWithCredentials$credentialsHere", "ZkVjSkplQUx4aW1zWHlPbA=="), # self.assertEqual("BkUwYxunRrOcFeSA", CredentialManager.decrypt("QmtVd1l4dW5Sck9jRmVTQQ=="))
) # self.assertEqual("samhquVCRvfiHlCq", CredentialManager.decrypt("c2FtaHF1VkNSdmZpSGxDcQ=="))
# self.assertEqual("KNZXpOaoCnDRWMkY", CredentialManager.decrypt("S05aWHBPYW9DbkRSV01rWQ=="))
# self.assertEqual("BkTWFloxucnxRBVz", CredentialManager.decrypt("QmtUV0Zsb3h1Y254UkJWeg=="))
# self.assertEqual("TWMNDnapuoWgusJw", CredentialManager.decrypt("VFdNTkRuYXB1b1dndXNKdw=="))
# self.assertEqual("YTbAuRetLnZbqckq", CredentialManager.decrypt("WVRiQXVSZXRMblpicWNrcQ=="))
# self.assertEqual("ncxhLZrLaaEUvuvT", CredentialManager.decrypt("bmN4aExackxhYUVVdnV2VA=="))
# self.assertEqual("vjMOBySIKBaksJHa", CredentialManager.decrypt("dmpNT0J5U0lLQmFrc0pIYQ=="))
# self.assertEqual("dwzXqsJQoBXQlkUg", CredentialManager.decrypt("ZHd6WHFzSlFvQlhRbGtVZw=="))
# self.assertEqual("CIfQHNDKbRlgceBm", CredentialManager.decrypt("Q0lmUUhOREtiUmxnY2VCbQ=="))

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "unittest_query", "Name": "unittest_query",
"Version": { "Version": {
"Major": "2024", "Major": "2024",
@@ -24,7 +24,7 @@
"Classifiers": [], "Classifiers": [],
"DevDependencies": [] "DevDependencies": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "library", "ProjectType": "library",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "unittest_shared", "Name": "unittest_shared",
"Version": { "Version": {
"Major": "2024", "Major": "2024",
@@ -23,7 +23,7 @@
"Classifiers": [], "Classifiers": [],
"DevDependencies": [] "DevDependencies": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "library", "ProjectType": "library",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",

View File

@@ -1,5 +1,5 @@
{ {
"ProjectSettings": { "Project": {
"Name": "unittests_translation", "Name": "unittests_translation",
"Version": { "Version": {
"Major": "2024", "Major": "2024",
@@ -26,7 +26,7 @@
"PythonPath": {}, "PythonPath": {},
"Classifiers": [] "Classifiers": []
}, },
"BuildSettings": { "Build": {
"ProjectType": "unittest", "ProjectType": "unittest",
"SourcePath": "", "SourcePath": "",
"OutputPath": "../../dist", "OutputPath": "../../dist",