Introduce full asyncio version (still some module to migrate). Defender JSONRPC Server ready and using with uvcorn

This commit is contained in:
adator
2025-11-20 00:29:32 +01:00
parent 1b30b1ff4e
commit aa15aea749
34 changed files with 2533 additions and 2627 deletions

View File

@@ -45,9 +45,6 @@ class Base:
# Liste des fonctions en attentes # Liste des fonctions en attentes
self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC
# Création du lock
self.lock = self.Settings.LOCK
# Init install variable # Init install variable
self.install: bool = False self.install: bool = False
@@ -57,8 +54,8 @@ class Base:
# Create the database # Create the database
# self.__create_db() # self.__create_db()
def init(self) -> None: async def init(self) -> None:
self.__create_db() await self.__create_db()
def __set_current_defender_version(self) -> None: def __set_current_defender_version(self) -> None:
"""This will put the current version of Defender """This will put the current version of Defender
@@ -145,7 +142,7 @@ class Base:
except Exception as err: except Exception as err:
self.logs.error(f'General Error: {err}') self.logs.error(f'General Error: {err}')
def create_log(self, log_message: str) -> None: async def create_log(self, log_message: str) -> None:
"""Enregiste les logs """Enregiste les logs
Args: Args:
@@ -156,11 +153,11 @@ class Base:
""" """
sql_insert = f"INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)" sql_insert = f"INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)"
mes_donnees = {'datetime': str(self.Utils.get_sdatetime()),'server_msg': f'{log_message}'} mes_donnees = {'datetime': str(self.Utils.get_sdatetime()),'server_msg': f'{log_message}'}
self.db_execute_query(sql_insert, mes_donnees) await self.db_execute_query(sql_insert, mes_donnees)
return None return None
def log_cmd(self, user_cmd: str, cmd: str) -> None: async def log_cmd(self, user_cmd: str, cmd: str) -> None:
"""Enregistre les commandes envoyées par les utilisateurs """Enregistre les commandes envoyées par les utilisateurs
Args: Args:
@@ -176,11 +173,11 @@ class Base:
insert_cmd_query = f"INSERT INTO {self.Config.TABLE_COMMAND} (datetime, user, commande) VALUES (:datetime, :user, :commande)" insert_cmd_query = f"INSERT INTO {self.Config.TABLE_COMMAND} (datetime, user, commande) VALUES (:datetime, :user, :commande)"
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'commande': cmd} mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'commande': cmd}
self.db_execute_query(insert_cmd_query, mes_donnees) await self.db_execute_query(insert_cmd_query, mes_donnees)
return None return None
def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool: async def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool:
"""Sync module local parameters with the database """Sync module local parameters with the database
if new module then local param will be stored in the database if new module then local param will be stored in the database
if old module then db param will be moved to the local dataclassObj if old module then db param will be moved to the local dataclassObj
@@ -207,7 +204,7 @@ class Base:
param_to_search = {'module_name': module_name, 'param_key': param_key} param_to_search = {'module_name': module_name, 'param_key': param_key}
search_query = f'''SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key''' search_query = f'''SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key'''
excecute_search_query = self.db_execute_query(search_query, param_to_search) excecute_search_query = await self.db_execute_query(search_query, param_to_search)
result_search_query = excecute_search_query.fetchone() result_search_query = excecute_search_query.fetchone()
if result_search_query is None: if result_search_query is None:
@@ -219,7 +216,7 @@ class Base:
insert_query = f'''INSERT INTO {core_table} (datetime, module_name, param_key, param_value) insert_query = f'''INSERT INTO {core_table} (datetime, module_name, param_key, param_value)
VALUES (:datetime, :module_name, :param_key, :param_value) VALUES (:datetime, :module_name, :param_key, :param_value)
''' '''
execution = self.db_execute_query(insert_query, param_to_insert) execution = await self.db_execute_query(insert_query, param_to_insert)
if execution.rowcount > 0: if execution.rowcount > 0:
self.logs.debug(f'New parameter added to the database: {param_key} --> {param_value}') self.logs.debug(f'New parameter added to the database: {param_key} --> {param_value}')
@@ -227,14 +224,14 @@ class Base:
# Delete from DB unused parameter # Delete from DB unused parameter
query_select = f"SELECT module_name, param_key, param_value FROM {core_table} WHERE module_name = :module_name" query_select = f"SELECT module_name, param_key, param_value FROM {core_table} WHERE module_name = :module_name"
parameter = {'module_name': module_name} parameter = {'module_name': module_name}
execute_query_select = self.db_execute_query(query_select, parameter) execute_query_select = await self.db_execute_query(query_select, parameter)
result_query_select = execute_query_select.fetchall() result_query_select = execute_query_select.fetchall()
for result in result_query_select: for result in result_query_select:
db_mod_name, db_param_key, db_param_value = result db_mod_name, db_param_key, db_param_value = result
if not hasattr(dataclassObj, db_param_key): if not hasattr(dataclassObj, db_param_key):
mes_donnees = {'param_key': db_param_key, 'module_name': db_mod_name} mes_donnees = {'param_key': db_param_key, 'module_name': db_mod_name}
execute_delete = self.db_execute_query(f'DELETE FROM {core_table} WHERE module_name = :module_name and param_key = :param_key', mes_donnees) execute_delete = await self.db_execute_query(f'DELETE FROM {core_table} WHERE module_name = :module_name and param_key = :param_key', mes_donnees)
row_affected = execute_delete.rowcount row_affected = execute_delete.rowcount
if row_affected > 0: if row_affected > 0:
self.logs.debug(f'A parameter has been deleted from the database: {db_param_key} --> {db_param_value} | Mod: {db_mod_name}') self.logs.debug(f'A parameter has been deleted from the database: {db_param_key} --> {db_param_value} | Mod: {db_mod_name}')
@@ -242,7 +239,7 @@ class Base:
# Sync local variable with Database # Sync local variable with Database
query = f"SELECT param_key, param_value FROM {core_table} WHERE module_name = :module_name" query = f"SELECT param_key, param_value FROM {core_table} WHERE module_name = :module_name"
parameter = {'module_name': module_name} parameter = {'module_name': module_name}
response = self.db_execute_query(query, parameter) response = await self.db_execute_query(query, parameter)
result = response.fetchall() result = response.fetchall()
for param, value in result: for param, value in result:
@@ -259,7 +256,7 @@ class Base:
self.logs.error(err) self.logs.error(err)
return False return False
def db_update_core_config(self, module_name:str, dataclass_obj: object, param_key:str, param_value: str) -> bool: async def db_update_core_config(self, module_name:str, dataclass_obj: object, param_key:str, param_value: str) -> bool:
core_table = self.Config.TABLE_CONFIG core_table = self.Config.TABLE_CONFIG
# Check if the param exist # Check if the param exist
@@ -269,7 +266,7 @@ class Base:
mes_donnees = {'module_name': module_name, 'param_key': param_key, 'param_value': param_value} mes_donnees = {'module_name': module_name, 'param_key': param_key, 'param_value': param_value}
search_param_query = f"SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key" search_param_query = f"SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key"
result = self.db_execute_query(search_param_query, mes_donnees) result = await self.db_execute_query(search_param_query, mes_donnees)
is_param_exist = result.fetchone() is_param_exist = result.fetchone()
if not is_param_exist is None: if not is_param_exist is None:
@@ -279,7 +276,7 @@ class Base:
'param_value': param_value 'param_value': param_value
} }
query = f'''UPDATE {core_table} SET datetime = :datetime, param_value = :param_value WHERE module_name = :module_name AND param_key = :param_key''' query = f'''UPDATE {core_table} SET datetime = :datetime, param_value = :param_value WHERE module_name = :module_name AND param_key = :param_key'''
update = self.db_execute_query(query, mes_donnees) update = await self.db_execute_query(query, mes_donnees)
updated_rows = update.rowcount updated_rows = update.rowcount
if updated_rows > 0: if updated_rows > 0:
setattr(dataclass_obj, param_key, self.int_if_possible(param_value)) setattr(dataclass_obj, param_key, self.int_if_possible(param_value))
@@ -293,9 +290,9 @@ class Base:
return True return True
def db_create_first_admin(self) -> None: async def db_create_first_admin(self) -> None:
user = self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}") user = await self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}")
if not user.fetchall(): if not user.fetchall():
admin = self.Config.OWNER admin = self.Config.OWNER
password = self.Utils.hash_password(self.Config.PASSWORD) password = self.Utils.hash_password(self.Config.PASSWORD)
@@ -308,7 +305,7 @@ class Base:
'language': 'EN', 'language': 'EN',
'level': 5 'level': 5
} }
self.db_execute_query(f""" await self.db_execute_query(f"""
INSERT INTO {self.Config.TABLE_ADMIN} INSERT INTO {self.Config.TABLE_ADMIN}
(createdOn, user, password, hostname, vhost, language, level) (createdOn, user, password, hostname, vhost, language, level)
VALUES VALUES
@@ -381,11 +378,28 @@ class Base:
return None return None
task = asyncio.create_task(func, name=name) task = asyncio.create_task(func, name=name)
task.add_done_callback(self.asynctask_done)
self.running_asynctasks.append(task) self.running_asynctasks.append(task)
self.logs.debug(f"++ New asynchrone task created as: {task.get_name()}") self.logs.debug(f"++ New asynchrone task created as: {task.get_name()}")
return task return task
def asynctask_done(self, task: asyncio.Task):
"""Log task when done
Args:
task (asyncio.Task): The Asyncio Task callback
"""
try:
if task.exception():
self.logs.error(f"[ASYNCIO] Task {task.get_name()} failed with exception: {task.exception()}")
else:
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} completed successfully.")
except asyncio.CancelledError as ce:
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with cancelled error.")
except asyncio.InvalidStateError as ie:
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with invalid state error.")
def is_thread_alive(self, thread_name: str) -> bool: def is_thread_alive(self, thread_name: str) -> bool:
"""Check if the thread is still running! using the is_alive method of Threads. """Check if the thread is still running! using the is_alive method of Threads.
@@ -429,7 +443,7 @@ class Base:
Returns: Returns:
int: Number of threads int: Number of threads
""" """
with self.lock: with self.Settings.LOCK:
count = 0 count = 0
for thr in self.running_threads: for thr in self.running_threads:
@@ -478,7 +492,7 @@ class Base:
self.running_sockets.remove(soc) self.running_sockets.remove(soc)
self.logs.debug(f"-- Socket ==> closed {str(soc.fileno())}") self.logs.debug(f"-- Socket ==> closed {str(soc.fileno())}")
def shutdown(self) -> None: async def shutdown(self) -> None:
"""Methode qui va préparer l'arrêt complêt du service """Methode qui va préparer l'arrêt complêt du service
""" """
# Nettoyage des timers # Nettoyage des timers
@@ -508,6 +522,9 @@ class Base:
self.running_sockets.remove(soc) self.running_sockets.remove(soc)
self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}") self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}")
await self.Loader.RpcServer.stop_server()
self.db_close()
return None return None
def db_init(self) -> tuple[Engine, Connection]: def db_init(self) -> tuple[Engine, Connection]:
@@ -524,7 +541,7 @@ class Base:
self.logs.info("-- Database connexion has been initiated") self.logs.info("-- Database connexion has been initiated")
return engine, cursor return engine, cursor
def __create_db(self) -> None: async def __create_db(self) -> None:
table_core_log = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_LOG} ( table_core_log = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_LOG} (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -594,27 +611,27 @@ class Base:
) )
''' '''
self.db_execute_query(table_core_log) await self.db_execute_query(table_core_log)
self.db_execute_query(table_core_log_command) await self.db_execute_query(table_core_log_command)
self.db_execute_query(table_core_module) await self.db_execute_query(table_core_module)
self.db_execute_query(table_core_admin) await self.db_execute_query(table_core_admin)
self.db_execute_query(table_core_client) await self.db_execute_query(table_core_client)
self.db_execute_query(table_core_channel) await self.db_execute_query(table_core_channel)
self.db_execute_query(table_core_config) await self.db_execute_query(table_core_config)
# Patch database # Patch database
self.db_patch(self.Config.TABLE_ADMIN, "language", "TEXT") await self.db_patch(self.Config.TABLE_ADMIN, "language", "TEXT")
if self.install: if self.install:
self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True) await self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True)
self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True) await self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
self.install = False self.install = False
return None return None
def db_execute_query(self, query:str, params:dict = {}) -> CursorResult: async def db_execute_query(self, query:str, params:dict = {}) -> CursorResult:
with self.lock: async with self.Loader.Settings.AILOCK:
insert_query = text(query) insert_query = text(query)
if not params: if not params:
response = self.cursor.execute(insert_query) response = self.cursor.execute(insert_query)
@@ -625,8 +642,8 @@ class Base:
return response return response
def db_is_column_exist(self, table_name: str, column_name: str) -> bool: async def db_is_column_exist(self, table_name: str, column_name: str) -> bool:
q = self.db_execute_query(f"PRAGMA table_info({table_name})") q = await self.db_execute_query(f"PRAGMA table_info({table_name})")
existing_columns = [col[1] for col in q.fetchall()] existing_columns = [col[1] for col in q.fetchall()]
if column_name in existing_columns: if column_name in existing_columns:
@@ -634,12 +651,12 @@ class Base:
else: else:
return False return False
def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool: async def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool:
if not self.db_is_column_exist(table_name, column_name): if not await self.db_is_column_exist(table_name, column_name):
patch = f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}" patch = f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}"
update_row = f"UPDATE {table_name} SET language = 'EN' WHERE language is null" update_row = f"UPDATE {table_name} SET language = 'EN' WHERE language is null"
self.db_execute_query(patch) await self.db_execute_query(patch)
self.db_execute_query(update_row) await self.db_execute_query(update_row)
self.logs.debug(f"The patch has been applied") self.logs.debug(f"The patch has been applied")
self.logs.debug(f"Table name: {table_name}, Column name: {column_name}, Column type: {column_type}") self.logs.debug(f"Table name: {table_name}, Column name: {column_name}, Column type: {column_type}")
return True return True
@@ -647,9 +664,9 @@ class Base:
return False return False
def db_close(self) -> None: def db_close(self) -> None:
try: try:
self.cursor.close() self.cursor.close()
self.logs.debug("Database engine closed!")
except AttributeError as ae: except AttributeError as ae:
self.logs.error(f"Attribute Error : {ae}") self.logs.error(f"Attribute Error : {ae}")

View File

@@ -24,22 +24,19 @@ class IModule(ABC):
# Log the module # Log the module
self.ctx.Logs.debug(f'Loading Module {self.module_name} ...') self.ctx.Logs.debug(f'Loading Module {self.module_name} ...')
def init(self) -> None: async def sync_db(self) -> None:
self.load()
self.create_tables()
# Sync the configuration with core configuration (Mandatory) # Sync the configuration with core configuration (Mandatory)
self.ctx.Base.db_sync_core_config(self.module_name, self.mod_config) await self.ctx.Base.db_sync_core_config(self.module_name, self.mod_config)
return None return None
def update_configuration(self, param_key: str, param_value: Union[str, int]) -> None: async def update_configuration(self, param_key: str, param_value: Union[str, int]) -> None:
"""Update the local and core configuration """Update the local and core configuration
Args: Args:
param_key (str): The parameter key param_key (str): The parameter key
param_value (str): The parameter value param_value (str): The parameter value
""" """
self.ctx.Base.db_update_core_config(self.module_name, self.mod_config, param_key, param_value) await self.ctx.Base.db_update_core_config(self.module_name, self.mod_config, param_key, param_value)
@property @property
@abstractmethod @abstractmethod
@@ -58,17 +55,17 @@ class IModule(ABC):
""" """
@abstractmethod @abstractmethod
def load(self) -> None: async def load(self) -> None:
"""This method is executed when the module is loaded or reloaded. """This method is executed when the module is loaded or reloaded.
""" """
@abstractmethod @abstractmethod
def unload(self) -> None: async def unload(self) -> None:
"""This method is executed when the module is unloaded or reloaded. """This method is executed when the module is unloaded or reloaded.
""" """
@abstractmethod @abstractmethod
def cmd(self, data: list) -> None: async def cmd(self, data: list) -> None:
"""When recieving server messages. """When recieving server messages.
Args: Args:
@@ -76,7 +73,7 @@ class IModule(ABC):
""" """
@abstractmethod @abstractmethod
def hcmds(self, user: str, channel: Optional[str], cmd: list[str], fullcmd: Optional[list[str]] = None) -> None: async def hcmds(self, user: str, channel: Optional[str], cmd: list[str], fullcmd: Optional[list[str]] = None) -> None:
"""These are the commands recieved from a client """These are the commands recieved from a client
Args: Args:

View File

@@ -4,31 +4,20 @@ from core.classes.protocols.command_handler import CommandHandler
if TYPE_CHECKING: if TYPE_CHECKING:
from core.definition import MClient, MSasl, MUser, MChannel from core.definition import MClient, MSasl, MUser, MChannel
from core.irc import Irc from core.loader import Loader
class IProtocol(ABC): class IProtocol(ABC):
Handler: Optional[CommandHandler] = None Handler: Optional[CommandHandler] = None
def __init__(self, uplink: 'Irc'): def __init__(self, context: 'Loader'):
self.name: Optional[str] = None self.name: Optional[str] = None
self.protocol_version: int = -1 self.protocol_version: int = -1
self.known_protocol: set[str] = set() self.known_protocol: set[str] = set()
self._ctx = context
self._Irc = uplink self.Handler = CommandHandler(context)
self._Config = uplink.Config
self._Base = uplink.Base
self._Settings = uplink.Base.Settings
self._Utils = uplink.Loader.Utils
self._Logs = uplink.Loader.Logs
self._User = uplink.User
self._Channel = uplink.Channel
self.Handler = CommandHandler(uplink.Loader)
self.init_protocol() self.init_protocol()
self._ctx.Logs.info(f"[PROTOCOL] Protocol [{self.__class__.__name__}] loaded!")
self._Logs.info(f"[PROTOCOL] Protocol [{self.__class__.__name__}] loaded!")
@abstractmethod @abstractmethod
def init_protocol(self): def init_protocol(self):
@@ -313,7 +302,7 @@ class IProtocol(ABC):
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
@abstractmethod @abstractmethod
async def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: def parse_uid(self, server_msg: list[str]) -> Optional['MUser']:
"""Parse UID and return dictionary. """Parse UID and return dictionary.
Args: Args:
@@ -324,7 +313,7 @@ class IProtocol(ABC):
""" """
@abstractmethod @abstractmethod
async def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]:
"""Parse quit and return dictionary. """Parse quit and return dictionary.
>>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit']
Args: Args:
@@ -335,7 +324,7 @@ class IProtocol(ABC):
""" """
@abstractmethod @abstractmethod
async def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]:
"""Parse nick changes and return dictionary. """Parse nick changes and return dictionary.
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
@@ -349,7 +338,7 @@ class IProtocol(ABC):
""" """
@abstractmethod @abstractmethod
async def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]:
"""Parse PRIVMSG message. """Parse PRIVMSG message.
>>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message']

View File

@@ -173,7 +173,7 @@ class Admin:
return admin.language return admin.language
def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool: async def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool:
"""Check the fingerprint """Check the fingerprint
Args: Args:
@@ -188,7 +188,7 @@ class Admin:
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp" query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp"
data = {'fp': fp} data = {'fp': fp}
exe = self.Base.db_execute_query(query, data) exe = await self.Base.db_execute_query(query, data)
result = exe.fetchone() result = exe.fetchone()
if result: if result:
account = result[0] account = result[0]
@@ -204,7 +204,7 @@ class Admin:
return False return False
def db_is_admin_exist(self, admin_nickname: str) -> bool: async def db_is_admin_exist(self, admin_nickname: str) -> bool:
"""Verify if the admin exist in the database! """Verify if the admin exist in the database!
Args: Args:
@@ -216,7 +216,7 @@ class Admin:
mes_donnees = {'admin': admin_nickname} mes_donnees = {'admin': admin_nickname}
query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user = :admin" query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user = :admin"
r = self.Base.db_execute_query(query_search_user, mes_donnees) r = await self.Base.db_execute_query(query_search_user, mes_donnees)
exist_user = r.fetchone() exist_user = r.fetchone()
if exist_user: if exist_user:
return True return True

View File

@@ -17,9 +17,7 @@ class Channel:
Args: Args:
loader (Loader): The Loader Instance loader (Loader): The Loader Instance
""" """
self.Logs = loader.Logs self._ctx = loader
self.Base = loader.Base
self.Utils = loader.Utils
def insert(self, new_channel: 'MChannel') -> bool: def insert(self, new_channel: 'MChannel') -> bool:
"""This method will insert a new channel and if the channel exist it will update the user list (uids) """This method will insert a new channel and if the channel exist it will update the user list (uids)
@@ -34,14 +32,14 @@ class Channel:
exist = False exist = False
if not self.is_valid_channel(new_channel.name): if not self.is_valid_channel(new_channel.name):
self.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #") self._ctx.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #")
return False return False
for record in self.UID_CHANNEL_DB: for record in self.UID_CHANNEL_DB:
if record.name.lower() == new_channel.name.lower(): if record.name.lower() == new_channel.name.lower():
# If the channel exist, update the user list and do not go further # If the channel exist, update the user list and do not go further
exist = True exist = True
# self.Logs.debug(f'{record.name} already exist') # self._ctx.Logs.debug(f'{record.name} already exist')
for user in new_channel.uids: for user in new_channel.uids:
record.uids.append(user) record.uids.append(user)
@@ -49,7 +47,7 @@ class Channel:
# Supprimer les doublons # Supprimer les doublons
del_duplicates = list(set(record.uids)) del_duplicates = list(set(record.uids))
record.uids = del_duplicates record.uids = del_duplicates
# self.Logs.debug(f'Updating a new UID to the channel {record}') # self._ctx.Logs.debug(f'Updating a new UID to the channel {record}')
return result return result
if not exist: if not exist:
@@ -57,10 +55,10 @@ class Channel:
new_channel.name = new_channel.name.lower() new_channel.name = new_channel.name.lower()
self.UID_CHANNEL_DB.append(new_channel) self.UID_CHANNEL_DB.append(new_channel)
result = True result = True
# self.Logs.debug(f'New Channel Created: ({new_channel})') # self._ctx.Logs.debug(f'New Channel Created: ({new_channel})')
if not result: if not result:
self.Logs.critical(f'The Channel Object was not inserted {new_channel}') self._ctx.Logs.critical(f'The Channel Object was not inserted {new_channel}')
self.clean_channel() self.clean_channel()
@@ -103,7 +101,7 @@ class Channel:
return result return result
for userid in chan_obj.uids: for userid in chan_obj.uids:
if self.Utils.clean_uid(userid) == self.Utils.clean_uid(uid): if self._ctx.Utils.clean_uid(userid) == self._ctx.Utils.clean_uid(uid):
chan_obj.uids.remove(userid) chan_obj.uids.remove(userid)
result = True result = True
@@ -111,7 +109,7 @@ class Channel:
return result return result
except ValueError as ve: except ValueError as ve:
self.Logs.error(f'{ve}') self._ctx.Logs.error(f'{ve}')
return False return False
def delete_user_from_all_channel(self, uid:str) -> bool: def delete_user_from_all_channel(self, uid:str) -> bool:
@@ -128,7 +126,7 @@ class Channel:
for record in self.UID_CHANNEL_DB: for record in self.UID_CHANNEL_DB:
for user_id in record.uids: for user_id in record.uids:
if self.Utils.clean_uid(user_id) == self.Utils.clean_uid(uid): if self._ctx.Utils.clean_uid(user_id) == self._ctx.Utils.clean_uid(uid):
record.uids.remove(user_id) record.uids.remove(user_id)
result = True result = True
@@ -136,7 +134,7 @@ class Channel:
return result return result
except ValueError as ve: except ValueError as ve:
self.Logs.error(f'{ve}') self._ctx.Logs.error(f'{ve}')
return False return False
def add_user_to_a_channel(self, channel_name: str, uid: str) -> bool: def add_user_to_a_channel(self, channel_name: str, uid: str) -> bool:
@@ -154,7 +152,7 @@ class Channel:
if chan_obj is None: if chan_obj is None:
# Create a new channel if the channel don't exist # Create a new channel if the channel don't exist
self.Logs.debug(f"New channel will be created ({channel_name} - {uid})") self._ctx.Logs.debug(f"New channel will be created ({channel_name} - {uid})")
return self.insert(MChannel(channel_name, uids=[uid])) return self.insert(MChannel(channel_name, uids=[uid]))
chan_obj.uids.append(uid) chan_obj.uids.append(uid)
@@ -163,7 +161,7 @@ class Channel:
return True return True
except Exception as err: except Exception as err:
self.Logs.error(f'{err}') self._ctx.Logs.error(f'{err}')
return False return False
def is_user_present_in_channel(self, channel_name: str, uid: str) -> bool: def is_user_present_in_channel(self, channel_name: str, uid: str) -> bool:
@@ -180,9 +178,9 @@ class Channel:
if chan is None: if chan is None:
return False return False
clean_uid = self.Utils.clean_uid(uid=uid) clean_uid = self._ctx.Utils.clean_uid(uid=uid)
for chan_uid in chan.uids: for chan_uid in chan.uids:
if self.Utils.clean_uid(chan_uid) == clean_uid: if self._ctx.Utils.clean_uid(chan_uid) == clean_uid:
return True return True
return False return False
@@ -197,7 +195,7 @@ class Channel:
return None return None
except Exception as err: except Exception as err:
self.Logs.error(f'{err}') self._ctx.Logs.error(f'{err}')
def get_channel(self, channel_name: str) -> Optional['MChannel']: def get_channel(self, channel_name: str) -> Optional['MChannel']:
"""Get the channel object """Get the channel object
@@ -237,13 +235,13 @@ class Channel:
else: else:
return True return True
except TypeError as te: except TypeError as te:
self.Logs.error(f'TypeError: [{channel_to_check}] - {te}') self._ctx.Logs.error(f'TypeError: [{channel_to_check}] - {te}')
return False return False
except Exception as err: except Exception as err:
self.Logs.error(f'Error Not defined: {err}') self._ctx.Logs.error(f'Error Not defined: {err}')
return False return False
def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool: async def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool:
"""You can add a channel or delete a channel. """You can add a channel or delete a channel.
Args: Args:
@@ -256,39 +254,49 @@ class Channel:
""" """
try: try:
channel_name = channel_name.lower() if self.is_valid_channel(channel_name) else None channel_name = channel_name.lower() if self.is_valid_channel(channel_name) else None
core_table = self.Base.Config.TABLE_CHANNEL core_table = self._ctx.Base.Config.TABLE_CHANNEL
if not channel_name: if not channel_name:
self.Logs.warning(f'The channel [{channel_name}] is not correct') self._ctx.Logs.warning(f'The channel [{channel_name}] is not correct')
return False return False
match action: match action:
case 'add': case 'add':
mes_donnees = {'module_name': module_name, 'channel_name': channel_name} mes_donnees = {'module_name': module_name, 'channel_name': channel_name}
response = self.Base.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees) response = await self._ctx.Base.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees)
is_channel_exist = response.fetchone() is_channel_exist = response.fetchone()
if is_channel_exist is None: if is_channel_exist is None:
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name} mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name}
insert = self.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees) insert = await self._ctx.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees)
if insert.rowcount: if insert.rowcount:
self.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}') self._ctx.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}')
return True return True
else: else:
return False return False
case 'del': case 'del':
mes_donnes = {'channel_name': channel_name, 'module_name': module_name} mes_donnes = {'channel_name': channel_name, 'module_name': module_name}
response = self.Base.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes) response = await self._ctx.Base.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes)
if response.rowcount > 0: if response.rowcount > 0:
self.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}') self._ctx.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}')
return True return True
else: else:
return False return False
except Exception as err: except Exception as err:
self.Logs.error(err) self._ctx.Logs.error(err)
return False return False
async def db_join_saved_channels(self) -> None:
"""## Joining saved channels"""
exec_query = await self._ctx.Base.db_execute_query(f'SELECT distinct channel_name FROM {self._ctx.Config.TABLE_CHANNEL}')
result_query = exec_query.fetchall()
if result_query:
for chan_name in result_query:
chan = chan_name[0]
await self._ctx.Irc.Protocol.send_sjoin(channel=chan)

View File

@@ -201,7 +201,7 @@ class Client:
return True return True
def db_is_account_exist(self, account: str) -> bool: async def db_is_account_exist(self, account: str) -> bool:
"""Check if the account exist in the database """Check if the account exist in the database
Args: Args:
@@ -213,7 +213,7 @@ class Client:
table_client = self.Base.Config.TABLE_CLIENT table_client = self.Base.Config.TABLE_CLIENT
account_to_check = {'account': account.lower()} account_to_check = {'account': account.lower()}
account_to_check_query = self.Base.db_execute_query(f""" account_to_check_query = await self.Base.db_execute_query(f"""
SELECT id FROM {table_client} WHERE LOWER(account) = :account SELECT id FROM {table_client} WHERE LOWER(account) = :account
""", account_to_check) """, account_to_check)

View File

@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
import socket import socket
if TYPE_CHECKING: if TYPE_CHECKING:
from core.irc import Irc from core.loader import Loader
# Modules impacted by rehashing! # Modules impacted by rehashing!
REHASH_MODULES = [ REHASH_MODULES = [
@@ -14,7 +14,10 @@ REHASH_MODULES = [
'core.classes.modules.config', 'core.classes.modules.config',
'core.base', 'core.base',
'core.classes.modules.commands', 'core.classes.modules.commands',
'core.classes.modules.rpc', 'core.classes.modules.rpc.rpc_channel',
'core.classes.modules.rpc.rpc_command',
'core.classes.modules.rpc.rpc_user',
'core.classes.modules.rpc.rpc',
'core.classes.interfaces.iprotocol', 'core.classes.interfaces.iprotocol',
'core.classes.interfaces.imodule', 'core.classes.interfaces.imodule',
'core.classes.protocols.command_handler', 'core.classes.protocols.command_handler',
@@ -24,66 +27,62 @@ REHASH_MODULES = [
] ]
def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -> None: async def restart_service(uplink: 'Loader', reason: str = "Restarting with no reason!") -> None:
""" """
Args: Args:
uplink (Irc): The Irc instance uplink (Irc): The Irc instance
reason (str): The reason of the restart. reason (str): The reason of the restart.
""" """
# reload modules. # unload modules.
for module in uplink.ModuleUtils.model_get_loaded_modules().copy(): for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
uplink.ModuleUtils.unload_one_module(uplink, module.module_name) await uplink.ModuleUtils.unload_one_module(module.module_name)
uplink.Base.garbage_collector_thread() uplink.Base.garbage_collector_thread()
uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!') uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!')
uplink.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason) await uplink.Irc.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason)
uplink.Logs.debug('Restarting Defender ...') uplink.Logs.debug('Restarting Defender ...')
uplink.IrcSocket.shutdown(socket.SHUT_RDWR)
uplink.IrcSocket.close()
while uplink.IrcSocket.fileno() != -1:
time.sleep(0.5)
uplink.Logs.warning('-- Waiting for socket to close ...')
# Reload configuration
uplink.Loader.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model
uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
for mod in REHASH_MODULES: for mod in REHASH_MODULES:
importlib.reload(sys.modules[mod]) importlib.reload(sys.modules[mod])
uplink.Protocol = uplink.Loader.PFactory.get() # Reload configuration
uplink.Protocol.register_command() uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model
uplink.Base = uplink.BaseModule.Base(uplink)
uplink.ModuleUtils.model_clear() # Clear loaded modules. uplink.ModuleUtils.model_clear() # Clear loaded modules.
uplink.User.UID_DB.clear() # Clear User Object uplink.User.UID_DB.clear() # Clear User Object
uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object
uplink.Client.CLIENT_DB.clear() # Clear Client object uplink.Client.CLIENT_DB.clear() # Clear Client object
uplink.Irc.Protocol.Handler.DB_IRCDCOMMS.clear()
uplink.init_service_user() # Reload Service modules
uplink.Utils.create_socket(uplink) for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
uplink.Protocol.send_link() await uplink.ModuleUtils.reload_one_module(module.module_name, uplink.Settings.current_admin)
uplink.Irc.signal = True
await uplink.Irc.run()
uplink.Config.DEFENDER_RESTART = 0 uplink.Config.DEFENDER_RESTART = 0
def rehash_service(uplink: 'Irc', nickname: str) -> None: async def rehash_service(uplink: 'Loader', nickname: str) -> None:
need_a_restart = ["SERVEUR_ID"] need_a_restart = ["SERVEUR_ID"]
uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS) uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS)
uplink.Loader.RpcServer.stop_server()
await uplink.RpcServer.stop_server()
restart_flag = False restart_flag = False
config_model_bakcup = uplink.Config config_model_bakcup = uplink.Config
mods = REHASH_MODULES mods = REHASH_MODULES
for mod in mods: for mod in mods:
importlib.reload(sys.modules[mod]) importlib.reload(sys.modules[mod])
uplink.Protocol.send_priv_msg( await uplink.Irc.Protocol.send_priv_msg(
nick_from=uplink.Config.SERVICE_NICKNAME, nick_from=uplink.Config.SERVICE_NICKNAME,
msg=f'[REHASH] Module [{mod}] reloaded', msg=f'[REHASH] Module [{mod}] reloaded',
channel=uplink.Config.SERVICE_CHANLOG channel=uplink.Config.SERVICE_CHANLOG
) )
uplink.Utils = sys.modules['core.utils'] uplink.Utils = sys.modules['core.utils']
uplink.Config = uplink.Loader.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model
uplink.Config.HSID = config_model_bakcup.HSID uplink.Config.HSID = config_model_bakcup.HSID
uplink.Config.DEFENDER_INIT = config_model_bakcup.DEFENDER_INIT uplink.Config.DEFENDER_INIT = config_model_bakcup.DEFENDER_INIT
uplink.Config.DEFENDER_RESTART = config_model_bakcup.DEFENDER_RESTART uplink.Config.DEFENDER_RESTART = config_model_bakcup.DEFENDER_RESTART
@@ -96,7 +95,7 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None:
for key, value in conf_bkp_dict.items(): for key, value in conf_bkp_dict.items():
if config_dict[key] != value and key != 'COLORS': if config_dict[key] != value and key != 'COLORS':
uplink.Protocol.send_priv_msg( await uplink.Irc.Protocol.send_priv_msg(
nick_from=uplink.Config.SERVICE_NICKNAME, nick_from=uplink.Config.SERVICE_NICKNAME,
msg=f'[{key}]: {value} ==> {config_dict[key]}', msg=f'[{key}]: {value} ==> {config_dict[key]}',
channel=uplink.Config.SERVICE_CHANLOG channel=uplink.Config.SERVICE_CHANLOG
@@ -105,27 +104,28 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None:
restart_flag = True restart_flag = True
if config_model_bakcup.SERVICE_NICKNAME != uplink.Config.SERVICE_NICKNAME: if config_model_bakcup.SERVICE_NICKNAME != uplink.Config.SERVICE_NICKNAME:
uplink.Protocol.send_set_nick(uplink.Config.SERVICE_NICKNAME) await uplink.Irc.Protocol.send_set_nick(uplink.Config.SERVICE_NICKNAME)
if restart_flag: if restart_flag:
uplink.Config.SERVEUR_ID = config_model_bakcup.SERVEUR_ID uplink.Config.SERVEUR_ID = config_model_bakcup.SERVEUR_ID
uplink.Protocol.send_priv_msg( await uplink.Irc.Protocol.send_priv_msg(
nick_from=uplink.Config.SERVICE_NICKNAME, nick_from=uplink.Config.SERVICE_NICKNAME,
channel=uplink.Config.SERVICE_CHANLOG, channel=uplink.Config.SERVICE_CHANLOG,
msg='You need to restart defender !') msg='You need to restart defender !')
# Reload Main Commands Module # Reload Main Commands Module
uplink.Commands = uplink.Loader.CommandModule.Command(uplink.Loader) uplink.Commands = uplink.CommandModule.Command(uplink)
uplink.Loader.RpcServer = uplink.Loader.RpcServerModule.JSONRPCServer(uplink.Loader)
uplink.Loader.RpcServer.start_server()
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands') uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader) uplink.Base = uplink.BaseModule.Base(uplink)
uplink.Protocol = uplink.Loader.PFactory.get() uplink.Irc.Protocol = uplink.PFactory.get()
uplink.Protocol.register_command() uplink.Irc.Protocol.register_command()
uplink.RpcServer = uplink.RpcServerModule.JSonRpcServer(uplink)
uplink.Base.create_asynctask(uplink.RpcServer.start_server())
# Reload Service modules # Reload Service modules
for module in uplink.ModuleUtils.model_get_loaded_modules().copy(): for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
uplink.ModuleUtils.reload_one_module(uplink, module.module_name, nickname) await uplink.ModuleUtils.reload_one_module(module.module_name, nickname)
return None return None

View File

@@ -0,0 +1 @@
__version__ = '1.0.0'

View File

@@ -1,8 +1,11 @@
import base64 import base64
import json import json
import logging from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.requests import Request
from starlette.routing import Route
import uvicorn
from enum import Enum from enum import Enum
from http.server import BaseHTTPRequestHandler, HTTPServer
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING, Any, Optional
from core.classes.modules.rpc.rpc_user import RPCUser from core.classes.modules.rpc.rpc_user import RPCUser
from core.classes.modules.rpc.rpc_channel import RPCChannel from core.classes.modules.rpc.rpc_channel import RPCChannel
@@ -11,120 +14,101 @@ from core.classes.modules.rpc.rpc_command import RPCCommand
if TYPE_CHECKING: if TYPE_CHECKING:
from core.loader import Loader from core.loader import Loader
ProxyLoader: Optional['Loader'] = None class JSonRpcServer:
class RPCRequestHandler(BaseHTTPRequestHandler): def __init__(self, context: 'Loader', *, hostname: str = 'localhost', port: int = 5000):
self._ctx = context
self.live: bool = False
self.host = hostname
self.port = port
self.routes: list[Route] = []
self.server: Optional[uvicorn.Server] = None
def log_message(self, format, *args): self.methods: dict = {
pass 'user.list': RPCUser(context).user_list,
'user.get': RPCUser(context).user_get,
def do_POST(self): 'channel.list': RPCChannel(context).channel_list,
logs = ProxyLoader.Logs 'command.list': RPCCommand(context).command_list,
self.server_version = 'Defender6' 'command.get.by.name': RPCCommand(context).command_get_by_name,
self.sys_version = ProxyLoader.Config.CURRENT_VERSION 'command.get.by.module': RPCCommand(context).command_get_by_module
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
request_data: dict = json.loads(body)
rip, rport = self.client_address
if not self.authenticate(request_data):
return None
response_data = {
'jsonrpc': '2.0',
'id': request_data.get('id', 123)
} }
method = request_data.get("method") async def start_server(self):
if not self.live:
self.routes = [Route('/api', self.request_handler, methods=['POST'])]
self.app_jsonrpc = Starlette(debug=False, routes=self.routes)
config = uvicorn.Config(self.app_jsonrpc, host=self.host, port=self.port, log_level=self._ctx.Config.DEBUG_LEVEL)
self.server = uvicorn.Server(config)
self.live = True
await self._ctx.Irc.Protocol.send_priv_msg(
self._ctx.Config.SERVICE_NICKNAME,
"[DEFENDER JSONRPC SERVER] RPC Server started!",
self._ctx.Config.SERVICE_CHANLOG
)
await self.server.serve()
self._ctx.Logs.debug("Server is going to shutdown!")
else:
self._ctx.Logs.debug("Server already running")
async def stop_server(self):
if self.server:
self.server.should_exit = True
await self.server.shutdown()
self.live = False
self._ctx.Logs.debug("JSON-RPC Server off!")
await self._ctx.Irc.Protocol.send_priv_msg(
self._ctx.Config.SERVICE_NICKNAME,
"[DEFENDER JSONRPC SERVER] RPC Server Stopped!",
self._ctx.Config.SERVICE_CHANLOG
)
async def request_handler(self, request: Request) -> JSONResponse:
request_data: dict = await request.json()
method = request_data.get("method", None)
params: dict[str, Any] = request_data.get("params", {}) params: dict[str, Any] = request_data.get("params", {})
auth: JSONResponse = self.authenticate(request.headers, request_data)
if not json.loads(auth.body).get('result', False):
return auth
response_data = {
"jsonrpc": "2.0",
"id": request_data.get('id', 123)
}
response_data['method'] = method response_data['method'] = method
rip = request.client.host
rport = request.client.port
http_code = 200 http_code = 200
match method: if method in self.methods:
case 'user.list': response_data['result'] = self.methods[method](**params)
user = RPCUser(ProxyLoader) return JSONResponse(response_data, http_code)
response_data['result'] = user.user_list()
logs.debug(f'[RPC] {method} recieved from {rip}:{rport}')
del user
case 'user.get':
user = RPCUser(ProxyLoader)
uid_or_nickname = params.get('uid_or_nickname', None)
response_data['result'] = user.user_get(uid_or_nickname)
logs.debug(f'[RPC] {method} recieved from {rip}:{rport}')
del user
case 'channel.list':
channel = RPCChannel(ProxyLoader)
response_data['result'] = channel.channel_list()
logs.debug(f'[RPC] {method} recieved from {rip}:{rport}')
del channel
case 'command.list':
command = RPCCommand(ProxyLoader)
response_data['result'] = command.command_list()
logs.debug(f'[RPC] {method} recieved from {rip}:{rport}')
del command
case 'command.get.by.module':
command = RPCCommand(ProxyLoader)
module_name = params.get('name', None)
response_data['result'] = command.command_get_by_module(module_name)
logs.debug(f'[RPC] {method} recieved from {rip}:{rport}')
del command
case 'command.get.by.name':
command = RPCCommand(ProxyLoader)
command_name = params.get('name', None)
response_data['result'] = command.command_get_by_name(command_name)
logs.debug(f'[RPC] {method} recieved from {rip}:{rport}')
del command
case _:
response_data['error'] = create_error_response(JSONRPCErrorCode.METHOD_NOT_FOUND) response_data['error'] = create_error_response(JSONRPCErrorCode.METHOD_NOT_FOUND)
logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}') self._ctx.Logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}')
http_code = 404 http_code = 404
return JSONResponse(response_data, http_code)
self.send_response(http_code) def authenticate(self, headers: dict, body: dict) -> JSONResponse:
self.send_header('Content-Type', 'application/json') ok_auth = {
self.end_headers() 'jsonrpc': '2.0',
self.wfile.write(json.dumps(response_data).encode('utf-8')) 'id': body.get('id', 123),
'result': True
}
return None logs = self._ctx.Logs
auth: str = headers.get('Authorization', '')
def do_GET(self): if not auth:
self.server_version = 'Defender6' return self.send_auth_error(body)
self.sys_version = ProxyLoader.Config.CURRENT_VERSION
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
request_data: dict = json.loads(body)
if not self.authenticate(request_data):
return None
response_data = {'jsonrpc': '2.0', 'id': request_data.get('id', 321),
'error': create_error_response(JSONRPCErrorCode.INVALID_REQUEST)}
self.send_response(404)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps(response_data).encode('utf-8'))
return None
def authenticate(self, request_data: dict) -> bool:
logs = ProxyLoader.Logs
auth = self.headers.get('Authorization', None)
if auth is None:
self.send_auth_error(request_data)
return False
# Authorization header format: Basic base64(username:password) # Authorization header format: Basic base64(username:password)
auth_type, auth_string = auth.split(' ', 1) auth_type, auth_string = auth.split(' ', 1)
if auth_type.lower() != 'basic': if auth_type.lower() != 'basic':
self.send_auth_error(request_data) return self.send_auth_error(body)
return False
try: try:
# Decode the base64-encoded username:password # Decode the base64-encoded username:password
@@ -132,70 +116,25 @@ class RPCRequestHandler(BaseHTTPRequestHandler):
username, password = decoded_credentials.split(":", 1) username, password = decoded_credentials.split(":", 1)
# Check the username and password. # Check the username and password.
for rpcuser in ProxyLoader.Irc.Config.RPC_USERS: for rpcuser in self._ctx.Config.RPC_USERS:
if rpcuser.get('USERNAME', None) == username and rpcuser.get('PASSWORD', None) == password: if rpcuser.get('USERNAME', None) == username and rpcuser.get('PASSWORD', None) == password:
return True return JSONResponse(ok_auth)
self.send_auth_error(request_data) return self.send_auth_error(body)
return False
except Exception as e: except Exception as e:
self.send_auth_error(request_data)
logs.error(e) logs.error(e)
return False return self.send_auth_error(body)
def send_auth_error(self, request_data: dict) -> None: def send_auth_error(self, request_data: dict) -> JSONResponse:
response_data = { response_data = {
'jsonrpc': '2.0', 'jsonrpc': '2.0',
'id': request_data.get('id', 123), 'id': request_data.get('id', 123),
'error': create_error_response(JSONRPCErrorCode.AUTHENTICATION_ERROR) 'error': create_error_response(JSONRPCErrorCode.AUTHENTICATION_ERROR)
} }
return JSONResponse(response_data)
self.send_response(401)
self.send_header('WWW-Authenticate', 'Basic realm="Authorization Required"')
self.end_headers()
self.wfile.write(json.dumps(response_data).encode('utf-8'))
class JSONRPCServer:
def __init__(self, loader: 'Loader'):
global ProxyLoader
ProxyLoader = loader
self._Loader = loader
self._Base = loader.Base
self._Logs = loader.Logs
self.rpc_server: Optional[HTTPServer] = None
self.connected: bool = False
def start_server(self, server_class=HTTPServer, handler_class=RPCRequestHandler, *, hostname: str = 'localhost', port: int = 5000):
logging.getLogger('http.server').setLevel(logging.CRITICAL)
server_address = (hostname, port)
self.rpc_server = server_class(server_address, handler_class)
self._Logs.debug(f"Server ready on http://{hostname}:{port}...")
self._Base.create_thread(self.thread_start_rpc_server, (), True)
def thread_start_rpc_server(self) -> None:
self._Loader.Irc.Protocol.send_priv_msg(
self._Loader.Config.SERVICE_NICKNAME, "Defender RPC Server has started successfuly!", self._Loader.Config.SERVICE_CHANLOG
)
self.connected = True
self.rpc_server.serve_forever()
ProxyLoader.Logs.debug(f"RPC Server down!")
def stop_server(self):
self._Base.create_thread(self.thread_stop_rpc_server)
def thread_stop_rpc_server(self):
self.rpc_server.shutdown()
ProxyLoader.Logs.debug(f"RPC Server shutdown!")
self.rpc_server.server_close()
ProxyLoader.Logs.debug(f"RPC Server clean-up!")
self._Base.garbage_collector_thread()
self._Loader.Irc.Protocol.send_priv_msg(
self._Loader.Config.SERVICE_NICKNAME, "Defender RPC Server has stopped successfuly!", self._Loader.Config.SERVICE_CHANLOG
)
self.connected = False
class JSONRPCErrorCode(Enum): class JSONRPCErrorCode(Enum):
PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON) PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON)

View File

@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from core.loader import Loader from core.loader import Loader
@@ -8,5 +8,5 @@ class RPCChannel:
self._Loader = loader self._Loader = loader
self._Channel = loader.Channel self._Channel = loader.Channel
def channel_list(self) -> list[dict]: def channel_list(self, **kwargs) -> list[dict]:
return [chan.to_dict() for chan in self._Channel.UID_CHANNEL_DB] return [chan.to_dict() for chan in self._Channel.UID_CHANNEL_DB]

View File

@@ -8,14 +8,22 @@ class RPCCommand:
self._Loader = loader self._Loader = loader
self._Command = loader.Commands self._Command = loader.Commands
def command_list(self) -> list[dict]: def command_list(self, **kwargs) -> list[dict]:
return [command.to_dict() for command in self._Command.DB_COMMANDS] return [command.to_dict() for command in self._Command.DB_COMMANDS]
def command_get_by_module(self, module_name: str) -> list[dict]: def command_get_by_module(self, **kwargs) -> list[dict]:
module_name = kwargs.get('module_name', None)
if module_name is None:
return []
return [command.to_dict() for command in self._Command.DB_COMMANDS if command.module_name.lower() == module_name.lower()] return [command.to_dict() for command in self._Command.DB_COMMANDS if command.module_name.lower() == module_name.lower()]
def command_get_by_name(self, command_name: str) -> dict: def command_get_by_name(self, **kwargs) -> dict:
command_name: str = kwargs.get('command_name', '')
if not command_name:
return dict()
for command in self._Command.DB_COMMANDS: for command in self._Command.DB_COMMANDS:
if command.command_name.lower() == command_name.lower(): if command.command_name.lower() == command_name.lower():
return command.to_dict() return command.to_dict()
return {} return dict()

View File

@@ -6,11 +6,10 @@ if TYPE_CHECKING:
class RPCUser: class RPCUser:
def __init__(self, loader: 'Loader'): def __init__(self, loader: 'Loader'):
self._Loader = loader self._ctx = loader
self._User = loader.User
def user_list(self) -> list[dict]: def user_list(self, **kwargs) -> list[dict]:
users = self._User.UID_DB.copy() users = self._ctx.User.UID_DB.copy()
copy_users: list['MUser'] = [] copy_users: list['MUser'] = []
for user in users: for user in users:
@@ -20,8 +19,9 @@ class RPCUser:
return [user.to_dict() for user in copy_users] return [user.to_dict() for user in copy_users]
def user_get(self, uidornickname: str) -> Optional[dict]: def user_get(self, **kwargs) -> Optional[dict]:
user = self._User.get_user(uidornickname) uidornickname = kwargs.get('uid_or_nickname', None)
user = self._ctx.User.get_user(uidornickname)
if user: if user:
user_copy = user.copy() user_copy = user.copy()
user_copy.connexion_datetime = user_copy.connexion_datetime.strftime('%d-%m-%Y') user_copy.connexion_datetime = user_copy.connexion_datetime.strftime('%d-%m-%Y')

View File

@@ -4,30 +4,29 @@ from .inspircd import Inspircd
from ..interfaces.iprotocol import IProtocol from ..interfaces.iprotocol import IProtocol
if TYPE_CHECKING: if TYPE_CHECKING:
from core.irc import Irc from core.loader import Loader
class ProtocolFactorty: class ProtocolFactorty:
def __init__(self, uplink: 'Irc'): def __init__(self, context: 'Loader'):
"""ProtocolFactory init. """ProtocolFactory init.
Args: Args:
uplink (Irc): The Irc object context (Loader): The Context object
""" """
self.__Config = uplink.Config self.__ctx = context
self.__uplink = uplink
def get(self) -> Optional[IProtocol]: def get(self) -> Optional[IProtocol]:
protocol = self.__Config.SERVEUR_PROTOCOL protocol = self.__ctx.Config.SERVEUR_PROTOCOL
match protocol: match protocol:
case 'unreal6': case 'unreal6':
self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded") self.__ctx.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
return Unrealircd6(self.__uplink) return Unrealircd6(self.__ctx)
case 'inspircd': case 'inspircd':
self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded") self.__ctx.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
return Inspircd(self.__uplink) return Inspircd(self.__ctx)
case _: case _:
self.__uplink.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)") self.__ctx.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)")
raise Exception("Unknown protocol!") raise Exception("Unknown protocol!")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ from json import dumps
from dataclasses import dataclass, field, asdict, fields, replace from dataclasses import dataclass, field, asdict, fields, replace
from typing import Literal, Any, Optional from typing import Literal, Any, Optional
from os import sep from os import sep
from core.classes.interfaces.imodule import IModule
@dataclass @dataclass
class MainModel: class MainModel:
@@ -354,7 +355,7 @@ class MCommand(MainModel):
class MModule(MainModel): class MModule(MainModel):
module_name: str = None module_name: str = None
class_name: str = None class_name: str = None
class_instance: Optional[Any] = None class_instance: Optional[IModule] = None
@dataclass @dataclass
class DefenderModuleHeader(MainModel): class DefenderModuleHeader(MainModel):

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,15 @@ import core.classes.protocols.factory as factory
class Loader: class Loader:
_instance = None
def __new__(cls, *agrs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self): def __init__(self):
# Load Main Modules # Load Main Modules
@@ -70,10 +79,11 @@ class Loader:
self.Irc: irc.Irc = irc.Irc(self) self.Irc: irc.Irc = irc.Irc(self)
self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc) self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self)
self.RpcServer: rpc_mod.JSONRPCServer = rpc_mod.JSONRPCServer(self) self.RpcServer: rpc_mod.JSonRpcServer = rpc_mod.JSonRpcServer(self)
self.Base.init()
self.Logs.debug(self.Utils.tr("Loader %s success", __name__)) self.Logs.debug(self.Utils.tr("Loader %s success", __name__))
async def start(self):
await self.Base.init()

View File

@@ -15,7 +15,7 @@ class ServiceLogging:
self.SERVER_PREFIX = None self.SERVER_PREFIX = None
self.LOGGING_CONSOLE = True self.LOGGING_CONSOLE = True
self.LOG_FILTERS: list[str] = [f":{self.SERVER_PREFIX}auth", "['PASS'"] self.LOG_FILTERS: list[str] = ["PING", f":{self.SERVER_PREFIX}auth", "['PASS'"]
self.file_handler = None self.file_handler = None
self.stdout_handler = None self.stdout_handler = None

View File

@@ -1,9 +1,9 @@
''' '''
This is the main operational file to handle modules This is the main operational file to handle modules
''' '''
from pathlib import Path
import sys import sys
import importlib import importlib
from pathlib import Path
from types import ModuleType from types import ModuleType
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from core.definition import DefenderModuleHeader, MModule from core.definition import DefenderModuleHeader, MModule
@@ -12,6 +12,7 @@ from core.utils import tr
if TYPE_CHECKING: if TYPE_CHECKING:
from core.loader import Loader from core.loader import Loader
from core.irc import Irc from core.irc import Irc
from core.classes.interfaces.imodule import IModule
class Module: class Module:
@@ -19,11 +20,7 @@ class Module:
DB_MODULE_HEADERS: list[DefenderModuleHeader] = [] DB_MODULE_HEADERS: list[DefenderModuleHeader] = []
def __init__(self, loader: 'Loader') -> None: def __init__(self, loader: 'Loader') -> None:
self.__Loader = loader self._ctx = loader
self.__Base = loader.Base
self.__Logs = loader.Logs
self.__Utils = loader.Utils
self.__Config = loader.Config
def get_all_available_modules(self) -> list[str]: def get_all_available_modules(self) -> list[str]:
"""Get list of all main modules """Get list of all main modules
@@ -34,7 +31,7 @@ class Module:
""" """
base_path = Path('mods') base_path = Path('mods')
modules_available = [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')] modules_available = [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')]
self.__Logs.debug(f"Modules available: {modules_available}") self._ctx.Logs.debug(f"Modules available: {modules_available}")
return modules_available return modules_available
def get_module_information(self, module_name: str) -> tuple[Optional[str], Optional[str], Optional[str]]: def get_module_information(self, module_name: str) -> tuple[Optional[str], Optional[str], Optional[str]]:
@@ -45,14 +42,14 @@ class Module:
module_name = module_name.lower() # --> mod_defender module_name = module_name.lower() # --> mod_defender
module_folder = module_name.split('_')[1].lower() # --> defender module_folder = module_name.split('_')[1].lower() # --> defender
class_name = module_name.split('_')[1].capitalize() # --> Defender class_name = module_name.split('_')[1].capitalize() # --> Defender
self.__Logs.debug(f"Module information Folder: {module_folder}, Name: {module_name}, Class: {class_name}") self._ctx.Logs.debug(f"Module information Folder: {module_folder}, Name: {module_name}, Class: {class_name}")
return module_folder, module_name, class_name return module_folder, module_name, class_name
def get_module_header(self, module_name: str) -> Optional[DefenderModuleHeader]: def get_module_header(self, module_name: str) -> Optional[DefenderModuleHeader]:
for mod_h in self.DB_MODULE_HEADERS: for mod_h in self.DB_MODULE_HEADERS:
if module_name.lower() == mod_h.name.lower(): if module_name.lower() == mod_h.name.lower():
self.__Logs.debug(f"Module Header found: {mod_h}") self._ctx.Logs.debug(f"Module Header found: {mod_h}")
return mod_h return mod_h
return None return None
@@ -68,7 +65,7 @@ class Module:
""" """
mod_header = DefenderModuleHeader(**module_header) mod_header = DefenderModuleHeader(**module_header)
if self.get_module_header(mod_header.name) is None: if self.get_module_header(mod_header.name) is None:
self.__Logs.debug(f"[MOD_HEADER] The module header has been created! ({mod_header.name} v{mod_header.version})") self._ctx.Logs.debug(f"[MOD_HEADER] The module header has been created! ({mod_header.name} v{mod_header.version})")
self.DB_MODULE_HEADERS.append(mod_header) self.DB_MODULE_HEADERS.append(mod_header)
return True return True
@@ -77,73 +74,74 @@ class Module:
def delete_module_header(self, module_name: str) -> bool: def delete_module_header(self, module_name: str) -> bool:
mod_header = self.get_module_header(module_name) mod_header = self.get_module_header(module_name)
if mod_header is not None: if mod_header is not None:
self.__Logs.debug(f"[MOD_HEADER] The module header has been deleted ({mod_header.name} v{mod_header.version})") self._ctx.Logs.debug(f"[MOD_HEADER] The module header has been deleted ({mod_header.name} v{mod_header.version})")
self.DB_MODULE_HEADERS.remove(mod_header) self.DB_MODULE_HEADERS.remove(mod_header)
return True return True
self.__Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})") self._ctx.Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})")
return False return False
async def load_one_module(self, uplink: 'Irc', module_name: str, nickname: str, is_default: bool = False) -> bool: async def load_one_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool:
module_folder, module_name, class_name = self.get_module_information(module_name) module_folder, module_name, class_name = self.get_module_information(module_name)
if module_folder is None or module_name is None or class_name is None: if module_folder is None or module_name is None or class_name is None:
self.__Logs.error(f"There is an error with the module name! {module_folder}, {module_name}, {class_name}") self._ctx.Logs.error(f"There is an error with the module name! {module_folder}, {module_name}, {class_name}")
return False return False
if self.is_module_exist_in_sys_module(module_name): if self.is_module_exist_in_sys_module(module_name):
self.__Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!") self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!")
if self.model_is_module_exist(module_name): if self.model_is_module_exist(module_name):
# Si le module existe dans la variable globale retourne False # Si le module existe dans la variable globale retourne False
self.__Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!") self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!")
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self.__Config.SERVICE_PREFIX}reload {module_name}", msg=f"Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self._ctx.Config.SERVICE_PREFIX}reload {module_name}",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
return False return False
return self.reload_one_module(uplink, module_name, nickname) return self.reload_one_module(module_name, nickname)
# Charger le module # Charger le module
try: try:
loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}')
my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe
create_instance_of_the_class = my_class(uplink.Loader) # Créer une nouvelle instance de la classe create_instance_of_the_class: 'IModule' = my_class(self._ctx) # Créer une nouvelle instance de la classe
await create_instance_of_the_class.load() if self._ctx.Utils.is_coroutinefunction(create_instance_of_the_class.load) else create_instance_of_the_class.load()
self.create_module_header(create_instance_of_the_class.MOD_HEADER) self.create_module_header(create_instance_of_the_class.MOD_HEADER)
except AttributeError as attr: except AttributeError as attr:
red = uplink.Config.COLORS.red red = self._ctx.Config.COLORS.red
nogc = uplink.Config.COLORS.nogc nogc = self._ctx.Config.COLORS.red
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr), msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr),
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.__Logs.error(msg=attr, exc_info=True) self._ctx.Logs.error(msg=attr, exc_info=True)
return False return False
if not hasattr(create_instance_of_the_class, 'cmd'): if not hasattr(create_instance_of_the_class, 'cmd'):
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=tr("cmd method is not available in the module (%s)", module_name), msg=tr("cmd method is not available in the module (%s)", module_name),
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.__Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available") self._ctx.Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available")
self.db_delete_module(module_name) await self.db_delete_module(module_name)
return False return False
# Charger la nouvelle class dans la variable globale # Charger la nouvelle class dans la variable globale
if self.model_insert_module(MModule(module_name, class_name, create_instance_of_the_class)): if self.model_insert_module(MModule(module_name, class_name, create_instance_of_the_class)):
# Enregistrer le module dans la base de données # Enregistrer le module dans la base de données
self.db_register_module(module_name, nickname, is_default) await self.db_register_module(module_name, nickname, is_default)
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=tr("Module %s loaded!", module_name), msg=tr("Module %s loaded!", module_name),
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.__Logs.debug(f"Module {class_name} has been loaded") self._ctx.Logs.debug(f"Module {class_name} has been loaded")
return True return True
return False return False
@@ -151,7 +149,7 @@ class Module:
def load_all_modules(self) -> bool: def load_all_modules(self) -> bool:
... ...
async def reload_one_module(self, uplink: 'Irc', module_name: str, nickname: str) -> bool: async def reload_one_module(self, module_name: str, nickname: str) -> bool:
"""Reloading one module and insert it into the model as well as the database """Reloading one module and insert it into the model as well as the database
Args: Args:
@@ -163,21 +161,21 @@ class Module:
bool: True if the module has been reloaded bool: True if the module has been reloaded
""" """
module_folder, module_name, class_name = self.get_module_information(module_name) module_folder, module_name, class_name = self.get_module_information(module_name)
red = self.__Config.COLORS.red red = self._ctx.Config.COLORS.red
nogc = self.__Config.COLORS.nogc nogc = self._ctx.Config.COLORS.nogc
try: try:
if self.is_module_exist_in_sys_module(module_name): if self.is_module_exist_in_sys_module(module_name):
module_model = self.model_get_module(module_name) module_model = self.model_get_module(module_name)
if module_model: if module_model:
self.delete_module_header(module_model.class_instance.MOD_HEADER['name']) self.delete_module_header(module_model.class_instance.MOD_HEADER['name'])
module_model.class_instance.unload() await module_model.class_instance.unload() if self._ctx.Utils.is_coroutinefunction(module_model.class_instance.unload) else module_model.class_instance.unload()
else: else:
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}", msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.__Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self.__Config.SERVICE_PREFIX}load {module_name}") self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self._ctx.Config.SERVICE_PREFIX}load {module_name}")
return False return False
# reload module dependencies # reload module dependencies
@@ -186,37 +184,38 @@ class Module:
the_module = sys.modules[f'mods.{module_folder}.{module_name}'] the_module = sys.modules[f'mods.{module_folder}.{module_name}']
importlib.reload(the_module) importlib.reload(the_module)
my_class = getattr(the_module, class_name, None) my_class = getattr(the_module, class_name, None)
new_instance = my_class(uplink.Loader) new_instance: 'IModule' = my_class(self._ctx)
await new_instance.load() if self._ctx.Utils.is_coroutinefunction(new_instance.load) else new_instance.load()
self.create_module_header(new_instance.MOD_HEADER) self.create_module_header(new_instance.MOD_HEADER)
module_model.class_instance = new_instance module_model.class_instance = new_instance
# Créer le module dans la base de données # Créer le module dans la base de données
self.db_register_module(module_name, nickname) await self.db_register_module(module_name, nickname)
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"Module [{module_folder}.{module_name}] has been reloaded!", msg=f"Module [{module_folder}.{module_name}] has been reloaded!",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.__Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!") self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!")
return True return True
else: else:
# Module is not loaded! Nothing to reload # Module is not loaded! Nothing to reload
self.__Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}") self._ctx.Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}")
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}", msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
return False return False
except (TypeError, AttributeError, KeyError, Exception) as err: except (TypeError, AttributeError, KeyError, Exception) as err:
self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True) self._ctx.Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True)
await uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"[RELOAD MODULE ERROR]: {err}", msg=f"[RELOAD MODULE ERROR]: {err}",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.db_delete_module(module_name) await self.db_delete_module(module_name)
def reload_all_modules(self) -> bool: def reload_all_modules(self) -> bool:
... ...
@@ -242,12 +241,12 @@ class Module:
try: try:
if 'mod_' not in name and 'schemas' not in name: if 'mod_' not in name and 'schemas' not in name:
importlib.reload(module) importlib.reload(module)
self.__Logs.debug(f'[LOAD_MODULE] Module {module} success') self._ctx.Logs.debug(f'[LOAD_MODULE] Module {module} success')
except Exception as err: except Exception as err:
self.__Logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}') self._ctx.Logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}')
def unload_one_module(self, uplink: 'Irc', module_name: str, keep_in_db: bool = True) -> bool: async def unload_one_module(self, module_name: str, keep_in_db: bool = True) -> bool:
"""Unload a module """Unload a module
Args: Args:
@@ -260,23 +259,23 @@ class Module:
""" """
try: try:
# Le nom du module. exemple: mod_defender # Le nom du module. exemple: mod_defender
red = self.__Config.COLORS.red red = self._ctx.Config.COLORS.red
nogc = self.__Config.COLORS.nogc nogc = self._ctx.Config.COLORS.nogc
module_folder, module_name, class_name = self.get_module_information(module_name) module_folder, module_name, class_name = self.get_module_information(module_name)
module = self.model_get_module(module_name) module = self.model_get_module(module_name)
if module is None: if module is None:
self.__Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!") self._ctx.Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!")
self.db_delete_module(module_name) await self.db_delete_module(module_name)
uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"[ {red}UNLOAD MODULE ERROR{nogc} ] This module {module_name} is not loaded!", msg=f"[ {red}UNLOAD MODULE ERROR{nogc} ] This module {module_name} is not loaded!",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
return False return False
if module: if module:
self.delete_module_header(module.class_instance.MOD_HEADER['name']) self.delete_module_header(module.class_instance.MOD_HEADER['name'])
module.class_instance.unload() await module.class_instance.unload() if self._ctx.Utils.is_coroutinefunction(module.class_instance.unload) else module.class_instance.unload()
self.DB_MODULES.remove(module) self.DB_MODULES.remove(module)
# Delete from the sys.modules. # Delete from the sys.modules.
@@ -284,25 +283,25 @@ class Module:
del sys.modules[f"mods.{module_folder}.{module_name}"] del sys.modules[f"mods.{module_folder}.{module_name}"]
if sys.modules.get(f'mods.{module_folder}.{module_name}'): if sys.modules.get(f'mods.{module_folder}.{module_name}'):
self.__Logs.debug(f"Module mods.{module_folder}.{module_name} still in the sys.modules") self._ctx.Logs.debug(f"Module mods.{module_folder}.{module_name} still in the sys.modules")
# Supprimer le module de la base de données # Supprimer le module de la base de données
if not keep_in_db: if not keep_in_db:
self.db_delete_module(module_name) await self.db_delete_module(module_name)
uplink.Protocol.send_priv_msg( await self._ctx.Irc.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self._ctx.Config.SERVICE_NICKNAME,
msg=f"[ UNLOAD MODULE INFO ] Module {module_name} has been unloaded!", msg=f"[ UNLOAD MODULE INFO ] Module {module_name} has been unloaded!",
channel=self.__Config.SERVICE_CHANLOG channel=self._ctx.Config.SERVICE_CHANLOG
) )
self.__Logs.debug(f"[ UNLOAD MODULE ] {module_name} has been unloaded!") self._ctx.Logs.debug(f"[ UNLOAD MODULE ] {module_name} has been unloaded!")
return True return True
self.__Logs.debug(f"[UNLOAD MODULE]: Module {module_name} not found in DB_MODULES variable!") self._ctx.Logs.debug(f"[UNLOAD MODULE]: Module {module_name} not found in DB_MODULES variable!")
return False return False
except Exception as err: except Exception as err:
self.__Logs.error(f"General Error: {err}", exc_info=True) self._ctx.Logs.error(f"General Error: {err}", exc_info=True)
return False return False
def unload_all_modules(self) -> bool: def unload_all_modules(self) -> bool:
@@ -319,9 +318,9 @@ class Module:
""" """
module_folder, module_name, class_name = self.get_module_information(module_name) module_folder, module_name, class_name = self.get_module_information(module_name)
if "mods." + module_folder + "." + module_name in sys.modules: if "mods." + module_folder + "." + module_name in sys.modules:
self.__Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) found in sys.modules") self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) found in sys.modules")
return True return True
self.__Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules") self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules")
return False return False
''' '''
@@ -338,10 +337,10 @@ class Module:
""" """
for module in self.DB_MODULES: for module in self.DB_MODULES:
if module.module_name.lower() == module_name.lower(): if module.module_name.lower() == module_name.lower():
self.__Logs.debug(f"[MODEL MODULE GET] The module {module_name} has been found in the model DB_MODULES") self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} has been found in the model DB_MODULES")
return module return module
self.__Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES") self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES")
return None return None
def model_get_loaded_modules(self) -> list[MModule]: def model_get_loaded_modules(self) -> list[MModule]:
@@ -351,7 +350,7 @@ class Module:
Returns: Returns:
list[MModule]: A list of module model object list[MModule]: A list of module model object
""" """
# self.__Logs.debug(f"[MODEL MODULE LOADED MODULES] {len(self.DB_MODULES)} modules found!") # self._ctx.Logs.debug(f"[MODEL MODULE LOADED MODULES] {len(self.DB_MODULES)} modules found!")
return self.DB_MODULES return self.DB_MODULES
def model_insert_module(self, module_model: MModule) -> bool: def model_insert_module(self, module_model: MModule) -> bool:
@@ -366,17 +365,17 @@ class Module:
module = self.model_get_module(module_model.module_name) module = self.model_get_module(module_model.module_name)
if module is None: if module is None:
self.DB_MODULES.append(module_model) self.DB_MODULES.append(module_model)
self.__Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} has been inserted in the local variable model DB_MODULES") self._ctx.Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} has been inserted in the local variable model DB_MODULES")
return True return True
self.__Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} already exist in the local variable model DB_MODULES") self._ctx.Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} already exist in the local variable model DB_MODULES")
return False return False
def model_clear(self) -> None: def model_clear(self) -> None:
"""Clear DB_MODULES list! """Clear DB_MODULES list!
""" """
self.DB_MODULES.clear() self.DB_MODULES.clear()
self.__Logs.debug("[MODEL MODULE CLEAR] The local variable model DB_MODULES has been cleared") self._ctx.Logs.debug("[MODEL MODULE CLEAR] The local variable model DB_MODULES has been cleared")
return None return None
def model_is_module_exist(self, module_name: str) -> bool: def model_is_module_exist(self, module_name: str) -> bool:
@@ -389,30 +388,30 @@ class Module:
bool: True if the module_name exist bool: True if the module_name exist
""" """
if self.model_get_module(module_name): if self.model_get_module(module_name):
self.__Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} exist in the local model DB_MODULES!") self._ctx.Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} exist in the local model DB_MODULES!")
return True return True
self.__Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} is not available in the local model DB_MODULES!") self._ctx.Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} is not available in the local model DB_MODULES!")
return False return False
''' '''
OPERATION DEDICATED TO DATABASE MANAGEMENT OPERATION DEDICATED TO DATABASE MANAGEMENT
''' '''
async def db_load_all_existing_modules(self, uplink: 'Irc') -> bool: async def db_load_all_existing_modules(self) -> bool:
"""Charge les modules qui existe déja dans la base de données """Charge les modules qui existe déja dans la base de données
Returns: Returns:
None: Aucun retour requis, elle charge puis c'est tout None: Aucun retour requis, elle charge puis c'est tout
""" """
self.__Logs.debug("[DB LOAD MODULE] Loading modules from the database!") self._ctx.Logs.debug("[DB LOAD MODULE] Loading modules from the database!")
result = self.__Base.db_execute_query(f"SELECT module_name FROM {self.__Config.TABLE_MODULE}") result = await self._ctx.Base.db_execute_query(f"SELECT module_name FROM {self._ctx.Config.TABLE_MODULE}")
for r in result.fetchall(): for r in result.fetchall():
await self.load_one_module(uplink, r[0], 'sys', True) await self.load_one_module(r[0], 'sys', True)
return True return True
def db_is_module_exist(self, module_name: str) -> bool: async def db_is_module_exist(self, module_name: str) -> bool:
"""Check if the module exist in the database """Check if the module exist in the database
Args: Args:
@@ -421,18 +420,18 @@ class Module:
Returns: Returns:
bool: True if the module exist in the database bool: True if the module exist in the database
""" """
query = f"SELECT id FROM {self.__Config.TABLE_MODULE} WHERE module_name = :module_name" query = f"SELECT id FROM {self._ctx.Config.TABLE_MODULE} WHERE module_name = :module_name"
mes_donnes = {'module_name': module_name.lower()} mes_donnes = {'module_name': module_name.lower()}
results = self.__Base.db_execute_query(query, mes_donnes) results = await self._ctx.Base.db_execute_query(query, mes_donnes)
if results.fetchall(): if results.fetchall():
self.__Logs.debug(f"[DB MODULE EXIST] The module {module_name} exist in the database!") self._ctx.Logs.debug(f"[DB MODULE EXIST] The module {module_name} exist in the database!")
return True return True
else: else:
self.__Logs.debug(f"[DB MODULE EXIST] The module {module_name} is not available in the database!") self._ctx.Logs.debug(f"[DB MODULE EXIST] The module {module_name} is not available in the database!")
return False return False
def db_register_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool: async def db_register_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool:
"""Insert a new module in the database """Insert a new module in the database
Args: Args:
@@ -440,49 +439,49 @@ class Module:
nickname (str): The user who loaded the module nickname (str): The user who loaded the module
isdefault (int): Is this a default module. Default 0 isdefault (int): Is this a default module. Default 0
""" """
if not self.db_is_module_exist(module_name): if not await self.db_is_module_exist(module_name):
insert_cmd_query = f"INSERT INTO {self.__Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)" insert_cmd_query = f"INSERT INTO {self._ctx.Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)"
mes_donnees = {'datetime': self.__Utils.get_sdatetime(), 'user': nickname, 'module_name': module_name.lower(), 'isdefault': is_default} mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'user': nickname, 'module_name': module_name.lower(), 'isdefault': is_default}
insert = self.__Base.db_execute_query(insert_cmd_query, mes_donnees) insert = await self._ctx.Base.db_execute_query(insert_cmd_query, mes_donnees)
if insert.rowcount > 0: if insert.rowcount > 0:
self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} has been inserted to the database!") self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} has been inserted to the database!")
return True return True
else: else:
self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} not inserted to the database!") self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} not inserted to the database!")
return False return False
self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} already exist in the database! Nothing to insert!") self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} already exist in the database! Nothing to insert!")
return False return False
def db_update_module(self, module_name: str, nickname: str) -> None: async def db_update_module(self, module_name: str, nickname: str) -> None:
"""Update the datetime and the user that updated the module """Update the datetime and the user that updated the module
Args: Args:
module_name (str): The module name to update module_name (str): The module name to update
nickname (str): The nickname who updated the module nickname (str): The nickname who updated the module
""" """
update_cmd_query = f"UPDATE {self.__Config.TABLE_MODULE} SET datetime = :datetime, LOWER(user) = :user WHERE LOWER(module_name) = :module_name" update_cmd_query = f"UPDATE {self._ctx.Config.TABLE_MODULE} SET datetime = :datetime, LOWER(user) = :user WHERE LOWER(module_name) = :module_name"
mes_donnees = {'datetime': self.__Utils.get_sdatetime(), 'user': nickname.lower(), 'module_name': module_name.lower()} mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'user': nickname.lower(), 'module_name': module_name.lower()}
result = self.__Base.db_execute_query(update_cmd_query, mes_donnees) result = await self._ctx.Base.db_execute_query(update_cmd_query, mes_donnees)
if result.rowcount > 0: if result.rowcount > 0:
self.__Logs.debug(f"[DB UPDATE MODULE] Module {module_name} has been updated!") self._ctx.Logs.debug(f"[DB UPDATE MODULE] Module {module_name} has been updated!")
return True return True
else: else:
self.__Logs.debug(f"[DB UPDATE MODULE] Module {module_name} not found! Nothing to update!") self._ctx.Logs.debug(f"[DB UPDATE MODULE] Module {module_name} not found! Nothing to update!")
return False return False
def db_delete_module(self, module_name:str) -> None: async def db_delete_module(self, module_name:str) -> None:
"""Delete a module from the database """Delete a module from the database
Args: Args:
module_name (str): The module name you want to delete module_name (str): The module name you want to delete
""" """
insert_cmd_query = f"DELETE FROM {self.__Config.TABLE_MODULE} WHERE LOWER(module_name) = :module_name" insert_cmd_query = f"DELETE FROM {self._ctx.Config.TABLE_MODULE} WHERE LOWER(module_name) = :module_name"
mes_donnees = {'module_name': module_name.lower()} mes_donnees = {'module_name': module_name.lower()}
delete = self.__Base.db_execute_query(insert_cmd_query, mes_donnees) delete = await self._ctx.Base.db_execute_query(insert_cmd_query, mes_donnees)
if delete.rowcount > 0: if delete.rowcount > 0:
self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} has been deleted from the dabatase!") self._ctx.Logs.debug(f"[DB MODULE DELETE] The module {module_name} has been deleted from the dabatase!")
return True return True
self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!") self._ctx.Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!")
return False return False

View File

@@ -13,6 +13,7 @@ from time import time
from random import choice from random import choice
from hashlib import md5, sha3_512 from hashlib import md5, sha3_512
from core.classes.modules.settings import global_settings from core.classes.modules.settings import global_settings
from asyncio import iscoroutinefunction
if TYPE_CHECKING: if TYPE_CHECKING:
from core.irc import Irc from core.irc import Irc
@@ -243,3 +244,14 @@ def hide_sensitive_data(srvmsg: list[str]) -> list[str]:
except ValueError: except ValueError:
return srvmsg return srvmsg
def is_coroutinefunction(func: Any) -> bool:
"""Check if the function is a coroutine or not
Args:
func (Any): an callable object
Returns:
bool: True if the function is a coroutine
"""
return iscoroutinefunction(func)

View File

@@ -13,6 +13,7 @@ from core import install
async def main(): async def main():
from core.loader import Loader from core.loader import Loader
loader = Loader() loader = Loader()
await loader.start()
await loader.Irc.run() await loader.Irc.run()
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -10,7 +10,7 @@ class CloneManager:
def __init__(self, uplink: 'Clone'): def __init__(self, uplink: 'Clone'):
self.Logs = uplink.Logs self.Logs = uplink.ctx.Logs
def insert(self, new_clone_object: MClone) -> bool: def insert(self, new_clone_object: MClone) -> bool:
"""Create new Clone object """Create new Clone object

View File

@@ -8,6 +8,7 @@ from mods.clone.clone_manager import CloneManager
if TYPE_CHECKING: if TYPE_CHECKING:
from faker import Faker from faker import Faker
from core.loader import Loader
class Clone(IModule): class Clone(IModule):
@@ -23,7 +24,15 @@ class Clone(IModule):
'core_version':'Defender-6' 'core_version':'Defender-6'
} }
def create_tables(self) -> None: def __init__(self, context: 'Loader') -> None:
super().__init__(context)
self._mod_config: Optional[schemas.ModConfModel] = None
@property
def mod_config(self) -> ModConfModel:
return self._mod_config
async def create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas. """Methode qui va créer la base de donnée si elle n'existe pas.
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
@@ -39,63 +48,69 @@ class Clone(IModule):
) )
''' '''
# self.Base.db_execute_query(table_channel) # await self.ctx.Base.db_execute_query(table_channel)
return None return None
def load(self) -> None: async def load(self) -> None:
self.ModConfig = self.ModConfModel()
# Variable qui va contenir les options de configuration du module Defender
self._mod_config: schemas.ModConfModel = self.ModConfModel()
# sync the database with local variable (Mandatory)
await self.sync_db()
self.stop = False self.stop = False
self.Schemas = schemas self.Schemas = schemas
self.Utils = utils self.Utils = utils
self.Threads = thds self.Threads = thds
self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB') self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB')
self.Clone = CloneManager(self) self.Clone = CloneManager(self)
metadata = self.Settings.get_cache('UID_CLONE_DB') metadata = self.ctx.Settings.get_cache('UID_CLONE_DB')
if metadata is not None: if metadata is not None:
self.Clone.UID_CLONE_DB = metadata self.Clone.UID_CLONE_DB = metadata
self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}") self.ctx.Logs.debug(f"Cache Size = {self.ctx.Settings.get_cache_size()}")
# Créer les nouvelles commandes du module # Créer les nouvelles commandes du module
self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones') self.ctx.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) await self.ctx.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_sjoin(self.Config.CLONE_CHANNEL) await self.ctx.Irc.Protocol.send_sjoin(self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_set_mode('+o', nickname=self.Config.SERVICE_NICKNAME, channel_name=self.Config.CLONE_CHANNEL) await self.ctx.Irc.Protocol.send_set_mode('+o', nickname=self.ctx.Config.SERVICE_NICKNAME, channel_name=self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_set_mode('+nts', channel_name=self.Config.CLONE_CHANNEL) await self.ctx.Irc.Protocol.send_set_mode('+nts', channel_name=self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_set_mode('+k', channel_name=self.Config.CLONE_CHANNEL, params=self.Config.CLONE_CHANNEL_PASSWORD) await self.ctx.Irc.Protocol.send_set_mode('+k', channel_name=self.ctx.Config.CLONE_CHANNEL, params=self.ctx.Config.CLONE_CHANNEL_PASSWORD)
def unload(self) -> None: async def unload(self) -> None:
"""Cette methode sera executée a chaque désactivation ou """Cette methode sera executée a chaque désactivation ou
rechargement de module rechargement de module
""" """
# Store Clones DB into the global Settings to retrieve it after the reload. # Store Clones DB into the global Settings to retrieve it after the reload.
self.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB) self.ctx.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB)
self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) await self.ctx.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_set_mode('-nts', channel_name=self.Config.CLONE_CHANNEL) await self.ctx.Irc.Protocol.send_set_mode('-nts', channel_name=self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_set_mode('-k', channel_name=self.Config.CLONE_CHANNEL) await self.ctx.Irc.Protocol.send_set_mode('-k', channel_name=self.ctx.Config.CLONE_CHANNEL)
self.Protocol.send_part_chan(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL) await self.ctx.Irc.Protocol.send_part_chan(self.ctx.Config.SERVICE_NICKNAME, self.ctx.Config.CLONE_CHANNEL)
self.Irc.Commands.drop_command_by_module(self.module_name) self.ctx.Commands.drop_command_by_module(self.module_name)
return None return None
def cmd(self, data:list) -> None: async def cmd(self, data:list) -> None:
try: try:
if not data or len(data) < 2: if not data or len(data) < 2:
return None return None
cmd = data.copy() if isinstance(data, list) else list(data).copy() cmd = data.copy() if isinstance(data, list) else list(data).copy()
index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd) index, command = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd)
if index == -1: if index == -1:
return None return None
match command: match command:
case 'PRIVMSG': case 'PRIVMSG':
self.Utils.handle_on_privmsg(self, cmd) await self.Utils.handle_on_privmsg(self, cmd)
return None return None
case 'QUIT': case 'QUIT':
@@ -105,10 +120,10 @@ class Clone(IModule):
return None return None
except Exception as err: except Exception as err:
self.Logs.error(f'General Error: {err}', exc_info=True) self.ctx.Logs.error(f'General Error: {err}', exc_info=True)
return None return None
def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None:
try: try:
@@ -117,18 +132,18 @@ class Clone(IModule):
command = str(cmd[0]).lower() command = str(cmd[0]).lower()
fromuser = user fromuser = user
dnickname = self.Config.SERVICE_NICKNAME dnickname = self.ctx.Config.SERVICE_NICKNAME
match command: match command:
case 'clone': case 'clone':
if len(cmd) == 1: if len(cmd) < 2:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
return None return None
option = str(cmd[1]).lower() option = str(cmd[1]).lower()
@@ -143,15 +158,13 @@ class Clone(IModule):
group = str(cmd[3]).lower() group = str(cmd[3]).lower()
connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2 connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2
self.Base.create_thread( self.ctx.Base.create_asynctask(
func=self.Threads.thread_connect_clones, func=self.Threads.coro_connect_clones(self, number_of_clones, group, False, connection_interval)
func_args=(self, number_of_clones, group, False, connection_interval)
) )
except Exception as err: except IndexError:
self.Logs.error(f'{err}') await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group] [freq]")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group] [freq]") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance")
case 'kill': case 'kill':
try: try:
@@ -160,27 +173,26 @@ class Clone(IModule):
option = str(cmd[2]) option = str(cmd[2])
if option.lower() == 'all': if option.lower() == 'all':
self.Base.create_thread(func=self.Threads.thread_kill_clones, func_args=(self, )) self.ctx.Base.create_asynctask(func=self.Threads.thread_kill_clones(self))
elif self.Clone.group_exists(option): elif self.Clone.group_exists(option):
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option) list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
if len(list_of_clones_in_group) > 0: if len(list_of_clones_in_group) > 0:
self.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}") self.ctx.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}")
for clone in list_of_clones_in_group: for clone in list_of_clones_in_group:
self.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False) await self.ctx.Irc.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False)
self.Clone.delete(clone.uid) self.Clone.delete(clone.uid)
else: else:
clone_obj = self.Clone.get_clone(option) clone_obj = self.Clone.get_clone(option)
if not clone_obj is None: if not clone_obj is None:
self.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False) await self.ctx.Irc.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False)
self.Clone.delete(clone_obj.uid) self.Clone.delete(clone_obj.uid)
except Exception as err: except IndexError:
self.Logs.error(f'{err}') await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
case 'join': case 'join':
try: try:
@@ -191,25 +203,24 @@ class Clone(IModule):
if option.lower() == 'all': if option.lower() == 'all':
for clone in self.Clone.UID_CLONE_DB: for clone in self.Clone.UID_CLONE_DB:
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False) await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False)
elif self.Clone.group_exists(option): elif self.Clone.group_exists(option):
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option) list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
if len(list_of_clones_in_group) > 0: if len(list_of_clones_in_group) > 0:
self.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}") self.ctx.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}")
for clone in list_of_clones_in_group: for clone in list_of_clones_in_group:
self.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False) await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False)
else: else:
if self.Clone.nickname_exists(option): if self.Clone.nickname_exists(option):
clone_uid = self.Clone.get_clone(option).uid clone_uid = self.Clone.get_clone(option).uid
self.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False) await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False)
except Exception as err: except IndexError:
self.Logs.error(f'{err}') await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
case 'part': case 'part':
try: try:
@@ -220,67 +231,66 @@ class Clone(IModule):
if option.lower() == 'all': if option.lower() == 'all':
for clone in self.Clone.UID_CLONE_DB: for clone in self.Clone.UID_CLONE_DB:
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
elif self.Clone.group_exists(option): elif self.Clone.group_exists(option):
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option) list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
if len(list_of_clones_in_group) > 0: if len(list_of_clones_in_group) > 0:
self.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}") self.ctx.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}")
for clone in list_of_clones_in_group: for clone in list_of_clones_in_group:
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
else: else:
if self.Clone.nickname_exists(option): if self.Clone.nickname_exists(option):
clone_uid = self.Clone.get_uid(option) clone_uid = self.Clone.get_uid(option)
if not clone_uid is None: if not clone_uid is None:
self.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False) await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False)
except Exception as err: except IndexError:
self.Logs.error(f'{err}') await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
case 'list': case 'list':
try: try:
# Syntax. /msg defender clone list <group_name> # Syntax. /msg defender clone list <group_name>
header = f" {'Nickname':<12}| {'Real name':<25}| {'Group name':<15}| {'Connected':<35}" header = f" {'Nickname':<12}| {'Real name':<25}| {'Group name':<15}| {'Connected':<35}"
line = "-"*67 line = "-"*67
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header) await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header)
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
group_name = cmd[2] if len(cmd) > 2 else None group_name = cmd[2] if len(cmd) > 2 else None
if group_name is None: if group_name is None:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
for clone_name in self.Clone.UID_CLONE_DB: for clone_name in self.Clone.UID_CLONE_DB:
self.Protocol.send_notice( await self.ctx.Irc.Protocol.send_notice(
nick_from=dnickname, nick_from=dnickname,
nick_to=fromuser, nick_to=fromuser,
msg=f" {clone_name.nickname:<12}| {clone_name.realname:<25}| {clone_name.group:<15}| {clone_name.connected:<35}") msg=f" {clone_name.nickname:<12}| {clone_name.realname:<25}| {clone_name.group:<15}| {clone_name.connected:<35}")
else: else:
if not self.Clone.group_exists(group_name): if not self.Clone.group_exists(group_name):
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!")
return None return None
clones = self.Clone.get_clones_from_groupname(group_name) clones = self.Clone.get_clones_from_groupname(group_name)
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
for clone in clones: for clone in clones:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
msg=f" {clone.nickname:<12}| {clone.realname:<25}| {clone.group:<15}| {clone.connected:<35}") msg=f" {clone.nickname:<12}| {clone.realname:<25}| {clone.group:<15}| {clone.connected:<35}")
except Exception as err: except IndexError:
self.Logs.error(f'{err}') await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
case 'say': case 'say':
try: try:
# clone say clone_nickname #channel message # clone say clone_nickname #channel message
clone_name = str(cmd[2]) clone_name = str(cmd[2])
clone_channel = str(cmd[3]) if self.Channel.is_valid_channel(str(cmd[3])) else None clone_channel = str(cmd[3]) if self.ctx.Channel.is_valid_channel(str(cmd[3])) else None
final_message = ' '.join(cmd[4:]) final_message = ' '.join(cmd[4:])
if clone_channel is None or not self.Clone.nickname_exists(clone_name): if clone_channel is None or not self.Clone.nickname_exists(clone_name):
self.Protocol.send_notice( await self.ctx.Irc.Protocol.send_notice(
nick_from=dnickname, nick_from=dnickname,
nick_to=fromuser, nick_to=fromuser,
msg=f"/msg {dnickname} clone say [clone_nickname] #channel message" msg=f"/msg {dnickname} clone say [clone_nickname] #channel message"
@@ -288,24 +298,21 @@ class Clone(IModule):
return None return None
if self.Clone.nickname_exists(clone_name): if self.Clone.nickname_exists(clone_name):
self.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel) await self.ctx.Irc.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel)
except Exception as err: except IndexError:
self.Logs.error(f'{err}') await self.ctx.Irc.Protocol.send_notice(
self.Protocol.send_notice(
nick_from=dnickname, nick_from=dnickname,
nick_to=fromuser, nick_to=fromuser,
msg=f"/msg {dnickname} clone say [clone_nickname] #channel message" msg=f"/msg {dnickname} clone say [clone_nickname] #channel message"
) )
case _: case _:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
except IndexError as ie:
self.Logs.error(f'Index Error: {ie}')
except Exception as err: except Exception as err:
self.Logs.error(f'General Error: {err}') self.ctx.Logs.error(f'General Error: {err}', exc_info=True)

View File

@@ -1,10 +1,11 @@
import asyncio
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from time import sleep from time import sleep
if TYPE_CHECKING: if TYPE_CHECKING:
from mods.clone.mod_clone import Clone from mods.clone.mod_clone import Clone
def thread_connect_clones(uplink: 'Clone', async def coro_connect_clones(uplink: 'Clone',
number_of_clones:int , number_of_clones:int ,
group: str = 'Default', group: str = 'Default',
auto_remote_ip: bool = False, auto_remote_ip: bool = False,
@@ -27,18 +28,18 @@ def thread_connect_clones(uplink: 'Clone',
break break
if not clone.connected: if not clone.connected:
uplink.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False) await uplink.ctx.Irc.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
uplink.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.Config.CLONE_CHANNEL, password=uplink.Config.CLONE_CHANNEL_PASSWORD, print_log=False) await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.ctx.Config.CLONE_CHANNEL, password=uplink.ctx.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
sleep(interval) await asyncio.sleep(interval)
clone.connected = True clone.connected = True
def thread_kill_clones(uplink: 'Clone'): async def thread_kill_clones(uplink: 'Clone'):
clone_to_kill = uplink.Clone.UID_CLONE_DB.copy() clone_to_kill = uplink.Clone.UID_CLONE_DB.copy()
for clone in clone_to_kill: for clone in clone_to_kill:
uplink.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False) await uplink.ctx.Irc.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False)
uplink.Clone.delete(clone.uid) uplink.Clone.delete(clone.uid)
del clone_to_kill del clone_to_kill

View File

@@ -125,8 +125,8 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
""" """
faker = faker_instance faker = faker_instance
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID) uid = generate_uid_for_clone(faker, uplink.ctx.Config.SERVEUR_ID)
umodes = uplink.Config.CLONE_UMODES umodes = uplink.ctx.Config.CLONE_UMODES
# Generate Username # Generate Username
username = generate_username_for_clone(faker) username = generate_username_for_clone(faker)
@@ -153,7 +153,7 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
checkNickname = uplink.Clone.nickname_exists(nickname) checkNickname = uplink.Clone.nickname_exists(nickname)
while checkUid: while checkUid:
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID) uid = generate_uid_for_clone(faker, uplink.ctx.Config.SERVEUR_ID)
checkUid = uplink.Clone.uid_exists(uid=uid) checkUid = uplink.Clone.uid_exists(uid=uid)
clone = uplink.Schemas.MClone( clone = uplink.Schemas.MClone(
@@ -174,12 +174,12 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
return True return True
def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None: async def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None:
senderObj, recieverObj, channel, message = uplink.Protocol.parse_privmsg(srvmsg) senderObj, recieverObj, channel, message = uplink.ctx.Irc.Protocol.parse_privmsg(srvmsg)
if senderObj is not None: if senderObj is not None:
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT: if senderObj.hostname in uplink.ctx.Config.CLONE_LOG_HOST_EXEMPT:
return return
senderMsg = message senderMsg = message
clone_obj = recieverObj clone_obj = recieverObj
@@ -187,12 +187,12 @@ def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None:
if clone_obj is None: if clone_obj is None:
return return
if clone_obj.uid != uplink.Config.SERVICE_ID: if clone_obj.uid != uplink.ctx.Config.SERVICE_ID:
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}" final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
uplink.Protocol.send_priv_msg( await uplink.ctx.Irc.Protocol.send_priv_msg(
nick_from=clone_obj.uid, nick_from=clone_obj.uid,
msg=final_message, msg=final_message,
channel=uplink.Config.CLONE_CHANNEL channel=uplink.ctx.Config.CLONE_CHANNEL
) )
return None return None

File diff suppressed because it is too large Load Diff

View File

@@ -4,243 +4,243 @@ if TYPE_CHECKING:
from mods.command.mod_command import Command from mods.command.mod_command import Command
def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None: async def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None:
command: str = str(cmd[0]).lower() command: str = str(cmd[0]).lower()
option: str = str(cmd[1]).lower() option: str = str(cmd[1]).lower()
allowed_modes: list[str] = uplink.Loader.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v'] allowed_modes: list[str] = uplink.ctx.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v']
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
fromuser = client fromuser = client
match option: match option:
case 'set': case 'set':
if len(cmd) < 5: if len(cmd) < 5:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]")
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}")
return None return None
nickname = str(cmd[2]) nickname = str(cmd[2])
mode = str(cmd[3]) mode = str(cmd[3])
chan: str = str(cmd[4]).lower() if uplink.Channel.is_valid_channel(cmd[4]) else None chan: str = str(cmd[4]).lower() if uplink.ctx.Channel.is_valid_channel(cmd[4]) else None
sign = mode[0] if mode.startswith( ('+', '-')) else None sign = mode[0] if mode.startswith( ('+', '-')) else None
clean_mode = mode[1:] if len(mode) > 0 else None clean_mode = mode[1:] if len(mode) > 0 else None
if sign is None: if sign is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -")
return None return None
if clean_mode not in allowed_modes: if clean_mode not in allowed_modes:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
return None return None
if chan is None: if chan is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
return None return None
db_data: dict[str, str] = {"nickname": nickname, "channel": chan} db_data: dict[str, str] = {"nickname": nickname, "channel": chan}
db_query = uplink.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data) db_query = await uplink.ctx.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data)
db_result = db_query.fetchone() db_result = db_query.fetchone()
if db_result is not None: if db_result is not None:
if sign == '+': if sign == '+':
db_data = {"updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode} db_data = {"updated_on": uplink.ctx.Utils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
db_result = uplink.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel", db_result = await uplink.ctx.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel",
params=db_data) params=db_data)
if db_result.rowcount > 0: if db_result.rowcount > 0:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}")
elif sign == '-': elif sign == '-':
db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"} db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"}
db_result = uplink.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode", db_result = await uplink.ctx.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode",
params=db_data) params=db_data)
if db_result.rowcount > 0: if db_result.rowcount > 0:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}")
else: else:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}")
return None return None
# Instert a new automode # Instert a new automode
if sign == '+': if sign == '+':
db_data = {"created_on": uplink.MainUtils.get_sdatetime(), "updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode} db_data = {"created_on": uplink.ctx.Utils.get_sdatetime(), "updated_on": uplink.ctx.Utils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
db_query = uplink.Base.db_execute_query( db_query = await uplink.ctx.Base.db_execute_query(
query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)", query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)",
params=db_data params=db_data
) )
if db_query.rowcount > 0: if db_query.rowcount > 0:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}")
if uplink.Channel.is_user_present_in_channel(chan, uplink.User.get_uid(nickname)): if uplink.ctx.Channel.is_user_present_in_channel(chan, uplink.ctx.User.get_uid(nickname)):
uplink.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}")
else: else:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist")
case 'list': case 'list':
db_query = uplink.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode") db_query = await uplink.ctx.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode")
db_results = db_query.fetchall() db_results = db_query.fetchall()
if not db_results: if not db_results:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
msg="There is no automode to display.") msg="There is no automode to display.")
for db_result in db_results: for db_result in db_results:
db_nickname, db_channel, db_mode = db_result db_nickname, db_channel, db_mode = db_result
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}") msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}")
case _: case _:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]")
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST")
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}")
def set_deopall(uplink: 'Command', channel_name: str) -> None: async def set_deopall(uplink: 'Command', channel_name: str) -> None:
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o")
return None return None
def set_devoiceall(uplink: 'Command', channel_name: str) -> None: async def set_devoiceall(uplink: 'Command', channel_name: str) -> None:
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v")
return None return None
def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None: async def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None:
chan_info = uplink.Channel.get_channel(channel_name) chan_info = uplink.ctx.Channel.get_channel(channel_name)
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
set_mode = pmode set_mode = pmode
mode:str = '' mode:str = ''
users:str = '' users:str = ''
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)] uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}")
for uid in uids_split: for uid in uids_split:
for i in range(0, len(uid)): for i in range(0, len(uid)):
mode += set_mode mode += set_mode
users += f'{uplink.User.get_nickname(uplink.MainUtils.clean_uid(uid[i]))} ' users += f'{uplink.ctx.User.get_nickname(uplink.ctx.Utils.clean_uid(uid[i]))} '
if i == len(uid) - 1: if i == len(uid) - 1:
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}")
mode = '' mode = ''
users = '' users = ''
def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None: async def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None:
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
if channel_name is None: if channel_name is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]")
return False return False
if len(cmd) == 1: if len(cmd) == 1:
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}") # await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}")
uplink.Protocol.send_set_mode(mode, nickname=client, channel_name=channel_name) await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=client, channel_name=channel_name)
return None return None
# deop nickname # deop nickname
if len(cmd) == 2: if len(cmd) == 2:
nickname = cmd[1] nickname = cmd[1]
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}") # await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
uplink.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name) await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name)
return None return None
nickname = cmd[2] nickname = cmd[2]
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}") # await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
uplink.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name) await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name)
return None return None
def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None: async def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None:
command = str(cmd[0]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
if sentchannel is None: if sentchannel is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
return None return None
nickname = cmd[2] nickname = cmd[2]
uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*")
uplink.Logs.debug(f'{client} has banned {nickname} from {sentchannel}') uplink.ctx.Logs.debug(f'{client} has banned {nickname} from {sentchannel}')
return None return None
def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None: async def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None:
command = str(cmd[0]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
if sentchannel is None: if sentchannel is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
return False return False
nickname = cmd[2] nickname = cmd[2]
final_reason = ' '.join(cmd[3:]) final_reason = ' '.join(cmd[3:])
uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
uplink.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}') uplink.ctx.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}')
return None return None
def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None: async def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None:
command = str(cmd[0]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
if sentchannel is None: if sentchannel is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
return False return False
nickname = cmd[2] nickname = cmd[2]
final_reason = ' '.join(cmd[3:]) final_reason = ' '.join(cmd[3:])
uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*")
uplink.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}') uplink.ctx.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}')
def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: async def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
if len(cmd) < 2: if len(cmd) < 2:
raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter") raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter")
command = str(cmd[0]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None sent_channel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
if sent_channel is None: if sent_channel is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
return None return None
# self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}') # self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}')
uplink.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel) await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel)
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}")
uplink.Channel.db_query_channel('add', uplink.module_name, sent_channel) await uplink.ctx.Channel.db_query_channel('add', uplink.module_name, sent_channel)
return None return None
def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: async def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
if len(cmd) < 2: if len(cmd) < 2:
raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter") raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter")
command = str(cmd[0]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.ctx.Config.SERVICE_NICKNAME
dchanlog = uplink.Config.SERVICE_CHANLOG dchanlog = uplink.ctx.Config.SERVICE_CHANLOG
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None sent_channel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
if sent_channel is None: if sent_channel is None:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
return None return None
if sent_channel == dchanlog: if sent_channel == dchanlog:
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]")
return None return None
uplink.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel) await uplink.ctx.Irc.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel)
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}") await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}")
uplink.Channel.db_query_channel('del', uplink.module_name, sent_channel) await uplink.ctx.Channel.db_query_channel('del', uplink.module_name, sent_channel)
return None return None

File diff suppressed because it is too large Load Diff

View File

@@ -1,115 +1,116 @@
import asyncio
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from time import sleep from time import sleep
if TYPE_CHECKING: if TYPE_CHECKING:
from mods.defender.mod_defender import Defender from mods.defender.mod_defender import Defender
def thread_apply_reputation_sanctions(uplink: 'Defender'): async def coro_apply_reputation_sanctions(uplink: 'Defender'):
while uplink.reputationTimer_isRunning: while uplink.reputationTimer_isRunning:
uplink.Utils.action_apply_reputation_santions(uplink) await uplink.mod_utils.action_apply_reputation_santions(uplink)
sleep(5) await asyncio.sleep(5)
def thread_cloudfilt_scan(uplink: 'Defender'): async def coro_cloudfilt_scan(uplink: 'Defender'):
while uplink.cloudfilt_isRunning: while uplink.cloudfilt_isRunning:
list_to_remove:list = [] list_to_remove:list = []
for user in uplink.Schemas.DB_CLOUDFILT_USERS: for user in uplink.Schemas.DB_CLOUDFILT_USERS:
uplink.Utils.action_scan_client_with_cloudfilt(uplink, user) uplink.mod_utils.action_scan_client_with_cloudfilt(uplink, user)
list_to_remove.append(user) list_to_remove.append(user)
sleep(1) await asyncio.sleep(1)
for user_model in list_to_remove: for user_model in list_to_remove:
uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model) uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model)
sleep(1) await asyncio.sleep(1)
def thread_freeipapi_scan(uplink: 'Defender'): async def coro_freeipapi_scan(uplink: 'Defender'):
while uplink.freeipapi_isRunning: while uplink.freeipapi_isRunning:
list_to_remove: list = [] list_to_remove: list = []
for user in uplink.Schemas.DB_FREEIPAPI_USERS: for user in uplink.Schemas.DB_FREEIPAPI_USERS:
uplink.Utils.action_scan_client_with_freeipapi(uplink, user) uplink.mod_utils.action_scan_client_with_freeipapi(uplink, user)
list_to_remove.append(user) list_to_remove.append(user)
sleep(1) await asyncio.sleep(1)
for user_model in list_to_remove: for user_model in list_to_remove:
uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model) uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model)
sleep(1) await asyncio.sleep(1)
def thread_abuseipdb_scan(uplink: 'Defender'): async def coro_abuseipdb_scan(uplink: 'Defender'):
while uplink.abuseipdb_isRunning: while uplink.abuseipdb_isRunning:
list_to_remove: list = [] list_to_remove: list = []
for user in uplink.Schemas.DB_ABUSEIPDB_USERS: for user in uplink.Schemas.DB_ABUSEIPDB_USERS:
uplink.Utils.action_scan_client_with_abuseipdb(uplink, user) uplink.mod_utils.action_scan_client_with_abuseipdb(uplink, user)
list_to_remove.append(user) list_to_remove.append(user)
sleep(1) await asyncio.sleep(1)
for user_model in list_to_remove: for user_model in list_to_remove:
uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model) uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model)
sleep(1) await asyncio.sleep(1)
def thread_local_scan(uplink: 'Defender'): async def coro_local_scan(uplink: 'Defender'):
while uplink.localscan_isRunning: while uplink.localscan_isRunning:
list_to_remove:list = [] list_to_remove:list = []
for user in uplink.Schemas.DB_LOCALSCAN_USERS: for user in uplink.Schemas.DB_LOCALSCAN_USERS:
uplink.Utils.action_scan_client_with_local_socket(uplink, user) uplink.mod_utils.action_scan_client_with_local_socket(uplink, user)
list_to_remove.append(user) list_to_remove.append(user)
sleep(1) await asyncio.sleep(1)
for user_model in list_to_remove: for user_model in list_to_remove:
uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model) uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model)
sleep(1) await asyncio.sleep(1)
def thread_psutil_scan(uplink: 'Defender'): async def coro_psutil_scan(uplink: 'Defender'):
while uplink.psutil_isRunning: while uplink.psutil_isRunning:
list_to_remove:list = [] list_to_remove:list = []
for user in uplink.Schemas.DB_PSUTIL_USERS: for user in uplink.Schemas.DB_PSUTIL_USERS:
uplink.Utils.action_scan_client_with_psutil(uplink, user) uplink.mod_utils.action_scan_client_with_psutil(uplink, user)
list_to_remove.append(user) list_to_remove.append(user)
sleep(1) await asyncio.sleep(1)
for user_model in list_to_remove: for user_model in list_to_remove:
uplink.Schemas.DB_PSUTIL_USERS.remove(user_model) uplink.Schemas.DB_PSUTIL_USERS.remove(user_model)
sleep(1) await asyncio.sleep(1)
def thread_autolimit(uplink: 'Defender'): async def coro_autolimit(uplink: 'Defender'):
if uplink.ModConfig.autolimit == 0: if uplink.mod_config.autolimit == 0:
uplink.Logs.debug("autolimit deactivated ... canceling the thread") uplink.ctx.Logs.debug("autolimit deactivated ... canceling the thread")
return None return None
while uplink.Irc.autolimit_started: while uplink.ctx.Irc.autolimit_started:
sleep(0.2) await asyncio.sleep(0.2)
uplink.Irc.autolimit_started = True uplink.ctx.Irc.autolimit_started = True
init_amount = uplink.ModConfig.autolimit_amount init_amount = uplink.mod_config.autolimit_amount
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
INIT = 1 INIT = 1
# Copy Channels to a list of dict # Copy Channels to a list of dict
chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in uplink.Channel.UID_CHANNEL_DB] chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in uplink.ctx.Channel.UID_CHANNEL_DB]
chan_list: list[str] = [c.name for c in uplink.Channel.UID_CHANNEL_DB] chan_list: list[str] = [c.name for c in uplink.ctx.Channel.UID_CHANNEL_DB]
while uplink.autolimit_isRunning: while uplink.autolimit_isRunning:
if uplink.ModConfig.autolimit == 0: if uplink.mod_config.autolimit == 0:
uplink.Logs.debug("autolimit deactivated ... stopping the current thread") uplink.ctx.Logs.debug("autolimit deactivated ... stopping the current thread")
break break
for chan in uplink.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
for chan_copy in chanObj_copy: for chan_copy in chanObj_copy:
if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]: if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]:
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}") await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
chan_copy["uids_count"] = len(chan.uids) chan_copy["uids_count"] = len(chan.uids)
if chan.name not in chan_list: if chan.name not in chan_list:
@@ -117,51 +118,55 @@ def thread_autolimit(uplink: 'Defender'):
chanObj_copy.append({"name": chan.name, "uids_count": 0}) chanObj_copy.append({"name": chan.name, "uids_count": 0})
# Verifier si un salon a été vidé # Verifier si un salon a été vidé
current_chan_in_list = [d.name for d in uplink.Channel.UID_CHANNEL_DB] current_chan_in_list = [d.name for d in uplink.ctx.Channel.UID_CHANNEL_DB]
for c in chan_list: for c in chan_list:
if c not in current_chan_in_list: if c not in current_chan_in_list:
chan_list.remove(c) chan_list.remove(c)
# Si c'est la premiere execution # Si c'est la premiere execution
if INIT == 1: if INIT == 1:
for chan in uplink.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}") await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
# Si le nouveau amount est différent de l'initial # Si le nouveau amount est différent de l'initial
if init_amount != uplink.ModConfig.autolimit_amount: if init_amount != uplink.mod_config.autolimit_amount:
init_amount = uplink.ModConfig.autolimit_amount init_amount = uplink.mod_config.autolimit_amount
for chan in uplink.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}") await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
INIT = 0 INIT = 0
if uplink.autolimit_isRunning: if uplink.autolimit_isRunning:
sleep(uplink.ModConfig.autolimit_interval) await asyncio.sleep(uplink.mod_config.autolimit_interval)
for chan in uplink.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} -l") # await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} -l")
await p.send_set_mode('-l', channel_name=chan.name)
uplink.Irc.autolimit_started = False uplink.ctx.Irc.autolimit_started = False
return None return None
def timer_release_mode_mute(uplink: 'Defender', action: str, channel: str): async def coro_release_mode_mute(uplink: 'Defender', action: str, channel: str):
"""DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING """DO NOT EXECUTE THIS FUNCTION DIRECTLY
IT WILL BLOCK THE PROCESS
Args: Args:
action (str): _description_ action (str): mode-m
channel (str): The related channel channel (str): The related channel
""" """
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
timeout = uplink.mod_config.flood_timer
await asyncio.sleep(timeout)
if not uplink.Channel.is_valid_channel(channel): if not uplink.ctx.Channel.is_valid_channel(channel):
uplink.Logs.debug(f"Channel is not valid {channel}") uplink.ctx.Logs.debug(f"Channel is not valid {channel}")
return return
match action: match action:
case 'mode-m': case 'mode-m':
# Action -m sur le salon # Action -m sur le salon
uplink.Protocol.send2socket(f":{service_id} MODE {channel} -m") await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel} -m")
case _: case _:
pass pass

View File

@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Optional
from mods.defender.schemas import FloodUser from mods.defender.schemas import FloodUser
if TYPE_CHECKING: if TYPE_CHECKING:
from core.loader import Loader
from core.definition import MUser from core.definition import MUser
from mods.defender.mod_defender import Defender from mods.defender.mod_defender import Defender
@@ -28,10 +29,10 @@ def handle_on_reputation(uplink: 'Defender', srvmsg: list[str]):
return return
# Possibilité de déclancher les bans a ce niveau. # Possibilité de déclancher les bans a ce niveau.
if not uplink.Base.is_valid_ip(ip): if not uplink.ctx.Base.is_valid_ip(ip):
return return
def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): async def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
"""_summary_ """_summary_
>>> srvmsg = ['@unrealircd.org/...', ':001C0MF01', 'MODE', '#services', '+l', '1'] >>> srvmsg = ['@unrealircd.org/...', ':001C0MF01', 'MODE', '#services', '+l', '1']
>>> srvmsg = ['...', ':001XSCU0Q', 'MODE', '#jail', '+b', '~security-group:unknown-users'] >>> srvmsg = ['...', ':001XSCU0Q', 'MODE', '#jail', '+b', '~security-group:unknown-users']
@@ -40,10 +41,10 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
srvmsg (list[str]): The Server MSG srvmsg (list[str]): The Server MSG
confmodel (ModConfModel): The Module Configuration confmodel (ModConfModel): The Module Configuration
""" """
irc = uplink.Irc irc = uplink.ctx.Irc
gconfig = uplink.Config gconfig = uplink.ctx.Config
p = uplink.Protocol p = irc.Protocol
confmodel = uplink.ModConfig confmodel = uplink.mod_config
channel = str(srvmsg[3]) channel = str(srvmsg[3])
mode = str(srvmsg[4]) mode = str(srvmsg[4])
@@ -52,25 +53,25 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
if confmodel.autolimit == 1: if confmodel.autolimit == 1:
if mode == '+l' or mode == '-l': if mode == '+l' or mode == '-l':
chan = irc.Channel.get_channel(channel) chan = uplink.ctx.Channel.get_channel(channel)
p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}") await p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}")
if gconfig.SALON_JAIL == channel: if gconfig.SALON_JAIL == channel:
if mode == '+b' and group_to_unban in group_to_check: if mode == '+b' and group_to_unban in group_to_check:
p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users") await p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users")
p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") await p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]): async def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]):
# ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg'] # ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg']
sender, reciever, channel, message = uplink.Protocol.parse_privmsg(srvmsg) sender, reciever, channel, message = uplink.ctx.Irc.Protocol.parse_privmsg(srvmsg)
if uplink.ModConfig.sentinel == 1 and channel.name != uplink.Config.SERVICE_CHANLOG: if uplink.mod_config.sentinel == 1 and channel.name != uplink.ctx.Config.SERVICE_CHANLOG:
uplink.Protocol.send_priv_msg(uplink.Config.SERVICE_NICKNAME, f"{sender.nickname} say on {channel.name}: {' '.join(message)}", uplink.Config.SERVICE_CHANLOG) await uplink.ctx.Irc.Protocol.send_priv_msg(uplink.ctx.Config.SERVICE_NICKNAME, f"{sender.nickname} say on {channel.name}: {' '.join(message)}", uplink.ctx.Config.SERVICE_CHANLOG)
action_on_flood(uplink, srvmsg) await action_on_flood(uplink, srvmsg)
return None return None
def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]): async def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
"""If Joining a new channel, it applies group bans. """If Joining a new channel, it applies group bans.
>>> srvmsg = ['@msgid..', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL'] >>> srvmsg = ['@msgid..', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL']
@@ -80,37 +81,37 @@ def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
srvmsg (list[str]): The Server MSG srvmsg (list[str]): The Server MSG
confmodel (ModConfModel): The Module Configuration confmodel (ModConfModel): The Module Configuration
""" """
irc = uplink.Irc irc = uplink.ctx.Irc
p = irc.Protocol p = irc.Protocol
gconfig = uplink.Config gconfig = uplink.ctx.Config
confmodel = uplink.ModConfig confmodel = uplink.mod_config
parsed_chan = srvmsg[4] if irc.Channel.is_valid_channel(srvmsg[4]) else None parsed_chan = srvmsg[4] if uplink.ctx.Channel.is_valid_channel(srvmsg[4]) else None
parsed_UID = uplink.Loader.Utils.clean_uid(srvmsg[5]) parsed_UID = uplink.ctx.Utils.clean_uid(srvmsg[5])
if parsed_chan is None or parsed_UID is None: if parsed_chan is None or parsed_UID is None:
return return
if confmodel.reputation == 1: if confmodel.reputation == 1:
get_reputation = irc.Reputation.get_reputation(parsed_UID) get_reputation = uplink.ctx.Reputation.get_reputation(parsed_UID)
if parsed_chan != gconfig.SALON_JAIL: if parsed_chan != gconfig.SALON_JAIL:
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users") await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users")
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
if get_reputation is not None: if get_reputation is not None:
isWebirc = get_reputation.isWebirc isWebirc = get_reputation.isWebirc
if not isWebirc: if not isWebirc:
if parsed_chan != gconfig.SALON_JAIL: if parsed_chan != gconfig.SALON_JAIL:
p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan) await p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan)
if confmodel.reputation_ban_all_chan == 1 and not isWebirc: if confmodel.reputation_ban_all_chan == 1 and not isWebirc:
if parsed_chan != gconfig.SALON_JAIL: if parsed_chan != gconfig.SALON_JAIL:
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*") await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*")
p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}") await p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}")
irc.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}') uplink.ctx.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}')
def handle_on_slog(uplink: 'Defender', srvmsg: list[str]): def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
"""Handling SLOG messages """Handling SLOG messages
@@ -122,27 +123,27 @@ def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
""" """
['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)'] ['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)']
if not uplink.Base.is_valid_ip(srvmsg[8]): if not uplink.ctx.Base.is_valid_ip(srvmsg[8]):
return None return None
# if self.ModConfig.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # if self.mod_config.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
# self.localscan_remote_ip.append(cmd[7]) # self.localscan_remote_ip.append(cmd[7])
# if self.ModConfig.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # if self.mod_config.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
# self.psutil_remote_ip.append(cmd[7]) # self.psutil_remote_ip.append(cmd[7])
# if self.ModConfig.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # if self.mod_config.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
# self.abuseipdb_remote_ip.append(cmd[7]) # self.abuseipdb_remote_ip.append(cmd[7])
# if self.ModConfig.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # if self.mod_config.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
# self.freeipapi_remote_ip.append(cmd[7]) # self.freeipapi_remote_ip.append(cmd[7])
# if self.ModConfig.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # if self.mod_config.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
# self.cloudfilt_remote_ip.append(cmd[7]) # self.cloudfilt_remote_ip.append(cmd[7])
return None return None
def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): async def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
"""Handle nickname changes. """Handle nickname changes.
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712'] >>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712']
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
@@ -151,22 +152,22 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
srvmsg (list[str]): The Server MSG srvmsg (list[str]): The Server MSG
confmodel (ModConfModel): The Module Configuration confmodel (ModConfModel): The Module Configuration
""" """
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
u, new_nickname, timestamp = p.parse_nick(srvmsg) u, new_nickname, timestamp = p.parse_nick(srvmsg)
if u is None: if u is None:
uplink.Logs.error(f"[USER OBJ ERROR {timestamp}] - {srvmsg}") uplink.ctx.Logs.error(f"[USER OBJ ERROR {timestamp}] - {srvmsg}")
return None return None
uid = u.uid uid = u.uid
confmodel = uplink.ModConfig confmodel = uplink.mod_config
get_reputation = uplink.Reputation.get_reputation(uid) get_reputation = uplink.ctx.Reputation.get_reputation(uid)
jail_salon = uplink.Config.SALON_JAIL jail_salon = uplink.ctx.Config.SALON_JAIL
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
if get_reputation is None: if get_reputation is None:
uplink.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass') uplink.ctx.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass')
return None return None
# Update the new nickname # Update the new nickname
@@ -176,42 +177,42 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
# If ban in all channel is ON then unban old nickname an ban the new nickname # If ban in all channel is ON then unban old nickname an ban the new nickname
if confmodel.reputation_ban_all_chan == 1: if confmodel.reputation_ban_all_chan == 1:
for chan in uplink.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
if chan.name != jail_salon: if chan.name != jail_salon:
p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*") await p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*")
p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*") await p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*")
def handle_on_quit(uplink: 'Defender', srvmsg: list[str]): async def handle_on_quit(uplink: 'Defender', srvmsg: list[str]):
"""Handle on quit message """Handle on quit message
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'QUIT', ':Quit:', 'quit message'] >>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'QUIT', ':Quit:', 'quit message']
Args: Args:
uplink (Irc): The Defender Module instance uplink (Irc): The Defender Module instance
srvmsg (list[str]): The Server MSG srvmsg (list[str]): The Server MSG
""" """
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
userobj, reason = p.parse_quit(srvmsg) userobj, reason = p.parse_quit(srvmsg)
confmodel = uplink.ModConfig confmodel = uplink.mod_config
if userobj is None: if userobj is None:
uplink.Logs.debug(f"This UID do not exist anymore: {srvmsg}") uplink.ctx.Logs.debug(f"This UID do not exist anymore: {srvmsg}")
return None return None
ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan) ban_all_chan = uplink.ctx.Base.int_if_possible(confmodel.reputation_ban_all_chan)
jail_salon = uplink.Config.SALON_JAIL jail_salon = uplink.ctx.Config.SALON_JAIL
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
get_user_reputation = uplink.Reputation.get_reputation(userobj.uid) get_user_reputation = uplink.ctx.Reputation.get_reputation(userobj.uid)
if get_user_reputation is not None: if get_user_reputation is not None:
final_nickname = get_user_reputation.nickname final_nickname = get_user_reputation.nickname
for chan in uplink.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
if chan.name != jail_salon and ban_all_chan == 1: if chan.name != jail_salon and ban_all_chan == 1:
p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*") await p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*")
uplink.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}") uplink.ctx.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}")
uplink.Reputation.delete(userobj.uid) uplink.ctx.Reputation.delete(userobj.uid)
uplink.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB") uplink.ctx.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB")
def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): async def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
"""_summary_ """_summary_
>>> ['@s2s-md...', ':001', 'UID', 'nickname', '0', '1754675249', '...', '125-168-141-239.hostname.net', '001BAPN8M', >>> ['@s2s-md...', ':001', 'UID', 'nickname', '0', '1754675249', '...', '125-168-141-239.hostname.net', '001BAPN8M',
'0', '+iwx', '*', '32001BBE.25ACEFE7.429FE90D.IP', 'ZA2ic7w==', ':realname'] '0', '+iwx', '*', '32001BBE.25ACEFE7.429FE90D.IP', 'ZA2ic7w==', ':realname']
@@ -220,10 +221,10 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
uplink (Defender): The Defender instance uplink (Defender): The Defender instance
srvmsg (list[str]): The Server MSG srvmsg (list[str]): The Server MSG
""" """
_User = uplink.Protocol.parse_uid(srvmsg) irc = uplink.ctx.Irc
gconfig = uplink.Config _User = irc.Protocol.parse_uid(srvmsg)
irc = uplink.Irc gconfig = uplink.ctx.Config
confmodel = uplink.ModConfig confmodel = uplink.mod_config
# If Init then do nothing # If Init then do nothing
if gconfig.DEFENDER_INIT == 1: if gconfig.DEFENDER_INIT == 1:
@@ -231,7 +232,7 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
# Get User information # Get User information
if _User is None: if _User is None:
irc.Logs.warning(f'Error when parsing UID', exc_info=True) uplink.ctx.Logs.warning(f'Error when parsing UID', exc_info=True)
return return
# If user is not service or IrcOp then scan them # If user is not service or IrcOp then scan them
@@ -250,38 +251,38 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
if not match(r'^.*[S|o?].*$', _User.umodes): if not match(r'^.*[S|o?].*$', _User.umodes):
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
# currentDateTime = self.Base.get_datetime() # currentDateTime = self.Base.get_datetime()
irc.Reputation.insert( uplink.ctx.Reputation.insert(
irc.Loader.Definition.MReputation( uplink.ctx.Definition.MReputation(
**_User.to_dict(), **_User.to_dict(),
secret_code=irc.Utils.generate_random_string(8) secret_code=uplink.ctx.Utils.generate_random_string(8)
) )
) )
if irc.Reputation.is_exist(_User.uid): if uplink.ctx.Reputation.is_exist(_User.uid):
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
action_add_reputation_sanctions(uplink, _User.uid) await action_add_reputation_sanctions(uplink, _User.uid)
irc.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})') uplink.ctx.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})')
#################### ####################
# ACTION FUNCTIONS # # ACTION FUNCTIONS #
#################### ####################
# [:<sid>] UID <uid> <ts> <nick> <real-host> <displayed-host> <real-user> <ip> <signon> <modes> [<mode-parameters>]+ :<real> # [:<sid>] UID <uid> <ts> <nick> <real-host> <displayed-host> <real-user> <ip> <signon> <modes> [<mode-parameters>]+ :<real>
# [:<sid>] UID nickname hopcount timestamp username hostname uid servicestamp umodes virthost cloakedhost ip :gecos # [:<sid>] UID nickname hopcount timestamp username hostname uid servicestamp umodes virthost cloakedhost ip :gecos
def action_on_flood(uplink: 'Defender', srvmsg: list[str]): async def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
confmodel = uplink.ModConfig confmodel = uplink.mod_config
if confmodel.flood == 0: if confmodel.flood == 0:
return None return None
irc = uplink.Irc irc = uplink.ctx.Irc
gconfig = uplink.Config gconfig = uplink.ctx.Config
p = uplink.Protocol p = irc.Protocol
flood_users = uplink.Schemas.DB_FLOOD_USERS flood_users = uplink.Schemas.DB_FLOOD_USERS
user_trigger = str(srvmsg[1]).replace(':','') user_trigger = str(srvmsg[1]).replace(':','')
channel = srvmsg[3] channel = srvmsg[3]
User = irc.User.get_user(user_trigger) User = uplink.ctx.User.get_user(user_trigger)
if User is None or not irc.Channel.is_valid_channel(channel_to_check=channel): if User is None or not uplink.ctx.Channel.is_valid_channel(channel_to_check=channel):
return return
flood_time = confmodel.flood_time flood_time = confmodel.flood_time
@@ -294,7 +295,7 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
get_detected_uid = User.uid get_detected_uid = User.uid
get_detected_nickname = User.nickname get_detected_nickname = User.nickname
unixtime = irc.Utils.get_unixtime() unixtime = uplink.ctx.Utils.get_unixtime()
get_diff_secondes = 0 get_diff_secondes = 0
def get_flood_user(uid: str) -> Optional[FloodUser]: def get_flood_user(uid: str) -> Optional[FloodUser]:
@@ -315,29 +316,29 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
fu.nbr_msg = 0 fu.nbr_msg = 0
get_diff_secondes = unixtime - fu.first_msg_time get_diff_secondes = unixtime - fu.first_msg_time
elif fu.nbr_msg > flood_message: elif fu.nbr_msg > flood_message:
irc.Logs.info('system de flood detecté') uplink.ctx.Logs.info('system de flood detecté')
p.send_priv_msg( await p.send_priv_msg(
nick_from=dnickname, nick_from=dnickname,
msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)", msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)",
channel=channel channel=channel
) )
p.send2socket(f":{service_id} MODE {channel} +m") await p.send2socket(f":{service_id} MODE {channel} +m")
irc.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}') uplink.ctx.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}')
fu.nbr_msg = 0 fu.nbr_msg = 0
fu.first_msg_time = unixtime fu.first_msg_time = unixtime
irc.Base.create_timer(flood_timer, dthreads.timer_release_mode_mute, (uplink, 'mode-m', channel)) uplink.ctx.Base.create_asynctask(dthreads.coro_release_mode_mute(uplink, 'mode-m', channel))
def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ): async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
irc = uplink.Irc irc = uplink.ctx.Irc
gconfig = uplink.Config gconfig = uplink.ctx.Config
p = uplink.Protocol p = irc.Protocol
confmodel = uplink.ModConfig confmodel = uplink.mod_config
get_reputation = irc.Reputation.get_reputation(jailed_uid) get_reputation = uplink.ctx.Reputation.get_reputation(jailed_uid)
if get_reputation is None: if get_reputation is None:
irc.Logs.warning(f'UID {jailed_uid} has not been found') uplink.ctx.Logs.warning(f'UID {jailed_uid} has not been found')
return return
salon_logs = gconfig.SERVICE_CHANLOG salon_logs = gconfig.SERVICE_CHANLOG
@@ -357,33 +358,33 @@ def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
if not get_reputation.isWebirc: if not get_reputation.isWebirc:
# Si le user ne vient pas de webIrc # Si le user ne vient pas de webIrc
p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail) await p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail)
p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME, await p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME,
msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}", msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}",
channel=salon_logs channel=salon_logs
) )
p.send_notice( await p.send_notice(
nick_from=gconfig.SERVICE_NICKNAME, nick_from=gconfig.SERVICE_NICKNAME,
nick_to=jailed_nickname, nick_to=jailed_nickname,
msg=f"[{color_red} {jailed_nickname} {color_black}] : Merci de tapez la commande suivante {color_bold}{service_prefix}code {code}{color_bold}" msg=f"[{color_red} {jailed_nickname} {color_black}] : Merci de tapez la commande suivante {color_bold}{service_prefix}code {code}{color_bold}"
) )
if reputation_ban_all_chan == 1: if reputation_ban_all_chan == 1:
for chan in irc.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
if chan.name != salon_jail: if chan.name != salon_jail:
p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*") await p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*")
p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}") await p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}")
irc.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})") uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})")
else: else:
irc.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)") uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)")
irc.Reputation.delete(jailed_uid) uplink.ctx.Reputation.delete(jailed_uid)
def action_apply_reputation_santions(uplink: 'Defender') -> None: async def action_apply_reputation_santions(uplink: 'Defender') -> None:
irc = uplink.Irc irc = uplink.ctx.Irc
gconfig = uplink.Config gconfig = uplink.ctx.Config
p = uplink.Protocol p = irc.Protocol
confmodel = uplink.ModConfig confmodel = uplink.mod_config
reputation_flag = confmodel.reputation reputation_flag = confmodel.reputation
reputation_timer = confmodel.reputation_timer reputation_timer = confmodel.reputation_timer
@@ -396,36 +397,36 @@ def action_apply_reputation_santions(uplink: 'Defender') -> None:
salon_jail = gconfig.SALON_JAIL salon_jail = gconfig.SALON_JAIL
uid_to_clean = [] uid_to_clean = []
if reputation_flag == 0 or reputation_timer == 0 or not irc.Reputation.UID_REPUTATION_DB: if reputation_flag == 0 or reputation_timer == 0 or not uplink.ctx.Reputation.UID_REPUTATION_DB:
return None return None
for user in irc.Reputation.UID_REPUTATION_DB: for user in uplink.ctx.Reputation.UID_REPUTATION_DB:
if not user.isWebirc: # Si il ne vient pas de WebIRC if not user.isWebirc: # Si il ne vient pas de WebIRC
if irc.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil): if uplink.ctx.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil):
p.send_priv_msg( await p.send_priv_msg(
nick_from=service_id, nick_from=service_id,
msg=f"[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité", msg=f"[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité",
channel=dchanlog channel=dchanlog
) )
p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code") await p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code")
p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0") await p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0")
irc.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity") uplink.ctx.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity")
uid_to_clean.append(user.uid) uid_to_clean.append(user.uid)
for uid in uid_to_clean: for uid in uid_to_clean:
# Suppression des éléments dans {UID_DB} et {REPUTATION_DB} # Suppression des éléments dans {UID_DB} et {REPUTATION_DB}
for chan in irc.Channel.UID_CHANNEL_DB: for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
if chan.name != salon_jail and ban_all_chan == 1: if chan.name != salon_jail and ban_all_chan == 1:
get_user_reputation = irc.Reputation.get_reputation(uid) get_user_reputation = uplink.ctx.Reputation.get_reputation(uid)
p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*") await p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*")
# Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}. # Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}.
irc.Channel.delete_user_from_all_channel(uid) uplink.ctx.Channel.delete_user_from_all_channel(uid)
irc.Reputation.delete(uid) uplink.ctx.Reputation.delete(uid)
irc.User.delete(uid) uplink.ctx.User.delete(uid)
def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: async def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
"""Analyse l'ip avec cloudfilt """Analyse l'ip avec cloudfilt
Cette methode devra etre lancer toujours via un thread ou un timer. Cette methode devra etre lancer toujours via un thread ou un timer.
Args: Args:
@@ -440,19 +441,19 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -
username = user_model.username username = user_model.username
hostname = user_model.hostname hostname = user_model.hostname
nickname = user_model.nickname nickname = user_model.nickname
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
if remote_ip in uplink.Config.WHITELISTED_IP: if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
return None return None
if uplink.ModConfig.cloudfilt_scan == 0: if uplink.mod_config.cloudfilt_scan == 0:
return None return None
if uplink.cloudfilt_key == '': if uplink.cloudfilt_key == '':
return None return None
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
service_chanlog = uplink.Config.SERVICE_CHANLOG service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
color_red = uplink.Config.COLORS.red color_red = uplink.ctx.Config.COLORS.red
nogc = uplink.Config.COLORS.nogc nogc = uplink.ctx.Config.COLORS.nogc
url = "https://developers18334.cloudfilt.com/" url = "https://developers18334.cloudfilt.com/"
@@ -466,7 +467,7 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -
decoded_response: dict = loads(response.text) decoded_response: dict = loads(response.text)
status_code = response.status_code status_code = response.status_code
if status_code != 200: if status_code != 200:
uplink.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}') uplink.ctx.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
return return
result = { result = {
@@ -479,22 +480,22 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -
# pseudo!ident@host # pseudo!ident@host
fullname = f'{nickname}!{username}@{hostname}' fullname = f'{nickname}!{username}@{hostname}'
p.send_priv_msg( await p.send_priv_msg(
nick_from=service_id, nick_from=service_id,
msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}", msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}",
channel=service_chanlog) channel=service_chanlog)
uplink.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}") uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}")
if result['listed']: if result['listed']:
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt") await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
uplink.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}") uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}")
response.close() response.close()
return result return result
def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: async def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
"""Analyse l'ip avec Freeipapi """Analyse l'ip avec Freeipapi
Cette methode devra etre lancer toujours via un thread ou un timer. Cette methode devra etre lancer toujours via un thread ou un timer.
Args: Args:
@@ -504,21 +505,21 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -
dict[str, any] | None: les informations du provider dict[str, any] | None: les informations du provider
keys : 'countryCode', 'isProxy' keys : 'countryCode', 'isProxy'
""" """
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
remote_ip = user_model.remote_ip remote_ip = user_model.remote_ip
username = user_model.username username = user_model.username
hostname = user_model.hostname hostname = user_model.hostname
nickname = user_model.nickname nickname = user_model.nickname
if remote_ip in uplink.Config.WHITELISTED_IP: if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
return None return None
if uplink.ModConfig.freeipapi_scan == 0: if uplink.mod_config.freeipapi_scan == 0:
return None return None
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
service_chanlog = uplink.Config.SERVICE_CHANLOG service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
color_red = uplink.Config.COLORS.red color_red = uplink.ctx.Config.COLORS.red
nogc = uplink.Config.COLORS.nogc nogc = uplink.ctx.Config.COLORS.nogc
url = f'https://freeipapi.com/api/json/{remote_ip}' url = f'https://freeipapi.com/api/json/{remote_ip}'
@@ -533,10 +534,10 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -
status_code = response.status_code status_code = response.status_code
if status_code == 429: if status_code == 429:
uplink.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.') uplink.ctx.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.')
return None return None
elif status_code != 200: elif status_code != 200:
uplink.Logs.warning(f'status code = {str(status_code)}') uplink.ctx.Logs.warning(f'status code = {str(status_code)}')
return None return None
result = { result = {
@@ -547,21 +548,21 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -
# pseudo!ident@host # pseudo!ident@host
fullname = f'{nickname}!{username}@{hostname}' fullname = f'{nickname}!{username}@{hostname}'
p.send_priv_msg( await p.send_priv_msg(
nick_from=service_id, nick_from=service_id,
msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}", msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}",
channel=service_chanlog) channel=service_chanlog)
uplink.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}") uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}")
if result['isProxy']: if result['isProxy']:
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi") await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
uplink.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}") uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}")
response.close() response.close()
return result return result
def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: async def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
"""Analyse l'ip avec AbuseIpDB """Analyse l'ip avec AbuseIpDB
Cette methode devra etre lancer toujours via un thread ou un timer. Cette methode devra etre lancer toujours via un thread ou un timer.
Args: Args:
@@ -571,15 +572,15 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -
Returns: Returns:
dict[str, str] | None: les informations du provider dict[str, str] | None: les informations du provider
""" """
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
remote_ip = user_model.remote_ip remote_ip = user_model.remote_ip
username = user_model.username username = user_model.username
hostname = user_model.hostname hostname = user_model.hostname
nickname = user_model.nickname nickname = user_model.nickname
if remote_ip in uplink.Config.WHITELISTED_IP: if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
return None return None
if uplink.ModConfig.abuseipdb_scan == 0: if uplink.mod_config.abuseipdb_scan == 0:
return None return None
if uplink.abuseipdb_key == '': if uplink.abuseipdb_key == '':
@@ -611,81 +612,81 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -
'totalReports': decoded_response.get('data', {}).get('totalReports', 0) 'totalReports': decoded_response.get('data', {}).get('totalReports', 0)
} }
service_id = uplink.Config.SERVICE_ID service_id = uplink.ctx.Config.SERVICE_ID
service_chanlog = uplink.Config.SERVICE_CHANLOG service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
color_red = uplink.Config.COLORS.red color_red = uplink.ctx.Config.COLORS.red
nogc = uplink.Config.COLORS.nogc nogc = uplink.ctx.Config.COLORS.nogc
# pseudo!ident@host # pseudo!ident@host
fullname = f'{nickname}!{username}@{hostname}' fullname = f'{nickname}!{username}@{hostname}'
p.send_priv_msg( await p.send_priv_msg(
nick_from=service_id, nick_from=service_id,
msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}", msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}",
channel=service_chanlog channel=service_chanlog
) )
uplink.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}") uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}")
if result['isTor']: if result['isTor']:
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb") await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}") uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}")
elif result['score'] >= 95: elif result['score'] >= 95:
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb") await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}") uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}")
response.close() response.close()
return result return result
def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'): async def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'):
"""local_scan """local_scan
Args: Args:
uplink (Defender): Defender instance object uplink (Defender): Defender instance object
user_model (MUser): l'objet User qui contient l'ip user_model (MUser): l'objet User qui contient l'ip
""" """
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
remote_ip = user_model.remote_ip remote_ip = user_model.remote_ip
username = user_model.username username = user_model.username
hostname = user_model.hostname hostname = user_model.hostname
nickname = user_model.nickname nickname = user_model.nickname
fullname = f'{nickname}!{username}@{hostname}' fullname = f'{nickname}!{username}@{hostname}'
if remote_ip in uplink.Config.WHITELISTED_IP: if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
return None return None
for port in uplink.Config.PORTS_TO_SCAN: for port in uplink.ctx.Config.PORTS_TO_SCAN:
try: try:
newSocket = '' newSocket = ''
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK) newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
newSocket.settimeout(0.5) newSocket.settimeout(0.5)
connection = (remote_ip, uplink.Base.int_if_possible(port)) connection = (remote_ip, uplink.ctx.Base.int_if_possible(port))
newSocket.connect(connection) newSocket.connect(connection)
p.send_priv_msg( await p.send_priv_msg(
nick_from=uplink.Config.SERVICE_NICKNAME, nick_from=uplink.ctx.Config.SERVICE_NICKNAME,
msg=f"[ {uplink.Config.COLORS.red}PROXY_SCAN{uplink.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]", msg=f"[ {uplink.ctx.Config.COLORS.red}PROXY_SCAN{uplink.ctx.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]",
channel=uplink.Config.SERVICE_CHANLOG channel=uplink.ctx.Config.SERVICE_CHANLOG
) )
# print(f"=======> Le port {str(port)} est ouvert !!") # print(f"=======> Le port {str(port)} est ouvert !!")
uplink.Base.running_sockets.append(newSocket) uplink.ctx.Base.running_sockets.append(newSocket)
# print(newSocket) # print(newSocket)
newSocket.shutdown(socket.SHUT_RDWR) newSocket.shutdown(socket.SHUT_RDWR)
newSocket.close() newSocket.close()
except (socket.timeout, ConnectionRefusedError): except (socket.timeout, ConnectionRefusedError):
uplink.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé") uplink.ctx.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé")
except AttributeError as ae: except AttributeError as ae:
uplink.Logs.warning(f"AttributeError ({remote_ip}): {ae}") uplink.ctx.Logs.warning(f"AttributeError ({remote_ip}): {ae}")
except socket.gaierror as err: except socket.gaierror as err:
uplink.Logs.warning(f"Address Info Error ({remote_ip}): {err}") uplink.ctx.Logs.warning(f"Address Info Error ({remote_ip}): {err}")
finally: finally:
# newSocket.shutdown(socket.SHUT_RDWR) # newSocket.shutdown(socket.SHUT_RDWR)
newSocket.close() newSocket.close()
uplink.Logs.info('=======> Fermeture de la socket') uplink.ctx.Logs.info('=======> Fermeture de la socket')
def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]: async def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]:
"""psutil_scan for Linux (should be run on the same location as the unrealircd server) """psutil_scan for Linux (should be run on the same location as the unrealircd server)
Args: Args:
@@ -694,13 +695,13 @@ def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> l
Returns: Returns:
list[int]: list of ports list[int]: list of ports
""" """
p = uplink.Protocol p = uplink.ctx.Irc.Protocol
remote_ip = user_model.remote_ip remote_ip = user_model.remote_ip
username = user_model.username username = user_model.username
hostname = user_model.hostname hostname = user_model.hostname
nickname = user_model.nickname nickname = user_model.nickname
if remote_ip in uplink.Config.WHITELISTED_IP: if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
return None return None
try: try:
@@ -708,16 +709,16 @@ def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> l
fullname = f'{nickname}!{username}@{hostname}' fullname = f'{nickname}!{username}@{hostname}'
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip] matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
uplink.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}") uplink.ctx.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}")
if matching_ports: if matching_ports:
p.send_priv_msg( await p.send_priv_msg(
nick_from=uplink.Config.SERVICE_NICKNAME, nick_from=uplink.ctx.Config.SERVICE_NICKNAME,
msg=f"[ {uplink.Config.COLORS.red}PSUTIL_SCAN{uplink.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}", msg=f"[ {uplink.ctx.Config.COLORS.red}PSUTIL_SCAN{uplink.ctx.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}",
channel=uplink.Config.SERVICE_CHANLOG channel=uplink.ctx.Config.SERVICE_CHANLOG
) )
return matching_ports return matching_ports
except psutil.AccessDenied as ad: except psutil.AccessDenied as ad:
uplink.Logs.critical(f'psutil_scan: Permission error: {ad}') uplink.ctx.Logs.critical(f'psutil_scan: Permission error: {ad}')

View File

@@ -48,7 +48,7 @@ class Test(IModule):
# self.ctx.Base.db_execute_query(table_logs) # self.ctx.Base.db_execute_query(table_logs)
return None return None
def load(self) -> None: async def load(self) -> None:
"""### Load Module Configuration (Mandatory) """### Load Module Configuration (Mandatory)
""" """
@@ -62,8 +62,11 @@ class Test(IModule):
# Build the default configuration model (Mandatory) # Build the default configuration model (Mandatory)
self._mod_config = self.ModConfModel(param_exemple1='str', param_exemple2=1) self._mod_config = self.ModConfModel(param_exemple1='str', param_exemple2=1)
# Init the module (Mandatory) # sync the database with local variable (Mandatory)
self.init() await self.sync_db()
if self.mod_config.param_exemple2 == 1:
await self.ctx.Irc.Protocol.send_priv_msg(self.ctx.Config.SERVICE_NICKNAME, "Param activated", self.ctx.Config.SERVICE_CHANLOG)
@property @property
def mod_config(self) -> ModConfModel: def mod_config(self) -> ModConfModel:
@@ -71,7 +74,7 @@ class Test(IModule):
def unload(self) -> None: def unload(self) -> None:
"""### This method is called when you unload, or you reload the module (Mandatory)""" """### This method is called when you unload, or you reload the module (Mandatory)"""
self.ctx.Irc.Commands.drop_command_by_module(self.module_name) self.ctx.Commands.drop_command_by_module(self.module_name)
return None return None
def cmd(self, data: list[str]) -> None: def cmd(self, data: list[str]) -> None:

View File

@@ -4,3 +4,5 @@ PyYAML==6.0.3
requests==2.32.5 requests==2.32.5
SQLAlchemy==2.0.44 SQLAlchemy==2.0.44
unrealircd_rpc_py==3.0.2 unrealircd_rpc_py==3.0.2
starlette==0.50.0
uvicorn==0.38.0

View File

@@ -1,10 +1,12 @@
{ {
"version": "6.3.3", "version": "6.4.0",
"requests": "2.32.5", "requests": "2.32.5",
"psutil": "7.1.2", "psutil": "7.1.2",
"unrealircd_rpc_py": "3.0.1", "unrealircd_rpc_py": "3.0.1",
"sqlalchemy": "2.0.44", "sqlalchemy": "2.0.44",
"faker": "37.12.0", "faker": "37.12.0",
"pyyaml": "6.0.3" "pyyaml": "6.0.3",
"starlette":"0.50.0",
"uvicorn":"0.38.0"
} }