From 9d9ede0e80f8615070ac2e661533e211823e99b1 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Fri, 1 Nov 2024 23:52:22 +0100 Subject: [PATCH] First Version 6 --- {core => config}/exemple_configuration.json | 0 core/Model.py | 506 ------------- core/base.py | 252 ++++--- core/classes/admin.py | 127 ++++ core/classes/channel.py | 225 ++++++ core/classes/clone.py | 162 ++++ core/classes/config.py | 57 ++ core/classes/protocol.py | 15 + core/classes/protocols/unreal6.py | 336 +++++++++ core/classes/reputation.py | 175 +++++ core/classes/settings.py | 10 + core/classes/user.py | 180 +++++ core/connection.py | 274 ------- core/dataClass.py | 274 ------- core/definition.py | 291 ++++++++ core/installation.py | 3 +- core/irc.py | 774 +++++++++++++------- core/loadConf.py | 260 ------- core/loader.py | 32 + main.py => defender.py | 9 +- mods/mod_clone.py | 468 +++++++----- mods/mod_command.py | 428 ++++++----- mods/mod_defender.py | 763 +++++++++++-------- mods/mod_jsonrpc.py | 107 ++- mods/mod_test.py | 16 +- mods/mod_votekick.py | 17 +- version.json | 2 +- 27 files changed, 3331 insertions(+), 2432 deletions(-) rename {core => config}/exemple_configuration.json (100%) delete mode 100644 core/Model.py create mode 100644 core/classes/admin.py create mode 100644 core/classes/channel.py create mode 100644 core/classes/clone.py create mode 100644 core/classes/config.py create mode 100644 core/classes/protocol.py create mode 100644 core/classes/protocols/unreal6.py create mode 100644 core/classes/reputation.py create mode 100644 core/classes/settings.py create mode 100644 core/classes/user.py delete mode 100644 core/connection.py delete mode 100644 core/dataClass.py create mode 100644 core/definition.py delete mode 100644 core/loadConf.py create mode 100644 core/loader.py rename main.py => defender.py (79%) diff --git a/core/exemple_configuration.json b/config/exemple_configuration.json similarity index 100% rename from core/exemple_configuration.json rename to config/exemple_configuration.json diff --git a/core/Model.py b/core/Model.py deleted file mode 100644 index 8576f49..0000000 --- a/core/Model.py +++ /dev/null @@ -1,506 +0,0 @@ -from dataclasses import dataclass, field -from datetime import datetime -from typing import Union -from core.base import Base - -class User: - - @dataclass - class UserModel: - uid: str - nickname: str - username: str - realname: str - hostname: str - umodes: str - vhost: str - isWebirc: bool - isWebsocket: bool - remote_ip: str - score_connexion: int - geoip: str = None - connexion_datetime: datetime = field(default=datetime.now()) - - UID_DB: list[UserModel] = [] - - def __init__(self, Base: Base) -> None: - self.log = Base.logs - pass - - def insert(self, newUser: UserModel) -> bool: - """Insert a new User object - - Args: - newUser (UserModel): New userModel object - - Returns: - bool: True if inserted - """ - result = False - exist = False - - for record in self.UID_DB: - if record.uid == newUser.uid: - # If the user exist then return False and do not go further - exist = True - self.log.debug(f'{record.uid} already exist') - return result - - if not exist: - self.UID_DB.append(newUser) - result = True - self.log.debug(f'New User Created: ({newUser})') - - if not result: - self.log.critical(f'The User Object was not inserted {newUser}') - - return result - - def update(self, uid: str, newNickname: str) -> bool: - """Update the nickname starting from the UID - - Args: - uid (str): UID of the user - newNickname (str): New nickname - - Returns: - bool: True if updated - """ - result = False - - for record in self.UID_DB: - if record.uid == uid: - # If the user exist then update and return True and do not go further - record.nickname = newNickname - result = True - self.log.debug(f'UID ({record.uid}) has been updated with new nickname {newNickname}') - return result - - if not result: - self.log.critical(f'The new nickname {newNickname} was not updated, uid = {uid}') - - return result - - def delete(self, uid: str) -> bool: - """Delete the User starting from the UID - - Args: - uid (str): UID of the user - - Returns: - bool: True if deleted - """ - result = False - - for record in self.UID_DB: - if record.uid == uid: - # If the user exist then remove and return True and do not go further - self.UID_DB.remove(record) - result = True - self.log.debug(f'UID ({record.uid}) has been deleted') - return result - - if not result: - self.log.critical(f'The UID {uid} was not deleted') - - return result - - def get_User(self, uidornickname: str) -> Union[UserModel, None]: - """Get The User Object model - - Args: - uidornickname (str): UID or Nickname - - Returns: - UserModel|None: The UserModel Object | None - """ - User = None - for record in self.UID_DB: - if record.uid == uidornickname: - User = record - elif record.nickname == uidornickname: - User = record - - self.log.debug(f'Search {uidornickname} -- result = {User}') - - return User - - def get_uid(self, uidornickname:str) -> Union[str, None]: - """Get the UID of the user starting from the UID or the Nickname - - Args: - uidornickname (str): UID or Nickname - - Returns: - str|None: Return the UID - """ - uid = None - for record in self.UID_DB: - if record.uid == uidornickname: - uid = record.uid - if record.nickname == uidornickname: - uid = record.uid - - self.log.debug(f'The UID that you are looking for {uidornickname} has been found {uid}') - return uid - - def get_nickname(self, uidornickname:str) -> Union[str, None]: - """Get the Nickname starting from UID or the nickname - - Args: - uidornickname (str): UID or Nickname of the user - - Returns: - str|None: the nickname - """ - nickname = None - for record in self.UID_DB: - if record.nickname == uidornickname: - nickname = record.nickname - if record.uid == uidornickname: - nickname = record.nickname - self.log.debug(f'The value to check {uidornickname} -> {nickname}') - return nickname - -class Admin: - - @dataclass - class AdminModel: - uid: str - nickname: str - username: str - hostname: str - umodes: str - vhost: str - level: int - connexion_datetime: datetime = field(default=datetime.now()) - - UID_ADMIN_DB: list[AdminModel] = [] - - def __init__(self, Base: Base) -> None: - self.log = Base.logs - pass - - def insert(self, newAdmin: AdminModel) -> bool: - - result = False - exist = False - - for record in self.UID_ADMIN_DB: - if record.uid == newAdmin.uid: - # If the admin exist then return False and do not go further - exist = True - self.log.debug(f'{record.uid} already exist') - return result - - if not exist: - self.UID_ADMIN_DB.append(newAdmin) - result = True - self.log.debug(f'UID ({newAdmin.uid}) has been created') - - if not result: - self.log.critical(f'The User Object was not inserted {newAdmin}') - - return result - - def update(self, uid: str, newNickname: str) -> bool: - - result = False - - for record in self.UID_ADMIN_DB: - if record.uid == uid: - # If the admin exist, update and do not go further - record.nickname = newNickname - result = True - self.log.debug(f'UID ({record.uid}) has been updated with new nickname {newNickname}') - return result - - if not result: - self.log.critical(f'The new nickname {newNickname} was not updated, uid = {uid}') - - return result - - def delete(self, uid: str) -> bool: - - result = False - - for record in self.UID_ADMIN_DB: - if record.uid == uid: - # If the admin exist, delete and do not go further - self.UID_ADMIN_DB.remove(record) - result = True - self.log.debug(f'UID ({record.uid}) has been created') - return result - - if not result: - self.log.critical(f'The UID {uid} was not deleted') - - return result - - def get_Admin(self, uidornickname: str) -> Union[AdminModel, None]: - - Admin = None - for record in self.UID_ADMIN_DB: - if record.uid == uidornickname: - Admin = record - elif record.nickname == uidornickname: - Admin = record - - self.log.debug(f'Search {uidornickname} -- result = {Admin}') - - return Admin - - def get_uid(self, uidornickname:str) -> Union[str, None]: - - uid = None - for record in self.UID_ADMIN_DB: - if record.uid == uidornickname: - uid = record.uid - if record.nickname == uidornickname: - uid = record.uid - - self.log.debug(f'The UID that you are looking for {uidornickname} has been found {uid}') - return uid - - def get_nickname(self, uidornickname:str) -> Union[str, None]: - - nickname = None - for record in self.UID_ADMIN_DB: - if record.nickname == uidornickname: - nickname = record.nickname - if record.uid == uidornickname: - nickname = record.nickname - self.log.debug(f'The value {uidornickname} -- {nickname}') - return nickname - -class Channel: - - @dataclass - class ChannelModel: - name: str - """### Channel name - It include the #""" - uids: list - """### List of UID available in the channel - including their modes ~ @ % + * - - Returns: - list: The list of UID's including theirs modes - """ - - UID_CHANNEL_DB: list[ChannelModel] = [] - """List that contains all the Channels objects (ChannelModel) - """ - - def __init__(self, Base: Base) -> None: - self.log = Base.logs - self.Base = Base - pass - - def insert(self, newChan: ChannelModel) -> bool: - """This method will insert a new channel and if the channel exist it will update the user list (uids) - - Args: - newChan (ChannelModel): The channel model object - - Returns: - bool: True if new channel, False if channel exist (However UID could be updated) - """ - result = False - exist = False - - for record in self.UID_CHANNEL_DB: - if record.name == newChan.name: - # If the channel exist, update the user list and do not go further - exist = True - self.log.debug(f'{record.name} already exist') - - for user in newChan.uids: - record.uids.append(user) - - # Supprimer les doublons - del_duplicates = list(set(record.uids)) - record.uids = del_duplicates - self.log.debug(f'Updating a new UID to the channel {record}') - return result - - - if not exist: - # If the channel don't exist, then create it - self.UID_CHANNEL_DB.append(newChan) - result = True - self.log.debug(f'New Channel Created: ({newChan})') - - if not result: - self.log.critical(f'The Channel Object was not inserted {newChan}') - - return result - - def delete(self, name: str) -> bool: - - result = False - - for record in self.UID_CHANNEL_DB: - if record.name == name: - # If the channel exist, then remove it and return True. - # As soon as the channel found, return True and stop the loop - self.UID_CHANNEL_DB.remove(record) - result = True - self.log.debug(f'Channel ({record.name}) has been created') - return result - - if not result: - self.log.critical(f'The Channel {name} was not deleted') - - return result - - def delete_user_from_channel(self, chan_name: str, uid:str) -> bool: - try: - result = False - - for record in self.UID_CHANNEL_DB: - if record.name == chan_name: - for user_id in record.uids: - if self.Base.clean_uid(user_id) == uid: - record.uids.remove(user_id) - self.log.debug(f'The UID {uid} has been removed, here is the new object: {record}') - result = True - - for record in self.UID_CHANNEL_DB: - if not record.uids: - self.UID_CHANNEL_DB.remove(record) - self.log.debug(f'The Channel {record.name} has been removed, here is the new object: {record}') - - return result - except ValueError as ve: - self.log.error(f'{ve}') - - def delete_user_from_all_channel(self, uid:str) -> bool: - try: - result = False - - for record in self.UID_CHANNEL_DB: - for user_id in record.uids: - if self.Base.clean_uid(user_id) == self.Base.clean_uid(uid): - record.uids.remove(user_id) - self.log.debug(f'The UID {uid} has been removed, here is the new object: {record}') - result = True - - for record in self.UID_CHANNEL_DB: - if not record.uids: - self.UID_CHANNEL_DB.remove(record) - self.log.debug(f'The Channel {record.name} has been removed, here is the new object: {record}') - - return result - except ValueError as ve: - self.log.error(f'{ve}') - - def get_Channel(self, name: str) -> Union[ChannelModel, None]: - - Channel = None - for record in self.UID_CHANNEL_DB: - if record.name == name: - Channel = record - - self.log.debug(f'Search {name} -- result = {Channel}') - - return Channel - -class Clones: - - @dataclass - class CloneModel: - alive: bool - nickname: str - username: str - realname: str - channels: list - vhost: str = None - init: bool = True - connected: bool = False - - UID_CLONE_DB: list[CloneModel] = [] - - def __init__(self, Base: Base) -> None: - self.log = Base.logs - - def insert(self, newCloneObject: CloneModel) -> bool: - """Create new Clone object - - Args: - newCloneObject (CloneModel): New CloneModel object - - Returns: - bool: True if inserted - """ - result = False - exist = False - - for record in self.UID_CLONE_DB: - if record.nickname == newCloneObject.nickname: - # If the user exist then return False and do not go further - exist = True - self.log.debug(f'{record.nickname} already exist') - return result - - if not exist: - self.UID_CLONE_DB.append(newCloneObject) - result = True - self.log.debug(f'New Clone Object Created: ({newCloneObject})') - - if not result: - self.log.critical(f'The Clone Object was not inserted {newCloneObject}') - - return result - - def delete(self, nickname: str) -> bool: - """Delete the Clone Object starting from the nickname - - Args: - nickname (str): nickname of the clone - - Returns: - bool: True if deleted - """ - result = False - - for record in self.UID_CLONE_DB: - if record.nickname == nickname: - # If the user exist then remove and return True and do not go further - self.UID_CLONE_DB.remove(record) - result = True - self.log.debug(f'The clone ({record.nickname}) has been deleted') - return result - - if not result: - self.log.critical(f'The UID {nickname} was not deleted') - - return result - - def exists(self, nickname: str) -> bool: - """Check if the nickname exist - - Args: - nickname (str): Nickname of the clone - - Returns: - bool: True if the nickname exist - """ - response = False - - for cloneObject in self.UID_CLONE_DB: - if cloneObject.nickname == nickname: - response = True - - return response - - def kill(self, nickname:str) -> bool: - - response = False - - for cloneObject in self.UID_CLONE_DB: - if cloneObject.nickname == nickname: - cloneObject.alive = False # Kill the clone - response = True - - return response diff --git a/core/base.py b/core/base.py index 75d0973..3a330b7 100644 --- a/core/base.py +++ b/core/base.py @@ -13,27 +13,39 @@ import ast import requests from dataclasses import fields -from typing import Union, Literal +from typing import Union, Literal, TYPE_CHECKING from base64 import b64decode, b64encode from datetime import datetime, timedelta, timezone from sqlalchemy import create_engine, Engine, Connection, CursorResult from sqlalchemy.sql import text -from core.loadConf import ConfigDataModel +from core.definition import MConfig + +if TYPE_CHECKING: + from core.classes.settings import Settings class Base: - def __init__(self, Config: ConfigDataModel) -> None: + def __init__(self, Config: MConfig, settings: 'Settings') -> None: self.Config = Config # Assigner l'objet de configuration + self.Settings: Settings = settings self.init_log_system() # Demarrer le systeme de log self.check_for_new_version(True) # Verifier si une nouvelle version est disponible - self.running_timers:list[threading.Timer] = [] # Liste des timers en cours - self.running_threads:list[threading.Thread] = [] # Liste des threads en cours - self.running_sockets: list[socket.socket] = [] # Les sockets ouvert - self.periodic_func:dict[object] = {} # Liste des fonctions en attentes + # Liste des timers en cours + self.running_timers:list[threading.Timer] = self.Settings.RUNNING_TIMERS - self.lock = threading.RLock() # Création du lock + # Liste des threads en cours + self.running_threads:list[threading.Thread] = self.Settings.RUNNING_THREADS + + # Les sockets ouvert + self.running_sockets: list[socket.socket] = self.Settings.RUNNING_SOCKETS + + # Liste des fonctions en attentes + self.periodic_func:dict[object] = self.Settings.PERIODIC_FUNC + + # Création du lock + self.lock = self.Settings.LOCK self.install: bool = False # Initialisation de la variable d'installation self.engine, self.cursor = self.db_init() # Initialisation de la connexion a la base de données @@ -48,16 +60,15 @@ class Base: with open(version_filename, 'r') as version_data: current_version:dict[str, str] = json.load(version_data) - self.Config.current_version = current_version['version'] + self.Config.CURRENT_VERSION = current_version['version'] return None def __get_latest_defender_version(self) -> None: try: self.logs.debug(f'Looking for a new version available on Github') - # print(f'===> Looking for a new version available on Github') token = '' - json_url = f'https://raw.githubusercontent.com/adator85/IRC_DEFENDER_MODULES/main/version.json' + json_url = f'https://raw.githubusercontent.com/adator85/DEFENDER/main/version.json' headers = { 'Authorization': f'token {token}', 'Accept': 'application/vnd.github.v3.raw' # Indique à GitHub que nous voulons le contenu brut du fichier @@ -71,7 +82,7 @@ class Base: response.raise_for_status() # Vérifie si la requête a réussi json_response:dict = response.json() # self.LATEST_DEFENDER_VERSION = json_response["version"] - self.Config.latest_version = json_response['version'] + self.Config.LATEST_VERSION = json_response['version'] return None except requests.HTTPError as err: @@ -99,8 +110,8 @@ class Base: self.__get_latest_defender_version() isNewVersion = False - latest_version = self.Config.latest_version - current_version = self.Config.current_version + latest_version = self.Config.LATEST_VERSION + current_version = self.Config.CURRENT_VERSION curr_major , curr_minor, curr_patch = current_version.split('.') last_major, last_minor, last_patch = latest_version.split('.') @@ -120,6 +131,10 @@ class Base: return isNewVersion except ValueError as ve: self.logs.error(f'Impossible to convert in version number : {ve}') + except AttributeError as atterr: + self.logs.error(f'Attribute Error: {atterr}') + except Exception as err: + self.logs.error(f'General Error: {err}') def get_unixtime(self) -> int: """ @@ -159,7 +174,7 @@ class Base: Returns: None: Aucun retour """ - 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.get_datetime()),'server_msg': f'{log_message}'} self.db_execute_query(sql_insert, mes_donnees) @@ -167,21 +182,34 @@ class Base: def init_log_system(self) -> None: # Create folder if not available - logs_directory = f'logs{os.sep}' + logs_directory = f'logs{self.Config.OS_SEP}' if not os.path.exists(f'{logs_directory}'): os.makedirs(logs_directory) # Init logs object self.logs = logging self.logs.basicConfig(level=self.Config.DEBUG_LEVEL, - filename='logs/defender.log', + filename=f'logs{self.Config.OS_SEP}defender.log', encoding='UTF-8', format='%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(funcName)s - %(message)s') + logger = logging.getLogger() + logger.addFilter(self.replace_filter) self.logs.info('#################### STARTING DEFENDER ####################') return None + def replace_filter(self, record: logging.LogRecord) -> bool: + + response = True + + # record.msg = record.getMessage().replace("PING", "[REDACTED]") + + response = False if "PING" in record.getMessage() else True + response = False if f":{self.Config.SERVICE_PREFIX}auth" in record.getMessage() else True + + return response # Retourne True pour permettre l'affichage du message + def log_cmd(self, user_cmd:str, cmd:str) -> None: """Enregistre les commandes envoyées par les utilisateurs @@ -195,7 +223,7 @@ class Base: cmd_list[2] = '*******' cmd = ' '.join(cmd_list) - insert_cmd_query = f"INSERT INTO {self.Config.table_commande} (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.get_datetime(), 'user': user_cmd, 'commande': cmd} self.db_execute_query(insert_cmd_query, mes_donnees) @@ -210,7 +238,7 @@ class Base: Returns: bool: True si le module existe déja dans la base de données sinon False """ - query = f"SELECT id FROM {self.Config.table_module} WHERE module_name = :module_name" + query = f"SELECT id FROM {self.Config.TABLE_MODULE} WHERE module_name = :module_name" mes_donnes = {'module_name': module_name} results = self.db_execute_query(query, mes_donnes) @@ -228,7 +256,7 @@ class Base: if not self.db_isModuleExist(module_name): self.logs.debug(f"Le module {module_name} n'existe pas alors ont le créer") - 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.Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)" mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'module_name': module_name, 'isdefault': isdefault} self.db_execute_query(insert_cmd_query, mes_donnees) else: @@ -243,7 +271,7 @@ class Base: user_cmd (str): le user qui a rechargé le module module_name (str): le module a rechargé """ - update_cmd_query = f"UPDATE {self.Config.table_module} SET datetime = :datetime, user = :user WHERE module_name = :module_name" + update_cmd_query = f"UPDATE {self.Config.TABLE_MODULE} SET datetime = :datetime, user = :user WHERE module_name = :module_name" mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'module_name': module_name} self.db_execute_query(update_cmd_query, mes_donnees) @@ -255,7 +283,7 @@ class Base: Args: cmd (str): le module a supprimer """ - insert_cmd_query = f"DELETE FROM {self.Config.table_module} WHERE module_name = :module_name" + insert_cmd_query = f"DELETE FROM {self.Config.TABLE_MODULE} WHERE module_name = :module_name" mes_donnees = {'module_name': module_name} self.db_execute_query(insert_cmd_query, mes_donnees) @@ -278,7 +306,7 @@ class Base: try: response = True current_date = self.get_datetime() - core_table = self.Config.table_config + core_table = self.Config.TABLE_CONFIG # Add local parameters to DB for field in fields(dataclassObj): @@ -342,7 +370,7 @@ class Base: def db_update_core_config(self, module_name:str, dataclassObj: 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 if not hasattr(dataclassObj, param_key): self.logs.error(f"Le parametre {param_key} n'existe pas dans la variable global") @@ -374,62 +402,62 @@ class Base: return True - 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. + # 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. - Args: - action (Literal['add','del']): Action on the database - module_name (str): The module name (mod_test) - channel_name (str): The channel name (With #) + # Args: + # action (Literal['add','del']): Action on the database + # module_name (str): The module name (mod_test) + # channel_name (str): The channel name (With #) - Returns: - bool: True if action done - """ - try: - channel_name = channel_name.lower() if self.Is_Channel(channel_name) else None - core_table = 'core_channel' + # Returns: + # bool: True if action done + # """ + # try: + # channel_name = channel_name.lower() if self.Is_Channel(channel_name) else None + # core_table = self.Config.TABLE_CHANNEL - if not channel_name: - self.logs.warn(f'The channel [{channel_name}] is not correct') - return False + # if not channel_name: + # self.logs.warning(f'The channel [{channel_name}] is not correct') + # return False - match action: + # match action: - case 'add': - mes_donnees = {'module_name': module_name, 'channel_name': channel_name} - response = self.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees) - isChannelExist = response.fetchone() + # case 'add': + # mes_donnees = {'module_name': module_name, 'channel_name': channel_name} + # response = self.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees) + # isChannelExist = response.fetchone() - if isChannelExist is None: - mes_donnees = {'datetime': self.get_datetime(), 'channel_name': channel_name, 'module_name': module_name} - insert = self.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees) - if insert.rowcount: - self.logs.debug(f'New channel added: channel={channel_name} / module_name={module_name}') - return True - else: - return False - pass + # if isChannelExist is None: + # mes_donnees = {'datetime': self.get_datetime(), 'channel_name': channel_name, 'module_name': module_name} + # insert = self.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees) + # if insert.rowcount: + # self.logs.debug(f'New channel added: channel={channel_name} / module_name={module_name}') + # return True + # else: + # return False + # pass - case 'del': - mes_donnes = {'channel_name': channel_name, 'module_name': module_name} - response = self.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes) + # case 'del': + # mes_donnes = {'channel_name': channel_name, 'module_name': module_name} + # response = self.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes) - if response.rowcount > 0: - self.logs.debug(f'Channel deleted: channel={channel_name} / module: {module_name}') - return True - else: + # if response.rowcount > 0: + # self.logs.debug(f'Channel deleted: channel={channel_name} / module: {module_name}') + # return True + # else: - return False + # return False - case _: - return False + # case _: + # return False - except Exception as err: - self.logs.error(err) + # except Exception as err: + # self.logs.error(err) def db_create_first_admin(self) -> None: - user = self.db_execute_query(f"SELECT id FROM {self.Config.table_admin}") + user = self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}") if not user.fetchall(): admin = self.Config.OWNER password = self.crypt_password(self.Config.PASSWORD) @@ -442,7 +470,7 @@ class Base: 'level': 5 } self.db_execute_query(f""" - INSERT INTO {self.Config.table_admin} + INSERT INTO {self.Config.TABLE_ADMIN} (createdOn, user, password, hostname, vhost, level) VALUES (:createdOn, :user, :password, :hostname, :vhost, :level)""" @@ -489,6 +517,25 @@ class Base: except AssertionError as ae: self.logs.error(f'{ae}') + def thread_count(self, thread_name: str) -> int: + """This method return the number of existing threads + currently running or not running + + Args: + thread_name (str): The name of the thread + + Returns: + int: Number of threads + """ + with self.lock: + count = 0 + + for thr in self.running_threads: + if thread_name == thr.getName(): + count += 1 + + return count + def garbage_collector_timer(self) -> None: """Methode qui supprime les timers qui ont finis leurs job """ @@ -511,6 +558,7 @@ class Base: try: for thread in self.running_threads: if thread.getName() != 'heartbeat': + # print(thread.getName(), thread.is_alive(), sep=' / ') if not thread.is_alive(): self.running_threads.remove(thread) self.logs.info(f"Thread {str(thread.getName())} {str(thread.native_id)} removed") @@ -564,8 +612,8 @@ class Base: def db_init(self) -> tuple[Engine, Connection]: - db_directory = self.Config.db_path - full_path_db = self.Config.db_path + self.Config.db_name + db_directory = self.Config.DB_PATH + full_path_db = self.Config.DB_PATH + self.Config.DB_NAME if not os.path.exists(db_directory): self.install = True @@ -578,14 +626,14 @@ class Base: 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, datetime TEXT, server_msg TEXT ) ''' - table_core_config = f'''CREATE TABLE IF NOT EXISTS {self.Config.table_config} ( + table_core_config = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_CONFIG} ( id INTEGER PRIMARY KEY AUTOINCREMENT, datetime TEXT, module_name TEXT, @@ -594,7 +642,7 @@ class Base: ) ''' - table_core_log_command = f'''CREATE TABLE IF NOT EXISTS {self.Config.table_commande} ( + table_core_log_command = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_COMMAND} ( id INTEGER PRIMARY KEY AUTOINCREMENT, datetime TEXT, user TEXT, @@ -602,7 +650,7 @@ class Base: ) ''' - table_core_module = f'''CREATE TABLE IF NOT EXISTS {self.Config.table_module} ( + table_core_module = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_MODULE} ( id INTEGER PRIMARY KEY AUTOINCREMENT, datetime TEXT, user TEXT, @@ -611,7 +659,7 @@ class Base: ) ''' - table_core_channel = f'''CREATE TABLE IF NOT EXISTS {self.Config.table_channel} ( + table_core_channel = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_CHANNEL} ( id INTEGER PRIMARY KEY AUTOINCREMENT, datetime TEXT, module_name TEXT, @@ -619,7 +667,7 @@ class Base: ) ''' - table_core_admin = f'''CREATE TABLE IF NOT EXISTS {self.Config.table_admin} ( + table_core_admin = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_ADMIN} ( id INTEGER PRIMARY KEY AUTOINCREMENT, createdOn TEXT, user TEXT, @@ -717,16 +765,19 @@ class Base: self.logs.critical(f'This remote ip is not valid : {ve}') return None - # def encode_ip(self, remote_ip_address: str) -> Union[str, None]: + def encode_ip(self, remote_ip_address: str) -> Union[str, None]: - # binary_ip = b64encode() - # try: - # decoded_ip = ipaddress.ip_address(binary_ip) + binary_ip = socket.inet_aton(remote_ip_address) + try: + encoded_ip = b64encode(binary_ip).decode() - # return decoded_ip.exploded - # except ValueError as ve: - # self.logs.critical(f'This remote ip is not valid : {ve}') - # return None + return encoded_ip + except ValueError as ve: + self.logs.critical(f'This remote ip is not valid : {ve}') + return None + except Exception as err: + self.logs.critical(f'General Error: {err}') + return None def get_random(self, lenght:int) -> str: """ @@ -756,7 +807,7 @@ class Base: # Vider le dictionnaire de fonction self.periodic_func.clear() - def clean_uid(self, uid:str) -> str: + def clean_uid(self, uid:str) -> Union[str, None]: """Clean UID by removing @ / % / + / ~ / * / : Args: @@ -765,34 +816,13 @@ class Base: Returns: str: Clean UID without any sign """ - - pattern = fr'[:|@|%|\+|~|\*]*' - parsed_UID = re.sub(pattern, '', uid) - - return parsed_UID - - def Is_Channel(self, channelToCheck: str) -> bool: - """Check if the string has the # caractere and return True if this is a channel - - Args: - channelToCheck (str): The string to test if it is a channel or not - - Returns: - bool: True if the string is a channel / False if this is not a channel - """ try: - - if channelToCheck is None: - return False + if uid is None: + return None - pattern = fr'^#' - isChannel = re.findall(pattern, channelToCheck) + pattern = fr'[:|@|%|\+|~|\*]*' + parsed_UID = re.sub(pattern, '', uid) - if not isChannel: - return False - else: - return True + return parsed_UID except TypeError as te: - self.logs.error(f'TypeError: [{channelToCheck}] - {te}') - except Exception as err: - self.logs.error(f'Error Not defined: {err}') + self.logs.error(f'Type Error: {te}') diff --git a/core/classes/admin.py b/core/classes/admin.py new file mode 100644 index 0000000..3f4e61c --- /dev/null +++ b/core/classes/admin.py @@ -0,0 +1,127 @@ +from typing import Union +import core.definition as df +from core.base import Base + + +class Admin: + + UID_ADMIN_DB: list[df.MAdmin] = [] + + def __init__(self, baseObj: Base) -> None: + self.Logs = baseObj.logs + pass + + def insert(self, newAdmin: df.MAdmin) -> bool: + + result = False + exist = False + + for record in self.UID_ADMIN_DB: + if record.uid == newAdmin.uid: + # If the admin exist then return False and do not go further + exist = True + self.Logs.debug(f'{record.uid} already exist') + return result + + if not exist: + self.UID_ADMIN_DB.append(newAdmin) + result = True + self.Logs.debug(f'UID ({newAdmin.uid}) has been created') + + if not result: + self.Logs.critical(f'The User Object was not inserted {newAdmin}') + + return result + + def update_nickname(self, uid: str, newNickname: str) -> bool: + + result = False + + for record in self.UID_ADMIN_DB: + if record.uid == uid: + # If the admin exist, update and do not go further + record.nickname = newNickname + result = True + self.Logs.debug(f'UID ({record.uid}) has been updated with new nickname {newNickname}') + return result + + if not result: + self.Logs.critical(f'The new nickname {newNickname} was not updated, uid = {uid}') + + return result + + def update_level(self, nickname: str, newLevel: int) -> bool: + + result = False + + for record in self.UID_ADMIN_DB: + if record.nickname == nickname: + # If the admin exist, update and do not go further + record.level = newLevel + result = True + self.Logs.debug(f'Admin ({record.nickname}) has been updated with new level {newLevel}') + return result + + if not result: + self.Logs.critical(f'The new level {newLevel} was not updated, nickname = {nickname}') + + return result + + def delete(self, uidornickname: str) -> bool: + + result = False + + for record in self.UID_ADMIN_DB: + if record.uid == uidornickname: + # If the admin exist, delete and do not go further + self.UID_ADMIN_DB.remove(record) + result = True + self.Logs.debug(f'UID ({record.uid}) has been deleted') + return result + if record.nickname == uidornickname: + # If the admin exist, delete and do not go further + self.UID_ADMIN_DB.remove(record) + result = True + self.Logs.debug(f'nickname ({record.nickname}) has been deleted') + return result + + if not result: + self.Logs.critical(f'The UID {uidornickname} was not deleted') + + return result + + def get_Admin(self, uidornickname: str) -> Union[df.MAdmin, None]: + + Admin = None + for record in self.UID_ADMIN_DB: + if record.uid == uidornickname: + Admin = record + elif record.nickname == uidornickname: + Admin = record + + #self.Logs.debug(f'Search {uidornickname} -- result = {Admin}') + + return Admin + + def get_uid(self, uidornickname:str) -> Union[str, None]: + + uid = None + for record in self.UID_ADMIN_DB: + if record.uid == uidornickname: + uid = record.uid + if record.nickname == uidornickname: + uid = record.uid + + self.Logs.debug(f'The UID that you are looking for {uidornickname} has been found {uid}') + return uid + + def get_nickname(self, uidornickname:str) -> Union[str, None]: + + nickname = None + for record in self.UID_ADMIN_DB: + if record.nickname == uidornickname: + nickname = record.nickname + if record.uid == uidornickname: + nickname = record.nickname + self.Logs.debug(f'The value {uidornickname} -- {nickname}') + return nickname \ No newline at end of file diff --git a/core/classes/channel.py b/core/classes/channel.py new file mode 100644 index 0000000..6ff2b16 --- /dev/null +++ b/core/classes/channel.py @@ -0,0 +1,225 @@ +from re import findall +from typing import Union, Literal, TYPE_CHECKING +from dataclasses import asdict + +if TYPE_CHECKING: + from core.definition import MChannel + from core.base import Base + +class Channel: + + UID_CHANNEL_DB: list['MChannel'] = [] + """List that contains all the Channels objects (ChannelModel) + """ + + def __init__(self, baseObj: 'Base') -> None: + + self.Logs = baseObj.logs + self.Base = baseObj + + return None + + def insert(self, newChan: 'MChannel') -> bool: + """This method will insert a new channel and if the channel exist it will update the user list (uids) + + Args: + newChan (ChannelModel): The channel model object + + Returns: + bool: True if new channel, False if channel exist (However UID could be updated) + """ + result = False + exist = False + + for record in self.UID_CHANNEL_DB: + if record.name.lower() == newChan.name.lower(): + # If the channel exist, update the user list and do not go further + exist = True + # self.Logs.debug(f'{record.name} already exist') + + for user in newChan.uids: + record.uids.append(user) + + # Supprimer les doublons + del_duplicates = list(set(record.uids)) + record.uids = del_duplicates + # self.Logs.debug(f'Updating a new UID to the channel {record}') + return result + + if not exist: + # If the channel don't exist, then create it + newChan.name = newChan.name.lower() + self.UID_CHANNEL_DB.append(newChan) + result = True + # self.Logs.debug(f'New Channel Created: ({newChan})') + + if not result: + self.Logs.critical(f'The Channel Object was not inserted {newChan}') + + self.clean_channel() + + return result + + def delete(self, name: str) -> bool: + + result = False + + for record in self.UID_CHANNEL_DB: + if record.name == name: + # If the channel exist, then remove it and return True. + # As soon as the channel found, return True and stop the loop + self.UID_CHANNEL_DB.remove(record) + result = True + # self.Logs.debug(f'Channel ({record.name}) has been created') + return result + + if not result: + self.Logs.critical(f'The Channel {name} was not deleted') + + return result + + def delete_user_from_channel(self, chan_name: str, uid:str) -> bool: + try: + result = False + + for record in self.UID_CHANNEL_DB: + if record.name == chan_name: + for user_id in record.uids: + if self.Base.clean_uid(user_id) == uid: + record.uids.remove(user_id) + # self.Logs.debug(f'The UID {uid} has been removed, here is the new object: {record}') + result = True + + self.clean_channel() + + return result + except ValueError as ve: + self.Logs.error(f'{ve}') + + def delete_user_from_all_channel(self, uid:str) -> bool: + try: + result = False + + for record in self.UID_CHANNEL_DB: + for user_id in record.uids: + if self.Base.clean_uid(user_id) == self.Base.clean_uid(uid): + record.uids.remove(user_id) + # self.Logs.debug(f'The UID {uid} has been removed, here is the new object: {record}') + result = True + + self.clean_channel() + + return result + except ValueError as ve: + self.Logs.error(f'{ve}') + + def clean_channel(self) -> None: + """Remove Channels if empty + """ + try: + for record in self.UID_CHANNEL_DB: + if not record.uids: + self.UID_CHANNEL_DB.remove(record) + # self.Logs.debug(f'The Channel {record.name} has been removed, here is the new object: {record}') + return None + except Exception as err: + self.Logs.error(f'{err}') + + def get_Channel(self, name: str) -> Union['MChannel', None]: + + Channel = None + for record in self.UID_CHANNEL_DB: + if record.name == name: + Channel = record + + # self.Logs.debug(f'Search {name} -- result = {Channel}') + + return Channel + + def get_Channel_AsDict(self, chan_name: str) -> Union[dict[str, any], None]: + + chanObj = self.get_Channel(chan_name=chan_name) + + if not chanObj is None: + chan_as_dict = asdict(chanObj) + return chan_as_dict + else: + return None + + def Is_Channel(self, channelToCheck: str) -> bool: + """Check if the string has the # caractere and return True if this is a channel + + Args: + channelToCheck (str): The string to test if it is a channel or not + + Returns: + bool: True if the string is a channel / False if this is not a channel + """ + try: + + if channelToCheck is None: + return False + + pattern = fr'^#' + isChannel = findall(pattern, channelToCheck) + + if not isChannel: + return False + else: + return True + except TypeError as te: + self.logs.error(f'TypeError: [{channelToCheck}] - {te}') + except Exception as err: + self.logs.error(f'Error Not defined: {err}') + + 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. + + Args: + action (Literal['add','del']): Action on the database + module_name (str): The module name (mod_test) + channel_name (str): The channel name (With #) + + Returns: + bool: True if action done + """ + try: + channel_name = channel_name.lower() if self.Is_Channel(channel_name) else None + core_table = self.Base.Config.TABLE_CHANNEL + + if not channel_name: + self.Logs.warning(f'The channel [{channel_name}] is not correct') + return False + + match action: + + case 'add': + 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) + isChannelExist = response.fetchone() + + if isChannelExist is None: + mes_donnees = {'datetime': self.Base.get_datetime(), '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) + if insert.rowcount: + self.Logs.debug(f'New channel added: channel={channel_name} / module_name={module_name}') + return True + else: + return False + + case 'del': + 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) + + if response.rowcount > 0: + self.Logs.debug(f'Channel deleted: channel={channel_name} / module: {module_name}') + return True + else: + return False + + case _: + return False + + except Exception as err: + self.Logs.error(err) + diff --git a/core/classes/clone.py b/core/classes/clone.py new file mode 100644 index 0000000..8b6b17e --- /dev/null +++ b/core/classes/clone.py @@ -0,0 +1,162 @@ +from dataclasses import asdict +from core.definition import MClone +from typing import Union +from core.base import Base + +class Clone: + + UID_CLONE_DB: list[MClone] = [] + + def __init__(self, baseObj: Base) -> None: + + self.Logs = baseObj.logs + + return None + + def insert(self, newCloneObject: MClone) -> bool: + """Create new Clone object + + Args: + newCloneObject (CloneModel): New CloneModel object + + Returns: + bool: True if inserted + """ + result = False + exist = False + + for record in self.UID_CLONE_DB: + if record.nickname == newCloneObject.nickname: + # If the user exist then return False and do not go further + exist = True + self.Logs.warning(f'Nickname {record.nickname} already exist') + return result + if record.uid == newCloneObject.uid: + exist = True + self.Logs.warning(f'UID: {record.uid} already exist') + return result + + if not exist: + self.UID_CLONE_DB.append(newCloneObject) + result = True + # self.Logs.debug(f'New Clone Object Created: ({newCloneObject})') + + if not result: + self.Logs.critical(f'The Clone Object was not inserted {newCloneObject}') + + return result + + def delete(self, uidornickname: str) -> bool: + """Delete the Clone Object starting from the nickname or the UID + + Args: + uidornickname (str): UID or nickname of the clone + + Returns: + bool: True if deleted + """ + result = False + + for record in self.UID_CLONE_DB: + if record.nickname == uidornickname or record.uid == uidornickname: + # If the user exist then remove and return True and do not go further + self.UID_CLONE_DB.remove(record) + result = True + # self.Logs.debug(f'The clone ({record.nickname}) has been deleted') + return result + + if not result: + self.Logs.critical(f'The UID or Nickname {uidornickname} was not deleted') + + return result + + def exists(self, nickname: str) -> bool: + """Check if the nickname exist + + Args: + nickname (str): Nickname of the clone + + Returns: + bool: True if the nickname exist + """ + response = False + + for cloneObject in self.UID_CLONE_DB: + if cloneObject.nickname == nickname: + response = True + + return response + + def uid_exists(self, uid: str) -> bool: + """Check if the nickname exist + + Args: + uid (str): uid of the clone + + Returns: + bool: True if the nickname exist + """ + response = False + + for cloneObject in self.UID_CLONE_DB: + if cloneObject.uid == uid: + response = True + + return response + + def get_Clone(self, uidornickname: str) -> Union[MClone, None]: + """Get MClone object or None + + Args: + uidornickname (str): The UID or the Nickname + + Returns: + Union[MClone, None]: Return MClone object or None + """ + for clone in self.UID_CLONE_DB: + if clone.uid == uidornickname: + return clone + if clone.nickname == uidornickname: + return clone + + def get_uid(self, uidornickname: str) -> Union[str, None]: + """Get the UID of the clone starting from the UID or the Nickname + + Args: + uidornickname (str): UID or Nickname + + Returns: + str|None: Return the UID + """ + uid = None + for record in self.UID_CLONE_DB: + if record.uid == uidornickname: + uid = record.uid + if record.nickname == uidornickname: + uid = record.uid + + # if not uid is None: + # self.Logs.debug(f'The UID that you are looking for {uidornickname} has been found {uid}') + + return uid + + def get_Clone_AsDict(self, uidornickname: str) -> Union[dict[str, any], None]: + + cloneObj = self.get_Clone(uidornickname=uidornickname) + + if not cloneObj is None: + cloneObj_as_dict = asdict(cloneObj) + return cloneObj_as_dict + else: + return None + + def kill(self, nickname:str) -> bool: + + response = False + + for cloneObject in self.UID_CLONE_DB: + if cloneObject.nickname == nickname: + cloneObject.alive = False # Kill the clone + response = True + + return response \ No newline at end of file diff --git a/core/classes/config.py b/core/classes/config.py new file mode 100644 index 0000000..1958200 --- /dev/null +++ b/core/classes/config.py @@ -0,0 +1,57 @@ +from json import load +from sys import exit +from os import sep +from typing import Union +from core.definition import MConfig + + + +class Configuration: + + def __init__(self) -> None: + + self.ConfigObject: MConfig = self.__load_service_configuration() + return None + + def __load_json_service_configuration(self): + try: + conf_filename = f'config{sep}configuration.json' + with open(conf_filename, 'r') as configuration_data: + configuration:dict[str, Union[str, int, list, dict]] = load(configuration_data) + + return configuration + + except FileNotFoundError as fe: + print(f'FileNotFound: {fe}') + print('Configuration file not found please create config/configuration.json') + exit(0) + except KeyError as ke: + print(f'Key Error: {ke}') + print('The key must be defined in core/configuration.json') + + def __load_service_configuration(self) -> MConfig: + try: + import_config = self.__load_json_service_configuration() + + Model_keys = MConfig().__dict__ + model_key_list: list = [] + json_config_key_list: list = [] + + for key in Model_keys: + model_key_list.append(key) + + for key in import_config: + json_config_key_list.append(key) + + for json_conf in json_config_key_list: + if not json_conf in model_key_list: + import_config.pop(json_conf, None) + print(f"\!/ The key {json_conf} is not expected, it has been removed from the system ! please remove it from configuration.json file \!/") + + ConfigObject: MConfig = MConfig( + **import_config + ) + + return ConfigObject + except TypeError as te: + print(te) \ No newline at end of file diff --git a/core/classes/protocol.py b/core/classes/protocol.py new file mode 100644 index 0000000..ce6f939 --- /dev/null +++ b/core/classes/protocol.py @@ -0,0 +1,15 @@ +from typing import Literal, TYPE_CHECKING +from .protocols.unreal6 import Unrealircd6 + +if TYPE_CHECKING: + from core.irc import Irc + +class Protocol: + + def __init__(self, protocol: Literal['unreal6'], ircInstance: 'Irc'): + + self.Protocol = None + if protocol == 'unreal6': + self.Protocol: Unrealircd6 = Unrealircd6(ircInstance) + else: + self.Protocol = None \ No newline at end of file diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py new file mode 100644 index 0000000..780ac6f --- /dev/null +++ b/core/classes/protocols/unreal6.py @@ -0,0 +1,336 @@ +from typing import TYPE_CHECKING +from ssl import SSLEOFError, SSLError + +if TYPE_CHECKING: + from core.irc import Irc + +class Unrealircd6: + + def __init__(self, ircInstance: 'Irc'): + self.__Irc = ircInstance + self.__Config = ircInstance.Config + self.__Base = ircInstance.Base + + def send2socket(self, message: str, print_log: bool = True) -> None: + """Envoit les commandes à envoyer au serveur. + + Args: + string (Str): contient la commande à envoyer au serveur. + """ + try: + with self.__Base.lock: + self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[0])) + if print_log: + self.__Base.logs.debug(f'<< {message}') + + except UnicodeDecodeError: + self.__Base.logs.error(f'Decode Error try iso-8859-1 - message: {message}') + self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[0],'replace')) + except UnicodeEncodeError: + self.__Base.logs.error(f'Encode Error try iso-8859-1 - message: {message}') + self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[0],'replace')) + except AssertionError as ae: + self.__Base.logs.warning(f'Assertion Error {ae} - message: {message}') + except SSLEOFError as soe: + self.__Base.logs.error(f"SSLEOFError: {soe} - {message}") + except SSLError as se: + self.__Base.logs.error(f"SSLError: {se} - {message}") + except OSError as oe: + self.__Base.logs.error(f"OSError: {oe} - {message}") + except AttributeError as ae: + self.__Base.logs.critical(f"Attribute Error: {ae}") + + def sendPrivMsg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): + """Sending PRIVMSG to a channel or to a nickname by batches + could be either channel or nickname not both together + Args: + msg (str): The message to send + nick_from (str): The sender nickname + channel (str, optional): The receiver channel. Defaults to None. + nick_to (str, optional): The reciever nickname. Defaults to None. + """ + try: + batch_size = self.__Config.BATCH_SIZE + User_from = self.__Irc.User.get_User(nick_from) + User_to = self.__Irc.User.get_User(nick_to) if nick_to is None else None + + if User_from is None: + self.__Base.logs.error(f"The sender nickname [{nick_from}] do not exist") + return None + + if not channel is None: + for i in range(0, len(str(msg)), batch_size): + batch = str(msg)[i:i+batch_size] + self.send2socket(f":{User_from.uid} PRIVMSG {channel} :{batch}") + + if not nick_to is None: + for i in range(0, len(str(msg)), batch_size): + batch = str(msg)[i:i+batch_size] + self.send2socket(f":{nick_from} PRIVMSG {User_to.uid} :{batch}") + except Exception as err: + self.__Base.logs.error(f"General Error: {err}") + + def sendNotice(self, nick_from: str, nick_to: str, msg: str) -> None: + """Sending NOTICE by batches + + Args: + msg (str): The message to send to the server + nick_from (str): The sender Nickname + nick_to (str): The reciever nickname + """ + try: + batch_size = self.__Config.BATCH_SIZE + User_from = self.__Irc.User.get_User(nick_from) + User_to = self.__Irc.User.get_User(nick_to) + + if User_from is None or User_to is None: + self.__Base.logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist") + return None + + for i in range(0, len(str(msg)), batch_size): + batch = str(msg)[i:i+batch_size] + self.send2socket(f":{User_from.uid} NOTICE {User_to.uid} :{batch}") + + except Exception as err: + self.__Base.logs.error(f"General Error: {err}") + + def link(self): + """Créer le link et envoyer les informations nécessaires pour la + connexion au serveur. + """ + + nickname = self.__Config.SERVICE_NICKNAME + username = self.__Config.SERVICE_USERNAME + realname = self.__Config.SERVICE_REALNAME + chan = self.__Config.SERVICE_CHANLOG + info = self.__Config.SERVICE_INFO + smodes = self.__Config.SERVICE_SMODES + cmodes = self.__Config.SERVICE_CMODES + umodes = self.__Config.SERVICE_UMODES + host = self.__Config.SERVICE_HOST + service_name = self.__Config.SERVICE_NAME + + password = self.__Config.SERVEUR_PASSWORD + link = self.__Config.SERVEUR_LINK + server_id = self.__Config.SERVEUR_ID + service_id = self.__Config.SERVICE_ID + + version = self.__Config.CURRENT_VERSION + unixtime = self.__Base.get_unixtime() + + self.send2socket(f":{server_id} PASS :{password}") + self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS") + # self.__Irc.send2socket(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS") + self.send2socket(f":{server_id} PROTOCTL EAUTH={link},,,{service_name}-v{version}") + self.send2socket(f":{server_id} PROTOCTL SID={server_id}") + self.send2socket(f":{server_id} SERVER {link} 1 :{info}") + self.send2socket(f":{server_id} {nickname} :Reserved for services") + #self.__Irc.send2socket(f":{sid} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * * :{realname}") + self.send2socket(f":{server_id} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * fwAAAQ== :{realname}") + # self.__Irc.send2socket(f":{server_id} SJOIN {unixtime} {chan} + :{service_id}") + self.sjoin(chan) + self.send2socket(f":{server_id} TKL + Q * {nickname} {host} 0 {unixtime} :Reserved for services") + + self.send2socket(f":{service_id} MODE {chan} {cmodes}") + self.send2socket(f":{service_id} MODE {chan} {umodes} {service_id}") + + self.__Base.logs.debug(f'>> {__name__} Link information sent to the server') + + def gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + # TKL + G user host set_by expire_timestamp set_at_timestamp :reason + + self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") + + return None + + def set_nick(self, newnickname: str) -> None: + + self.send2socket(f":{self.__Config.SERVICE_NICKNAME} NICK {newnickname}") + return None + + def squit(self, server_id: str, server_link: str, reason: str) -> None: + + self.send2socket(f":{server_id} SQUIT {server_link} :{reason}") + return None + + def ungline(self, nickname:str, hostname: str) -> None: + + self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}") + + return None + + def kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + # TKL + k user host set_by expire_timestamp set_at_timestamp :reason + + self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") + + return None + + def sjoin(self, channel: str) -> None: + + self.send2socket(f":{self.__Config.SERVEUR_ID} SJOIN {self.__Base.get_unixtime()} {channel} + :{self.__Config.SERVICE_ID}") + + # Add defender to the channel uids list + self.__Irc.Channel.insert(self.__Irc.Loader.Definition.MChannel(name=channel, uids=[self.__Config.SERVICE_ID])) + return None + + def join(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: + """Joining a channel + + Args: + uidornickname (str): UID or nickname that need to join + channel (str): channel to join + password (str, optional): The password of the channel to join. Default to None + print_log (bool, optional): Write logs. Defaults to True. + """ + + userObj = self.__Irc.User.get_User(uidornickname) + passwordChannel = password if not password is None else '' + + if userObj is None: + return None + + if not self.__Irc.Channel.Is_Channel(channel): + return None + + self.send2socket(f":{userObj.uid} JOIN {channel} {passwordChannel}", print_log=print_log) + + # Add defender to the channel uids list + self.__Irc.Channel.insert(self.__Irc.Loader.Definition.MChannel(name=channel, uids=[userObj.uid])) + return None + + def part(self, uidornickname:str, channel: str, print_log: bool = True) -> None: + """Part from a channel + + Args: + uidornickname (str): UID or nickname that need to join + channel (str): channel to join + print_log (bool, optional): Write logs. Defaults to True. + """ + + userObj = self.__Irc.User.get_User(uidornickname) + + if userObj is None: + return None + + if not self.__Irc.Channel.Is_Channel(channel): + return None + + self.send2socket(f":{userObj.uid} PART {channel}", print_log=print_log) + + # Add defender to the channel uids list + self.__Irc.Channel.delete_user_from_channel(channel, userObj.uid) + return None + + def unkline(self, nickname:str, hostname: str) -> None: + + self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}") + + return None + + def on_server_ping(self, serverMsg: list[str]) -> None: + """Send a PONG message to the server + + Args: + serverMsg (list[str]): List of str coming from the server + """ + try: + + pong = str(serverMsg[1]).replace(':','') + self.send2socket(f"PONG :{pong}", print_log=False) + + return None + except Exception as err: + self.__Base.logs.error(f"{__name__} - General Error: {err}") + + def on_version(self, serverMsg: list[str]) -> None: + """Sending Server Version to the server + + Args: + serverMsg (list[str]): List of str coming from the server + """ + # ['@unrealircd.org/userhost=StatServ@stats.deb.biz.st;draft/bot;bot;msgid=ehfAq3m2yjMjhgWEfi1UCS;time=2024-10-26T13:49:06.299Z', ':00BAAAAAI', 'PRIVMSG', '12ZAAAAAB', ':\x01VERSION\x01'] + # Réponse a un CTCP VERSION + try: + + nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1])) + dnickname = self.__Config.SERVICE_NICKNAME + arg = serverMsg[4].replace(':', '') + + if nickname is None: + return None + + if arg == '\x01VERSION\x01': + self.send2socket(f':{dnickname} NOTICE {nickname} :\x01VERSION Service {self.__Config.SERVICE_NICKNAME} V{self.__Config.CURRENT_VERSION}\x01') + + return None + except Exception as err: + self.__Base.logs.error(f"{__name__} - General Error: {err}") + + def on_time(self, serverMsg: list[str]) -> None: + """Sending TIME answer to a requestor + + Args: + serverMsg (list[str]): List of str coming from the server + """ + # ['@unrealircd.org/userhost=StatServ@stats.deb.biz.st;draft/bot;bot;msgid=ehfAq3m2yjMjhgWEfi1UCS;time=2024-10-26T13:49:06.299Z', ':00BAAAAAI', 'PRIVMSG', '12ZAAAAAB', ':\x01TIME\x01'] + # Réponse a un CTCP VERSION + try: + + nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1])) + dnickname = self.__Config.SERVICE_NICKNAME + arg = serverMsg[4].replace(':', '') + current_datetime = self.__Base.get_datetime() + + if nickname is None: + return None + + if arg == '\x01TIME\x01': + self.send2socket(f':{dnickname} NOTICE {nickname} :\x01TIME {current_datetime}\x01') + + return None + except Exception as err: + self.__Base.logs.error(f"{__name__} - General Error: {err}") + + def on_ping(self, serverMsg: list[str]) -> None: + """Sending a PING answer to requestor + + Args: + serverMsg (list[str]): List of str coming from the server + """ + # ['@unrealircd.org/userhost=StatServ@stats.deb.biz.st;draft/bot;bot;msgid=ehfAq3m2yjMjhgWEfi1UCS;time=2024-10-26T13:49:06.299Z', ':001INC60B', 'PRIVMSG', '12ZAAAAAB', ':\x01PING', '762382207\x01'] + # Réponse a un CTCP VERSION + try: + + nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1])) + dnickname = self.__Config.SERVICE_NICKNAME + arg = serverMsg[4].replace(':', '') + + if nickname is None: + return None + + if arg == '\x01PING': + recieved_unixtime = int(serverMsg[5].replace('\x01','')) + current_unixtime = self.__Base.get_unixtime() + ping_response = current_unixtime - recieved_unixtime + + # self.__Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') + self.sendNotice( + nick_from=dnickname, + nick_to=nickname, + msg=f"\x01PING {ping_response} secs\x01" + ) + + return None + except Exception as err: + self.__Base.logs.error(f"{__name__} - General Error: {err}") + + def on_version_msg(self, serverMsg: list[str]) -> None: + + # ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender'] + getUser = self.__Irc.User.get_User(self.__Irc.User.clean_uid(serverMsg[1])) + + if getUser is None: + return None + + self.send2socket(f'{self.__Config.SERVEUR_ID} 351 {getUser.nickname} {self.__Config.CURRENT_VERSION} {self.__Config.SERVICE_NAME} *:') \ No newline at end of file diff --git a/core/classes/reputation.py b/core/classes/reputation.py new file mode 100644 index 0000000..d39b984 --- /dev/null +++ b/core/classes/reputation.py @@ -0,0 +1,175 @@ +from typing import Union +from core.definition import MReputation +from core.base import Base + +class Reputation: + + UID_REPUTATION_DB: list[MReputation] = [] + + def __init__(self, baseObj: Base) -> None: + + self.Logs = baseObj.logs + self.MReputation: MReputation = MReputation + + return None + + def insert(self, newReputationUser: MReputation) -> bool: + """Insert a new Reputation User object + + Args: + newReputationUser (MReputation): New Reputation Model object + + Returns: + bool: True if inserted + """ + result = False + exist = False + + for record in self.UID_REPUTATION_DB: + if record.uid == newReputationUser.uid: + # If the user exist then return False and do not go further + exist = True + self.Logs.debug(f'{record.uid} already exist') + return result + + if not exist: + self.UID_REPUTATION_DB.append(newReputationUser) + result = True + self.Logs.debug(f'New Reputation User Captured: ({newReputationUser})') + + if not result: + self.Logs.critical(f'The Reputation User Object was not inserted {newReputationUser}') + + return result + + def update(self, uid: str, newNickname: str) -> bool: + """Update the nickname starting from the UID + + Args: + uid (str): UID of the user + newNickname (str): New nickname + + Returns: + bool: True if updated + """ + result = False + + for record in self.UID_REPUTATION_DB: + if record.uid == uid: + # If the user exist then update and return True and do not go further + record.nickname = newNickname + result = True + self.Logs.debug(f'Reputation UID ({record.uid}) has been updated with new nickname {newNickname}') + return result + + if not result: + self.Logs.critical(f'Reputation new nickname {newNickname} was not updated, uid = {uid}') + + return result + + def delete(self, uid: str) -> bool: + """Delete the User starting from the UID + + Args: + uid (str): UID of the user + + Returns: + bool: True if deleted + """ + result = False + + for record in self.UID_REPUTATION_DB: + if record.uid == uid: + # If the user exist then remove and return True and do not go further + self.UID_REPUTATION_DB.remove(record) + result = True + self.Logs.debug(f'UID ({record.uid}) has been deleted') + return result + + if not result: + self.Logs.critical(f'The UID {uid} was not deleted') + + return result + + def get_Reputation(self, uidornickname: str) -> Union[MReputation, None]: + """Get The User Object model + + Args: + uidornickname (str): UID or Nickname + + Returns: + UserModel|None: The UserModel Object | None + """ + User = None + for record in self.UID_REPUTATION_DB: + if record.uid == uidornickname: + User = record + elif record.nickname == uidornickname: + User = record + + if not User is None: + self.Logs.debug(f'Reputation found for {uidornickname} -> {User}') + + return User + + def get_uid(self, uidornickname:str) -> Union[str, None]: + """Get the UID of the user starting from the UID or the Nickname + + Args: + uidornickname (str): UID or Nickname + + Returns: + str|None: Return the UID + """ + uid = None + for record in self.UID_REPUTATION_DB: + if record.uid == uidornickname: + uid = record.uid + if record.nickname == uidornickname: + uid = record.uid + + if not uid is None: + self.Logs.debug(f'Reputation UID found for {uidornickname} -> {uid}') + + return uid + + def get_nickname(self, uidornickname:str) -> Union[str, None]: + """Get the Nickname starting from UID or the nickname + + Args: + uidornickname (str): UID or Nickname of the user + + Returns: + str|None: the nickname + """ + nickname = None + for record in self.UID_REPUTATION_DB: + if record.nickname == uidornickname: + nickname = record.nickname + if record.uid == uidornickname: + nickname = record.nickname + + if not nickname is None: + self.Logs.debug(f'Reputation nickname found for {uidornickname} -> {nickname}') + + return nickname + + def is_exist(self, uidornickname: str) -> bool: + """Check if the UID or the nickname exist in the reputation DB + + Args: + uidornickname (str): The UID or the NICKNAME + + Returns: + bool: True if exist + """ + + found = False + + for record in self.UID_REPUTATION_DB: + if record.uid == uidornickname: + found = True + if record.nickname == uidornickname: + found = True + + return found diff --git a/core/classes/settings.py b/core/classes/settings.py new file mode 100644 index 0000000..e19a9e2 --- /dev/null +++ b/core/classes/settings.py @@ -0,0 +1,10 @@ +from threading import Timer, Thread, RLock +from socket import socket + +class Settings: + + RUNNING_TIMERS: list[Timer] = [] + RUNNING_THREADS: list[Thread] = [] + RUNNING_SOCKETS: list[socket] = [] + PERIODIC_FUNC: dict[object] = {} + LOCK: RLock = RLock() diff --git a/core/classes/user.py b/core/classes/user.py new file mode 100644 index 0000000..8d22172 --- /dev/null +++ b/core/classes/user.py @@ -0,0 +1,180 @@ +import re +from typing import Union, TYPE_CHECKING +from dataclasses import asdict + +if TYPE_CHECKING: + from core.base import Base + from core.definition import MUser + +class User: + + UID_DB: list['MUser'] = [] + + def __init__(self, baseObj: 'Base') -> None: + + self.Logs = baseObj.logs + self.Base = baseObj + + return None + + def insert(self, newUser: 'MUser') -> bool: + """Insert a new User object + + Args: + newUser (UserModel): New userModel object + + Returns: + bool: True if inserted + """ + result = False + exist = False + + for record in self.UID_DB: + if record.uid == newUser.uid: + # If the user exist then return False and do not go further + exist = True + self.Logs.debug(f'{record.uid} already exist') + return result + + if not exist: + self.UID_DB.append(newUser) + result = True + # self.Logs.debug(f'New User Created: ({newUser})') + + if not result: + self.Logs.critical(f'The User Object was not inserted {newUser}') + + return result + + def update(self, uid: str, newNickname: str) -> bool: + """Update the nickname starting from the UID + + Args: + uid (str): UID of the user + newNickname (str): New nickname + + Returns: + bool: True if updated + """ + result = False + + for record in self.UID_DB: + if record.uid == uid: + # If the user exist then update and return True and do not go further + record.nickname = newNickname + result = True + # self.Logs.debug(f'UID ({record.uid}) has been updated with new nickname {newNickname}') + return result + + if not result: + self.Logs.critical(f'The new nickname {newNickname} was not updated, uid = {uid}') + + return result + + def delete(self, uid: str) -> bool: + """Delete the User starting from the UID + + Args: + uid (str): UID of the user + + Returns: + bool: True if deleted + """ + result = False + + for record in self.UID_DB: + if record.uid == uid: + # If the user exist then remove and return True and do not go further + self.UID_DB.remove(record) + result = True + # self.Logs.debug(f'UID ({record.uid}) has been deleted') + return result + + if not result: + self.Logs.critical(f'The UID {uid} was not deleted') + + return result + + def get_User(self, uidornickname: str) -> Union['MUser', None]: + """Get The User Object model + + Args: + uidornickname (str): UID or Nickname + + Returns: + UserModel|None: The UserModel Object | None + """ + User = None + for record in self.UID_DB: + if record.uid == uidornickname: + User = record + elif record.nickname == uidornickname: + User = record + + # self.Logs.debug(f'Search {uidornickname} -- result = {User}') + + return User + + def get_uid(self, uidornickname:str) -> Union[str, None]: + """Get the UID of the user starting from the UID or the Nickname + + Args: + uidornickname (str): UID or Nickname + + Returns: + str|None: Return the UID + """ + uid = None + for record in self.UID_DB: + if record.uid == uidornickname: + uid = record.uid + if record.nickname == uidornickname: + uid = record.uid + + # if not uid is None: + # self.Logs.debug(f'The UID that you are looking for {uidornickname} has been found {uid}') + + return uid + + def get_nickname(self, uidornickname:str) -> Union[str, None]: + """Get the Nickname starting from UID or the nickname + + Args: + uidornickname (str): UID or Nickname of the user + + Returns: + str|None: the nickname + """ + nickname = None + for record in self.UID_DB: + if record.nickname == uidornickname: + nickname = record.nickname + if record.uid == uidornickname: + nickname = record.nickname + # self.Logs.debug(f'The value to check {uidornickname} -> {nickname}') + return nickname + + def get_User_AsDict(self, uidornickname: str) -> Union[dict[str, any], None]: + + userObj = self.get_User(uidornickname=uidornickname) + + if not userObj is None: + user_as_dict = asdict(userObj) + return user_as_dict + else: + return None + + def clean_uid(self, uid: str) -> str: + """Clean UID by removing @ / % / + / ~ / * / : + + Args: + uid (str): The UID to clean + + Returns: + str: Clean UID without any sign + """ + + pattern = fr'[:|@|%|\+|~|\*]*' + parsed_UID = re.sub(pattern, '', uid) + + return parsed_UID \ No newline at end of file diff --git a/core/connection.py b/core/connection.py deleted file mode 100644 index a6e2583..0000000 --- a/core/connection.py +++ /dev/null @@ -1,274 +0,0 @@ -import socket -import ssl -import traceback -from ssl import SSLSocket -from typing import Union -from core.loadConf import Config -from core.Model import Clones -from core.base import Base - -class Connection: - - def __init__(self, server_port: int, nickname: str, username: str, realname: str, channels:list[str], CloneObject: Clones, ssl:bool = False) -> None: - - self.Config = Config().ConfigObject - self.Base = Base(self.Config) - self.IrcSocket: Union[socket.socket, SSLSocket] = None - self.nickname = nickname - self.username = username - self.realname = realname - self.clone_chanlog = self.Config.CLONE_CHANNEL - self.clone_log_exempt = self.Config.CLONE_LOG_HOST_EXEMPT - self.channels:list[str] = channels - self.CHARSET = ['utf-8', 'iso-8859-1'] - self.Clones = CloneObject - self.signal: bool = True - for clone in self.Clones.UID_CLONE_DB: - if clone.nickname == nickname: - self.currentCloneObject = clone - - self.create_socket(self.Config.SERVEUR_IP, self.Config.SERVEUR_HOSTNAME, server_port, ssl) - self.send_connection_information_to_server(self.IrcSocket) - self.connect() - - def create_socket(self, server_ip: str, server_hostname: str, server_port: int, ssl: bool = False) -> bool: - - try: - soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK) - connexion_information = (server_ip, server_port) - - if ssl: - # Créer un object ssl - ssl_context = self.__ssl_context() - ssl_connexion = ssl_context.wrap_socket(soc, server_hostname=server_hostname) - ssl_connexion.connect(connexion_information) - self.IrcSocket:SSLSocket = ssl_connexion - self.SSL_VERSION = self.IrcSocket.version() - self.Base.logs.debug(f'> Connexion en mode SSL : Version = {self.SSL_VERSION}') - else: - soc.connect(connexion_information) - self.IrcSocket:socket.socket = soc - self.Base.logs.debug(f'> Connexion en mode normal') - - return True - - except ssl.SSLEOFError as soe: - self.Base.logs.critical(f"SSLEOFError __create_socket: {soe} - {soc.fileno()}") - return False - except ssl.SSLError as se: - self.Base.logs.critical(f"SSLError __create_socket: {se} - {soc.fileno()}") - return False - except OSError as oe: - self.Base.logs.critical(f"OSError __create_socket: {oe} - {soc.fileno()}") - return False - except AttributeError as ae: - self.Base.logs.critical(f"AttributeError __create_socket: {ae} - {soc.fileno()}") - return False - - def send2socket(self, send_message:str, disconnect: bool = False) -> None: - """Envoit les commandes à envoyer au serveur. - - Args: - string (Str): contient la commande à envoyer au serveur. - """ - try: - with self.Base.lock: - self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0])) - self.Base.logs.debug(f'<<{self.currentCloneObject.nickname}>>: {send_message}') - - except UnicodeDecodeError: - self.Base.logs.error(f'Decode Error try iso-8859-1 - message: {send_message}') - self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[1],'replace')) - except UnicodeEncodeError: - self.Base.logs.error(f'Encode Error try iso-8859-1 - message: {send_message}') - self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[1],'replace')) - except AssertionError as ae: - self.Base.logs.warning(f'Assertion Error {ae} - message: {send_message}') - except ssl.SSLEOFError as soe: - self.Base.logs.error(f"SSLEOFError: {soe} - {send_message}") - except ssl.SSLError as se: - self.Base.logs.error(f"SSLError: {se} - {send_message}") - except OSError as oe: - self.Base.logs.error(f"OSError: {oe} - {send_message}") - - def send_connection_information_to_server(self, writer:Union[socket.socket, SSLSocket]) -> None: - """Créer le link et envoyer les informations nécessaires pour la - connexion au serveur. - - Args: - writer (StreamWriter): permet l'envoi des informations au serveur. - """ - try: - nickname = self.nickname - username = self.username - realname = self.realname - - # Envoyer un message d'identification - writer.send(f"USER {nickname} {username} {username} {nickname} {username} :{username}\r\n".encode('utf-8')) - writer.send(f"USER {username} {username} {username} :{realname}\r\n".encode('utf-8')) - writer.send(f"NICK {nickname}\r\n".encode('utf-8')) - - self.Base.logs.debug('Link information sent to the server') - - return None - except AttributeError as ae: - self.Base.logs.critical(f'{ae}') - - def connect(self): - try: - while self.signal: - try: - # 4072 max what the socket can grab - buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) - data_in_bytes = self.IrcSocket.recv(buffer_size) - data = data_in_bytes.splitlines(True) - count_bytes = len(data_in_bytes) - - while count_bytes > 4070: - # If the received message is > 4070 then loop and add the value to the variable - new_data = self.IrcSocket.recv(buffer_size) - data_in_bytes += new_data - count_bytes = len(new_data) - - data = data_in_bytes.splitlines(True) - - if not data: - # If no data then quit the loop - break - - self.parser(data) - except ssl.SSLEOFError as soe: - self.Base.logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}") - self.signal = False - except ssl.SSLError as se: - self.Base.logs.error(f"SSLError __connect_to_irc: {se} - {data}") - self.signal = False - except OSError as oe: - self.Base.logs.error(f"OSError __connect_to_irc: {oe} - {data}") - self.signal = False - - self.IrcSocket.shutdown(socket.SHUT_WR) - self.IrcSocket.shutdown(socket.SHUT_RD) - self.currentCloneObject.init = False - self.Base.logs.info(f"<<{self.currentCloneObject.nickname}>> Clone Disconnected ...") - - except AssertionError as ae: - self.Base.logs.error(f'Assertion error : {ae}') - except ValueError as ve: - self.Base.logs.error(f'Value Error : {ve}') - except ssl.SSLEOFError as soe: - self.Base.logs.error(f"OS Error __connect_to_irc: {soe}") - except AttributeError as atte: - self.Base.logs.critical(f"{atte}") - self.Base.logs.critical(f"{traceback.format_exc()}") - except Exception as e: - self.Base.logs.error(f"Exception: {e}") - - def parser(self, cmd:list[bytes]): - try: - - for data in cmd: - response = data.decode(self.CHARSET[0]).split() - current_clone_nickname = self.currentCloneObject.nickname - # print(response) - - match response[0]: - case 'PING': - pong = str(response[1]).replace(':','') - self.send2socket(f"PONG :{pong}") - return None - case 'ERROR': - error_value = str(response[1]).replace(':','') - if error_value == 'Closing': - self.Base.logs.info(f"<<{self.currentCloneObject.nickname}>> {response} ...") - self.currentCloneObject.connected = False - else: - self.Base.logs.info(f"<<{self.currentCloneObject.nickname}>> {response} ...") - # self.signal = False - - match response[1]: - case '376': - # End of MOTD - self.currentCloneObject.connected = True - self.currentCloneObject.init = False - for channel in self.channels: - self.send2socket(f"JOIN {channel}") - - self.send2socket(f"JOIN {self.clone_chanlog} {self.Config.CLONE_CHANNEL_PASSWORD}") - - return None - - case '422': - # Missing MOTD - self.currentCloneObject.connected = True - self.currentCloneObject.init = False - for channel in self.channels: - self.send2socket(f"JOIN {channel}") - - self.send2socket(f"JOIN {self.clone_chanlog} {self.Config.CLONE_CHANNEL_PASSWORD}") - return None - - case '433': - # Nickname already in use - self.currentCloneObject.connected = False - self.currentCloneObject.init = False - self.send2socket(f'QUIT :Thanks and goodbye') - self.Base.logs.warning(f"Nickname {self.currentCloneObject.nickname} already in use >> Clone should be disconnected") - return None - - case 'PRIVMSG': - self.Base.logs.debug(f'<<{self.currentCloneObject.nickname}>> Response: {response}') - self.Base.logs.debug(f'<<{self.currentCloneObject.nickname}>> Alive: {self.currentCloneObject.alive}') - fullname = str(response[0]).replace(':', '') - nickname = fullname.split('!')[0].replace(':','') - - if response[2] == current_clone_nickname and nickname != self.Config.SERVICE_NICKNAME: - message = [] - for i in range(3, len(response)): - message.append(response[i]) - final_message = ' '.join(message) - - exampt = False - for log_exception in self.clone_log_exempt: - if log_exception in fullname: - exampt = True - - if not exampt: - self.send2socket(f"PRIVMSG {self.clone_chanlog} :{fullname} => {final_message[1:]}") - - if nickname == self.Config.SERVICE_NICKNAME: - command = str(response[3]).replace(':','') - - if command == 'KILL': - self.send2socket(f'QUIT :Thanks and goodbye') - - if command == 'JOIN': - channel_to_join = str(response[4]) - self.send2socket(f"JOIN {channel_to_join}") - - if command == 'SAY': - clone_channel = str(response[4]) - message = [] - for i in range(5, len(response)): - message.append(response[i]) - final_message = ' '.join(message) - - self.send2socket(f"PRIVMSG {clone_channel} :{final_message}") - - except UnicodeEncodeError: - for data in cmd: - response = data.decode(self.CHARSET[1],'replace').split() - except UnicodeDecodeError: - for data in cmd: - response = data.decode(self.CHARSET[1],'replace').split() - except AssertionError as ae: - self.Base.logs.error(f"Assertion error : {ae}") - - def __ssl_context(self) -> ssl.SSLContext: - ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ctx.check_hostname = False - ctx.verify_mode = ssl.CERT_NONE - - self.Base.logs.debug(f'SSLContext initiated with verified mode {ctx.verify_mode}') - - return ctx \ No newline at end of file diff --git a/core/dataClass.py b/core/dataClass.py deleted file mode 100644 index 4f99cb4..0000000 --- a/core/dataClass.py +++ /dev/null @@ -1,274 +0,0 @@ -from dataclasses import dataclass, field -from datetime import datetime -from typing import Union - -class User: - - @dataclass - class UserDataClass: - uid: str - nickname: str - username: str - hostname: str - umodes: str - vhost: str - isWebirc: bool - connexion_datetime: datetime = field(default=datetime.now()) - - UID_DB:list[UserDataClass] = [] - - def __init__(self) -> None: - pass - - def insert(self, user: UserDataClass) -> bool: - """Insert new user - - Args: - user (UserDataClass): The User dataclass - - Returns: - bool: True if the record has been created - """ - exists = False - inserted = False - - for record in self.UID_DB: - if record.uid == user.uid: - exists = True - print(f'{user.uid} already exist') - - if not exists: - self.UID_DB.append(user) - print(f'New record with uid: {user.uid}') - inserted = True - - return inserted - - def update(self, uid: str, newnickname: str) -> bool: - """Updating a single record with a new nickname - - Args: - uid (str): the uid of the user - newnickname (str): the new nickname - - Returns: - bool: True if the record has been updated - """ - status = False - for user in self.UID_DB: - if user.uid == uid: - user.nickname = newnickname - status = True - print(f'Updating record with uid: {uid}') - - return status - - def delete(self, uid: str) -> bool: - """Delete a user based on his uid - - Args: - uid (str): The UID of the user - - Returns: - bool: True if the record has been deleted - """ - status = False - for user in self.UID_DB: - if user.uid == uid: - self.UID_DB.remove(user) - status = True - print(f'Removing record with uid: {uid}') - - return status - - def isexist(self, uidornickname:str) -> bool: - """do the UID or Nickname exist ? - - Args: - uidornickname (str): The UID or the Nickname - - Returns: - bool: True if exist or False if don't exist - """ - result = False - for record in self.UID_DB: - if record.uid == uidornickname: - result = True - if record.nickname == uidornickname: - result = True - - return result - - def get_User(self, uidornickname) -> Union[UserDataClass, None]: - - UserObject = None - for record in self.UID_DB: - if record.uid == uidornickname: - UserObject = record - elif record.nickname == uidornickname: - UserObject = record - - return UserObject - - def get_uid(self, uidornickname:str) -> Union[str, None]: - - uid = None - for record in self.UID_DB: - if record.uid == uidornickname: - uid = record.uid - if record.nickname == uidornickname: - uid = record.uid - - return uid - - def get_nickname(self, uidornickname:str) -> Union[str, None]: - - nickname = None - for record in self.UID_DB: - if record.nickname == uidornickname: - nickname = record.nickname - if record.uid == uidornickname: - nickname = record.nickname - - return nickname - -class Admin: - @dataclass - class AdminDataClass: - uid: str - nickname: str - username: str - hostname: str - umodes: str - vhost: str - level: int - connexion_datetime: datetime = field(default=datetime.now()) - - UID_ADMIN_DB:list[AdminDataClass] = [] - - def __init__(self) -> None: - pass - - def insert(self, admin: AdminDataClass) -> bool: - """Insert new user - - Args: - user (UserDataClass): The User dataclass - - Returns: - bool: True if the record has been created - """ - exists = False - inserted = False - - for record in self.UID_ADMIN_DB: - if record.uid == admin.uid: - exists = True - print(f'{admin.uid} already exist') - - if not exists: - self.UID_ADMIN_DB.append(admin) - print(f'New record with uid: {admin.uid}') - inserted = True - - return inserted - - def update(self, uid: str, newnickname: str) -> bool: - """Updating a single record with a new nickname - - Args: - uid (str): the uid of the user - newnickname (str): the new nickname - - Returns: - bool: True if the record has been updated - """ - status = False - for admin in self.UID_ADMIN_DB: - if admin.uid == uid: - admin.nickname = newnickname - status = True - print(f'Updating record with uid: {uid}') - - return status - - def delete(self, uid: str) -> bool: - """Delete a user based on his uid - - Args: - uid (str): The UID of the user - - Returns: - bool: True if the record has been deleted - """ - status = False - for admin in self.UID_ADMIN_DB: - if admin.uid == uid: - self.UID_ADMIN_DB.remove(admin) - status = True - print(f'Removing record with uid: {uid}') - - return status - - def isexist(self, uidornickname:str) -> bool: - """do the UID or Nickname exist ? - - Args: - uidornickname (str): The UID or the Nickname - - Returns: - bool: True if exist or False if don't exist - """ - result = False - for record in self.UID_ADMIN_DB: - if record.uid == uidornickname: - result = True - if record.nickname == uidornickname: - result = True - - return result - - def get_Admin(self, uidornickname) -> Union[AdminDataClass, None]: - - AdminObject = None - for record in self.UID_ADMIN_DB: - if record.uid == uidornickname: - AdminObject = record - elif record.nickname == uidornickname: - AdminObject = record - - return AdminObject - - def get_uid(self, uidornickname:str) -> Union[str, None]: - - uid = None - for record in self.UID_ADMIN_DB: - if record.uid == uidornickname: - uid = record.uid - if record.nickname == uidornickname: - uid = record.uid - - return uid - - def get_nickname(self, uidornickname:str) -> Union[str, None]: - - nickname = None - for record in self.UID_ADMIN_DB: - if record.nickname == uidornickname: - nickname = record.nickname - if record.uid == uidornickname: - nickname = record.nickname - - return nickname - - def get_level(self, uidornickname:str) -> int: - - level = 0 - for record in self.UID_ADMIN_DB: - if record.uid == uidornickname: - level = record.level - if record.nickname == uidornickname: - level = record.level - - return level - diff --git a/core/definition.py b/core/definition.py new file mode 100644 index 0000000..2cce6ee --- /dev/null +++ b/core/definition.py @@ -0,0 +1,291 @@ +from datetime import datetime +from dataclasses import dataclass, field +from typing import Literal +from os import sep + +@dataclass +class MUser: + """Model User""" + + uid: str = None + nickname: str = None + username: str = None + realname: str = None + hostname: str = None + umodes: str = None + vhost: str = None + isWebirc: bool = False + isWebsocket: bool = False + remote_ip: str = None + score_connexion: int = 0 + geoip: str = None + connexion_datetime: datetime = field(default=datetime.now()) + +@dataclass +class MAdmin: + """Model Admin""" + + uid: str = None + nickname: str = None + username: str = None + realname: str = None + hostname: str = None + umodes: str = None + vhost: str = None + isWebirc: bool = False + isWebsocket: bool = False + remote_ip: str = None + score_connexion: int = 0 + geoip: str = None + connexion_datetime: datetime = field(default=datetime.now()) + level: int = 0 + +@dataclass +class MReputation: + """Model Reputation""" + uid: str = None + nickname: str = None + username: str = None + realname: str = None + hostname: str = None + umodes: str = None + vhost: str = None + isWebirc: bool = False + isWebsocket: bool = False + remote_ip: str = None + score_connexion: int = 0 + geoip: str = None + connexion_datetime: datetime = field(default=datetime.now()) + secret_code: str = None + +@dataclass +class MChannel: + """Model Channel""" + + name: str = None + """### Channel name + It include the #""" + uids: list[str] = field(default_factory=list[str]) + """### List of UID available in the channel + including their modes ~ @ % + * + + Returns: + list: The list of UID's including theirs modes + """ + +@dataclass +class ColorModel: + white: str = "\x0300" + black: str = "\x0301" + blue: str = "\x0302" + green: str = "\x0303" + red: str = "\x0304" + yellow: str = "\x0306" + bold: str = "\x02" + nogc: str = "\x03" + +@dataclass +class MConfig: + """Model Configuration""" + + SERVEUR_IP: str = "127.0.0.1" + """Server public IP (could be 127.0.0.1 localhost)""" + + SERVEUR_HOSTNAME: str = "your.host.name" + """IRC Server Hostname (your.hostname.extension)""" + + SERVEUR_LINK: str = "your.link.url" + """The link hostname (should be the same as your unrealircd link block)""" + + SERVEUR_PORT: int = 6697 + """Server port as configured in your unrealircd link block""" + + SERVEUR_PASSWORD: str = "YOUR.STRONG.PASSWORD" + """Your link password""" + + SERVEUR_ID: str = "Z01" + """Service identification could be Z01 should be unique""" + + SERVEUR_SSL: bool = True + """Activate SSL connexion""" + + SERVEUR_PROTOCOL: str = "unreal6" + """Which server are you going to use. (default: unreal6)""" + + SERVEUR_CHARSET: list[str] = field(default_factory=list[str]) + """0: utf-8 | 1: iso-8859-1""" + + SERVICE_NAME: str = "Defender" + """Service name (Ex. Defender)""" + + SERVICE_NICKNAME: str = "Defender" + """Nickname of the service (Ex. Defender)""" + + SERVICE_REALNAME: str = "Defender IRC Service" + """Realname of the service""" + + SERVICE_USERNAME: str = "Security" + """Username of the service""" + + SERVICE_HOST: str = "Your.Service.Hostname" + """The service hostname""" + + SERVICE_INFO: str = "Defender IRC Service" + """Swhois of the service""" + + SERVICE_CHANLOG: str = "#services" + """The channel used by the service (ex. #services)""" + + SERVICE_SMODES: str = "+ioqBS" + """The service mode (ex. +ioqBS)""" + + SERVICE_CMODES: str = "ntsO" + """The mode of the log channel (ex. ntsO)""" + + SERVICE_UMODES: str = "o" + """The mode of the service when joining chanlog (ex. o, the service will be operator in the chanlog)""" + + SERVICE_PREFIX: str = "!" + """The default prefix to communicate with the service""" + + SERVICE_ID: str = field(init=False) + """The service unique ID""" + + OWNER: str = "admin" + """The nickname of the admin of the service""" + + PASSWORD: str = "password" + """The password of the admin of the service""" + + JSONRPC_URL: str = None + """The RPC url, if local https://127.0.0.1:PORT/api should be fine""" + + JSONRPC_PATH_TO_SOCKET_FILE: str = None + """The full path of the socket file (/PATH/TO/YOUR/UNREALIRCD/SOCKET/FILE.socket)""" + + JSONRPC_METHOD: str = None + """3 methods are available; requests/socket/unixsocket""" + + JSONRPC_USER: str = None + """The RPC User defined in your unrealircd.conf""" + + JSONRPC_PASSWORD: str = None + """The RPC Password defined in your unrealircd.conf""" + + SALON_JAIL: str = "#jail" + """The JAIL channel (ex. #jail)""" + + SALON_JAIL_MODES: str = "sS" + """The jail channel modes (ex. sS)""" + + SALON_LIBERER: str = "#welcome" + """Channel where the nickname will be released""" + + CLONE_CHANNEL: str = "clones" + """Channel where clones are hosted and will log PRIVMSG""" + + CLONE_CMODES: str = "+nts" + """Clone channel modes (ex. +nts)""" + + CLONE_LOG_HOST_EXEMPT: list[str] = field(default_factory=list[str]) + """Hosts that clones will not log""" + + CLONE_CHANNEL_PASSWORD: str = "clone_Password_1234" + """Clone password channel""" + + API_TIMEOUT: int = 60 + """Default api timeout in second. (default: 60)""" + + PORTS_TO_SCAN: list[int] = field(default_factory=list[int]) + """List of ports to scan available for proxy_scan in the mod_defender module""" + + WHITELISTED_IP: list[str] = field(default_factory=list[str]) + """List of remote IP to don't scan""" + + GLINE_DURATION: str = "30" + """Gline duration""" + + DEBUG_LEVEL:Literal[10, 20, 30, 40, 50] = 20 + """Logs level: DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50. (default: 20)""" + + TABLE_ADMIN: str = "core_admin" + """Admin table""" + + TABLE_COMMAND: str = "core_command" + """Core command table""" + + TABLE_LOG: str = "core_log" + """Core log table""" + + TABLE_MODULE: str = "core_module" + """Core module table""" + + TABLE_CONFIG: str = "core_config" + """Core configuration table""" + + TABLE_CHANNEL: str = "core_channel" + """Core channel table""" + + CURRENT_VERSION: str = None + """Current version of Defender""" + + LATEST_VERSION: str = None + """The Latest version fetched from github""" + + DB_NAME: str = "defender" + """The database name""" + + DB_PATH: str = f"db{sep}" + """The database path""" + + COLORS: ColorModel = field(default_factory=ColorModel) + """Available colors in Defender""" + + BATCH_SIZE: int = 400 + """The batch size used for privmsg and notice""" + + DEFENDER_CONNEXION_DATETIME: datetime = field(default=datetime.now()) + """First Connexion datetime of the service""" + + DEFENDER_INIT: int = 1 + """Init flag. When Defender is ready, this variable will be set to 0. (default: 1)""" + + DEFENDER_RESTART: int = 0 + """Restart flag. When Defender should restart this variable should be set to 1 (default: 0)""" + + DEFENDER_HEARTBEAT: bool = True + """Activate the hearbeat pulse (default: True)""" + + DEFENDER_HEARTBEAT_FREQUENCY: int = 2 + """Frequency in seconds between every pulse (default: 30 seconds)""" + + OS_SEP: str = sep + """The OS Separator. (default: os.sep)""" + + HSID: str = None + """Host Server ID. The Server ID of the server who is hosting Defender. (Default: None)""" + + SSL_VERSION: str = None + """If SSL is used. This variable will be filled out by the system. (Default: None)""" + + def __post_init__(self): + # Initialiser SERVICE_ID après la création de l'objet + self.SERVICE_ID: str = f"{self.SERVEUR_ID}AAAAAB" + """The service ID which is SERVEUR_ID and AAAAAB""" + + self.SERVEUR_CHARSET: list = ["utf-8", "iso-8859-1"] + """0: utf-8 | 1: iso-8859-1""" + +@dataclass +class MClone: + """Model Clone""" + connected: bool = False + uid: str = None + nickname: str = None + username: str = None + realname: str = None + channels: list = field(default_factory=list) + vhost: str = None + hostname: str = 'localhost' + remote_ip: str = '127.0.0.1' + group: str = 'Default' diff --git a/core/installation.py b/core/installation.py index e988bd5..9b61ee6 100644 --- a/core/installation.py +++ b/core/installation.py @@ -37,6 +37,7 @@ class Install: self.set_configuration() if self.skip_install: + self.install_dependencies() self.check_packages_version() return None @@ -84,7 +85,7 @@ class Install: # If the Python version is not good then Exit exit("/!\\ Python version error /!\\") - if not os.path.exists(os.path.join(self.config.defender_install_folder, 'core', 'configuration.json')): + if not os.path.exists(os.path.join(self.config.defender_install_folder, 'config', 'configuration.json')): # If configuration file do not exist exit("/!\\ Configuration file (core/configuration.json) doesn't exist! please create it /!\\") diff --git a/core/irc.py b/core/irc.py index 844d4ff..ff060d1 100644 --- a/core/irc.py +++ b/core/irc.py @@ -9,37 +9,80 @@ import traceback from ssl import SSLSocket from datetime import datetime, timedelta from typing import Union -from core.loadConf import Config -from core.base import Base -from core.Model import User, Admin, Channel, Clones +from core.loader import Loader +from core.classes.protocol import Protocol class Irc: + _instance = None - def __init__(self) -> 'Irc': + def __new__(cls, *agrs): - self.defender_connexion_datetime = datetime.now() # Date et heure de la premiere connexion de Defender - self.first_score: int = 100 - self.loaded_classes:dict[str, 'Irc'] = {} # Definir la variable qui contiendra la liste modules chargés - self.beat = 30 # Lancer toutes les 30 secondes des actions de nettoyages - self.hb_active = True # Heartbeat active - self.HSID = '' # ID du serveur qui accueil le service ( Host Serveur Id ) - self.IrcSocket:Union[socket.socket, SSLSocket] = None + if cls._instance is None: + cls._instance = super().__new__(cls) - self.INIT = 1 # Variable d'intialisation | 1 -> indique si le programme est en cours d'initialisation - self.RESTART = 0 # Variable pour le redemarrage du bot | 0 -> indique que le programme n'es pas en cours de redemarrage - self.CHARSET = ['utf-8', 'iso-8859-1'] # Charset utiliser pour décoder/encoder les messages + return cls._instance + + def __init__(self, loader: Loader) -> 'Irc': + + # Loader class + self.Loader = loader + + # Load the configuration + self.Config = self.Loader.Config + + # Date et heure de la premiere connexion de Defender + self.defender_connexion_datetime = self.Config.DEFENDER_CONNEXION_DATETIME + + # Lancer toutes les 30 secondes des actions de nettoyages + self.beat = self.Config.DEFENDER_HEARTBEAT_FREQUENCY + + # Heartbeat active + self.hb_active = self.Config.DEFENDER_HEARTBEAT + + # ID du serveur qui accueil le service ( Host Serveur Id ) + self.HSID = self.Config.HSID + + # Charset utiliser pour décoder/encoder les messages + self.CHARSET = self.Config.SERVEUR_CHARSET """0: utf-8 | 1: iso-8859-1""" - self.SSL_VERSION = None # Version SSL + # Use Base Instance + self.Base = self.Loader.Base - self.Config = Config().ConfigObject + # Get Settings. + self.Settings = self.Base.Settings + + # Use User Instance + self.User = self.Loader.User + + # Use Admin Instance + self.Admin = self.Loader.Admin + + # Use Channel Instance + self.Channel = self.Loader.Channel + + # Use Clones Instance + self.Clone = self.Loader.Clone + + # Use Reputation Instance + self.Reputation = self.Loader.Reputation + + self.autolimit_started: bool = False + """This variable is to make sure the thread is not running""" + + self.first_score: int = 100 + + self.loaded_classes:dict[str, 'Irc'] = {} # Definir la variable qui contiendra la liste modules chargés + + self.IrcSocket:Union[socket.socket, SSLSocket] = None # Liste des commandes internes du bot self.commands_level = { 0: ['help', 'auth', 'copyright', 'uptime', 'firstauth'], 1: ['load','reload','unload', 'deauth', 'checkversion'], - 2: ['show_modules', 'show_timers', 'show_threads', 'show_channels', 'show_users', 'show_admins'], - 3: ['quit', 'restart','addaccess','editaccess', 'delaccess'] + 2: ['show_modules', 'show_timers', 'show_threads', 'show_channels', 'show_users', 'show_admins', 'show_configuration'], + 3: ['quit', 'restart','addaccess','editaccess', 'delaccess'], + 4: ['rehash'] } # l'ensemble des commandes. @@ -48,12 +91,6 @@ class Irc: for command in self.commands_level[level]: self.commands.append(command) - self.Base = Base(self.Config) - self.User = User(self.Base) - self.Admin = Admin(self.Base) - self.Channel = Channel(self.Base) - self.Clones = Clones(self.Base) - self.__create_table() self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, )) @@ -72,6 +109,18 @@ class Irc: except AssertionError as ae: self.Base.logs.critical(f'Assertion error: {ae}') + def init_service_user(self) -> None: + + self.User.insert(self.Loader.Definition.MUser( + uid=self.Config.SERVICE_ID, + nickname=self.Config.SERVICE_NICKNAME, + username=self.Config.SERVICE_USERNAME, + realname=self.Config.SERVICE_REALNAME, + hostname=self.Config.SERVICE_HOST, + umodes=self.Config.SERVICE_SMODES + )) + return None + def __create_socket(self) -> None: """Create a socket to connect SSL or Normal connection """ @@ -85,8 +134,8 @@ class Irc: ssl_connexion = ssl_context.wrap_socket(soc, server_hostname=self.Config.SERVEUR_HOSTNAME) ssl_connexion.connect(connexion_information) self.IrcSocket:SSLSocket = ssl_connexion - self.SSL_VERSION = self.IrcSocket.version() - self.Base.logs.info(f"Connexion en mode SSL : Version = {self.SSL_VERSION}") + self.Config.SSL_VERSION = self.IrcSocket.version() + self.Base.logs.info(f"Connexion en mode SSL : Version = {self.Config.SSL_VERSION}") else: soc.connect(connexion_information) self.IrcSocket:socket.socket = soc @@ -102,6 +151,9 @@ class Irc: self.Base.logs.critical(f"OSError: {oe} - {soc.fileno()}") if 'connection refused' in str(oe).lower(): sys.exit(oe) + if soc.fileno() == -1: + sys.exit(soc.fileno()) + except AttributeError as ae: self.Base.logs.critical(f"AttributeError: {ae} - {soc.fileno()}") @@ -116,15 +168,21 @@ class Irc: def __connect_to_irc(self, ircInstance: 'Irc') -> None: try: + + self.init_service_user() self.ircObject = ircInstance # créer une copie de l'instance Irc - self.__link(self.IrcSocket) # établir la connexion au serveur IRC + self.Protocol = Protocol( + protocol=self.Config.SERVEUR_PROTOCOL, + ircInstance=self.ircObject + ).Protocol + self.Protocol.link() # Etablir le link en fonction du protocol choisi self.signal = True # Une variable pour initier la boucle infinie self.__join_saved_channels() # Join existing channels self.load_existing_modules() # Charger les modules existant dans la base de données while self.signal: try: - if self.RESTART == 1: + if self.Config.DEFENDER_RESTART == 1: self.Base.logs.debug('Restarting Defender ...') self.IrcSocket.shutdown(socket.SHUT_RDWR) self.IrcSocket.close() @@ -135,14 +193,16 @@ class Irc: # Reload configuration self.Base.logs.debug('Reloading configuration') - self.Config = Config().ConfigObject - self.Base = Base(self.Config) + self.Config = self.Loader.ConfModule.Configuration().ConfigObject + self.Base = self.Loader.BaseModule.Base(self.Config) + self.Protocol = Protocol(self.Config.SERVEUR_PROTOCOL, ircInstance).Protocol + self.init_service_user() self.__create_socket() - self.__link(self.IrcSocket) + self.Protocol.link() self.__join_saved_channels() self.load_existing_modules() - self.RESTART = 0 + self.Config.DEFENDER_RESTART = 0 # 4072 max what the socket can grab buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) @@ -169,6 +229,8 @@ class Irc: self.Base.logs.error(f"SSLError __connect_to_irc: {se} - {data}") except OSError as oe: self.Base.logs.error(f"SSLError __connect_to_irc: {oe} - {data}") + except (socket.error, ConnectionResetError): + print("Connexion reset") self.IrcSocket.shutdown(socket.SHUT_RDWR) self.IrcSocket.close() @@ -187,59 +249,9 @@ class Irc: self.Base.logs.critical(f"General Error: {e}") self.Base.logs.critical(traceback.format_exc()) - def __link(self, writer:Union[socket.socket, SSLSocket]) -> None: - """Créer le link et envoyer les informations nécessaires pour la - connexion au serveur. - - Args: - writer (StreamWriter): permet l'envoi des informations au serveur. - """ - try: - nickname = self.Config.SERVICE_NICKNAME - username = self.Config.SERVICE_USERNAME - realname = self.Config.SERVICE_REALNAME - chan = self.Config.SERVICE_CHANLOG - info = self.Config.SERVICE_INFO - smodes = self.Config.SERVICE_SMODES - cmodes = self.Config.SERVICE_CMODES - umodes = self.Config.SERVICE_UMODES - host = self.Config.SERVICE_HOST - service_name = self.Config.SERVICE_NAME - - password = self.Config.SERVEUR_PASSWORD - link = self.Config.SERVEUR_LINK - sid = self.Config.SERVEUR_ID - service_id = self.Config.SERVICE_ID - - version = self.Config.current_version - unixtime = self.Base.get_unixtime() - charset = self.CHARSET[0] - - # Envoyer un message d'identification - writer.send(f":{sid} PASS :{password}\r\n".encode(charset)) - writer.send(f":{sid} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS\r\n".encode(charset)) - # writer.send(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS\r\n".encode(charset)) - writer.send(f":{sid} PROTOCTL EAUTH={link},,,{service_name}-v{version}\r\n".encode(charset)) - writer.send(f":{sid} PROTOCTL SID={sid}\r\n".encode(charset)) - writer.send(f":{sid} SERVER {link} 1 :{info}\r\n".encode(charset)) - writer.send(f":{sid} {nickname} :Reserved for services\r\n".encode(charset)) - #writer.send(f":{sid} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * * :{realname}\r\n".encode(charset)) - writer.send(f":{sid} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * fwAAAQ== :{realname}\r\n".encode(charset)) - writer.send(f":{sid} SJOIN {unixtime} {chan} + :{service_id}\r\n".encode(charset)) - writer.send(f":{sid} TKL + Q * {nickname} {host} 0 {unixtime} :Reserved for services\r\n".encode(charset)) - - writer.send(f":{service_id} MODE {chan} +{cmodes}\r\n".encode(charset)) - writer.send(f":{service_id} MODE {chan} +{umodes} {service_id}\r\n".encode(charset)) - - self.Base.logs.debug('>> Link information sent to the server') - - return None - except AttributeError as ae: - self.Base.logs.critical(f'{ae}') - def __join_saved_channels(self) -> None: """## Joining saved channels""" - core_table = self.Config.table_channel + core_table = self.Config.TABLE_CHANNEL query = f'''SELECT distinct channel_name FROM {core_table}''' exec_query = self.Base.db_execute_query(query) @@ -248,9 +260,9 @@ class Irc: if result_query: for chan_name in result_query: chan = chan_name[0] - self.send2socket(f":{self.Config.SERVEUR_ID} SJOIN {self.Base.get_unixtime()} {chan} + :{self.Config.SERVICE_ID}") + self.Protocol.sjoin(channel=chan) - def send2socket(self, send_message:str) -> None: + def send2socket(self, send_message:str, print_log: bool = True) -> None: """Envoit les commandes à envoyer au serveur. Args: @@ -259,7 +271,8 @@ class Irc: try: with self.Base.lock: self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0])) - self.Base.logs.debug(f'{send_message}') + if print_log: + self.Base.logs.debug(f'< {send_message}') except UnicodeDecodeError: self.Base.logs.error(f'Decode Error try iso-8859-1 - message: {send_message}') @@ -276,40 +289,40 @@ class Irc: except OSError as oe: self.Base.logs.error(f"OSError: {oe} - {send_message}") - def sendNotice(self, msg:str, nickname: str) -> None: - """Sending NOTICE by batches + # def sendNotice(self, msg:str, nickname: str) -> None: + # """Sending NOTICE by batches - Args: - msg (str): The message to send to the server - nickname (str): The reciever Nickname - """ - batch_size = self.Config.BATCH_SIZE - service_nickname = self.Config.SERVICE_NICKNAME + # Args: + # msg (str): The message to send to the server + # nickname (str): The reciever Nickname + # """ + # batch_size = self.Config.BATCH_SIZE + # service_nickname = self.Config.SERVICE_NICKNAME - for i in range(0, len(str(msg)), batch_size): - batch = str(msg)[i:i+batch_size] - self.send2socket(f":{service_nickname} NOTICE {nickname} :{batch}") + # for i in range(0, len(str(msg)), batch_size): + # batch = str(msg)[i:i+batch_size] + # # self.send2socket(f":{service_nickname} NOTICE {nickname} :{batch}") - def sendPrivMsg(self, msg: str, channel: str = None, nickname: str = None): - """Sending PRIVMSG to a channel or to a nickname by batches - could be either channel or nickname not both together - Args: - msg (str): The message to send - channel (str, optional): The receiver channel. Defaults to None. - nickname (str, optional): The reciever nickname. Defaults to None. - """ - batch_size = self.Config.BATCH_SIZE - service_nickname = self.Config.SERVICE_NICKNAME + # def sendPrivMsg(self, msg: str, channel: str = None, nickname: str = None): + # """Sending PRIVMSG to a channel or to a nickname by batches + # could be either channel or nickname not both together + # Args: + # msg (str): The message to send + # channel (str, optional): The receiver channel. Defaults to None. + # nickname (str, optional): The reciever nickname. Defaults to None. + # """ + # batch_size = self.Config.BATCH_SIZE + # service_nickname = self.Config.SERVICE_NICKNAME - if not channel is None: - for i in range(0, len(str(msg)), batch_size): - batch = str(msg)[i:i+batch_size] - self.send2socket(f":{service_nickname} PRIVMSG {channel} :{batch}") + # if not channel is None: + # for i in range(0, len(str(msg)), batch_size): + # batch = str(msg)[i:i+batch_size] + # # self.send2socket(f":{service_nickname} PRIVMSG {channel} :{batch}") - if not nickname is None: - for i in range(0, len(str(msg)), batch_size): - batch = str(msg)[i:i+batch_size] - self.send2socket(f":{service_nickname} PRIVMSG {nickname} :{batch}") + # if not nickname is None: + # for i in range(0, len(str(msg)), batch_size): + # batch = str(msg)[i:i+batch_size] + # # self.send2socket(f":{service_nickname} PRIVMSG {nickname} :{batch}") def send_response(self, responses:list[bytes]) -> None: try: @@ -354,7 +367,7 @@ class Irc: Returns: None: Aucun retour requis, elle charge puis c'est tout """ - result = self.Base.db_execute_query(f"SELECT module_name FROM {self.Config.table_module}") + result = self.Base.db_execute_query(f"SELECT module_name FROM {self.Config.TABLE_MODULE}") for r in result.fetchall(): self.load_module('sys', r[0], True) @@ -383,7 +396,6 @@ class Irc: time.sleep(beat) service_id = self.Config.SERVICE_ID hsid = self.HSID - # self.send2socket(f':{service_id} PING :{hsid}') self.Base.execute_periodic_action() def create_ping_timer(self, time_to_wait:float, class_name:str, method_name: str, method_args: list=[]) -> None: @@ -436,7 +448,7 @@ class Irc: """ service_id = self.Config.SERVICE_ID hsid = self.HSID - self.send2socket(f':{service_id} PING :{hsid}') + self.Protocol.send2socket(f':{service_id} PING :{hsid}') return None @@ -454,7 +466,11 @@ class Irc: self.Base.logs.info('module name = ' + module_name) if class_name in self.loaded_classes: # Si le module existe dans la variable globale retourne False - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self.Config.SERVICE_PREFIX}reload {module_name}") + self.Protocol.sendPrivMsg( + nick_from=self.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}", + channel=self.Config.SERVICE_CHANLOG + ) return False the_module = sys.modules['mods.' + module_name] @@ -467,7 +483,11 @@ class Irc: if not init: self.Base.db_record_module(fromuser, module_name) - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} chargé") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Module {module_name} chargé", + channel=self.Config.SERVICE_CHANLOG + ) return False # Charger le module @@ -477,7 +497,11 @@ class Irc: create_instance_of_the_class = my_class(self.ircObject) # Créer une nouvelle instance de la classe if not hasattr(create_instance_of_the_class, 'cmd'): - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} ne contient pas de méthode cmd") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Module {module_name} ne contient pas de méthode cmd", + channel=self.Config.SERVICE_CHANLOG + ) self.Base.logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available") self.Base.db_delete_module(module_name) return False @@ -488,7 +512,11 @@ class Irc: # Enregistrer le module dans la base de données if not init: self.Base.db_record_module(fromuser, module_name) - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} chargé") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Module {module_name} chargé", + channel=self.Config.SERVICE_CHANLOG + ) # self.Base.logs.info(self.loaded_classes) self.Base.logs.info(f"Module {class_name} has been loaded") @@ -496,11 +524,19 @@ class Irc: except ModuleNotFoundError as moduleNotFound: self.Base.logs.error(f"MODULE_NOT_FOUND: {moduleNotFound}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.COLORS.red}MODULE_NOT_FOUND{self.Config.COLORS.black} ]: {moduleNotFound}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[ {self.Config.COLORS.red}MODULE_NOT_FOUND{self.Config.COLORS.black} ]: {moduleNotFound}", + channel=self.Config.SERVICE_CHANLOG + ) self.Base.db_delete_module(module_name) except Exception as e: self.Base.logs.error(f"Something went wrong with a module you want to load : {e}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.COLORS.red}ERROR{self.Config.COLORS.black} ]: {e}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[ {self.Config.COLORS.red}ERROR{self.Config.COLORS.black} ]: {e}", + channel=self.Config.SERVICE_CHANLOG + ) def unload_module(self, mod_name: str) -> bool: """Unload a module @@ -528,7 +564,11 @@ class Irc: # Supprimer le module de la base de données self.Base.db_delete_module(module_name) - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} supprimé") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Module {module_name} supprimé", + channel=self.Config.SERVICE_CHANLOG + ) return True except Exception as err: @@ -563,26 +603,50 @@ class Irc: self.loaded_classes[class_name] = new_instance self.Base.db_update_module(from_user, mod_name) - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} rechargé") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Module {module_name} rechargé", + channel=self.Config.SERVICE_CHANLOG + ) return False else: - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} n'est pas chargé !") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Module {module_name} n'est pas chargé !", + channel=self.Config.SERVICE_CHANLOG + ) except TypeError as te: self.Base.logs.error(f"A TypeError raised: {te}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :A TypeError raised: {te}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"A TypeError raised: {te}", + channel=self.Config.SERVICE_CHANLOG + ) self.Base.db_delete_module(module_name) except AttributeError as ae: self.Base.logs.error(f"Missing Attribute: {ae}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Missing Attribute: {ae}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Missing Attribute: {ae}", + channel=self.Config.SERVICE_CHANLOG + ) self.Base.db_delete_module(module_name) except KeyError as ke: self.Base.logs.error(f"Key Error: {ke}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Key Error: {ke}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Key Error: {ke}", + channel=self.Config.SERVICE_CHANLOG + ) self.Base.db_delete_module(module_name) except Exception as e: self.Base.logs.error(f"Something went wrong with a module you want to reload: {e}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Something went wrong with the module: {e}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Something went wrong with the module: {e}", + channel=self.Config.SERVICE_CHANLOG + ) self.Base.db_delete_module(module_name) def insert_db_admin(self, uid:str, level:int) -> None: @@ -590,25 +654,14 @@ class Irc: if self.User.get_User(uid) is None: return None - getUser = self.User.get_User(uid) + getUser = self.User.get_User_AsDict(uid) - nickname = getUser.nickname - username = getUser.username - hostname = getUser.hostname - umodes = getUser.umodes - vhost = getUser.vhost level = int(level) self.Admin.insert( - self.Admin.AdminModel( - uid=uid, - nickname=nickname, - username=username, - hostname=hostname, - umodes=umodes, - vhost=vhost, - level=level, - connexion_datetime=datetime.now() + self.Loader.Definition.MAdmin( + **getUser, + level=level ) ) @@ -645,24 +698,24 @@ class Irc: spassword = self.Base.crypt_password(password) mes_donnees = {'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) exist_user = r.fetchone() # On verifie si le user exist dans la base if not exist_user: mes_donnees = {'datetime': self.Base.get_datetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level} - self.Base.db_execute_query(f'''INSERT INTO {self.Config.table_admin} + self.Base.db_execute_query(f'''INSERT INTO {self.Config.TABLE_ADMIN} (createdOn, user, password, hostname, vhost, level) VALUES (:datetime, :user, :password, :hostname, :vhost, :level) ''', mes_donnees) response = f"{nickname} ajouté en tant qu'administrateur de niveau {level}" - self.send2socket(f':{self.Config.SERVICE_NICKNAME} NOTICE {nickname} : {response}') + self.Protocol.sendNotice(nick_from=self.Config.SERVICE_NICKNAME, nick_to=nickname, msg=response) self.Base.logs.info(response) return response else: response = f'{nickname} Existe déjà dans les users enregistrés' - self.send2socket(f':{self.Config.SERVICE_NICKNAME} NOTICE {nickname} : {response}') + self.Protocol.sendNotice(nick_from=self.Config.SERVICE_NICKNAME, nick_to=nickname, msg=response) self.Base.logs.info(response) return response @@ -714,10 +767,10 @@ class Irc: dnickname = self.Config.SERVICE_NICKNAME if self.Base.check_for_new_version(True): - self.send2socket(f':{dnickname} NOTICE {fromuser} : New Version available : {self.Config.current_version} >>> {self.Config.latest_version}') - self.send2socket(f':{dnickname} NOTICE {fromuser} : Please run (git pull origin main) in the current folder') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" New Version available : {self.Config.CURRENT_VERSION} >>> {self.Config.LATEST_VERSION}") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=" Please run (git pull origin main) in the current folder") else: - self.send2socket(f':{dnickname} NOTICE {fromuser} : You have the latest version of defender') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=" You have the latest version of defender") return None @@ -743,18 +796,17 @@ class Irc: if original_response[2] == 'PRIVMSG' and original_response[4] == ':auth': data_copy = original_response.copy() data_copy[6] = '**********' - self.Base.logs.debug(data_copy) + self.Base.logs.debug(f">> {data_copy}") else: - self.Base.logs.debug(original_response) + self.Base.logs.debug(f">> {original_response}") else: - self.Base.logs.debug(original_response) + self.Base.logs.debug(f">> {original_response}") match original_response[0]: case 'PING': # Sending PONG response to the serveur - pong = str(original_response[1]).replace(':','') - self.send2socket(f"PONG :{pong}") + self.Protocol.on_server_ping(original_response) return None case 'PROTOCTL': @@ -766,6 +818,7 @@ class Irc: if '=' in original_response[5]: serveur_hosting_id = str(original_response[5]).split('=') self.HSID = serveur_hosting_id[1] + self.Config.HSID = serveur_hosting_id[1] return False case _: @@ -800,14 +853,14 @@ class Irc: server_uid = self.Base.clean_uid(original_response[5]) self.Channel.insert( - self.Channel.ChannelModel( + self.Loader.Definition.MChannel( name=channel_joined, uids=[server_uid] ) ) case 'REPUTATION': - # :001 REPUTATION 91.168.141.239 118 + # :001 REPUTATION 127.0.0.1 118 try: self.first_connexion_ip = original_response[2] @@ -844,10 +897,10 @@ class Irc: case 'EOS': hsid = str(original_response[0]).replace(':','') - if hsid == self.HSID: - if self.INIT == 1: - current_version = self.Config.current_version - latest_version = self.Config.latest_version + if hsid == self.Config.HSID: + if self.Config.DEFENDER_INIT == 1: + current_version = self.Config.CURRENT_VERSION + latest_version = self.Config.LATEST_VERSION if self.Base.check_for_new_version(False): version = f'{current_version} >>> {latest_version}' else: @@ -858,7 +911,7 @@ class Irc: print(f"# SERVEUR : {self.Config.SERVEUR_IP} ") print(f"# PORT : {self.Config.SERVEUR_PORT} ") print(f"# SSL : {self.Config.SERVEUR_SSL} ") - print(f"# SSL VER : {self.SSL_VERSION} ") + print(f"# SSL VER : {self.Config.SSL_VERSION} ") print(f"# NICKNAME : {self.Config.SERVICE_NICKNAME} ") print(f"# CHANNEL : {self.Config.SERVICE_CHANLOG} ") print(f"# VERSION : {version} ") @@ -869,18 +922,26 @@ class Irc: self.Base.logs.info(f"# SERVEUR : {self.Config.SERVEUR_IP} ") self.Base.logs.info(f"# PORT : {self.Config.SERVEUR_PORT} ") self.Base.logs.info(f"# SSL : {self.Config.SERVEUR_SSL} ") - self.Base.logs.info(f"# SSL VER : {self.SSL_VERSION} ") + self.Base.logs.info(f"# SSL VER : {self.Config.SSL_VERSION} ") self.Base.logs.info(f"# NICKNAME : {self.Config.SERVICE_NICKNAME} ") self.Base.logs.info(f"# CHANNEL : {self.Config.SERVICE_CHANLOG} ") self.Base.logs.info(f"# VERSION : {version} ") self.Base.logs.info(f"################################################") if self.Base.check_for_new_version(False): - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} : New Version available {version}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f" New Version available {version}", + channel=self.Config.SERVICE_CHANLOG + ) # Initialisation terminé aprés le premier PING - self.sendPrivMsg(msg=f'[{self.Config.COLORS.green}INFORMATION{self.Config.COLORS.nogc}] >> Defender is ready', channel=self.Config.SERVICE_CHANLOG) - self.INIT = 0 + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[{self.Config.COLORS.green}INFORMATION{self.Config.COLORS.nogc}] >> Defender is ready", + channel=self.Config.SERVICE_CHANLOG + ) + self.Config.DEFENDER_INIT = 0 # Send EOF to other modules for classe_name, classe_object in self.loaded_classes.items(): @@ -897,6 +958,10 @@ class Irc: match original_response[2]: + case 'VERSION': + + self.Protocol.on_version_msg(original_response) + case 'QUIT': # :001N1WD7L QUIT :Quit: free_znc_1 @@ -954,7 +1019,7 @@ class Irc: list_users.append(parsed_UID) self.Channel.insert( - self.Channel.ChannelModel( + self.Loader.Definition.MChannel( name=channel, uids=list_users ) @@ -1011,7 +1076,7 @@ class Irc: score_connexion = self.first_score self.User.insert( - self.User.UserModel( + self.Loader.Definition.MUser( uid=uid, nickname=nickname, username=username, @@ -1047,11 +1112,11 @@ class Irc: if cmd[1] == 'PRIVMSG' and str(cmd[3]).replace(self.Config.SERVICE_PREFIX,'') == ':auth': cmd_copy = cmd.copy() cmd_copy[5] = '**********' - self.Base.logs.info(cmd_copy) + self.Base.logs.info(f'>> {cmd_copy}') else: - self.Base.logs.info(cmd) + self.Base.logs.info(f'>> {cmd}') else: - self.Base.logs.info(f'{cmd}') + self.Base.logs.info(f'>> {cmd}') pattern = fr'(:\{self.Config.SERVICE_PREFIX})(.*)$' hcmds = re.search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . @@ -1063,13 +1128,17 @@ class Irc: arg.remove(f':{self.Config.SERVICE_PREFIX}') if not arg[0].lower() in self.commands: self.Base.logs.debug(f"This command {arg[0]} is not available") - self.sendNotice(f"This command [{self.Config.COLORS.bold}{arg[0]}{self.Config.COLORS.bold}] is not available", user_trigger) + self.Protocol.sendNotice( + nick_from=self.Config.SERVICE_NICKNAME, + nick_to=user_trigger, + msg=f"This command [{self.Config.COLORS.bold}{arg[0]}{self.Config.COLORS.bold}] is not available" + ) return None cmd_to_send = convert_to_string.replace(':','') self.Base.log_cmd(user_trigger, cmd_to_send) - fromchannel = str(cmd[2]).lower() if self.Base.Is_Channel(cmd[2]) else None + fromchannel = str(cmd[2]).lower() if self.Channel.Is_Channel(cmd[2]) else None self._hcmds(user_trigger, fromchannel, arg, cmd) if cmd[2] == self.Config.SERVICE_ID: @@ -1084,23 +1153,17 @@ class Irc: # Réponse a un CTCP VERSION if arg[0] == '\x01VERSION\x01': - self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01VERSION Service {self.Config.SERVICE_NICKNAME} V{self.Config.current_version}\x01') + self.Protocol.on_version(original_response) return False # Réponse a un TIME if arg[0] == '\x01TIME\x01': - current_datetime = self.Base.get_datetime() - self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01TIME {current_datetime}\x01') + self.Protocol.on_time(original_response) return False # Réponse a un PING if arg[0] == '\x01PING': - recieved_unixtime = int(arg[1].replace('\x01','')) - current_unixtime = self.Base.get_unixtime() - ping_response = current_unixtime - recieved_unixtime - - self.send2socket(f'PONG :{recieved_unixtime}') - self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01PING {ping_response} secs\x01') + self.Protocol.on_ping(original_response) return False if not arg[0].lower() in self.commands: @@ -1112,7 +1175,7 @@ class Irc: fromchannel = None if len(arg) >= 2: - fromchannel = str(arg[1]).lower() if self.Base.Is_Channel(arg[1]) else None + fromchannel = str(arg[1]).lower() if self.Channel.Is_Channel(arg[1]) else None self._hcmds(user_trigger, fromchannel, arg, cmd) @@ -1172,8 +1235,18 @@ class Irc: case 'notallowed': try: current_command = cmd[0] - self.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}{current_command}{self.Config.COLORS.black} ] - Accès Refusé à {self.User.get_nickname(fromuser)}') - self.send2socket(f':{dnickname} NOTICE {fromuser} : Accès Refusé') + self.Protocol.sendPrivMsg( + msg=f'[ {self.Config.COLORS.red}{current_command}{self.Config.COLORS.black} ] - Accès Refusé à {self.User.get_nickname(fromuser)}', + nick_from=dnickname, + channel=dchanlog + ) + + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f'Accès Refusé' + ) + except IndexError as ie: self.Base.logs.error(f'{ie}') @@ -1182,7 +1255,12 @@ class Irc: current_command = cmd[0] uid_to_deauth = self.User.get_uid(fromuser) self.delete_db_admin(uid_to_deauth) - self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais déconnecter de {dnickname}") + + self.Protocol.sendPrivMsg( + msg=f"[ {self.Config.COLORS.red}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais déconnecter de {dnickname}", + nick_from=dnickname, + channel=dchanlog + ) case 'firstauth': # firstauth OWNER_NICKNAME OWNER_PASSWORD @@ -1190,12 +1268,16 @@ class Irc: current_uid = self.User.get_uid(fromuser) current_command = str(cmd[0]) - query = f"SELECT count(id) as c FROM {self.Config.table_admin}" + query = f"SELECT count(id) as c FROM {self.Config.TABLE_ADMIN}" result = self.Base.db_execute_query(query) result_db = result.fetchone() if result_db[0] > 0: - self.send2socket(f":{dnickname} NOTICE {fromuser} :You can't use this command anymore ! Please use [{self.Config.SERVICE_PREFIX}auth] instead") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"You can't use this command anymore ! Please use [{self.Config.SERVICE_PREFIX}auth] instead" + ) return False if current_nickname is None: @@ -1212,27 +1294,57 @@ class Irc: if current_nickname != cmd_owner: self.Base.logs.critical(f"The current nickname [{fromuser}] is different than the nickname sent [{cmd_owner}] !") - self.send2socket(f":{dnickname} NOTICE {fromuser} :The current nickname [{fromuser}] is different than the nickname sent [{cmd_owner}] !") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"The current nickname [{fromuser}] is different than the nickname sent [{cmd_owner}] !" + ) return False if current_nickname != config_owner: self.Base.logs.critical(f"The current nickname [{current_nickname}] is different than the configuration owner [{config_owner}] !") - self.send2socket(f":{dnickname} NOTICE {fromuser} :The current nickname [{current_nickname}] is different than the configuration owner [{config_owner}] !") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"The current nickname [{current_nickname}] is different than the configuration owner [{config_owner}] !" + ) return False if cmd_owner != config_owner: self.Base.logs.critical(f"The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !") - self.send2socket(f":{dnickname} NOTICE {fromuser} :The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !" + ) return False if cmd_owner == config_owner and cmd_password == config_password: self.Base.db_create_first_admin() self.insert_db_admin(current_uid, 5) - self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Connexion a {dnickname} réussie!") + self.Protocol.sendPrivMsg( + msg=f"[ {self.Config.COLORS.green}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}", + nick_from=dnickname, + channel=dchanlog + ) + + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"Connexion a {dnickname} réussie!" + ) else: - self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} a tapé un mauvais mot de pass") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Mot de passe incorrecte") + self.Protocol.sendPrivMsg( + msg=f"[ {self.Config.COLORS.red}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} a tapé un mauvais mot de pass", + nick_from=dnickname, + channel=dchanlog + ) + + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"Mot de passe incorrecte" + ) case 'auth': # ['auth', 'adator', 'password'] @@ -1242,48 +1354,53 @@ class Irc: if fromuser != user_to_log: # If the current nickname is different from the nickname you want to log in with - self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Your current nickname is different from the nickname you want to log in with") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Your current nickname is different from the nickname you want to log in with") return False if not user_to_log is None: mes_donnees = {'user': user_to_log, 'password': self.Base.crypt_password(password)} - query = f"SELECT id, level FROM {self.Config.table_admin} WHERE user = :user AND password = :password" + query = f"SELECT id, level FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password" result = self.Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if not user_from_db is None: uid_user = self.User.get_uid(user_to_log) self.insert_db_admin(uid_user, user_from_db[1]) - self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Connexion a {dnickname} réussie!") + self.Protocol.sendPrivMsg(nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}{str(current_command).upper()} ]{self.Config.COLORS.nogc} - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}", + channel=dchanlog) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Connexion a {dnickname} réussie!") else: - self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} a tapé un mauvais mot de pass") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Mot de passe incorrecte") + self.Protocol.sendPrivMsg(nick_from=dnickname, + msg=f"[ {self.Config.COLORS.red}{str(current_command).upper()} ]{self.Config.COLORS.nogc} - {self.User.get_nickname(fromuser)} a tapé un mauvais mot de pass", + channel=dchanlog) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Mot de passe incorrecte") else: - self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :L'utilisateur {user_to_log} n'existe pas") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"L'utilisateur {user_to_log} n'existe pas") case 'addaccess': try: # .addaccess adator 5 password if len(cmd) < 4: - self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]') - self.send2socket(f':{dnickname} NOTICE {fromuser} : level: from 1 to 4') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} addaccess [nickname] [level] [password]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4") newnickname = cmd[1] newlevel = self.Base.int_if_possible(cmd[2]) password = cmd[3] response = self.create_defender_user(newnickname, newlevel, password) - self.send2socket(f':{dnickname} NOTICE {fromuser} : {response}') + + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"{response}") self.Base.logs.info(response) except IndexError as ie: self.Base.logs.error(f'_hcmd addaccess: {ie}') - self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") except TypeError as te: self.Base.logs.error(f'_hcmd addaccess: out of index : {te}') - self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") case 'editaccess': # .editaccess [USER] [PASSWORD] [LEVEL] @@ -1293,12 +1410,12 @@ class Irc: user_password = self.Base.crypt_password(cmd[2]) if len(cmd) < 4 or len(cmd) > 4: - self.send2socket(f':{dnickname} NOTICE {fromuser} : .editaccess [USER] [NEWPASSWORD] [NEWLEVEL]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}editaccess [USER] [NEWPASSWORD] [NEWLEVEL]") return None get_admin = self.Admin.get_Admin(fromuser) if get_admin is None: - self.send2socket(f':{dnickname} NOTICE {fromuser} : This user {fromuser} has no Admin access') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" This user {fromuser} has no Admin access") return None current_user = self.User.get_nickname(fromuser) @@ -1306,39 +1423,40 @@ class Irc: current_user_level = get_admin.level if user_new_level > 5: - self.send2socket(f':{dnickname} NOTICE {fromuser} : Maximum authorized level is 5') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Maximum authorized level is 5") return None # Rechercher le user dans la base de données. mes_donnees = {'user': user_to_edit} - query = f"SELECT user, level FROM {self.Config.table_admin} WHERE user = :user" + query = f"SELECT user, level FROM {self.Config.TABLE_ADMIN} WHERE user = :user" result = self.Base.db_execute_query(query, mes_donnees) isUserExist = result.fetchone() if not isUserExist is None: if current_user_level < int(isUserExist[1]): - self.send2socket(f':{dnickname} NOTICE {fromuser} : You are not allowed to edit this access') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" You are not allowed to edit this access") return None if current_user_level == int(isUserExist[1]) and current_user != user_to_edit: - self.send2socket(f":{dnickname} NOTICE {fromuser} : You can't edit access of a user with same level") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" You can't edit access of a user with same level") return None # Le user existe dans la base de données data_to_update = {'user': user_to_edit, 'password': user_password, 'level': user_new_level} - sql_update = f"UPDATE {self.Config.table_admin} SET level = :level, password = :password WHERE user = :user" + sql_update = f"UPDATE {self.Config.TABLE_ADMIN} SET level = :level, password = :password WHERE user = :user" exec_query = self.Base.db_execute_query(sql_update, data_to_update) if exec_query.rowcount > 0: - self.send2socket(f':{dnickname} NOTICE {fromuser} : User {user_to_edit} has been modified with level {str(user_new_level)}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" User {user_to_edit} has been modified with level {str(user_new_level)}") + self.Admin.update_level(user_to_edit, user_new_level) else: - self.send2socket(f":{dnickname} NOTICE {fromuser} : Impossible de modifier l'utilisateur {str(user_new_level)}") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Impossible de modifier l'utilisateur {str(user_new_level)}") except TypeError as te: self.Base.logs.error(f"Type error : {te}") except ValueError as ve: self.Base.logs.error(f"Value Error : {ve}") - self.send2socket(f':{dnickname} NOTICE {fromuser} : .editaccess [USER] [NEWPASSWORD] [NEWLEVEL]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" {self.Config.SERVICE_PREFIX}editaccess [USER] [NEWPASSWORD] [NEWLEVEL]") case 'delaccess': # .delaccess [USER] [CONFIRMUSER] @@ -1346,18 +1464,18 @@ class Irc: user_confirmation = cmd[2] if user_to_del != user_confirmation: - self.send2socket(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer") self.Base.logs.warning(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer') return None if len(cmd) < 3: - self.send2socket(f':{dnickname} NOTICE {fromuser} : .delaccess [USER] [CONFIRMUSER]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}delaccess [USER] [CONFIRMUSER]") return None - + get_admin = self.Admin.get_Admin(fromuser) - + if get_admin is None: - self.send2socket(f':{dnickname} NOTICE {fromuser} : This user {fromuser} has no admin access') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no admin access") return None current_user = self.User.get_nickname(fromuser) @@ -1366,24 +1484,25 @@ class Irc: # Rechercher le user dans la base de données. mes_donnees = {'user': user_to_del} - query = f"SELECT user, level FROM {self.Config.table_admin} WHERE user = :user" + query = f"SELECT user, level FROM {self.Config.TABLE_ADMIN} WHERE user = :user" result = self.Base.db_execute_query(query, mes_donnees) info_user = result.fetchone() - + if not info_user is None: level_user_to_del = info_user[1] if current_user_level <= level_user_to_del: - self.send2socket(f':{dnickname} NOTICE {fromuser} : You are not allowed to delete this access') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"You are not allowed to delete this access") self.Base.logs.warning(f':{dnickname} NOTICE {fromuser} : You are not allowed to delete this access') return None data_to_delete = {'user': user_to_del} - sql_delete = f"DELETE FROM {self.Config.table_admin} WHERE user = :user" + sql_delete = f"DELETE FROM {self.Config.TABLE_ADMIN} WHERE user = :user" exec_query = self.Base.db_execute_query(sql_delete, data_to_delete) if exec_query.rowcount > 0: - self.send2socket(f':{dnickname} NOTICE {fromuser} : User {user_to_del} has been deleted !') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"User {user_to_del} has been deleted !") + self.Admin.delete(user_to_del) else: - self.send2socket(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Impossible de supprimer l'utilisateur.") self.Base.logs.warning(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.") case 'help': @@ -1395,25 +1514,27 @@ class Irc: else: user_level = 0 - self.send2socket(f':{dnickname} NOTICE {fromuser} : ***************** LISTE DES COMMANDES *****************') - self.send2socket(f':{dnickname} NOTICE {fromuser} : ') + self.Protocol.sendNotice(nick_from=dnickname,nick_to=fromuser,msg=f" ***************** LISTE DES COMMANDES *****************") + self.Protocol.sendNotice(nick_from=dnickname,nick_to=fromuser,msg=f" ") for levDef in self.commands_level: if int(user_level) >= int(count_level_definition): - self.send2socket(f':{dnickname} NOTICE {fromuser} : ***************** {self.Config.COLORS.nogc}[ {self.Config.COLORS.green}LEVEL {str(levDef)} {self.Config.COLORS.nogc}] *****************') + self.Protocol.sendNotice(nick_from=dnickname,nick_to=fromuser, + msg=f" ***************** {self.Config.COLORS.nogc}[ {self.Config.COLORS.green}LEVEL {str(levDef)} {self.Config.COLORS.nogc}] *****************" + ) batch = 7 for i in range(0, len(self.commands_level[count_level_definition]), batch): groupe = self.commands_level[count_level_definition][i:i + batch] # Extraire le groupe batch_commands = ' | '.join(groupe) - self.send2socket(f':{dnickname} NOTICE {fromuser} : {batch_commands}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" {batch_commands}") - self.send2socket(f':{dnickname} NOTICE {fromuser} : ') + self.Protocol.sendNotice(nick_from=dnickname,nick_to=fromuser,msg=f" ") count_level_definition += 1 - self.send2socket(f':{dnickname} NOTICE {fromuser} : ***************** FIN DES COMMANDES *****************') + self.Protocol.sendNotice(nick_from=dnickname,nick_to=fromuser,msg=f" ***************** FIN DES COMMANDES *****************") case 'load': try: @@ -1440,31 +1561,35 @@ class Irc: self.reload_module(from_user=fromuser, mod_name=module_name) except Exception as e: self.Base.logs.error(f"Something went wrong with a module you want to reload: {e}") - self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Something went wrong with the module: {e}") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"Something went wrong with the module: {e}", + channel=dchanlog + ) self.Base.db_delete_module(module_name) case 'quit': try: - reason = [] - for i in range(1, len(cmd)): - reason.append(cmd[i]) - final_reason = ' '.join(reason) + + final_reason = ' '.join(cmd[1:]) self.hb_active = False self.Base.shutdown() self.Base.execute_periodic_action() - self.send2socket(f':{dnickname} NOTICE {fromuser} : Arrêt du service {dnickname}') - self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}') + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"Arrêt du service {dnickname}" + ) + self.Protocol.squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason) self.Base.logs.info(f'Arrêt du server {dnickname}') - self.RESTART = 0 + self.Config.DEFENDER_RESTART = 0 self.signal = False except IndexError as ie: self.Base.logs.error(f'{ie}') - self.send2socket(f"QUIT Good bye") - case 'restart': reason = [] for i in range(1, len(cmd)): @@ -1477,12 +1602,83 @@ class Irc: for class_name in self.loaded_classes: self.loaded_classes[class_name].unload() - self.send2socket(f':{dnickname} NOTICE {fromuser} : Redémarrage du service {dnickname}') - self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}') + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"Redémarrage du service {dnickname}" + ) + + self.Protocol.squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason) self.Base.logs.info(f'Redémarrage du server {dnickname}') self.loaded_classes.clear() - self.RESTART = 1 # Set restart status to 1 saying that the service will restart - self.INIT = 1 # set init to 1 saying that the service will be re initiated + self.Config.DEFENDER_RESTART = 1 # Set restart status to 1 saying that the service will restart + self.Config.DEFENDER_INIT = 1 # set init to 1 saying that the service will be re initiated + + case 'rehash': + need_a_restart = ["SERVEUR_ID"] + restart_flag = False + Config_bakcup = self.Config.__dict__.copy() + serveur_id = self.Config.SERVEUR_ID + service_nickname = self.Config.SERVICE_NICKNAME + hsid = self.Config.HSID + ssl_version = self.Config.SSL_VERSION + defender_init = self.Config.DEFENDER_INIT + defender_restart = self.Config.DEFENDER_RESTART + current_version = self.Config.CURRENT_VERSION + latest_version = self.Config.LATEST_VERSION + + mods = ["core.config", "core.base", "core.classes.protocols.unreal6", "core.classes.protocol"] + + mod_unreal6 = sys.modules['core.classes.protocols.unreal6'] + mod_protocol = sys.modules['core.classes.protocol'] + mod_base = sys.modules['core.base'] + mod_config = sys.modules['core.classes.config'] + + importlib.reload(mod_config) + self.Config = self.Loader.ConfModule.Configuration().ConfigObject + self.Config.HSID = hsid + self.Config.DEFENDER_INIT = defender_init + self.Config.DEFENDER_RESTART = defender_restart + self.Config.SSL_VERSION = ssl_version + self.Config.CURRENT_VERSION = current_version + self.Config.LATEST_VERSION = latest_version + importlib.reload(mod_base) + + conf_bkp_dict: dict = Config_bakcup + config_dict: dict = self.Config.__dict__ + + for key, value in conf_bkp_dict.items(): + if config_dict[key] != value: + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f'[{key}]: {value} ==> {config_dict[key]}', + channel=self.Config.SERVICE_CHANLOG + ) + if key in need_a_restart: + restart_flag = True + + if service_nickname != self.Config.SERVICE_NICKNAME: + self.Protocol.set_nick(self.Config.SERVICE_NICKNAME) + + if restart_flag: + self.Config.SERVEUR_ID = serveur_id + self.Protocol.sendPrivMsg(nick_from=self.Config.SERVICE_NICKNAME, msg='You need to restart defender !', channel=self.Config.SERVICE_CHANLOG) + + self.Base = self.Loader.BaseModule.Base(self.Config, self.Settings) + + importlib.reload(mod_unreal6) + importlib.reload(mod_protocol) + + self.Protocol = Protocol(self.Config.SERVEUR_PROTOCOL, self.ircObject).Protocol + + for mod in mods: + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f'> Module [{mod}] reloaded', + channel=self.Config.SERVICE_CHANLOG + ) + + self.reload_module(fromuser, 'mod_command') case 'show_modules': @@ -1490,7 +1686,7 @@ class Irc: all_modules = self.Base.get_all_modules() loaded = False - results = self.Base.db_execute_query(f'SELECT datetime, user, module_name FROM {self.Config.table_module}') + results = self.Base.db_execute_query(f'SELECT datetime, user, module_name FROM {self.Config.TABLE_MODULE}') results = results.fetchall() for module in all_modules: @@ -1501,23 +1697,43 @@ class Irc: loaded = True if loaded: - self.send2socket(f":{dnickname} NOTICE {fromuser} :{module} - {self.Config.COLORS.green}Loaded{self.Config.COLORS.nogc} by {loaded_user} on {loaded_datetime}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"{module} - {self.Config.COLORS.green}Loaded{self.Config.COLORS.nogc} by {loaded_user} on {loaded_datetime}" + ) loaded = False else: - self.send2socket(f":{dnickname} NOTICE {fromuser} :{module} - {self.Config.COLORS.red}Not Loaded{self.Config.COLORS.nogc}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"{module} - {self.Config.COLORS.red}Not Loaded{self.Config.COLORS.nogc}" + ) case 'show_timers': if self.Base.running_timers: for the_timer in self.Base.running_timers: - self.send2socket(f":{dnickname} NOTICE {fromuser} :>> {the_timer.getName()} - {the_timer.is_alive()}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f">> {the_timer.getName()} - {the_timer.is_alive()}" + ) else: - self.send2socket(f":{dnickname} NOTICE {fromuser} :Aucun timers en cours d'execution") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg="Aucun timers en cours d'execution" + ) case 'show_threads': for thread in self.Base.running_threads: - self.send2socket(f":{dnickname} NOTICE {fromuser} :>> {thread.getName()} ({thread.is_alive()})") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f">> {thread.getName()} ({thread.is_alive()})" + ) case 'show_channels': @@ -1528,22 +1744,56 @@ class Irc: parsed_UID = re.sub(pattern, '', uid) list_nicknames.append(self.User.get_nickname(parsed_UID)) - self.send2socket(f":{dnickname} NOTICE {fromuser} : Channel: {chan.name} - Users: {list_nicknames}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"Channel: {chan.name} - Users: {list_nicknames}" + ) case 'show_users': + count_users = len(self.User.UID_DB) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Total Connected Users: {count_users}") for db_user in self.User.UID_DB: - self.send2socket(f":{dnickname} NOTICE {fromuser} :UID : {db_user.uid} - isWebirc: {db_user.isWebirc} - isWebSocket: {db_user.isWebsocket} - Nickname: {db_user.nickname} - Connection: {db_user.connexion_datetime}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"UID : {db_user.uid} - isWebirc: {db_user.isWebirc} - isWebSocket: {db_user.isWebsocket} - Nickname: {db_user.nickname} - Connection: {db_user.connexion_datetime}" + ) case 'show_admins': + for db_admin in self.Admin.UID_ADMIN_DB: - self.send2socket(f":{dnickname} NOTICE {fromuser} :UID : {db_admin.uid} - Nickname: {db_admin.nickname} - Level: {db_admin.level} - Connection: {db_admin.connexion_datetime}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"UID : {db_admin.uid} - Nickname: {db_admin.nickname} - Level: {db_admin.level} - Connection: {db_admin.connexion_datetime}" + ) + + case 'show_configuration': + + config_dict = self.Config.__dict__ + + for key, value in config_dict.items(): + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f'{key} > {value}' + ) case 'uptime': uptime = self.get_defender_uptime() - self.send2socket(f':{dnickname} NOTICE {fromuser} : {uptime}') + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"{uptime}" + ) case 'copyright': - self.send2socket(f':{dnickname} NOTICE {fromuser} : # Defender V.{self.Config.current_version} Developped by adator® #') + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"# Defender V.{self.Config.CURRENT_VERSION} Developped by adator® #" + ) case 'checkversion': diff --git a/core/loadConf.py b/core/loadConf.py deleted file mode 100644 index cbf4d49..0000000 --- a/core/loadConf.py +++ /dev/null @@ -1,260 +0,0 @@ -import sys -import json -from os import sep -from typing import Union, Literal -from dataclasses import dataclass, field - -########################################## -# CONFIGURATION FILE # -########################################## - -@dataclass -class ColorModel: - white: str = "\x0300" - black: str = "\x0301" - blue: str = "\x0302" - green: str = "\x0303" - red: str = "\x0304" - yellow: str = "\x0306" - bold: str = "\x02" - nogc: str = "\x03" - -@dataclass -class ConfigDataModel: - - SERVEUR_IP: str - """Server public IP (could be 127.0.0.1 localhost)""" - - SERVEUR_HOSTNAME: str - """IRC Server Hostname (your.hostname.extension)""" - - SERVEUR_LINK: str - """The link hostname (should be the same as your unrealircd link block)""" - - SERVEUR_PORT: int - """Server port as configured in your unrealircd link block""" - - SERVEUR_PASSWORD: str - """Your link password""" - - SERVEUR_ID: str - """Service identification could be Z01 should be unique""" - - SERVEUR_SSL: bool - """Activate SSL connexion""" - - SERVICE_NAME: str - """Service name (Ex. Defender)""" - - SERVICE_NICKNAME: str - """Nickname of the service (Ex. Defender)""" - - SERVICE_REALNAME: str - """Realname of the service""" - - SERVICE_USERNAME: str - """Username of the service""" - - SERVICE_HOST: str - """The service hostname""" - - SERVICE_INFO: str - """Swhois of the service""" - - SERVICE_CHANLOG: str - """The channel used by the service (ex. #services)""" - - SERVICE_SMODES: str - """The service mode (ex. +ioqBS)""" - - SERVICE_CMODES: str - """The mode of the log channel (ex. ntsO)""" - - SERVICE_UMODES: str - """The mode of the service when joining chanlog (ex. o, the service will be operator in the chanlog)""" - - SERVICE_PREFIX: str - """The default prefix to communicate with the service""" - - SERVICE_ID: str = field(init=False) - """The service unique ID""" - - OWNER: str - """The nickname of the admin of the service""" - - PASSWORD: str - """The password of the admin of the service""" - - JSONRPC_URL: str - """The RPC url, if local https://127.0.0.1:PORT/api should be fine""" - - JSONRPC_PATH_TO_SOCKET_FILE: str - """The full path of the socket file (/PATH/TO/YOUR/UNREALIRCD/SOCKET/FILE.socket)""" - - JSONRPC_METHOD: str - """3 methods are available; requests/socket/unixsocket""" - - JSONRPC_USER: str - """The RPC User defined in your unrealircd.conf""" - - JSONRPC_PASSWORD: str - """The RPC Password defined in your unrealircd.conf""" - - SALON_JAIL: str - """The JAIL channel (ex. #jail)""" - - SALON_JAIL_MODES: str - """The jail channel modes (ex. sS)""" - - SALON_LIBERER: str - """Channel where the nickname will be released""" - - CLONE_CHANNEL: str - """Channel where clones are hosted and will log PRIVMSG""" - - CLONE_CMODES: str - """Clone channel modes""" - - CLONE_LOG_HOST_EXEMPT: list[str] - """Hosts that clones will not log""" - - CLONE_CHANNEL_PASSWORD: str - """Clone password channel""" - - API_TIMEOUT: int - """Default api timeout in second""" - - PORTS_TO_SCAN: list - """List of ports to scan available for proxy_scan in the mod_defender module""" - - WHITELISTED_IP: list - """List of remote IP to don't scan""" - - GLINE_DURATION: str - """Gline duration""" - - DEBUG_LEVEL:Literal[10, 20, 30, 40, 50] - """Logs level: DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50""" - - table_admin: str - """Admin table""" - - table_commande: str - """Core command table""" - - table_log: str - """Core log table""" - - table_module: str - """Core module table""" - - table_config: str - """Core configuration table""" - - table_channel: str - """Core channel table""" - - current_version: str - """Current version of Defender""" - - latest_version: str - """The Latest version fetched from github""" - - db_name: str - """The database name""" - - db_path: str - """The database path""" - - COLORS: ColorModel = field(default_factory=ColorModel) - """Available colors in Defender""" - - BATCH_SIZE: int = 400 - """The batch size used for privmsg and notice""" - - def __post_init__(self): - # Initialiser SERVICE_ID après la création de l'objet - self.SERVICE_ID:str = f"{self.SERVEUR_ID}AAAAAB" - """The service ID which is SERVEUR_ID and AAAAAB""" - -class Config: - - def __init__(self): - - self.ConfigObject: ConfigDataModel = self.__load_service_configuration() - return None - - def __load_json_service_configuration(self): - try: - conf_filename = f'core{sep}configuration.json' - with open(conf_filename, 'r') as configuration_data: - configuration:dict[str, Union[str, int, list, dict]] = json.load(configuration_data) - - return configuration - - except FileNotFoundError as fe: - print(f'FileNotFound: {fe}') - print('Configuration file not found please create core/configuration.json') - sys.exit(0) - except KeyError as ke: - print(f'Key Error: {ke}') - print('The key must be defined in core/configuration.json') - - def __load_service_configuration(self) -> ConfigDataModel: - import_config = self.__load_json_service_configuration() - - ConfigObject: ConfigDataModel = ConfigDataModel( - SERVEUR_IP=import_config["SERVEUR_IP"] if "SERVEUR_IP" in import_config else '127.0.0.1', - SERVEUR_HOSTNAME=import_config["SERVEUR_HOSTNAME"] if "SERVEUR_HOSTNAME" in import_config else None, - SERVEUR_LINK=import_config["SERVEUR_LINK"] if "SERVEUR_LINK" in import_config else None, - SERVEUR_PORT=import_config["SERVEUR_PORT"] if "SERVEUR_PORT" in import_config else 6667, - SERVEUR_PASSWORD=import_config["SERVEUR_PASSWORD"] if "SERVEUR_PASSWORD" in import_config else None, - SERVEUR_ID=import_config["SERVEUR_ID"] if "SERVEUR_ID" in import_config else '19Z', - SERVEUR_SSL=import_config["SERVEUR_SSL"] if "SERVEUR_SSL" in import_config else False, - SERVICE_NAME=import_config["SERVICE_NAME"] if "SERVICE_NAME" in import_config else 'Defender', - SERVICE_NICKNAME=import_config["SERVICE_NICKNAME"] if "SERVICE_NICKNAME" in import_config else 'Defender', - SERVICE_REALNAME=import_config["SERVICE_REALNAME"] if "SERVICE_REALNAME" in import_config else 'Defender Security', - SERVICE_USERNAME=import_config["SERVICE_USERNAME"] if "SERVICE_USERNAME" in import_config else 'IRCSecurity', - SERVICE_HOST=import_config["SERVICE_HOST"] if "SERVICE_HOST" in import_config else 'defender.local.network', - SERVICE_INFO=import_config["SERVICE_INFO"] if "SERVICE_INFO" in import_config else 'Defender Network IRC Service', - SERVICE_CHANLOG=import_config["SERVICE_CHANLOG"] if "SERVICE_CHANLOG" in import_config else '#services', - SERVICE_SMODES=import_config["SERVICE_SMODES"] if "SERVICE_SMODES" in import_config else '+ioqBS', - SERVICE_CMODES=import_config["SERVICE_CMODES"] if "SERVICE_CMODES" in import_config else 'ntsOP', - SERVICE_UMODES=import_config["SERVICE_UMODES"] if "SERVICE_UMODES" in import_config else 'o', - SERVICE_PREFIX=import_config["SERVICE_PREFIX"] if "SERVICE_PREFIX" in import_config else '!', - OWNER=import_config["OWNER"] if "OWNER" in import_config else 'admin', - PASSWORD=import_config["PASSWORD"] if "PASSWORD" in import_config else 'admin', - - JSONRPC_METHOD=import_config["JSONRPC_METHOD"] if "JSONRPC_METHOD" in import_config else 'socket', - JSONRPC_URL=import_config["JSONRPC_URL"] if "JSONRPC_URL" in import_config else None, - JSONRPC_PATH_TO_SOCKET_FILE=import_config["JSONRPC_PATH_TO_SOCKET_FILE"] if "JSONRPC_PATH_TO_SOCKET_FILE" in import_config else None, - JSONRPC_USER=import_config["JSONRPC_USER"] if "JSONRPC_USER" in import_config else None, - JSONRPC_PASSWORD=import_config["JSONRPC_PASSWORD"] if "JSONRPC_PASSWORD" in import_config else None, - - SALON_JAIL=import_config["SALON_JAIL"] if "SALON_JAIL" in import_config else '#jail', - SALON_JAIL_MODES=import_config["SALON_JAIL_MODES"] if "SALON_JAIL_MODES" in import_config else 'sS', - SALON_LIBERER=import_config["SALON_LIBERER"] if "SALON_LIBERER" in import_config else '#welcome', - - CLONE_CHANNEL=import_config["CLONE_CHANNEL"] if "CLONE_CHANNEL" in import_config else '#clones', - CLONE_CMODES=import_config["CLONE_CMODES"] if "CLONE_CMODES" in import_config else '+nts', - CLONE_LOG_HOST_EXEMPT=import_config["CLONE_LOG_HOST_EXEMPT"] if "CLONE_LOG_HOST_EXEMPT" in import_config else [], - CLONE_CHANNEL_PASSWORD=import_config["CLONE_CHANNEL_PASSWORD"] if "CLONE_CHANNEL_PASSWORD" in import_config else "clone_Password_1234", - - API_TIMEOUT=import_config["API_TIMEOUT"] if "API_TIMEOUT" in import_config else 2, - PORTS_TO_SCAN=import_config["PORTS_TO_SCAN"] if "PORTS_TO_SCAN" in import_config else [], - WHITELISTED_IP=import_config["WHITELISTED_IP"] if "WHITELISTED_IP" in import_config else ['127.0.0.1'], - GLINE_DURATION=import_config["GLINE_DURATION"] if "GLINE_DURATION" in import_config else '30', - DEBUG_LEVEL=import_config["DEBUG_LEVEL"] if "DEBUG_LEVEL" in import_config else 20, - table_admin='core_admin', - table_commande='core_command', - table_log='core_log', - table_module='core_module', - table_config='core_config', - table_channel='core_channel', - current_version='', - latest_version='', - db_name='defender', - db_path=f'db{sep}' - ) - - return ConfigObject diff --git a/core/loader.py b/core/loader.py new file mode 100644 index 0000000..759b49b --- /dev/null +++ b/core/loader.py @@ -0,0 +1,32 @@ +from core.classes import user, admin, channel, clone, reputation, settings +import core.definition as df +import core.base as baseModule +import core.classes.config as confModule + +class Loader: + + def __init__(self): + + # Load Modules + self.Definition: df = df + + self.ConfModule: confModule = confModule + + self.BaseModule: baseModule = baseModule + + # Load Classes + self.Settings: settings = settings.Settings() + + self.Config: df.MConfig = self.ConfModule.Configuration().ConfigObject + + self.Base: baseModule.Base = self.BaseModule.Base(self.Config, self.Settings) + + self.User: user.User = user.User(self.Base) + + self.Admin: admin.Admin = admin.Admin(self.Base) + + self.Channel: channel.Channel = channel.Channel(self.Base) + + self.Clone: clone.Clone = clone.Clone(self.Base) + + self.Reputation: reputation.Reputation = reputation.Reputation(self.Base) diff --git a/main.py b/defender.py similarity index 79% rename from main.py rename to defender.py index 6e5de0c..2c40dbd 100644 --- a/main.py +++ b/defender.py @@ -12,12 +12,19 @@ from core import installation # LANCEMENT DE DEFENDER # ######################### +# 1. Chargement de la configuration +# 2. Chargement de l'ensemble des classes +# 3. +# + try: installation.Install() + from core.loader import Loader from core.irc import Irc - ircInstance = Irc() + loader = Loader() + ircInstance = Irc(loader) ircInstance.init_irc(ircInstance) except AssertionError as ae: diff --git a/mods/mod_clone.py b/mods/mod_clone.py index 0facb8d..5360b46 100644 --- a/mods/mod_clone.py +++ b/mods/mod_clone.py @@ -1,9 +1,11 @@ from dataclasses import dataclass, fields, field +import copy import random, faker, time, logging from datetime import datetime -from typing import Union -from core.irc import Irc -from core.connection import Connection +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from core.irc import Irc class Clone(): @@ -11,7 +13,7 @@ class Clone(): class ModConfModel: clone_nicknames: list[str] - def __init__(self, ircInstance:Irc) -> None: + def __init__(self, ircInstance: 'Irc') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() @@ -19,6 +21,9 @@ class Clone(): # Add Irc Object to the module (Mandatory) self.Irc = ircInstance + # Add Irc Protocol Object to the module (Mandatory) + self.Protocol = ircInstance.Protocol + # Add Global Configuration to the module (Mandatory) self.Config = ircInstance.Config @@ -34,7 +39,10 @@ class Clone(): # Add Channel object to the module (Mandatory) self.Channel = ircInstance.Channel - self.Clone = ircInstance.Clones + # Add clone object to the module (Optionnal) + self.Clone = ircInstance.Clone + + self.Definition = ircInstance.Loader.Definition # Créer les nouvelles commandes du module self.commands_level = { @@ -55,14 +63,22 @@ class Clone(): # Créer les tables necessaire a votre module (ce n'es pas obligatoire) self.__create_tables() + self.CloneCopy = [self.Definition.MClone()] + self.stop = False + logging.getLogger('faker').setLevel(logging.CRITICAL) + + self.fakeEN = faker.Faker('en_GB') + self.fakeFR = faker.Faker('fr_FR') + # Load module configuration (Mandatory) self.__load_module_configuration() - self.Base.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} JOIN {self.Config.CLONE_CHANNEL}") - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.CLONE_CHANNEL} +o {self.Config.SERVICE_NICKNAME}") - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} +nts") - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} +k {self.Config.CLONE_CHANNEL_PASSWORD}") + self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) + self.Protocol.join(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL) + + self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.CLONE_CHANNEL} +o {self.Config.SERVICE_NICKNAME}") + self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} +nts") + self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} +k {self.Config.CLONE_CHANNEL_PASSWORD}") def __set_commands(self, commands:dict[int, list[str]]) -> None: """### Rajoute les commandes du module au programme principal @@ -96,7 +112,7 @@ class Clone(): ) ''' - self.Base.db_execute_query(table_channel) + # self.Base.db_execute_query(table_channel) return None @@ -122,163 +138,215 @@ class Clone(): rechargement de module """ - # kill all clones before unload - for clone in self.ModConfig.clone_nicknames: - self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone} :KILL') - - self.Base.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -nts") - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -k {self.Config.CLONE_CHANNEL_PASSWORD}") - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} PART {self.Config.CLONE_CHANNEL}") - return None - - def thread_clone_clean_up(self, wait: float): - - activated = True - - while activated: - clone_to_kill: list[str] = [] - - for clone in self.Clone.UID_CLONE_DB: - if not clone.connected and clone.alive and not clone.init: - clone_to_kill.append(clone.nickname) - clone.alive = False - - for clone_nickname in clone_to_kill: - if self.Clone.delete(clone_nickname): - self.Logs.debug(f'<<{clone_nickname}>> object has been deleted') - - del clone_to_kill - - # If no more clones then stop this thread - if not self.Clone.UID_CLONE_DB: - break - - time.sleep(wait) - - def thread_change_hostname(self): - - fake = faker.Faker('en_GB') - for clone in self.Clone.UID_CLONE_DB: - if not clone.vhost is None: - continue - - rand_1 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) - rand_2 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) - rand_3 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) - - rand_ip = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP' - found = False - - while not found: - if clone.connected: - self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} CHGHOST {clone.nickname} {rand_ip}') - found = True - clone.vhost = rand_ip - break - if not clone in self.Clone.UID_CLONE_DB: - found = True - break - - def thread_create_clones_with_interval(self, number_of_clones:int, channels: list, connection_interval: float): - - for i in range(number_of_clones): - nickname, username, realname = self.generate_names() - self.Base.create_thread( - self.thread_create_clones, - (nickname, username, realname, channels, 6697, True) - ) - time.sleep(connection_interval) - - self.Base.create_thread( - self.thread_change_hostname - ) - - # self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{str(number_of_clones)} clones joined the network') - - self.Base.create_thread(self.thread_clone_clean_up, (5, ), run_once=True) - - def thread_create_clones(self, nickname: str, username: str, realname: str, channels: list, server_port: int, ssl: bool) -> None: - - Connection(server_port=server_port, nickname=nickname, username=username, realname=realname, channels=channels, CloneObject=self.Clone, ssl=ssl) + self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) + self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -nts") + self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -k {self.Config.CLONE_CHANNEL_PASSWORD}") + self.Protocol.part(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL) return None - def thread_join_channels(self, channel_name: str, wait: float, clone_name:str = None): - self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Clones start to join {channel_name} with {wait} secondes frequency') - if clone_name is None: - for clone in self.Clone.UID_CLONE_DB: - if not channel_name in clone.channels: - time.sleep(wait) - self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone.nickname} :JOIN {channel_name}') - clone.channels.append(channel_name) - else: - for clone in self.Clone.UID_CLONE_DB: - if clone_name == clone.nickname: - if not channel_name in clone.channels: - time.sleep(wait) - self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone.nickname} :JOIN {channel_name}') - clone.channels.append(channel_name) + def generate_vhost(self) -> str: - def generate_names(self) -> tuple[str, str, str]: + fake = self.fakeEN + + rand_1 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) + rand_2 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) + rand_3 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) + + vhost = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP' + return vhost + + def generate_clones(self, group: str = 'Default') -> None: try: - logging.getLogger('faker').setLevel(logging.CRITICAL) - fake = faker.Faker('en_GB') - # nickname = fake.first_name() - # username = fake.last_name() + # :5TC UID Q 1 1727473203 qb4u localhost 5TC00000Q * Sdiop network/service/test * AAAAAAAAAAAAAAAAAAAAAQ== :qbot4u + + fakeEN = self.fakeEN + fakeFR = self.fakeFR + unixtime = self.Base.get_unixtime() + + chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + generate_uid = fakeEN.random_sample(chaine, 6) + uid = self.Config.SERVEUR_ID + ''.join(generate_uid) # Generate Username chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' - new_username = fake.random_sample(chaine, 9) + new_username = fakeEN.random_sample(chaine, 9) username = ''.join(new_username) # Create realname XX F|M Department - gender = fake.random_choices(['F','M'], 1) + gender = fakeEN.random_choices(['F','M'], 1) gender = ''.join(gender) - + if gender == 'F': - nickname = fake.first_name_female() + nickname = fakeEN.first_name_female() elif gender == 'M': - nickname = fake.first_name_male() + nickname = fakeEN.first_name_male() else: - nickname = fake.first_name() + nickname = fakeEN.first_name() age = random.randint(20, 60) - fake_fr = faker.Faker(['fr_FR', 'en_GB']) - department = fake_fr.department_name() + department = fakeFR.department_name() realname = f'{age} {gender} {department}' - if self.Clone.exists(nickname=nickname): + ip = self.Base.encode_ip(fakeEN.ipv4_private()) + + vhost = self.generate_vhost() + + checkNickname = self.Clone.exists(nickname=nickname) + checkUid = self.Clone.uid_exists(uid=uid) + + while checkNickname: caracteres = '0123456789' randomize = ''.join(random.choice(caracteres) for _ in range(2)) nickname = nickname + str(randomize) - self.Clone.insert( - self.Clone.CloneModel(alive=True, nickname=nickname, username=username, realname=realname, channels=[]) - ) - else: - self.Clone.insert( - self.Clone.CloneModel(alive=True, nickname=nickname, username=username, realname=realname, channels=[]) - ) + checkNickname = self.Clone.exists(nickname=nickname) - return (nickname, username, realname) + while checkUid: + chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + generate_uid = fakeEN.random_sample(chaine, 6) + uid = self.Config.SERVEUR_ID + ''.join(generate_uid) + checkUid = self.Clone.uid_exists(uid=uid) + + clone = self.Definition.MClone( + connected=False, + nickname=nickname, + username=username, + realname=realname, + uid=uid, + remote_ip=ip, + vhost=vhost, + group=group, + channels=[] + ) + + self.Clone.insert(clone) + self.CloneCopy.append(clone) + + return None except AttributeError as ae: self.Logs.error(f'Attribute Error : {ae}') except Exception as err: - self.Logs.error(err) + self.Logs.error(f"General Error: {err}") + + def thread_connect_clones(self, number_of_clones:int , group: str, interval: float = 0.2) -> None: + + for i in range(0, number_of_clones): + self.generate_clones(group=group) + + for clone in self.Clone.UID_CLONE_DB: + + if self.stop: + print(f"Stop creating clones ...") + self.stop = False + break + + if not clone.connected: + cloneObj_asdict = self.Clone.get_Clone_AsDict(clone.uid) + + for key in ['connected','group','channels']: + cloneObj_asdict.pop(key, None) + + self.User.insert( + self.Definition.MUser(**cloneObj_asdict) + ) + + self.Protocol.send2socket(f":{self.Config.SERVEUR_ID} UID {clone.nickname} 1 {self.Base.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * +ixwz {clone.vhost} * {clone.remote_ip} :{clone.realname}", False) + self.Protocol.join(uidornickname=clone.uid, channel=self.Config.CLONE_CHANNEL, password=self.Config.CLONE_CHANNEL_PASSWORD, print_log=False) + self.Irc.Channel.insert(self.Irc.Loader.Definition.MChannel(name=self.Config.CLONE_CHANNEL, uids=[clone.uid])) + + time.sleep(interval) + clone.connected = True + + def thread_kill_clones(self, fromuser: str) -> None: + + clone_to_kill: list[str] = [] + for clone in self.Clone.UID_CLONE_DB: + self.Protocol.send2socket(f':{clone.uid} QUIT :Goood bye', False) + clone_to_kill.append(clone.uid) + + for clone_uid in clone_to_kill: + self.Irc.Channel.delete_user_from_all_channel(clone_uid) + self.Clone.delete(clone_uid) + self.User.delete(clone_uid) + + del clone_to_kill + + self.clean_clones(fromuser) + + return None + + def clean_clones(self, fromuser: str) -> None: + + connected = 0 + for c in self.CloneCopy: + if c.connected: + connected += 1 + + self.Protocol.sendNotice(nick_from=self.Config.SERVICE_NICKNAME, nick_to=fromuser, msg=f"Clean in progress | Total Clones in memory {len(self.CloneCopy) - 1} - {connected} / {len(self.CloneCopy) - 1} Connected ...") + clone_to_kill: list[str] = [] + + # clean from Channels + for clone in self.CloneCopy: + self.Irc.Channel.delete_user_from_all_channel(clone.uid) + + # clean from users + for clone in self.CloneCopy: + self.Protocol.send2socket(f':{clone.uid} QUIT :Goood bye', False) + clone_to_kill.append(clone.uid) + + # clean original clone object + for clone_uid in clone_to_kill: + self.User.delete(clone_uid) + self.Clone.delete(clone_uid) + + self.CloneCopy = [self.Definition.MClone()] + self.Protocol.sendNotice(nick_from=self.Config.SERVICE_NICKNAME, nick_to=fromuser, + msg="Clone cleaning done!") + return None def cmd(self, data:list) -> None: + try: + service_id = self.Config.SERVICE_ID # Defender serveur id + cmd = list(data).copy() - service_id = self.Config.SERVICE_ID # Defender serveur id - cmd = list(data).copy() + if len(cmd) < 2: + return None - if len(cmd) < 2: - return None + match cmd[1]: - match cmd[1]: + case 'REPUTATION': + pass - case 'REPUTATION': - pass + if len(cmd) < 3: + return None + + match cmd[2]: + case 'PRIVMSG': + # print(cmd) + uid_sender = self.User.clean_uid(cmd[1]) + senderObj = self.User.get_User(uid_sender) + + if senderObj.hostname in self.Config.CLONE_LOG_HOST_EXEMPT: + return None + + if not senderObj is None: + senderMsg = ' '.join(cmd[4:]) + getClone = self.Clone.get_Clone(cmd[3]) + + if getClone is None: + return None + + if getClone.uid != self.Config.SERVICE_ID: + final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}" + self.Protocol.sendPrivMsg( + nick_from=senderObj.uid, + msg=final_message, + channel=self.Config.CLONE_CHANNEL + ) + + except Exception as err: + self.Base.logs.error(f'General Error: {err}') def _hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None: @@ -293,10 +361,11 @@ class Clone(): case 'clone': if len(cmd) == 1: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6 2.5') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | nickname]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list") option = str(cmd[1]).lower() @@ -304,46 +373,47 @@ class Clone(): case 'connect': try: - # clone connect 5 + # clone connect 5 Group 3 + self.stop = False number_of_clones = int(cmd[2]) - connection_interval = int(cmd[3]) if len(cmd) == 4 else 0.5 + group = str(cmd[3]).lower() + connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.5 + self.Base.create_thread( - self.thread_create_clones_with_interval, - (number_of_clones, [], connection_interval) - ) + func=self.thread_connect_clones, + func_args=(number_of_clones, group, connection_interval) + ) except Exception as err: self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect [number of clone you want to connect] [Connection Interval]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} clone connect 6 2.5') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance") case 'kill': try: # clone kill [all | nickname] + self.stop = True clone_name = str(cmd[2]) clone_to_kill: list[str] = [] if clone_name.lower() == 'all': - for clone in self.Clone.UID_CLONE_DB: - self.Irc.send2socket(f':{dnickname} PRIVMSG {clone.nickname} :KILL') - clone_to_kill.append(clone.nickname) - clone.alive = False - - for clone_nickname in clone_to_kill: - self.Clone.delete(clone_nickname) - - del clone_to_kill + self.Base.create_thread(func=self.thread_kill_clones, func_args=(fromuser, )) else: if self.Clone.exists(clone_name): - self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :KILL') - self.Clone.kill(clone_name) - self.Clone.delete(clone_name) + + self.Protocol.send2socket(f':{clone_name} QUIT :Goood bye') + + clone_uid = self.Clone.get_uid(clone_name) + if not clone_uid is None: + self.Irc.Channel.delete_user_from_all_channel(clone_uid) + self.Clone.delete(clone_name) + self.User.delete(clone_uid) except Exception as err: self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill all') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill clone_nickname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill all") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill clone_nickname") case 'join': try: @@ -352,21 +422,53 @@ class Clone(): clone_channel_to_join = str(cmd[3]) if clone_name.lower() == 'all': - self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2)) + + for clone in self.Clone.UID_CLONE_DB: + self.Protocol.join(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False) + self.Irc.Channel.insert(self.Irc.Loader.Definition.MChannel(name=clone_channel_to_join, uids=[clone.uid])) + else: - self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2, clone_name)) + if self.Clone.exists(clone_name): + if not self.Clone.get_uid(clone_name) is None: + self.Protocol.join(uidornickname=clone_name, channel=clone_channel_to_join, print_log=False) + self.Irc.Channel.insert(self.Irc.Loader.Definition.MChannel(name=clone_channel_to_join, uids=[self.Clone.get_uid(clone_name)])) except Exception as err: self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join all #channel') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join clone_nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join all #channel") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join clone_nickname #channel") + + case 'part': + try: + # clone part [all | nickname] #channel + clone_name = str(cmd[2]) + clone_channel_to_part = str(cmd[3]) + + if clone_name.lower() == 'all': + + for clone in self.Clone.UID_CLONE_DB: + self.Protocol.part(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) + self.Irc.Channel.delete_user_from_channel(clone_channel_to_part, clone.uid) + + else: + if self.Clone.exists(clone_name): + clone_uid = self.Clone.get_uid(clone_name) + if not clone_uid is None: + self.Protocol.part(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False) + self.Irc.Channel.delete_user_from_channel(clone_channel_to_part, clone_uid) + + except Exception as err: + self.Logs.error(f'{err}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part all #channel") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part clone_nickname #channel") case 'list': try: clone_count = len(self.Clone.UID_CLONE_DB) - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :>> Number of connected clones: {clone_count}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f">> Number of connected clones: {clone_count}") for clone_name in self.Clone.UID_CLONE_DB: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :>> Nickname: {clone_name.nickname} | Username: {clone_name.username} | Realname: {clone_name.realname} | Vhost: {clone_name.vhost} | Init: {clone_name.init} | Live: {clone_name.alive} | Connected: {clone_name.connected}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, + msg=f">> Nickname: {clone_name.nickname} | Username: {clone_name.username} | Realname: {clone_name.realname} | Vhost: {clone_name.vhost} | UID: {clone_name.uid} | Group: {clone_name.group} | Connected: {clone_name.connected}") except Exception as err: self.Logs.error(f'{err}') @@ -374,30 +476,36 @@ class Clone(): try: # clone say clone_nickname #channel message clone_name = str(cmd[2]) - clone_channel = str(cmd[3]) if self.Base.Is_Channel(str(cmd[3])) else None + clone_channel = str(cmd[3]) if self.Channel.Is_Channel(str(cmd[3])) else None - message = [] - for i in range(4, len(cmd)): - message.append(cmd[i]) - final_message = ' '.join(message) + final_message = ' '.join(cmd[4:]) if clone_channel is None or not self.Clone.exists(clone_name): - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message') + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"/msg {dnickname} clone say [clone_nickname] #channel message" + ) return None - + if self.Clone.exists(clone_name): - self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :SAY {clone_channel} {final_message}') + self.Protocol.sendPrivMsg(nick_from=clone_name, msg=final_message, channel=clone_channel) except Exception as err: self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message') + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=fromuser, + msg=f"/msg {dnickname} clone say [clone_nickname] #channel message" + ) case _: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel [message]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | nickname]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list") + except IndexError as ie: self.Logs.error(f'Index Error: {ie}') except Exception as err: diff --git a/mods/mod_command.py b/mods/mod_command.py index 6377a3f..b5ad745 100644 --- a/mods/mod_command.py +++ b/mods/mod_command.py @@ -1,5 +1,8 @@ +from typing import TYPE_CHECKING from dataclasses import dataclass, fields -from core.irc import Irc + +if TYPE_CHECKING: + from core.irc import Irc class Command(): @@ -9,7 +12,7 @@ class Command(): """ pass - def __init__(self, ircInstance:Irc) -> None: + def __init__(self, ircInstance: 'Irc') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() @@ -17,6 +20,9 @@ class Command(): # Add Irc Object to the module (Mandatory) self.Irc = ircInstance + # Add Protocol object to the module (Mandatory) + self.Protocol = ircInstance.Protocol + # Add Global Configuration to the module (Mandatory) self.Config = ircInstance.Config @@ -34,10 +40,10 @@ class Command(): # Create module commands (Mandatory) self.commands_level = { - 1: ['join', 'part'], - 2: ['owner', 'deowner', 'protect', 'deprotect', 'op', 'deop', 'halfop', 'dehalfop', 'voice', - 'devoice', 'opall', 'deopall', 'devoiceall', 'voiceall', 'ban', - 'unban','kick', 'kickban', 'umode', 'mode', 'svsjoin', 'svspart', 'svsnick', 'topic', + 1: ['join', 'part','owner', 'deowner', 'protect', 'deprotect', 'op', + 'deop', 'halfop', 'dehalfop', 'voice','devoice', 'topic'], + 2: ['opall', 'deopall', 'devoiceall', 'voiceall', 'ban', + 'unban','kick', 'kickban', 'umode', 'mode', 'get_mode', 'svsjoin', 'svspart', 'svsnick', 'wallops', 'globops','gnotice','whois', 'names', 'invite', 'inviteme', 'sajoin', 'sapart', 'kill', 'gline', 'ungline', 'kline', 'unkline', 'shun', 'unshun', @@ -130,7 +136,7 @@ class Command(): return None - def cmd(self, data:list) -> None: + def cmd(self, data: list) -> None: service_id = self.Config.SERVICE_ID dnickname = self.Config.SERVICE_NICKNAME @@ -149,7 +155,11 @@ class Command(): case '403' | '401': try: message = ' '.join(cmd[3:]) - self.Irc.send2socket(f":{dnickname} NOTICE {self.user_to_notice} :[{red}ERROR MSG{nogc}] {message}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=self.user_to_notice, + msg=f"[{red}ERROR MSG{nogc}] {message}" + ) self.Base.logs.error(f"{cmd[1]} - {message}") except KeyError as ke: self.Base.logs.error(ke) @@ -161,7 +171,11 @@ class Command(): # [':irc.deb.biz.st', '006', 'Dev-PyDefender', ':`-services.deb.biz.st', '------', '|', 'Users:', '9', '(47.37%)', '[00B]'] # [':irc.deb.biz.st', '018', 'Dev-PyDefender', ':4', 'servers', 'and', '19', 'users,', 'average', '4.75', 'users', 'per', 'server'] message = ' '.join(cmd[3:]) - self.Irc.send2socket(f":{dnickname} NOTICE {self.user_to_notice} : [{green}SERVER MSG{nogc}] {message}") + self.Protocol.sendNotice( + nick_from=dnickname, + nick_to=self.user_to_notice, + msg=f"[{green}SERVER MSG{nogc}] {message}" + ) except KeyError as ke: self.Base.logs.error(ke) except Exception as err: @@ -179,11 +193,11 @@ class Command(): match type_of_stats: case 's': - self.Irc.send2socket(f":{dnickname} NOTICE {self.user_to_notice} : No shun") + self.Protocol.sendNotice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No shun") case 'G': - self.Irc.send2socket(f":{dnickname} NOTICE {self.user_to_notice} : No gline") + self.Protocol.sendNotice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No gline") case 'k': - self.Irc.send2socket(f":{dnickname} NOTICE {self.user_to_notice} : No kline") + self.Protocol.sendNotice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No kline") except KeyError as ke: self.Base.logs.error(ke) @@ -198,13 +212,18 @@ class Command(): author = str(cmd[7]) reason = ' '.join(cmd[8:]) - self.Irc.send2socket(f":{dnickname} NOTICE {self.user_to_notice} : {bold}Author{nogc}: {author} - {bold}Host{nogc}: {host} - {bold}Reason{nogc}: {reason}") + self.Protocol.sendNotice(nick_from=dnickname,nick_to=self.user_to_notice, + msg=f"{bold}Author{nogc}: {author} - {bold}Host{nogc}: {host} - {bold}Reason{nogc}: {reason}" + ) except KeyError as ke: self.Base.logs.error(ke) except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') + case _: + pass + return None def _hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None: @@ -221,16 +240,16 @@ class Command(): case 'deopall': try: - self.Irc.send2socket(f":{service_id} SVSMODE {fromchannel} -o") + self.Protocol.send2socket(f":{service_id} SVSMODE {fromchannel} -o") - except IndexError as e: - self.Logs.warning(f'_hcmd OP: {str(e)}') + except IndexError as ie: + self.Logs.warning(f'_hcmd OP: {str(ie)}') except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') case 'devoiceall': try: - self.Irc.send2socket(f":{service_id} SVSMODE {fromchannel} -v") + self.Protocol.send2socket(f":{service_id} SVSMODE {fromchannel} -v") except IndexError as e: self.Logs.warning(f'_hcmd OP: {str(e)}') @@ -245,13 +264,13 @@ class Command(): users:str = '' uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}") for uid in uids_split: for i in range(0, len(uid)): mode += set_mode users += f'{self.User.get_nickname(self.Base.clean_uid(uid[i]))} ' if i == len(uid) - 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}") mode = '' users = '' except IndexError as e: @@ -267,13 +286,13 @@ class Command(): users:str = '' uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}") for uid in uids_split: for i in range(0, len(uid)): mode += set_mode users += f'{self.User.get_nickname(self.Base.clean_uid(uid[i]))} ' if i == len(uid) - 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}") mode = '' users = '' except IndexError as e: @@ -288,25 +307,25 @@ class Command(): # [':adator', 'PRIVMSG', '#services', ':.o', '#services', 'dktmb'] try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} op [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} op [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} MODE {fromchannel} +o {fromuser}") + self.Protocol.send2socket(f":{dnickname} MODE {fromchannel} +o {fromuser}") return True # deop nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +o {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +o {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +o {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +o {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd OP: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} op [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} op [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -315,25 +334,25 @@ class Command(): # .deop #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deop [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deop [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -o {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -o {fromuser}") return True # deop nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -o {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -o {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -o {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -o {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd DEOP: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deop [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deop [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -342,25 +361,25 @@ class Command(): # .owner #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} owner [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} owner [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +q {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +q {fromuser}") return True # owner nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +q {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +q {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +q {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +q {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd OWNER: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} owner [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} owner [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -369,25 +388,25 @@ class Command(): # .deowner #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -q {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -q {fromuser}") return True # deowner nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -q {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -q {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -q {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -q {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd DEOWNER: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -396,25 +415,25 @@ class Command(): # .protect #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +a {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +a {fromuser}") return True # deowner nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +a {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +a {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +a {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +a {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd DEOWNER: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -423,25 +442,25 @@ class Command(): # .deprotect #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -a {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -a {fromuser}") return True # deowner nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -a {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -a {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -a {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -a {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd DEOWNER: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -450,25 +469,25 @@ class Command(): # .halfop #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +h {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +h {fromuser}") return True # deop nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +h {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +h {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +h {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +h {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd halfop: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -477,25 +496,25 @@ class Command(): # .dehalfop #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -h {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -h {fromuser}") return True # dehalfop nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -h {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -h {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -h {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -h {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd DEHALFOP: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -504,25 +523,25 @@ class Command(): # .voice #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} voice [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} voice [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +v {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +v {fromuser}") return True # voice nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +v {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +v {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} +v {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +v {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd VOICE: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} voice [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} voice [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') @@ -531,124 +550,115 @@ class Command(): # .devoice #channel user try: if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]") return False if len(cmd) == 1: - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -v {fromuser}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -v {fromuser}") return True # dehalfop nickname if len(cmd) == 2: nickname = cmd[1] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -v {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -v {nickname}") return True nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {fromchannel} -v {nickname}") + self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -v {nickname}") except IndexError as e: self.Logs.warning(f'_hcmd DEVOICE: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') case 'ban': # .ban #channel nickname try: - sentchannel = str(cmd[1]) if self.Base.Is_Channel(cmd[1]) else None + sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None if sentchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") return False nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") + self.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") self.Logs.debug(f'{fromuser} has banned {nickname} from {sentchannel}') except IndexError as e: self.Logs.warning(f'_hcmd BAN: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') case 'unban': # .unban #channel nickname try: - sentchannel = str(cmd[1]) if self.Base.Is_Channel(cmd[1]) else None + sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None if sentchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} ban [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} ban [#SALON] [NICKNAME]") return False nickname = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {sentchannel} -b {nickname}!*@*") + self.Protocol.send2socket(f":{service_id} MODE {sentchannel} -b {nickname}!*@*") self.Logs.debug(f'{fromuser} has unbanned {nickname} from {sentchannel}') except IndexError as e: self.Logs.warning(f'_hcmd UNBAN: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} unban [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} unban [#SALON] [NICKNAME]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') case 'kick': # .kick #channel nickname reason try: - sentchannel = str(cmd[1]) if self.Base.Is_Channel(cmd[1]) else None + sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None if sentchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} ban [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} ban [#SALON] [NICKNAME]") return False nickname = cmd[2] - reason = [] + final_reason = ' '.join(cmd[3:]) - for i in range(3, len(cmd)): - reason.append(cmd[i]) - - final_reason = ' '.join(reason) - - self.Irc.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") + self.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") self.Logs.debug(f'{fromuser} has kicked {nickname} from {sentchannel} : {final_reason}') except IndexError as e: self.Logs.warning(f'_hcmd KICK: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} kick [#SALON] [NICKNAME] [REASON]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} kick [#SALON] [NICKNAME] [REASON]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') case 'kickban': # .kickban #channel nickname reason try: - sentchannel = str(cmd[1]) if self.Base.Is_Channel(cmd[1]) else None + sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None if sentchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} ban [#SALON] [NICKNAME]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} ban [#SALON] [NICKNAME]") return False nickname = cmd[2] - reason = [] + final_reason = ' '.join(cmd[3:]) - for i in range(3, len(cmd)): - reason.append(cmd[i]) - - final_reason = ' '.join(reason) - - self.Irc.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") - self.Irc.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") + self.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") + self.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") self.Logs.debug(f'{fromuser} has kicked and banned {nickname} from {sentchannel} : {final_reason}') except IndexError as e: self.Logs.warning(f'_hcmd KICKBAN: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} kickban [#SALON] [NICKNAME] [REASON]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} kickban [#SALON] [NICKNAME] [REASON]") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') case 'join': try: - sent_channel = str(cmd[1]) if self.Base.Is_Channel(cmd[1]) else None + sent_channel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None if sent_channel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{self.Config.SERVICE_PREFIX}JOIN #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}JOIN #channel") return False - self.Irc.send2socket(f':{service_id} JOIN {sent_channel}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {dnickname} JOINED {sent_channel}') - self.Base.db_query_channel('add', self.module_name, sent_channel) + # self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}') + self.Protocol.join(uidornickname=dnickname,channel=sent_channel) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} JOINED {sent_channel}") + self.Channel.db_query_channel('add', self.module_name, sent_channel) except IndexError as ie: self.Logs.error(f'{ie}') @@ -658,18 +668,19 @@ class Command(): case 'part': try: - sent_channel = str(cmd[1]) if self.Base.Is_Channel(cmd[1]) else None + sent_channel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None if sent_channel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{self.Config.SERVICE_PREFIX}PART #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}PART #channel") return False if sent_channel == dchanlog: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : {dnickname} CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL") return False - self.Irc.send2socket(f':{service_id} PART {sent_channel}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {dnickname} LEFT {sent_channel}') - self.Base.db_query_channel('del', self.module_name, sent_channel) + self.Protocol.part(uidornickname=dnickname, channel=sent_channel) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} LEFT {sent_channel}") + + self.Channel.db_query_channel('del', self.module_name, sent_channel) except IndexError as ie: self.Logs.error(f'{ie}') @@ -679,21 +690,22 @@ class Command(): case 'topic': try: if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") return None chan = str(cmd[1]) - if not self.Base.Is_Channel(chan): - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The channel must start with #") - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") + if not self.Channel.Is_Channel(chan): + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"The channel must start with #") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") return None topic_msg = ' '.join(cmd[2:]).strip() if topic_msg: - self.Irc.send2socket(f':{dnickname} TOPIC {chan} :{topic_msg}') + self.Protocol.send2socket(f':{dnickname} TOPIC {chan} :{topic_msg}') else: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :You need to specify the topic") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the topic") except KeyError as ke: self.Base.logs.error(ke) @@ -703,15 +715,15 @@ class Command(): case 'wallops': try: if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} WALLOPS THE_WALLOPS_MESSAGE") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} WALLOPS THE_WALLOPS_MESSAGE") return None wallops_msg = ' '.join(cmd[1:]).strip() if wallops_msg: - self.Irc.send2socket(f':{dnickname} WALLOPS {wallops_msg} ({dnickname})') + self.Protocol.send2socket(f':{dnickname} WALLOPS {wallops_msg} ({dnickname})') else: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :You need to specify the wallops message") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the wallops message") except KeyError as ke: self.Base.logs.error(ke) @@ -721,15 +733,15 @@ class Command(): case 'globops': try: if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} GLOBOPS THE_GLOBOPS_MESSAGE") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} GLOBOPS THE_GLOBOPS_MESSAGE") return None globops_msg = ' '.join(cmd[1:]).strip() if globops_msg: - self.Irc.send2socket(f':{dnickname} GLOBOPS {globops_msg} ({dnickname})') + self.Protocol.send2socket(f':{dnickname} GLOBOPS {globops_msg} ({dnickname})') else: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :You need to specify the globops message") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the globops message") except KeyError as ke: self.Base.logs.error(ke) @@ -739,15 +751,15 @@ class Command(): case 'gnotice': try: if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} THE_GLOBAL_NOTICE_MESSAGE") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} THE_GLOBAL_NOTICE_MESSAGE") return None gnotice_msg = ' '.join(cmd[1:]).strip() if gnotice_msg: - self.Irc.send2socket(f':{dnickname} NOTICE $*.* :[{self.Config.COLORS.red}GLOBAL NOTICE{self.Config.COLORS.nogc}] {gnotice_msg}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to='$*.*', msg=f"[{self.Config.COLORS.red}GLOBAL NOTICE{self.Config.COLORS.nogc}] {gnotice_msg}") else: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :You need to specify the global notice message") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the global notice message") except KeyError as ke: self.Base.logs.error(ke) @@ -758,17 +770,17 @@ class Command(): try: self.user_to_notice = fromuser if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") return None nickname = str(cmd[1]) if self.User.get_nickname(nickname) is None: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :Nickname not found !") - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Nickname not found !") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") return None - self.Irc.send2socket(f':{dnickname} WHOIS {nickname}') + self.Protocol.send2socket(f':{dnickname} WHOIS {nickname}') except KeyError as ke: self.Base.logs.error(ke) @@ -778,17 +790,17 @@ class Command(): case 'names': try: if len(cmd) == 1: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} #CHANNEL") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #CHANNEL") return None chan = str(cmd[1]) - if not self.Base.Is_Channel(chan): - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The channel must start with #") - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} #channel") + if not self.Channel.Is_Channel(chan): + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"The channel must start with #") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel") return None - self.Irc.send2socket(f':{dnickname} NAMES {chan}') + self.Protocol.send2socket(f':{dnickname} NAMES {chan}') except KeyError as ke: self.Base.logs.error(ke) @@ -798,23 +810,23 @@ class Command(): case 'invite': try: if len(cmd) < 3: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} #CHANNEL NICKNAME") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #CHANNEL NICKNAME") return None chan = str(cmd[1]) nickname = str(cmd[2]) - if not self.Base.Is_Channel(chan): - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The channel must start with #") - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} #channel nickname") + if not self.Channel.Is_Channel(chan): + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"The channel must start with #") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel nickname") return None if self.User.get_nickname(nickname) is None: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :Nickname not found !") - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()} #channel NICKNAME") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"Nickname not found !") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel NICKNAME") return None - self.Irc.send2socket(f':{dnickname} INVITE {nickname} {chan}') + self.Protocol.send2socket(f':{dnickname} INVITE {nickname} {chan}') except KeyError as ke: self.Base.logs.error(ke) @@ -824,10 +836,10 @@ class Command(): case 'inviteme': try: if len(cmd) == 0: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :/msg {dnickname} {str(cmd[0]).upper()}") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()}") return None - self.Irc.send2socket(f':{dnickname} INVITE {fromuser} {self.Config.SERVICE_CHANLOG}') + self.Protocol.send2socket(f':{dnickname} INVITE {fromuser} {self.Config.SERVICE_CHANLOG}') except KeyError as ke: self.Base.logs.error(ke) @@ -837,7 +849,7 @@ class Command(): case 'map': try: self.user_to_notice = fromuser - self.Irc.send2socket(f':{dnickname} MAP') + self.Protocol.send2socket(f':{dnickname} MAP') except KeyError as ke: self.Base.logs.error(ke) @@ -850,7 +862,7 @@ class Command(): nickname = str(cmd[1]) umode = str(cmd[2]) - self.Irc.send2socket(f':{dnickname} SVSMODE {nickname} {umode}') + self.Protocol.send2socket(f':{dnickname} SVSMODE {nickname} {umode}') except KeyError as ke: self.Base.logs.error(ke) except Exception as err: @@ -862,47 +874,51 @@ class Command(): try: if len(cmd) < 2: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") return None if fromchannel is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") return None if len(cmd) == 2: channel_mode = cmd[1] - if self.Base.Is_Channel(fromchannel): - self.Irc.send2socket(f":{dnickname} MODE {fromchannel} {channel_mode}") + if self.Channel.Is_Channel(fromchannel): + self.Protocol.send2socket(f":{dnickname} MODE {fromchannel} {channel_mode}") else: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : Right command : Channel [{fromchannel}] is not correct should start with #") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : Channel [{fromchannel}] is not correct should start with #") return None if len(cmd) == 3: provided_channel = cmd[1] channel_mode = cmd[2] - self.Irc.send2socket(f":{service_id} MODE {provided_channel} {channel_mode}") + self.Protocol.send2socket(f":{service_id} MODE {provided_channel} {channel_mode}") return None except IndexError as e: self.Logs.warning(f'_hcmd OP: {str(e)}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') + case 'get_mode': + + self.Protocol.send2socket(f'MODE {channel}') + case 'svsjoin': try: # .svsjoin nickname #channel nickname = str(cmd[1]) channel = str(cmd[2]) if len(cmd) != 3: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} SVSJOIN nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN nickname #channel") return None - self.Irc.send2socket(f':{self.Config.SERVEUR_ID} SVSJOIN {nickname} {channel}') + self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSJOIN {nickname} {channel}') except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} SVSJOIN nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN nickname #channel") self.Logs.warning(f'Unknown Error: {str(err)}') case 'svspart': @@ -911,14 +927,14 @@ class Command(): nickname = str(cmd[1]) channel = str(cmd[2]) if len(cmd) != 3: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} SVSPART nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART nickname #channel") return None - self.Irc.send2socket(f':{self.Config.SERVEUR_ID} SVSPART {nickname} {channel}') + self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSPART {nickname} {channel}') except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} SVSPART nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART nickname #channel") self.Logs.warning(f'Unknown Error: {str(err)}') case 'sajoin': @@ -927,14 +943,14 @@ class Command(): nickname = str(cmd[1]) channel = str(cmd[2]) if len(cmd) < 3: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") return None - self.Irc.send2socket(f':{self.Config.SERVEUR_ID} SAJOIN {nickname} {channel}') + self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SAJOIN {nickname} {channel}') except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") self.Logs.warning(f'Unknown Error: {str(err)}') case 'sapart': @@ -943,14 +959,14 @@ class Command(): nickname = str(cmd[1]) channel = str(cmd[2]) if len(cmd) < 3: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") return None - self.Irc.send2socket(f':{self.Config.SERVEUR_ID} SAPART {nickname} {channel}') + self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SAPART {nickname} {channel}') except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname #channel') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") self.Logs.warning(f'Unknown Error: {str(err)}') case 'svsnick': @@ -961,19 +977,19 @@ class Command(): unixtime = self.Base.get_unixtime() if self.User.get_nickname(nickname) is None: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : This nickname do not exist') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" This nickname do not exist") return None if len(cmd) != 3: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname newnickname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") return None - self.Irc.send2socket(f':{self.Config.SERVEUR_ID} SVSNICK {nickname} {newnickname} {unixtime}') + self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSNICK {nickname} {newnickname} {unixtime}') except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname newnickname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") self.Logs.warning(f'Unknown Error: {str(err)}') case 'kill': @@ -981,17 +997,17 @@ class Command(): # 'kill', 'gline', 'ungline', 'shun', 'unshun' # .kill nickname reason if len(cmd) < 3: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname reason") return None nickname = str(cmd[1]) kill_reason = ' '.join(cmd[2:]) - self.Irc.send2socket(f":{service_id} KILL {nickname} {kill_reason} ({self.Config.COLORS.red}{dnickname}{self.Config.COLORS.nogc})") + self.Protocol.send2socket(f":{service_id} KILL {nickname} {kill_reason} ({self.Config.COLORS.red}{dnickname}{self.Config.COLORS.nogc})") except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} SVSNICK nickname newnickname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSNICK nickname newnickname") self.Logs.warning(f'Unknown Error: {str(err)}') case 'gline': @@ -999,7 +1015,7 @@ class Command(): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .gline [nickname] [host] [reason] if len(cmd) < 4: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None nickname = str(cmd[1]) @@ -1009,15 +1025,16 @@ class Command(): gline_reason = ' '.join(cmd[3:]) if nickname == '*' and hostname == '*': - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : You want to close the server ? i would recommand ./unrealircd stop :)') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} TKL + G {nickname} {hostname} {dnickname} {expire_time} {set_at_timestamp} :{gline_reason}") + self.Protocol.gline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason) + except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") self.Logs.warning(f'Unknown Error: {str(err)}') case 'ungline': @@ -1026,18 +1043,19 @@ class Command(): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .ungline nickname host if len(cmd) < 2: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname hostname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") return None nickname = str(cmd[1]) hostname = str(cmd[2]) - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {dnickname}") + # self.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {dnickname}") + self.Protocol.ungline(nickname=nickname, hostname=hostname) except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname hostname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") self.Logs.warning(f'Unknown Error: {str(err)}') case 'kline': @@ -1045,7 +1063,7 @@ class Command(): # TKL + k user host set_by expire_timestamp set_at_timestamp :reason # .gline [nickname] [host] [reason] if len(cmd) < 4: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None nickname = str(cmd[1]) @@ -1055,15 +1073,16 @@ class Command(): gline_reason = ' '.join(cmd[3:]) if nickname == '*' and hostname == '*': - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : You want to close the server ? i would recommand ./unrealircd stop :)') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} TKL + k {nickname} {hostname} {dnickname} {expire_time} {set_at_timestamp} :{gline_reason}") + self.Protocol.kline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason) + except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") self.Logs.warning(f'Unknown Error: {str(err)}') case 'unkline': @@ -1072,18 +1091,18 @@ class Command(): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .ungline nickname host if len(cmd) < 2: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname hostname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") return None nickname = str(cmd[1]) hostname = str(cmd[2]) - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} TKL - k {nickname} {hostname} {dnickname}") + self.Protocol.unkline(nickname=nickname, hostname=hostname) except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname hostname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") self.Logs.warning(f'Unknown Error: {str(err)}') case 'shun': @@ -1092,7 +1111,7 @@ class Command(): # .shun [nickname] [host] [reason] if len(cmd) < 4: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None nickname = str(cmd[1]) @@ -1102,15 +1121,15 @@ class Command(): shun_reason = ' '.join(cmd[3:]) if nickname == '*' and hostname == '*': - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : You want to close the server ? i would recommand ./unrealircd stop :)') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} TKL + s {nickname} {hostname} {dnickname} {expire_time} {set_at_timestamp} :{shun_reason}") + self.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL + s {nickname} {hostname} {dnickname} {expire_time} {set_at_timestamp} :{shun_reason}") except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname host reason') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") self.Logs.warning(f'Unknown Error: {str(err)}') case 'unshun': @@ -1119,49 +1138,52 @@ class Command(): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .unshun nickname host if len(cmd) < 2: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname hostname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") return None nickname = str(cmd[1]) hostname = str(cmd[2]) - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} TKL - s {nickname} {hostname} {dnickname}") + self.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL - s {nickname} {hostname} {dnickname}") except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()} nickname hostname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") self.Logs.warning(f'Unknown Error: {str(err)}') case 'glinelist': try: self.user_to_notice = fromuser - self.Irc.send2socket(f":{self.Config.SERVICE_ID} STATS G") + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} STATS G") except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") self.Logs.warning(f'Unknown Error: {str(err)}') case 'shunlist': try: self.user_to_notice = fromuser - self.Irc.send2socket(f":{self.Config.SERVICE_ID} STATS s") + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} STATS s") except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") self.Logs.warning(f'Unknown Error: {str(err)}') case 'klinelist': try: self.user_to_notice = fromuser - self.Irc.send2socket(f":{self.Config.SERVICE_ID} STATS k") + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} STATS k") except KeyError as ke: self.Base.logs.error(ke) except Exception as err: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : /msg {dnickname} {command.upper()}') - self.Logs.warning(f'Unknown Error: {str(err)}') \ No newline at end of file + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") + self.Logs.warning(f'Unknown Error: {str(err)}') + + case _: + pass \ No newline at end of file diff --git a/mods/mod_defender.py b/mods/mod_defender.py index 0ead555..5670edf 100644 --- a/mods/mod_defender.py +++ b/mods/mod_defender.py @@ -6,10 +6,9 @@ import psutil import requests from dataclasses import dataclass, fields, field from datetime import datetime -from typing import Union +from typing import Union, TYPE_CHECKING from sys import exit -from core.irc import Irc -from core.Model import User +import core.definition as df # Le module crée devra réspecter quelques conditions # 1. Le nom de la classe devra toujours s'appeler comme le module. Exemple => nom de class Defender | nom du module mod_defender @@ -23,6 +22,10 @@ from core.Model import User # _hcmds(self, user:str, cmd: list) # unload(self) +if TYPE_CHECKING: + from core.irc import Irc + + class Defender(): @dataclass @@ -42,27 +45,11 @@ class Defender(): flood_message: int flood_time: int flood_timer: int + autolimit: int + autolimit_amount: int + autolimit_interval: int - @dataclass - class ReputationModel: - uid: str - nickname: str - username: str - hostname: str - realname: str - umodes: str - vhost: str - ip: str - score: int - isWebirc: bool - isWebsocket: bool - secret_code: str - connected_datetime: str - updated_datetime: str - - UID_REPUTATION_DB: list[ReputationModel] = [] - - def __init__(self, ircInstance:Irc) -> None: + def __init__(self, ircInstance: 'Irc') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() @@ -70,6 +57,12 @@ class Defender(): # Add Irc Object to the module (Mandatory) self.Irc = ircInstance + # Add Loader Object to the module (Mandatory) + self.Loader = ircInstance.Loader + + # Add server protocol Object to the module (Mandatory) + self.Protocol = ircInstance.Protocol + # Add Global Configuration to the module (Mandatory) self.Config = ircInstance.Config @@ -85,11 +78,13 @@ class Defender(): # Add Channel object to the module (Mandatory) self.Channel = ircInstance.Channel + # Add Reputation object to the module (Optional) + self.Reputation = ircInstance.Reputation + # Create module commands (Mandatory) self.commands_level = { 0: ['code'], - 1: ['info'], - 2: ['owner', 'deowner', 'op', 'deop', 'halfop', 'dehalfop', 'voice', 'devoice', 'ban', 'unban','kick', 'kickban'], + 1: ['info', 'autolimit'], 3: ['reputation','proxy_scan', 'flood', 'status', 'timer','show_reputation', 'sentinel'] } @@ -114,11 +109,11 @@ class Defender(): self.timeout = self.Config.API_TIMEOUT # Listes qui vont contenir les ip a scanner avec les différentes API - self.abuseipdb_UserModel: list[User.UserModel] = [] - self.freeipapi_UserModel: list[User.UserModel] = [] - self.cloudfilt_UserModel: list[User.UserModel] = [] - self.psutil_UserModel: list[User.UserModel] = [] - self.localscan_UserModel: list[User.UserModel] = [] + self.abuseipdb_UserModel: list[df.MUser] = [] + self.freeipapi_UserModel: list[df.MUser] = [] + self.cloudfilt_UserModel: list[df.MUser] = [] + self.psutil_UserModel: list[df.MUser] = [] + self.localscan_UserModel: list[df.MUser] = [] # Variables qui indique que les threads sont en cours d'éxecutions self.abuseipdb_isRunning:bool = True @@ -127,6 +122,7 @@ class Defender(): self.psutil_isRunning:bool = True self.localscan_isRunning:bool = True self.reputationTimer_isRunning:bool = True + self.autolimit_isRunning: bool = True # Variable qui va contenir les users self.flood_system = {} @@ -145,10 +141,11 @@ class Defender(): self.Base.create_thread(func=self.thread_local_scan) self.Base.create_thread(func=self.thread_psutil_scan) self.Base.create_thread(func=self.thread_reputation_timer) + self.Base.create_thread(func=self.thread_autolimit) if self.ModConfig.reputation == 1: - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} SJOIN {self.Base.get_unixtime()} {self.Config.SALON_JAIL} + :{self.Config.SERVICE_NICKNAME}") - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.SALON_JAIL} +o {self.Config.SERVICE_NICKNAME}") + self.Protocol.sjoin(self.Config.SALON_JAIL) + self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.SALON_JAIL} +o {self.Config.SERVICE_NICKNAME}") return None @@ -214,7 +211,8 @@ class Defender(): reputation=0, reputation_timer=1, reputation_seuil=26, reputation_score_after_release=27, reputation_ban_all_chan=0,reputation_sg=1, local_scan=0, psutil_scan=0, abuseipdb_scan=0, freeipapi_scan=0, cloudfilt_scan=0, - flood=0, flood_message=5, flood_time=1, flood_timer=20 + flood=0, flood_message=5, flood_time=1, flood_timer=20, + autolimit=1, autolimit_amount=3, autolimit_interval=3 ) # Sync the configuration with core configuration (Mandatory) @@ -233,11 +231,11 @@ class Defender(): """Cette methode sera executée a chaque désactivation ou rechargement de module """ - self.abuseipdb_UserModel: list[User.UserModel] = [] - self.freeipapi_UserModel: list[User.UserModel] = [] - self.cloudfilt_UserModel: list[User.UserModel] = [] - self.psutil_UserModel: list[User.UserModel] = [] - self.localscan_UserModel: list[User.UserModel] = [] + self.abuseipdb_UserModel: list[df.MUser] = [] + self.freeipapi_UserModel: list[df.MUser] = [] + self.cloudfilt_UserModel: list[df.MUser] = [] + self.psutil_UserModel: list[df.MUser] = [] + self.localscan_UserModel: list[df.MUser] = [] self.abuseipdb_isRunning:bool = False self.freeipapi_isRunning:bool = False @@ -245,80 +243,9 @@ class Defender(): self.psutil_isRunning:bool = False self.localscan_isRunning:bool = False self.reputationTimer_isRunning:bool = False + self.autolimit_isRunning: bool = False return None - def reputation_insert(self, reputationModel: ReputationModel) -> bool: - - response = False - - # Check if the user already exist - for reputation in self.UID_REPUTATION_DB: - if reputation.uid == reputationModel.uid: - return response - - self.UID_REPUTATION_DB.append(reputationModel) - self.Logs.debug(f'Reputation inserted: {reputationModel}') - response = True - - return response - - def reputation_delete(self, uidornickname:str) -> bool: - - response = False - - for record in self.UID_REPUTATION_DB: - if record.uid == uidornickname: - self.UID_REPUTATION_DB.remove(record) - response = True - self.Logs.debug(f'UID ({record.uid}) has been deleted') - elif record.nickname == uidornickname: - self.UID_REPUTATION_DB.remove(record) - response = True - self.Logs.debug(f'Nickname ({record.nickname}) has been deleted') - - if not response: - self.Logs.critical(f'The UID {uidornickname} was not deleted') - - return response - - def reputation_check(self, uidornickname: str) -> bool: - """Check if the uid exist in the dataclass - - Args: - uidornickname (str): UID or nickname of the user - - Returns: - bool: True if the user exist in the reputation dataclass - """ - response = False - - for reputation in self.UID_REPUTATION_DB: - if reputation.uid == uidornickname: - response = True - elif reputation.nickname == uidornickname: - response = True - - return response - - def reputation_get_Reputation(self, uidornickname: str) -> Union[ReputationModel, None]: - """Get a user reputation object with all information - - Args: - uidornickname (str): The UID or Nickname of the suspected user - - Returns: - ReputationModel or None: Return the Reputation Model or None if the user doesn't exist - """ - - Reputation_user = None - for reputation in self.UID_REPUTATION_DB: - if reputation.uid == uidornickname: - Reputation_user = reputation - elif reputation.nickname == uidornickname: - Reputation_user = reputation - - return Reputation_user - def insert_db_trusted(self, uid: str, nickname:str) -> None: uid = self.User.get_uid(uid) @@ -336,7 +263,7 @@ class Defender(): def join_saved_channels(self) -> None: - result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.table_channel}") + result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}") channels = result.fetchall() jail_chan = self.Config.SALON_JAIL jail_chan_mode = self.Config.SALON_JAIL_MODES @@ -348,10 +275,11 @@ class Defender(): for channel in channels: chan = channel[0] - self.Irc.send2socket(f":{self.Config.SERVEUR_ID} SJOIN {unixtime} {chan} + :{self.Config.SERVICE_ID}") + # self.Irc.send2socket(f":{self.Config.SERVEUR_ID} SJOIN {unixtime} {chan} + :{self.Config.SERVICE_ID}") + self.Protocol.sjoin(chan) if chan == jail_chan: - self.Irc.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") - self.Irc.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") + self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") + self.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") return None @@ -397,7 +325,7 @@ class Defender(): # - Defender devra intégrer une liste d'IDs (pseudo/host) exemptés de 'Reputation security' malgré un score de rép. faible et un pseudo non enregistré. try: - get_reputation = self.reputation_get_Reputation(uid) + get_reputation = self.Reputation.get_Reputation(uid) if get_reputation is None: self.Logs.error(f'UID {uid} has not been found') @@ -413,6 +341,7 @@ class Defender(): color_red = self.Config.COLORS.red color_black = self.Config.COLORS.black color_bold = self.Config.COLORS.bold + nogc = self.Config.COLORS.nogc service_id = self.Config.SERVICE_ID service_prefix = self.Config.SERVICE_PREFIX reputation_ban_all_chan = self.ModConfig.reputation_ban_all_chan @@ -420,21 +349,28 @@ class Defender(): if not get_reputation.isWebirc: # Si le user ne vient pas de webIrc - self.Irc.send2socket(f":{service_id} SAJOIN {jailed_nickname} {salon_jail}") - self.Irc.send2socket(f":{service_id} PRIVMSG {salon_logs} :[{color_red} REPUTATION {color_black}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}") - self.Irc.send2socket(f":{service_id} NOTICE {jailed_nickname} :[{color_red} {jailed_nickname} {color_black}] : Merci de tapez la commande suivante {color_bold}{service_prefix}code {code}{color_bold}") + self.Protocol.send2socket(f":{service_id} SAJOIN {jailed_nickname} {salon_jail}") + self.Protocol.sendPrivMsg(nick_from=self.Config.SERVICE_NICKNAME, + msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}", + channel=salon_logs + ) + self.Protocol.sendNotice( + nick_from=self.Config.SERVICE_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}" + ) if reputation_ban_all_chan == 1: for chan in self.Channel.UID_CHANNEL_DB: if chan.name != salon_jail: - self.Irc.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*") - self.Irc.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*") + self.Protocol.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}") self.Logs.info(f"system_reputation : {jailed_nickname} à été capturé par le système de réputation") # self.Irc.create_ping_timer(int(self.ModConfig.reputation_timer) * 60, 'Defender', 'system_reputation_timer') # self.Base.create_timer(int(self.ModConfig.reputation_timer) * 60, self.system_reputation_timer) else: self.Logs.info(f"system_reputation : {jailed_nickname} à été supprimé du système de réputation car connecté via WebIrc ou il est dans la 'Trusted list'") - self.reputation_delete(uid) + self.Repurtation.delete(uid) except IndexError as e: self.Logs.error(f"system_reputation : {str(e)}") @@ -449,6 +385,7 @@ class Defender(): dchanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red color_black = self.Config.COLORS.black + nogc = self.Config.COLORS.nogc salon_jail = self.Config.SALON_JAIL if reputation_flag == 0: @@ -458,12 +395,16 @@ class Defender(): uid_to_clean = [] - for user in self.UID_REPUTATION_DB: + for user in self.Reputation.UID_REPUTATION_DB: if not user.isWebirc: # Si il ne vient pas de WebIRC if self.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score) <= int(reputation_seuil): - self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} :[{color_red} REPUTATION {color_black}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité") - self.Irc.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code ") - self.Irc.send2socket(f":{self.Config.SERVEUR_LINK} REPUTATION {user.ip} 0") + self.Protocol.sendPrivMsg( + nick_from=service_id, + msg=f":{service_id} PRIVMSG {dchanlog} :[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité", + channel=dchanlog + ) + self.Protocol.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code ") + self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} REPUTATION {user.ip} 0") self.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity") uid_to_clean.append(user.uid) @@ -472,12 +413,12 @@ class Defender(): # Suppression des éléments dans {UID_DB} et {REPUTATION_DB} for chan in self.Channel.UID_CHANNEL_DB: if chan.name != salon_jail and ban_all_chan == 1: - get_user_reputation = self.reputation_get_Reputation(uid) - self.Irc.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*") + get_user_reputation = self.Reputation.get_Reputation(uid) + self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*") # Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}. self.Channel.delete_user_from_all_channel(uid) - self.reputation_delete(uid) + self.Reputation.delete(uid) self.User.delete(uid) except AssertionError as ae: @@ -509,7 +450,7 @@ class Defender(): match action: case 'mode-m': # Action -m sur le salon - self.Irc.send2socket(f":{service_id} MODE {channel} -m") + self.Protocol.send2socket(f":{service_id} MODE {channel} -m") case _: pass @@ -552,8 +493,12 @@ class Defender(): elif self.flood_system[get_detected_uid]['nbr_msg'] > flood_message: self.Irc.Base.logs.info('system de flood detecté') - self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} : {color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)') - self.Irc.send2socket(f":{service_id} MODE {channel} +m") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)", + channel=channel + ) + self.Protocol.send2socket(f":{service_id} MODE {channel} +m") self.Irc.Base.logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}') self.flood_system[get_detected_uid]['nbr_msg'] = 0 self.flood_system[get_detected_uid]['first_msg_time'] = unixtime @@ -562,23 +507,28 @@ class Defender(): def run_db_action_timer(self, wait_for: float = 0) -> None: - query = "SELECT parameter FROM def_config" + query = f"SELECT param_key FROM {self.Config.TABLE_CONFIG}" res = self.Base.db_execute_query(query) service_id = self.Config.SERVICE_ID dchanlog = self.Config.SERVICE_CHANLOG for param in res.fetchall(): if param[0] == 'reputation': - self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} : ===> {param[0]}") + self.Protocol.sendPrivMsg( + nick_from=service_id, + msg=f" ===> {param[0]}", + channel=dchanlog + ) else: - self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} : {param[0]}") - # print(f":{service_id} PRIVMSG {dchanlog} : {param[0]}") - - # self.Base.garbage_collector_timer() + self.Protocol.sendPrivMsg( + nick_from=service_id, + msg=f"{param[0]}", + channel=dchanlog + ) return None - def scan_ports(self, userModel: User.UserModel) -> None: + def scan_ports(self, userModel: df.MUser) -> None: """local_scan Args: @@ -603,7 +553,11 @@ class Defender(): connection = (remote_ip, self.Base.int_if_possible(port)) newSocket.connect(connection) - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.COLORS.red}PROXY_SCAN{self.Config.COLORS.black} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[ {self.Config.COLORS.red}PROXY_SCAN{self.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]", + channel=self.Config.SERVICE_CHANLOG + ) # print(f"=======> Le port {str(port)} est ouvert !!") self.Base.running_sockets.append(newSocket) # print(newSocket) @@ -640,7 +594,7 @@ class Defender(): except ValueError as ve: self.Logs.warning(f"thread_local_scan Error : {ve}") - def get_ports_connexion(self, userModel: User.UserModel) -> list[int]: + def get_ports_connexion(self, userModel: df.MUser) -> list[int]: """psutil_scan for Linux (should be run on the same location as the unrealircd server) Args: @@ -666,7 +620,11 @@ class Defender(): self.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}") if matching_ports: - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.COLORS.red}PSUTIL_SCAN{self.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}") + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[ {self.Config.COLORS.red}PSUTIL_SCAN{self.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}", + channel=self.Config.SERVICE_CHANLOG + ) return matching_ports @@ -693,7 +651,7 @@ class Defender(): except ValueError as ve: self.Logs.warning(f"thread_psutil_scan Error : {ve}") - def abuseipdb_scan(self, userModel: User.UserModel) -> Union[dict[str, any], None]: + def abuseipdb_scan(self, userModel: df.MUser) -> Union[dict[str, any], None]: """Analyse l'ip avec AbuseIpDB Cette methode devra etre lancer toujours via un thread ou un timer. Args: @@ -748,16 +706,21 @@ class Defender(): service_chanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red color_black = self.Config.COLORS.black + nogc = self.Config.COLORS.nogc # pseudo!ident@host fullname = f'{nickname}!{username}@{hostname}' - self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}ABUSEIPDB_SCAN{color_black} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}") + self.Protocol.sendPrivMsg( + 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'])}", + channel=service_chanlog + ) if result['isTor']: - self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb") + self.Protocol.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb") elif result['score'] >= 95: - self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb") + self.Protocol.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb") response.close() @@ -791,7 +754,7 @@ class Defender(): except ValueError as ve: self.Logs.error(f"thread_abuseipdb_scan Error : {ve}") - def freeipapi_scan(self, userModel: User.UserModel) -> Union[dict[str, any], None]: + def freeipapi_scan(self, userModel: df.MUser) -> Union[dict[str, any], None]: """Analyse l'ip avec Freeipapi Cette methode devra etre lancer toujours via un thread ou un timer. Args: @@ -816,6 +779,7 @@ class Defender(): service_chanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red color_black = self.Config.COLORS.black + nogc = self.Config.COLORS.nogc url = f'https://freeipapi.com/api/json/{remote_ip}' @@ -845,10 +809,14 @@ class Defender(): # pseudo!ident@host fullname = f'{nickname}!{username}@{hostname}' - self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}FREEIPAPI_SCAN{color_black} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}") + self.Protocol.sendPrivMsg( + nick_from=service_id, + msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}", + channel=service_chanlog + ) if result['isProxy']: - self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi") + self.Protocol.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi") response.close() return result @@ -862,7 +830,7 @@ class Defender(): while self.freeipapi_isRunning: - list_to_remove: list[User.UserModel] = [] + list_to_remove: list[df.MUser] = [] for user in self.freeipapi_UserModel: self.freeipapi_scan(user) list_to_remove.append(user) @@ -877,7 +845,7 @@ class Defender(): except ValueError as ve: self.Logs.error(f"thread_freeipapi_scan Error : {ve}") - def cloudfilt_scan(self, userModel: User.UserModel) -> Union[dict[str, any], None]: + def cloudfilt_scan(self, userModel: df.MUser) -> Union[dict[str, any], None]: """Analyse l'ip avec cloudfilt Cette methode devra etre lancer toujours via un thread ou un timer. Args: @@ -904,6 +872,7 @@ class Defender(): service_chanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red color_black = self.Config.COLORS.black + nogc = self.Config.COLORS.nogc url = f"https://developers18334.cloudfilt.com/" @@ -931,10 +900,14 @@ class Defender(): # pseudo!ident@host fullname = f'{nickname}!{username}@{hostname}' - self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}CLOUDFILT_SCAN{color_black} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}") + self.Protocol.sendPrivMsg( + 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'])}", + channel=service_chanlog + ) if result['listed']: - self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt") + self.Protocol.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt") response.close() @@ -963,6 +936,68 @@ class Defender(): except ValueError as ve: self.Logs.error(f"Thread_cloudfilt_scan Error : {ve}") + def thread_autolimit(self) -> None: + + if self.ModConfig.autolimit == 0: + self.Logs.debug(f"autolimit deactivated ... canceling the thread") + return None + + while self.Irc.autolimit_started: + time.sleep(0.2) + + self.Irc.autolimit_started = True + init_amount = self.ModConfig.autolimit_amount + INIT = 1 + + # Copy Channels to a list of dict + chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in self.Channel.UID_CHANNEL_DB] + chan_list: list[str] = [c.name for c in self.Channel.UID_CHANNEL_DB] + + while self.autolimit_isRunning: + + if self.ModConfig.autolimit == 0: + self.Logs.debug(f"autolimit deactivated ... stopping the current thread") + break + + for chan in self.Channel.UID_CHANNEL_DB: + for chan_copy in chanObj_copy: + if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]: + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + self.ModConfig.autolimit_amount}") + chan_copy["uids_count"] = len(chan.uids) + + if not chan.name in chan_list: + chan_list.append(chan.name) + chanObj_copy.append({"name": chan.name, "uids_count": 0}) + + # Verifier si un salon a été vidé + current_chan_in_list = [d.name for d in self.Channel.UID_CHANNEL_DB] + for c in chan_list: + if not c in current_chan_in_list: + chan_list.remove(c) + + # Si c'est la premiere execution + if INIT == 1: + for chan in self.Channel.UID_CHANNEL_DB: + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + self.ModConfig.autolimit_amount}") + + # Si le nouveau amount est différent de l'initial + if init_amount != self.ModConfig.autolimit_amount: + init_amount = self.ModConfig.autolimit_amount + for chan in self.Channel.UID_CHANNEL_DB: + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + self.ModConfig.autolimit_amount}") + + INIT = 0 + + if self.autolimit_isRunning: + time.sleep(self.ModConfig.autolimit_interval) + + for chan in self.Channel.UID_CHANNEL_DB: + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {chan.name} -l") + + self.Irc.autolimit_started = False + + return None + def cmd(self, data: list) -> None: try: service_id = self.Config.SERVICE_ID # Defender serveur id @@ -1000,8 +1035,8 @@ class Defender(): if self.Config.SALON_JAIL == channel: if mode == '+b' and group_to_unban in group_to_check: - self.Irc.send2socket(f":{service_id} MODE {self.Config.SALON_JAIL} -b ~security-group:unknown-users") - self.Irc.send2socket(f":{service_id} MODE {self.Config.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + self.Protocol.send2socket(f":{service_id} MODE {self.Config.SALON_JAIL} -b ~security-group:unknown-users") + self.Protocol.send2socket(f":{service_id} MODE {self.Config.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") case 'PRIVMSG': cmd.pop(0) @@ -1012,7 +1047,7 @@ class Defender(): case 'UID': # If Init then do nothing - if self.Irc.INIT == 1: + if self.Config.DEFENDER_INIT == 1: return None # Supprimer la premiere valeur et finir le code normalement @@ -1036,21 +1071,23 @@ class Defender(): reputation_flag = self.ModConfig.reputation reputation_seuil = self.ModConfig.reputation_seuil - if self.Irc.INIT == 0: + if self.Config.DEFENDER_INIT == 0: # Si le user n'es pas un service ni un IrcOP if not re.match(fr'^.*[S|o?].*$', _User.umodes): if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: currentDateTime = self.Base.get_datetime() - self.reputation_insert( - self.ReputationModel( - uid=_User.uid, nickname=_User.nickname, username=_User.username, realname=_User.realname, - hostname=_User.hostname, umodes=_User.umodes, vhost=_User.vhost, ip=_User.remote_ip, score=_User.score_connexion, - secret_code=self.Base.get_random(8), isWebirc=_User.isWebirc, isWebsocket=_User.isWebsocket, connected_datetime=currentDateTime, - updated_datetime=currentDateTime + self.Reputation.insert( + self.Loader.Definition.MReputation( + **_User, + secret_code=self.Base.get_random(8) + # uid=_User.uid, nickname=_User.nickname, username=_User.username, realname=_User.realname, + # hostname=_User.hostname, umodes=_User.umodes, vhost=_User.vhost, ip=_User.remote_ip, score=_User.score_connexion, + # secret_code=self.Base.get_random(8), isWebirc=_User.isWebirc, isWebsocket=_User.isWebsocket, connected_datetime=currentDateTime, + # updated_datetime=currentDateTime ) ) # self.Irc.send2socket(f":{service_id} WHOIS {nickname}") - if self.reputation_check(_User.uid): + if self.Reputation.is_exist(_User.uid): if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: self.system_reputation(_User.uid) self.Logs.info('Démarrer le systeme de reputation') @@ -1066,23 +1103,23 @@ class Defender(): pattern = fr'^:[@|%|\+|~|\*]*' parsed_UID = re.sub(pattern, '', parsed_UID) - get_reputation = self.reputation_get_Reputation(parsed_UID) + get_reputation = self.Reputation.get_Reputation(parsed_UID) if parsed_chan != self.Config.SALON_JAIL: - self.Irc.send2socket(f":{service_id} MODE {parsed_chan} +b ~security-group:unknown-users") - self.Irc.send2socket(f":{service_id} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + self.Protocol.send2socket(f":{service_id} MODE {parsed_chan} +b ~security-group:unknown-users") + self.Protocol.send2socket(f":{service_id} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") if not get_reputation is None: isWebirc = get_reputation.isWebirc if not isWebirc: if parsed_chan != self.Config.SALON_JAIL: - self.Irc.send2socket(f":{service_id} SAPART {get_reputation.nickname} {parsed_chan}") + self.Protocol.send2socket(f":{service_id} SAPART {get_reputation.nickname} {parsed_chan}") if self.ModConfig.reputation_ban_all_chan == 1 and not isWebirc: if parsed_chan != self.Config.SALON_JAIL: - self.Irc.send2socket(f":{service_id} MODE {parsed_chan} +b {get_reputation.nickname}!*@*") - self.Irc.send2socket(f":{service_id} KICK {parsed_chan} {get_reputation.nickname}") + self.Protocol.send2socket(f":{service_id} MODE {parsed_chan} +b {get_reputation.nickname}!*@*") + self.Protocol.send2socket(f":{service_id} KICK {parsed_chan} {get_reputation.nickname}") self.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}') except KeyError as ke: @@ -1116,7 +1153,7 @@ class Defender(): try: cmd.pop(0) uid = str(cmd[0]).replace(':','') - get_Reputation = self.reputation_get_Reputation(uid) + get_Reputation = self.Reputation.get_Reputation(uid) jail_salon = self.Config.SALON_JAIL service_id = self.Config.SERVICE_ID @@ -1133,8 +1170,8 @@ class Defender(): if self.ModConfig.reputation_ban_all_chan == 1: for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_salon: - self.Irc.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*") - self.Irc.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*") except KeyError as ke: self.Logs.error(f'cmd - NICK - KeyError: {ke}') @@ -1149,14 +1186,14 @@ class Defender(): jail_salon = self.Config.SALON_JAIL service_id = self.Config.SERVICE_ID - get_user_reputation = self.reputation_get_Reputation(final_UID) + get_user_reputation = self.Reputation.get_Reputation(final_UID) if not get_user_reputation is None: final_nickname = get_user_reputation.nickname for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_salon and ban_all_chan == 1: - self.Irc.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*") - self.reputation_delete(final_UID) + self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*") + self.Reputation.delete(final_UID) except KeyError as ke: self.Logs.error(f"{ke} / {cmd} / length {str(len(cmd))}") @@ -1169,7 +1206,7 @@ class Defender(): command = str(cmd[0]).lower() fromuser = user - fromchannel = channel if self.Base.Is_Channel(channel) else None + fromchannel = channel if self.Channel.Is_Channel(channel) else None channel = fromchannel dnickname = self.Config.SERVICE_NICKNAME # Defender nickname @@ -1194,21 +1231,23 @@ class Defender(): case 'show_reputation': - if not self.UID_REPUTATION_DB: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : No one is suspected') + if not self.Reputation.UID_REPUTATION_DB: + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=" No one is suspected") - for suspect in self.UID_REPUTATION_DB: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Uid: {suspect.uid} | Nickname: {suspect.nickname} | Reputation: {suspect.score} | Secret code: {suspect.secret_code} | Connected on: {suspect.connected_datetime}') + for suspect in self.Reputation.UID_REPUTATION_DB: + self.Protocol.sendNotice(nick_from=dnickname, + nick_to=fromuser, + msg=f" Uid: {suspect.uid} | Nickname: {suspect.nickname} | Reputation: {suspect.score} | Secret code: {suspect.secret_code} | Connected on: {suspect.connected_datetime}") case 'code': try: release_code = cmd[1] jailed_nickname = self.User.get_nickname(fromuser) jailed_UID = self.User.get_uid(fromuser) - get_reputation = self.reputation_get_Reputation(jailed_UID) + get_reputation = self.Reputation.get_Reputation(jailed_UID) if get_reputation is None: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : No code is requested ...") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...") return False jailed_IP = get_reputation.ip @@ -1222,31 +1261,85 @@ class Defender(): color_black = self.Config.COLORS.black if release_code == get_reputation.secret_code: - self.Irc.send2socket(f':{dnickname} PRIVMSG {jailed_salon} : Bon mot de passe. Allez du vent !') + self.Protocol.sendPrivMsg(nick_from=dnickname, msg="Bon mot de passe. Allez du vent !", channel=jailed_salon) if self.ModConfig.reputation_ban_all_chan == 1: for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jailed_salon: - self.Irc.send2socket(f":{service_id} MODE {chan.name} -b {jailed_nickname}!*@*") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {jailed_nickname}!*@*") - self.reputation_delete(jailed_UID) + self.Reputation.delete(jailed_UID) self.Logs.debug(f'{jailed_UID} - {jailed_nickname} removed from REPUTATION_DB') - self.Irc.send2socket(f":{service_id} SAPART {jailed_nickname} {jailed_salon}") - self.Irc.send2socket(f":{service_id} SAJOIN {jailed_nickname} {welcome_salon}") - self.Irc.send2socket(f":{link} REPUTATION {jailed_IP} {self.ModConfig.reputation_score_after_release}") + self.Protocol.send2socket(f":{service_id} SAPART {jailed_nickname} {jailed_salon}") + self.Protocol.send2socket(f":{service_id} SAJOIN {jailed_nickname} {welcome_salon}") + self.Protocol.send2socket(f":{link} REPUTATION {jailed_IP} {self.ModConfig.reputation_score_after_release}") self.User.get_User(jailed_UID).score_connexion = reputation_seuil + 1 - self.Irc.send2socket(f":{service_id} PRIVMSG {jailed_nickname} :[{color_green} MOT DE PASS CORRECT {color_black}] : You have now the right to enjoy the network !") + self.Protocol.sendPrivMsg(nick_from=dnickname, + msg=f"[{color_green} MOT DE PASS CORRECT {color_black}] : You have now the right to enjoy the network !", + nick_to=jailed_nickname) else: - self.Irc.send2socket(f':{dnickname} PRIVMSG {jailed_salon} : Mauvais password') - self.Irc.send2socket(f":{service_id} PRIVMSG {jailed_nickname} :[{color_green} MAUVAIS PASSWORD {color_black}]") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg="Mauvais password", + channel=jailed_salon + ) + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[{color_green} MAUVAIS PASSWORD {color_black}]", + nick_to=jailed_nickname + ) - except IndexError: - self.Logs.error('_hcmd code: out of index') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]') + except IndexError as ie: + self.Logs.error(f'Index Error: {ie}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} code [code]") except KeyError as ke: self.Logs.error(f'_hcmd code: KeyError {ke}') - # self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]') + + case 'autolimit': + try: + # autolimit on + # autolimit set [amount] [interval] + + arg = str(cmd[1]).lower() + + match arg: + case 'on': + if self.ModConfig.autolimit == 0: + self.__update_configuration('autolimit', 1) + self.autolimit_isRunning = True + self.Base.create_thread(self.thread_autolimit) + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Activated", channel=self.Config.SERVICE_CHANLOG) + else: + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already activated", channel=self.Config.SERVICE_CHANLOG) + + case 'off': + if self.ModConfig.autolimit == 1: + self.__update_configuration('autolimit', 0) + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Deactivated", channel=self.Config.SERVICE_CHANLOG) + else: + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already Deactivated", channel=self.Config.SERVICE_CHANLOG) + + case 'set': + amount = int(cmd[2]) + interval = int(cmd[3]) + + self.__update_configuration('autolimit_amount', amount) + self.__update_configuration('autolimit_interval', interval) + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Amount set to ({amount}) | Interval set to ({interval})", + channel=self.Config.SERVICE_CHANLOG + ) + + case _: + self.Protocol.sendNotice(nick_from=dnickname, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON", nickname=fromuser) + self.Protocol.sendNotice(nick_from=dnickname, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]", nickname=fromuser) + + except Exception as err: + self.Protocol.sendNotice(nick_from=dnickname, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON", nickname=fromuser) + self.Protocol.sendNotice(nick_from=dnickname, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]", nickname=fromuser) + self.Logs.error(f"Value Error -> {err}") case 'reputation': # .reputation [on/off] --> activate or deactivate reputation system @@ -1263,44 +1356,53 @@ class Defender(): if activation == 'on': if self.ModConfig.reputation == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already activated", channel=dchanlog) return False # self.update_db_configuration('reputation', 1) self.__update_configuration(key, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Activated by {fromuser}") - self.Irc.send2socket(f":{service_id} JOIN {jail_chan}") - self.Irc.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") - self.Irc.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) + + self.Protocol.join(uidornickname=dnickname, channel=jail_chan) + self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") + self.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") if self.ModConfig.reputation_sg == 1: for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_chan: - self.Irc.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users") - self.Irc.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") - self.Base.db_query_channel('add', self.module_name, jail_chan) + self.Channel.db_query_channel('add', self.module_name, jail_chan) if activation == 'off': if self.ModConfig.reputation == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already deactivated") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already deactivated", + channel=dchanlog + ) return False self.__update_configuration(key, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}REPUTATION{self.Config.COLORS.black} ] : Deactivated by {fromuser}") - self.Irc.send2socket(f":{service_id} SAMODE {jail_chan} -{dumodes} {dnickname}") - self.Irc.send2socket(f":{service_id} MODE {jail_chan} -sS") - self.Irc.send2socket(f":{service_id} PART {jail_chan}") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.red}REPUTATION{self.Config.COLORS.black} ] : Deactivated by {fromuser}", + channel=dchanlog + ) + self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} -{dumodes} {dnickname}") + self.Protocol.send2socket(f":{service_id} MODE {jail_chan} -sS") + self.Protocol.send2socket(f":{service_id} PART {jail_chan}") for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_chan: - self.Irc.send2socket(f":{service_id} MODE {chan.name} -b ~security-group:unknown-users") - self.Irc.send2socket(f":{service_id} MODE {chan.name} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b ~security-group:unknown-users") + self.Protocol.send2socket(f":{service_id} MODE {chan.name} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") - self.Base.db_query_channel('del', self.module_name, jail_chan) + self.Channel.db_query_channel('del', self.module_name, jail_chan) if len_cmd == 4: get_set = str(cmd[1]).lower() @@ -1318,23 +1420,39 @@ class Defender(): if get_value == 'on': if self.ModConfig.reputation_ban_all_chan == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already activated") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already activated", + channel=dchanlog + ) return False # self.update_db_configuration(key, 1) self.__update_configuration(key, 1) - self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Activated by {fromuser}') + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Activated by {fromuser}", + channel=dchanlog + ) elif get_value == 'off': if self.ModConfig.reputation_ban_all_chan == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already deactivated") + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already deactivated", + channel=dchanlog + ) return False # self.update_db_configuration(key, 0) self.__update_configuration(key, 0) - self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Deactivated by {fromuser}') + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Deactivated by {fromuser}", + channel=dchanlog + ) case 'limit': reputation_seuil = int(cmd[3]) @@ -1343,53 +1461,69 @@ class Defender(): # self.update_db_configuration(key, reputation_seuil) self.__update_configuration(key, reputation_seuil) - self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION SEUIL{self.Config.COLORS.black} ] : Limit set to {str(reputation_seuil)} by {fromuser}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Reputation set to {reputation_seuil}') + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}REPUTATION SEUIL{self.Config.COLORS.black} ] : Limit set to {str(reputation_seuil)} by {fromuser}", + channel=dchanlog + ) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation set to {reputation_seuil}") case 'timer': reputation_timer = int(cmd[3]) key = 'reputation_timer' self.__update_configuration(key, reputation_timer) - self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION TIMER{self.Config.COLORS.black} ] : Timer set to {str(reputation_timer)} minute(s) by {fromuser}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Reputation set to {reputation_timer}') + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}REPUTATION TIMER{self.Config.COLORS.black} ] : Timer set to {str(reputation_timer)} minute(s) by {fromuser}", + channel=dchanlog + ) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation set to {reputation_timer}") case 'score_after_release': reputation_score_after_release = int(cmd[3]) key = 'reputation_score_after_release' self.__update_configuration(key, reputation_score_after_release) - self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION SCORE AFTER RELEASE{self.Config.COLORS.black} ] : Reputation score after release set to {str(reputation_score_after_release)} by {fromuser}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Reputation score after release set to {reputation_score_after_release}') + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}REPUTATION SCORE AFTER RELEASE{self.Config.COLORS.black} ] : Reputation score after release set to {str(reputation_score_after_release)} by {fromuser}", + channel=dchanlog + ) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_score_after_release}") case 'security_group': reputation_sg = int(cmd[3]) key = 'reputation_sg' self.__update_configuration(key, reputation_sg) - self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}REPUTATION SECURITY-GROUP{self.Config.COLORS.black} ] : Reputation Security-group set to {str(reputation_sg)} by {fromuser}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Reputation score after release set to {reputation_sg}') + self.Protocol.sendPrivMsg( + nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}REPUTATION SECURITY-GROUP{self.Config.COLORS.black} ] : Reputation Security-group set to {str(reputation_sg)} by {fromuser}", + channel=dchanlog + ) + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_sg}") case _: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Right command : /msg {dnickname} reputation [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Right command : /msg {dnickname} reputation set banallchan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Right command : /msg {dnickname} reputation set limit [1234]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Right command : /msg {dnickname} reputation set score_after_release [1234]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Right command : /msg {dnickname} reputation set timer [1234]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Right command : /msg {dnickname} reputation set action [kill|None]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set action [kill|None]") except IndexError as ie: self.Logs.warning(f'{ie}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set banallchan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set limit [1234]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set score_after_release [1234]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set timer [1234]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set action [kill|None]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set action [kill|None]") except ValueError as ve: self.Logs.warning(f'{ve}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : La valeur devrait etre un entier >= 0') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" La valeur devrait etre un entier >= 0") case 'proxy_scan': @@ -1405,11 +1539,11 @@ class Defender(): set_key = str(cmd[1]).lower() if set_key != 'set': - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') option = str(cmd[2]).lower() # => local_scan, psutil_scan, abuseipdb_scan action = str(cmd[3]).lower() # => on / off @@ -1418,105 +1552,105 @@ class Defender(): case 'local_scan': if action == 'on': if self.ModConfig.local_scan == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None self.__update_configuration(option, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': if self.ModConfig.local_scan == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None self.__update_configuration(option, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case 'psutil_scan': if action == 'on': if self.ModConfig.psutil_scan == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None self.__update_configuration(option, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': if self.ModConfig.psutil_scan == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None self.__update_configuration(option, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case 'abuseipdb_scan': if action == 'on': if self.ModConfig.abuseipdb_scan == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None self.__update_configuration(option, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': if self.ModConfig.abuseipdb_scan == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None self.__update_configuration(option, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case 'freeipapi_scan': if action == 'on': if self.ModConfig.freeipapi_scan == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None self.__update_configuration(option, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': if self.ModConfig.freeipapi_scan == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None self.__update_configuration(option, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case 'cloudfilt_scan': if action == 'on': if self.ModConfig.cloudfilt_scan == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None self.__update_configuration(option, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': if self.ModConfig.cloudfilt_scan == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None self.__update_configuration(option, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case _: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') else: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') case 'flood': # .flood on/off @@ -1531,21 +1665,21 @@ class Defender(): key = 'flood' if activation == 'on': if self.ModConfig.flood == 1: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Already activated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Already activated", channel=dchanlog) return False self.__update_configuration(key, 1) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Activated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) if activation == 'off': if self.ModConfig.flood == 0: - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.red}FLOOD{self.Config.COLORS.black} ] : Already Deactivated") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.red}FLOOD{self.Config.COLORS.black} ] : Already Deactivated", channel=dchanlog) return False self.__update_configuration(key, 0) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Deactivated by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog) if len_cmd == 4: set_key = str(cmd[2]).lower() @@ -1557,21 +1691,27 @@ class Defender(): set_value = int(cmd[3]) self.__update_configuration(key, set_value) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood message set to {set_value} by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood message set to {set_value} by {fromuser}", + channel=dchanlog) case 'flood_time': key = 'flood_time' set_value = int(cmd[3]) self.__update_configuration(key, set_value) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood time set to {set_value} by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood time set to {set_value} by {fromuser}", + channel=dchanlog) case 'flood_timer': key = 'flood_timer' set_value = int(cmd[3]) self.__update_configuration(key, set_value) - self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood timer set to {set_value} by {fromuser}") + self.Protocol.sendPrivMsg(nick_from=dnickname, + msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood timer set to {set_value} by {fromuser}", + channel=dchanlog) case _: pass @@ -1583,23 +1723,24 @@ class Defender(): color_green = self.Config.COLORS.green color_red = self.Config.COLORS.red color_black = self.Config.COLORS.black + nogc = self.Config.COLORS.nogc try: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.ModConfig.reputation == 1 else color_red}Reputation{color_black}] ==> {self.ModConfig.reputation}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_seuil ==> {self.ModConfig.reputation_seuil}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_after_release ==> {self.ModConfig.reputation_score_after_release}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_ban_all_chan ==> {self.ModConfig.reputation_ban_all_chan}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_timer ==> {self.ModConfig.reputation_timer}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [Proxy_scan]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.ModConfig.local_scan == 1 else color_red}local_scan{color_black} ==> {self.ModConfig.local_scan}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.ModConfig.psutil_scan == 1 else color_red}psutil_scan{color_black} ==> {self.ModConfig.psutil_scan}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.ModConfig.abuseipdb_scan == 1 else color_red}abuseipdb_scan{color_black} ==> {self.ModConfig.abuseipdb_scan}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.ModConfig.freeipapi_scan == 1 else color_red}freeipapi_scan{color_black} ==> {self.ModConfig.freeipapi_scan}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.ModConfig.cloudfilt_scan == 1 else color_red}cloudfilt_scan{color_black} ==> {self.ModConfig.cloudfilt_scan}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.ModConfig.flood == 1 else color_red}Flood{color_black}] ==> {self.ModConfig.flood}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_action ==> Coming soon') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_message ==> {self.ModConfig.flood_message}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_time ==> {self.ModConfig.flood_time}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_timer ==> {self.ModConfig.flood_timer}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.reputation == 1 else color_red}Reputation{nogc}] ==> {self.ModConfig.reputation}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_seuil ==> {self.ModConfig.reputation_seuil}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_after_release ==> {self.ModConfig.reputation_score_after_release}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_ban_all_chan ==> {self.ModConfig.reputation_ban_all_chan}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_timer ==> {self.ModConfig.reputation_timer}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' [Proxy_scan]') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.local_scan == 1 else color_red}local_scan{nogc} ==> {self.ModConfig.local_scan}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.psutil_scan == 1 else color_red}psutil_scan{nogc} ==> {self.ModConfig.psutil_scan}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.abuseipdb_scan == 1 else color_red}abuseipdb_scan{nogc} ==> {self.ModConfig.abuseipdb_scan}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.freeipapi_scan == 1 else color_red}freeipapi_scan{nogc} ==> {self.ModConfig.freeipapi_scan}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.cloudfilt_scan == 1 else color_red}cloudfilt_scan{nogc} ==> {self.ModConfig.cloudfilt_scan}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Flood{nogc}] ==> {self.ModConfig.flood}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_action ==> Coming soon') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.ModConfig.flood_message}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.ModConfig.flood_time}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.ModConfig.flood_timer}') except KeyError as ke: self.Logs.error(f"Key Error : {ke}") @@ -1615,22 +1756,22 @@ class Defender(): if self.Base.clean_uid(uid_in_chan) == UserObject.uid: channels.append(chan.name) - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : UID : {UserObject.uid}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : NICKNAME : {UserObject.nickname}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : USERNAME : {UserObject.username}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : REALNAME : {UserObject.realname}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : HOSTNAME : {UserObject.hostname}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : VHOST : {UserObject.vhost}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : IP : {UserObject.remote_ip}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Country : {UserObject.geoip}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : WebIrc : {UserObject.isWebirc}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : WebWebsocket : {UserObject.isWebsocket}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : REPUTATION : {UserObject.score_connexion}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : MODES : {UserObject.umodes}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : CHANNELS : {channels}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : CONNECTION TIME : {UserObject.connexion_datetime}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' UID : {UserObject.uid}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' NICKNAME : {UserObject.nickname}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' USERNAME : {UserObject.username}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' REALNAME : {UserObject.realname}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' HOSTNAME : {UserObject.hostname}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' VHOST : {UserObject.vhost}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' IP : {UserObject.remote_ip}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' Country : {UserObject.geoip}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' WebIrc : {UserObject.isWebirc}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {channels}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}') else: - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : This user {nickoruid} doesn't exist") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f":{dnickname} NOTICE {fromuser} : This user {nickoruid} doesn't exist") except KeyError as ke: self.Logs.warning(f"Key error info user : {ke}") @@ -1645,9 +1786,9 @@ class Defender(): if activation == 'on': for chan in self.Channel.UID_CHANNEL_DB: if not chan.name in channel_to_dont_quit: - self.Irc.send2socket(f":{service_id} JOIN {chan.name}") + self.Protocol.join(uidornickname=dnickname, channel=chan.name) if activation == 'off': for chan in self.Channel.UID_CHANNEL_DB: if not chan.name in channel_to_dont_quit: - self.Irc.send2socket(f":{service_id} PART {chan.name}") + self.Protocol.part(uidornickname=dnickname, channel=chan.name) self.join_saved_channels() diff --git a/mods/mod_jsonrpc.py b/mods/mod_jsonrpc.py index 3ea26b2..dcdaf76 100644 --- a/mods/mod_jsonrpc.py +++ b/mods/mod_jsonrpc.py @@ -1,8 +1,11 @@ +import logging +from typing import TYPE_CHECKING from dataclasses import dataclass -from core.irc import Irc from unrealircd_rpc_py.Live import Live from unrealircd_rpc_py.Loader import Loader +if TYPE_CHECKING: + from core.irc import Irc class Jsonrpc(): @@ -12,7 +15,7 @@ class Jsonrpc(): """ jsonrpc: int = 0 - def __init__(self, ircInstance:Irc) -> None: + def __init__(self, ircInstance: 'Irc') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() @@ -20,6 +23,9 @@ class Jsonrpc(): # Add Irc Object to the module (Mandatory) self.Irc = ircInstance + # Add Protocol to the module (Mandatory) + self.Protocol = ircInstance.Protocol + # Add Global Configuration to the module (Mandatory) self.Config = ircInstance.Config @@ -50,6 +56,7 @@ class Jsonrpc(): # Insert module commands into the core one (Mandatory) self.__set_commands(self.commands_level) + logging.getLogger('websockets').setLevel(logging.WARNING) # Create you own tables (Mandatory) # self.__create_tables() @@ -71,8 +78,7 @@ class Jsonrpc(): username=self.Config.JSONRPC_USER, password=self.Config.JSONRPC_PASSWORD, callback_object_instance=self, - callback_method_name='callback_sent_to_irc', - debug_level=10 + callback_method_name='callback_sent_to_irc' ) self.Rpc: Loader = Loader( @@ -85,10 +91,18 @@ class Jsonrpc(): self.subscribed = False if self.Rpc.Error.code != 0: - self.Irc.sendPrivMsg(f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.Rpc.Error.message}", self.Config.SERVICE_CHANLOG) + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.Rpc.Error.message}", + channel=self.Config.SERVICE_CHANLOG + ) if self.UnrealIrcdRpcLive.Error.code != 0: - self.Irc.sendPrivMsg(f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.Error.message}", self.Config.SERVICE_CHANLOG) + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.Error.message}", + channel=self.Config.SERVICE_CHANLOG + ) if self.ModConfig.jsonrpc == 1: self.Base.create_thread(self.thread_start_jsonrpc, run_once=True) @@ -139,7 +153,10 @@ class Jsonrpc(): red = self.Config.COLORS.red if json_response.result == True: - self.Irc.sendPrivMsg(msg=f"[{bold}{green}JSONRPC{nogc}{bold}] Event activated", channel=dchanlog) + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[{bold}{green}JSONRPC{nogc}{bold}] Event activated", + channel=dchanlog) return None level = json_response.result.level @@ -150,7 +167,7 @@ class Jsonrpc(): build_msg = f"{green}{log_source}{nogc}: [{bold}{level}{bold}] {subsystem}.{event_id} - {msg}" - self.Irc.sendPrivMsg(msg=build_msg, channel=dchanlog) + self.Protocol.sendPrivMsg(nick_from=dnickname, msg=build_msg, channel=dchanlog) def thread_start_jsonrpc(self): @@ -158,7 +175,11 @@ class Jsonrpc(): self.UnrealIrcdRpcLive.subscribe(["all"]) self.subscribed = True else: - self.Irc.sendPrivMsg(f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.Error.message}", self.Config.SERVICE_CHANLOG) + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.Error.message}", + channel=self.Config.SERVICE_CHANLOG + ) def __load_module_configuration(self) -> None: """### Load Module Configuration @@ -208,8 +229,8 @@ class Jsonrpc(): option = str(cmd[1]).lower() if len(command) == 1: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} jsonrpc on') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} jsonrpc off') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc on') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc off') match option: @@ -217,9 +238,17 @@ class Jsonrpc(): for thread in self.Base.running_threads: if thread.getName() == 'thread_start_jsonrpc': if thread.is_alive(): - self.Irc.sendPrivMsg(f"Thread {thread.getName()} is running", dchannel) + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Thread {thread.getName()} is running", + channel=dchannel + ) else: - self.Irc.sendPrivMsg(f"Thread {thread.getName()} is not running, wait untill the process will be cleaned up", dchannel) + self.Protocol.sendPrivMsg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"Thread {thread.getName()} is not running, wait untill the process will be cleaned up", + channel=dchannel + ) self.Base.create_thread(self.thread_start_jsonrpc, run_once=True) self.__update_configuration('jsonrpc', 1) @@ -236,7 +265,7 @@ class Jsonrpc(): option = str(cmd[1]).lower() if len(command) == 1: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} jruser get nickname') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jruser get nickname') match option: @@ -250,37 +279,37 @@ class Jsonrpc(): UserInfo = rpc.User.get(uid_to_get) if rpc.Error.code != 0: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{rpc.Error.message}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'{rpc.Error.message}') return None chan_list = [] for chan in UserInfo.user.channels: chan_list.append(chan.name) - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :UID : {UserInfo.id}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :NICKNAME : {UserInfo.name}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :USERNAME : {UserInfo.user.username}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :REALNAME : {UserInfo.user.realname}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :MODES : {UserInfo.user.modes}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CHANNELS : {chan_list}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :SECURITY GROUP : {UserInfo.user.security_groups}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :REPUTATION : {UserInfo.user.reputation}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'UID : {UserInfo.id}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'NICKNAME : {UserInfo.name}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'REALNAME : {UserInfo.user.realname}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'MODES : {UserInfo.user.modes}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {chan_list}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'SECURITY GROUP : {UserInfo.user.security_groups}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'REPUTATION : {UserInfo.user.reputation}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :IP : {UserInfo.ip}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :COUNTRY CODE : {UserInfo.geoip.country_code}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :ASN : {UserInfo.geoip.asn}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :ASNAME : {UserInfo.geoip.asname}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CLOAKED HOST : {UserInfo.user.cloakedhost}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :HOSTNAME : {UserInfo.hostname}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :VHOST : {UserInfo.user.vhost}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CLIENT PORT : {UserInfo.client_port}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :SERVER PORT : {UserInfo.server_port}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'IP : {UserInfo.ip}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'COUNTRY CODE : {UserInfo.geoip.country_code}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'ASN : {UserInfo.geoip.asn}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'ASNAME : {UserInfo.geoip.asname}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'CLOAKED HOST : {UserInfo.user.cloakedhost}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'HOSTNAME : {UserInfo.hostname}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'VHOST : {UserInfo.user.vhost}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'CLIENT PORT : {UserInfo.client_port}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'SERVER PORT : {UserInfo.server_port}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CERTFP : {UserInfo.tls.certfp}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CIPHER : {UserInfo.tls.cipher}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'CERTFP : {UserInfo.tls.certfp}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'CIPHER : {UserInfo.tls.cipher}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :IDLE SINCE : {UserInfo.idle_since}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CONNECTED SINCE : {UserInfo.connected_since}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'IDLE SINCE : {UserInfo.idle_since}') + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f'CONNECTED SINCE : {UserInfo.connected_since}') except IndexError as ie: self.Logs.error(ie) @@ -290,11 +319,11 @@ class Jsonrpc(): self.Base.create_thread(self.thread_ask_ia, ('',)) - self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : This is a notice to the sender ...") - self.Irc.send2socket(f":{dnickname} PRIVMSG {fromuser} : This is private message to the sender ...") + self.Protocol.sendNotice(nick_from=dnickname, nick_to=fromuser, msg=f" This is a notice to the sender ...") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg="This is private message to the sender ...", nick_to=fromuser) if not fromchannel is None: - self.Irc.send2socket(f":{dnickname} PRIVMSG {fromchannel} : This is channel message to the sender ...") + self.Protocol.sendPrivMsg(nick_from=dnickname, msg="This is channel message to the sender ...", channel=fromchannel) # How to update your module configuration self.__update_configuration('param_exemple2', 7) diff --git a/mods/mod_test.py b/mods/mod_test.py index 8189c80..aaeed38 100644 --- a/mods/mod_test.py +++ b/mods/mod_test.py @@ -1,5 +1,8 @@ +from typing import TYPE_CHECKING from dataclasses import dataclass, fields -from core.irc import Irc + +if TYPE_CHECKING: + from core.irc import Irc class Test(): @@ -10,7 +13,7 @@ class Test(): param_exemple1: str param_exemple2: int - def __init__(self, ircInstance:Irc) -> None: + def __init__(self, ircInstance: 'Irc') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() @@ -18,6 +21,12 @@ class Test(): # Add Irc Object to the module (Mandatory) self.Irc = ircInstance + # Add Loader Object to the module (Mandatory) + self.Loader = ircInstance.Loader + + # Add server protocol Object to the module (Mandatory) + self.Protocol = ircInstance.Protocol + # Add Global Configuration to the module (Mandatory) self.Config = ircInstance.Config @@ -33,6 +42,9 @@ class Test(): # Add Channel object to the module (Mandatory) self.Channel = ircInstance.Channel + # Add Reputation object to the module (Optional) + self.Reputation = ircInstance.Reputation + # Create module commands (Mandatory) self.commands_level = { 0: ['test-command'], diff --git a/mods/mod_votekick.py b/mods/mod_votekick.py index 5a8de26..a3806a2 100644 --- a/mods/mod_votekick.py +++ b/mods/mod_votekick.py @@ -1,7 +1,10 @@ -from core.irc import Irc +from typing import TYPE_CHECKING import re from dataclasses import dataclass, field +if TYPE_CHECKING: + from core.irc import Irc + # Activer le systeme sur un salon (activate #salon) # Le service devra se connecter au salon # Le service devra se mettre en op @@ -23,7 +26,7 @@ class Votekick(): VOTE_CHANNEL_DB:list[VoteChannelModel] = [] - def __init__(self, ircInstance:Irc) -> None: + def __init__(self, ircInstance: 'Irc') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() @@ -195,7 +198,7 @@ class Votekick(): def join_saved_channels(self) -> None: param = {'module_name': self.module_name} - result = self.Base.db_execute_query(f"SELECT id, channel_name FROM {self.Config.table_channel} WHERE module_name = :module_name", param) + result = self.Base.db_execute_query(f"SELECT id, channel_name FROM {self.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param) channels = result.fetchall() unixtime = self.Base.get_unixtime() @@ -285,7 +288,7 @@ class Votekick(): self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command') return None - sentchannel = str(cmd[2]).lower() if self.Base.Is_Channel(str(cmd[2]).lower()) else None + sentchannel = str(cmd[2]).lower() if self.Channel.Is_Channel(str(cmd[2]).lower()) else None if sentchannel is None: self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL") @@ -299,7 +302,7 @@ class Votekick(): ) ) - self.Base.db_query_channel('add', self.module_name, sentchannel) + self.Channel.db_query_channel('add', self.module_name, sentchannel) self.Irc.send2socket(f":{dnickname} JOIN {sentchannel}") self.Irc.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}") @@ -316,7 +319,7 @@ class Votekick(): self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command') return None - sentchannel = str(cmd[2]).lower() if self.Base.Is_Channel(str(cmd[2]).lower()) else None + sentchannel = str(cmd[2]).lower() if self.Channel.Is_Channel(str(cmd[2]).lower()) else None if sentchannel is None: self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL") @@ -326,7 +329,7 @@ class Votekick(): for chan in self.VOTE_CHANNEL_DB: if chan.channel_name == sentchannel: self.VOTE_CHANNEL_DB.remove(chan) - self.Base.db_query_channel('del', self.module_name, chan.channel_name) + self.Channel.db_query_channel('del', self.module_name, chan.channel_name) self.Logs.debug(f"The Channel {sentchannel} has been deactivated from the vote system") except Exception as err: diff --git a/version.json b/version.json index c786334..98162f5 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "5.4.0", + "version": "6.0.0", "requests": "2.32.3", "psutil": "6.0.0",