Added api-key commands #162-3

This commit is contained in:
Sven Heidemann 2023-02-09 20:22:46 +01:00
parent d03ea1d970
commit 7f14aff1bd
8 changed files with 174 additions and 10 deletions

View File

@ -283,7 +283,17 @@
"technician": {
"restart_message": "Bin gleich wieder da :D",
"shutdown_message": "Trauert nicht um mich, es war eine logische Entscheidung. Das Wohl von Vielen, es wiegt schwerer als das Wohl von Wenigen oder eines Einzelnen. Ich war es und ich werde es immer sein, Euer Freund. Lebt lange und in Frieden :)",
"log_message": "Hier sind deine Logdateien! :)"
"log_message": "Hier sind deine Logdateien! :)",
"api_key": {
"get": "API-Schlüssel für {}: {}",
"add": {
"success": "API-Schlüssel für {} wurde erstellt: {}"
},
"remove": {
"not_found": "API-Schlüssel konnte nicht gefunden werden!",
"success": "API-Schlüssel wurde entfernt :D"
}
}
}
},
"api": {

View File

@ -18,6 +18,10 @@ class ApiKeyRepositoryABC(ABC):
def get_api_key(self, identifier: str, key: str) -> ApiKey:
pass
@abstractmethod
def get_api_key_by_key(self, key: str) -> ApiKey:
pass
@abstractmethod
def add_api_key(self, api_key: ApiKey):
pass

View File

@ -27,7 +27,8 @@ class ApiKeyMigration(MigrationABC):
`LastModifiedAt` DATETIME(6),
PRIMARY KEY(`Id`),
FOREIGN KEY (`CreatorId`) REFERENCES `Users`(`UserId`),
CONSTRAINT UC_Identifier_Key UNIQUE (`Identifier`,`Key`)
CONSTRAINT UC_Identifier_Key UNIQUE (`Identifier`,`Key`),
CONSTRAINT UC_Key UNIQUE (`Key`)
);
"""
)

View File

@ -4,7 +4,7 @@ from bot_data.db_context import DBContext
class AutoRoleFix1Migration(MigrationABC):
name = "0.3.0_AutoRoleMigration"
name = "0.3.0_AutoRoleFixMigration"
def __init__(self, logger: DatabaseLogger, db: DBContext):
MigrationABC.__init__(self)

View File

@ -54,6 +54,15 @@ class ApiKey(TableABC):
"""
)
@staticmethod
def get_select_by_key(key: str) -> str:
return str(
f"""
SELECT * FROM `ApiKeys`
WHERE `Key` = '{key}';
"""
)
@property
def insert_string(self) -> str:
return str(

View File

@ -1,7 +1,6 @@
from typing import Optional
from cpl_core.database.context import DatabaseContextABC
from cpl_core.utils import CredentialManager
from cpl_query.extension import List
from bot_core.logging.database_logger import DatabaseLogger
@ -32,10 +31,6 @@ class ApiKeyRepositoryService(ApiKeyRepositoryABC):
return value
def _api_key_from_result(self, sql_result: tuple) -> ApiKey:
code = self._get_value_from_result(sql_result[3])
if code is not None:
code = CredentialManager.decrypt(code)
api_key = ApiKey(
self._get_value_from_result(sql_result[1]),
self._get_value_from_result(sql_result[2]),
@ -58,7 +53,11 @@ class ApiKeyRepositoryService(ApiKeyRepositoryABC):
def get_api_key(self, identifier: str, key: str) -> ApiKey:
self._logger.trace(__name__, f"Send SQL command: {ApiKey.get_select_string(identifier, key)}")
return self._get_value_from_result(self._context.select(ApiKey.get_select_string(identifier, key))[0])
return self._api_key_from_result(self._context.select(ApiKey.get_select_string(identifier, key))[0])
def get_api_key_by_key(self, key: str) -> ApiKey:
self._logger.trace(__name__, f"Send SQL command: {ApiKey.get_select_by_key(key)}")
return self._api_key_from_result(self._context.select(ApiKey.get_select_by_key(key))[0])
def add_api_key(self, api_key: ApiKey):
self._logger.trace(__name__, f"Send SQL command: {api_key.insert_string}")

View File

@ -0,0 +1,139 @@
import hashlib
import uuid
from typing import List as TList
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.command import DiscordCommandABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import Context
from bot_api.configuration.authentication_settings import AuthenticationSettings
from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_core.abc.message_service_abc import MessageServiceABC
from bot_core.helper.command_checks import CommandChecks
from bot_core.logging.command_logger import CommandLogger
from bot_data.abc.api_key_repository_abc import ApiKeyRepositoryABC
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.api_key import ApiKey
from modules.permission.abc.permission_service_abc import PermissionServiceABC
class ApiKeyGroup(DiscordCommandABC):
def __init__(
self,
logger: CommandLogger,
auth_settings: AuthenticationSettings,
message_service: MessageServiceABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsABC,
permission_service: PermissionServiceABC,
translate: TranslatePipe,
db: DatabaseContextABC,
servers: ServerRepositoryABC,
users: UserRepositoryABC,
api_keys: ApiKeyRepositoryABC,
):
DiscordCommandABC.__init__(self)
self._logger = logger
self._auth_settings = auth_settings
self._message_service = message_service
self._bot = bot
self._client_utils = client_utils
self._permissions = permission_service
self._t = translate
self._db = db
self._servers = servers
self._users = users
self._api_keys = api_keys
def _get_api_key_str(self, api_key: ApiKey) -> str:
return hashlib.sha256(
f"{api_key.identifier}:{api_key.key}+{self._auth_settings.secret_key}".encode("utf-8")
).hexdigest()
@commands.hybrid_group(name="api-key")
@commands.guild_only()
async def api_key(self, ctx: Context):
pass
@api_key.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_technician()
async def get(self, ctx: Context, key: str, wait: int = None):
self._logger.debug(__name__, f"Received command api-key get {ctx}: {key},{wait}")
api_key = self._api_keys.get_api_key_by_key(key)
await self._message_service.send_ctx_msg(
ctx,
self._t.transform("modules.technician.api_key.get").format(
api_key.identifier, self._get_api_key_str(api_key)
),
)
self._logger.trace(__name__, f"Finished command api-key get")
@get.autocomplete("key")
async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
keys = self._api_keys.get_api_keys()
return [
app_commands.Choice(name=f"{key.identifier}: {key.key}", value=key.key)
for key in self._client_utils.get_auto_complete_list(keys, current, lambda x: x.key)
]
@api_key.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator()
async def add(self, ctx: Context, identifier: str):
self._logger.debug(__name__, f"Received command api-key add {ctx}: {identifier}")
server = self._servers.get_server_by_discord_id(ctx.guild.id)
user = self._users.get_user_by_discord_id_and_server_id(ctx.author.id, server.server_id)
api_key = ApiKey(identifier, str(uuid.uuid4()), user)
self._api_keys.add_api_key(api_key)
self._db.save_changes()
await self._message_service.send_ctx_msg(
ctx,
self._t.transform("modules.technician.api_key.add.success").format(
identifier, self._get_api_key_str(api_key)
),
)
self._logger.trace(__name__, f"Finished command api-key add")
@api_key.command()
@commands.guild_only()
@CommandChecks.check_is_ready()
@CommandChecks.check_is_member_moderator()
async def remove(self, ctx: Context, key: str):
self._logger.debug(__name__, f"Received command api-key remove {ctx}: {key}")
keys = self._api_keys.get_api_keys().where(lambda x: x.key == key)
if keys.count() < 1:
await self._message_service.send_ctx_msg(
ctx,
self._t.transform("modules.technician.api_key.remove.not_found"),
)
api_key = keys.single()
self._api_keys.delete_api_key(api_key)
self._db.save_changes()
await self._message_service.send_ctx_msg(ctx, self._t.transform("modules.technician.api_key.remove.success"))
self._logger.trace(__name__, f"Finished command api-key remove")
@remove.autocomplete("key")
async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> TList[app_commands.Choice[str]]:
keys = self._api_keys.get_api_keys()
return [
app_commands.Choice(name=f"{key.identifier}: {key.key}", value=key.key)
for key in self._client_utils.get_auto_complete_list(keys, current, lambda x: x.key)
]

View File

@ -6,10 +6,11 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from modules.base.abc.base_helper_abc import BaseHelperABC
from modules.base.service.base_helper_service import BaseHelperService
from modules.technician.command.api_key_group import ApiKeyGroup
from modules.technician.command.log_command import LogCommand
from modules.technician.command.restart_command import RestartCommand
from modules.technician.command.shutdown_command import ShutdownCommand
from modules.base.service.base_helper_service import BaseHelperService
class TechnicianModule(ModuleABC):
@ -25,4 +26,5 @@ class TechnicianModule(ModuleABC):
self._dc.add_command(RestartCommand)
self._dc.add_command(ShutdownCommand)
self._dc.add_command(LogCommand)
self._dc.add_command(ApiKeyGroup)
# events