From 99f8949681b6083649a61bdbb7a1f71ac855aa3a Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 28 Oct 2025 01:02:27 +0100 Subject: [PATCH 01/56] Create Makefile installation; update copyright core command. TODO replace installation.py script. --- Makefile | 55 +++++++++++++++++++++++++++++++++++++ core/install.py | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ core/irc.py | 2 +- requirements.txt | 6 +++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 Makefile create mode 100644 core/install.py create mode 100644 requirements.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..28b9a68 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +OS := $(shell uname -s) +CURRENT_USER := $(shell whoami) +PYTHON_VERSION := $(shell python3 -V) +HOME_DIR := $(shell echo $$HOME) +SHELL := /bin/bash + +install: +ifeq ($(wildcard config/configuration.yaml),) + $(error You must provide the Configuration file: config/configuration.yaml) +endif + +ifeq ($(OS), Linux) + $(info Installation for os : $(OS)) + $(info Python version: $(PYTHON_VERSION)) + $(info Home directory: $(HOME_DIR)) + + @python3 core/install.py --check-version + @if [ $$? -eq 0 ]; then \ + echo "Python Version OK! Well done :)"; \ + else \ + echo "Error: Script failed with exit code $$?"; \ + exit 1; \ + fi + + $(info Creating the systemd user folder...) + mkdir -p $(HOME_DIR)/.config/systemd/user + + $(info Creating Python Virtual Environment...) + python3 -m venv .pyenv + @. .pyenv/bin/activate && \ + python -m pip install --upgrade pip && \ + pip cache purge && \ + pip install -r requirements.txt + + @. .pyenv/bin/activate && python core/install.py --install + loginctl enable-linger $(CURRENT_USER) + @sleep 2 + @export echo $DBUS_SESSION_BUS_ADDRESS && \ + systemctl --user daemon-reload && \ + systemctl --user start defender + +endif + +clean: +ifeq ($(OS), Linux) + @if [ -e .pyenv ]; then \ + rm -rf .pyenv; \ + echo "Virtual Env has been removed!"; \ + fi + @if [ -e $(HOME_DIR)/.config/systemd/user/defender.service ]; then \ + rm $(HOME_DIR)/.config/systemd/user/defender.service; \ + echo "Systemd file has been removed!"; \ + fi + @export echo $DBUS_SESSION_BUS_ADDRESS && systemctl --user daemon-reload && echo "Systemd Daemon reloaded!" +endif diff --git a/core/install.py b/core/install.py new file mode 100644 index 0000000..dd5457c --- /dev/null +++ b/core/install.py @@ -0,0 +1,70 @@ +import argparse +import os +import sys +from pathlib import Path +from platform import python_version_tuple + +parser = argparse.ArgumentParser(description="Python Installation Code") +parser.add_argument('--check-version', action='store_true', help='Check if the python version is ok!') +parser.add_argument('--install', action='store_true', help='Run the installation') +args = parser.parse_args() + +PYTHON_REQUIRED_VERSION = (3, 10, 0) +PYTHON_SYSTEM_VERSION = tuple(map(int, python_version_tuple())) +ROOT_PATH = os.getcwd() +PYENV = Path(f'{ROOT_PATH}/.pyenv/bin/python') +USER_HOME_DIRECTORY = Path.home() +SYSTEMD_PATH = Path(USER_HOME_DIRECTORY).joinpath('.config', 'systemd', 'user') +PY_EXEC = 'defender.py' +SERVICE_FILE_NAME = 'defender.service' + +def check_python_requirement(): + if PYTHON_SYSTEM_VERSION < PYTHON_REQUIRED_VERSION: + raise RuntimeError(f"Your Python Version is not meeting the requirement, System Version: {PYTHON_SYSTEM_VERSION} < Required Version {PYTHON_REQUIRED_VERSION}") + +def create_service_file(): + + pyenv = PYENV + systemd_path = SYSTEMD_PATH + py_exec = PY_EXEC + service_file_name = SERVICE_FILE_NAME + + if not Path(systemd_path).exists(): + print("[!] Folder not available") + sys.exit(1) + + contain = f'''[Unit] +Description=Defender IRC Service + +[Service] +ExecStart={pyenv} {py_exec} +WorkingDirectory={ROOT_PATH} +SyslogIdentifier=Defender +Restart=on-failure + +[Install] +WantedBy=default.target +''' + with open(Path(systemd_path).joinpath(service_file_name), "w") as file: + file.write(contain) + print('Service file generated with current configuration') + print('Running IRC Service ...') + + print(f"#"*24) + print("Installation complete ...") + print("If the configuration is correct, then you must see your service connected to your irc server") + print(f"If any issue, you can see the log file for debug {ROOT_PATH}{os.sep}logs{os.sep}defender.log") + print(f"#"*24) + +def main(): + if args.check_version: + check_python_requirement() + sys.exit(0) + + if args.install: + create_service_file() + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/core/irc.py b/core/irc.py index 5602238..8ee2e96 100644 --- a/core/irc.py +++ b/core/irc.py @@ -1220,7 +1220,7 @@ class Irc: self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f">> Defender V.{self.Config.CURRENT_VERSION} Developped by adator®." + msg=f">> Defender V{self.Config.CURRENT_VERSION} Developped by adator®." ) return None diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f8c2d3a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +Faker==33.1.2 +psutil==6.1.1 +PyYAML==6.0.2 +requests==2.32.3 +SQLAlchemy==2.0.36 +unrealircd_rpc_py==3.0.2 \ No newline at end of file From e5a5f0160393fe1ab1302975ea352845756c84a9 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 28 Oct 2025 23:33:43 +0100 Subject: [PATCH 02/56] Adding 'make update' to update from git repository. remove previous installation.py file, the update of packages is done via install.py file. --- Makefile | 7 + README.md | 139 ++++++------- config/exemple_configuration.yaml | 2 +- core/install.py | 82 +++++++- core/installation.py | 314 ------------------------------ defender.py | 4 +- requirements.txt | 10 +- version.json | 10 +- 8 files changed, 173 insertions(+), 395 deletions(-) delete mode 100644 core/installation.py diff --git a/Makefile b/Makefile index 28b9a68..ed7516b 100644 --- a/Makefile +++ b/Makefile @@ -53,3 +53,10 @@ ifeq ($(OS), Linux) fi @export echo $DBUS_SESSION_BUS_ADDRESS && systemctl --user daemon-reload && echo "Systemd Daemon reloaded!" endif + +update: +ifeq ($(OS), Linux) + $(info Starting update from the main repository...) + @. .pyenv/bin/activate && python core/install.py --git-update + $(info Update done!) +endif diff --git a/README.md b/README.md index ecae94a..d651878 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,11 @@ Il permet aux opérateurs de gérer efficacement un canal, tout en offrant aux u - Python version 3.10 ou supérieure ```bash # Bash - $ git clone https://github.com/adator85/IRC_DEFENDER_MODULES.git + $ git clone https://github.com/adator85/DEFENDER.git defender + $ cd defender/ # Renommer le fichier exemple_configuration.json en configuration.json # Configurer le fichier configuration.json - $ python3 main.py + $ make install ``` Si votre configuration est bonne, votre service est censé etre connecté a votre réseau IRC Pour Les prochains lancement de defender vous devez utiliser la commande suivante: @@ -49,11 +50,11 @@ Pour Les prochains lancement de defender vous devez utiliser la commande suivant # Installation manuelle: ```bash # Bash - $ git clone https://github.com/adator85/IRC_DEFENDER_MODULES.git - $ cd IRC_DEFENDER_MODULES + $ git clone https://github.com/adator85/DEFENDER.git defender + $ cd defender/ $ python3 -m venv .pyenv $ source .pyenv/bin/activate - (pyenv)$ pip install sqlalchemy, psutil, requests, faker, unrealircd_rpc_py, pyyaml + (pyenv)$ pip install -r requirements.txt # Créer un service nommé "defender.service" # pour votre service et placer le dans "/PATH/TO/USER/.config/systemd/user/" @@ -104,87 +105,91 @@ Pour Les prochains lancement de defender vous devez utiliser la commande suivant GLINE_DURATION: Durée de bannissement temporaire d'un utilisateur en minutes. (default : "30") DEBUG (Debug) - DEBUG_LEVEL: Niveau de verbosité des messages de debug (plus grand est le nombre, plus il y a d'informations). (default : 20) Pour une production + DEBUG_LEVEL: Niveau de verbosité des messages de debug (plus petit est le nombre, plus il y a d'informations). (default : 20) Pour une production + DEBUG_HARD: Généralement utiliser pour les developpeurs. ``` Modification de la configuration - Vous devez modifier le fichier configuration.json en remplaçant les valeurs par défaut avec vos propres informations. Assurez-vous de bien lire la description de chaque paramètre pour une configuration optimale du service. + Vous devez modifier le fichier configuration.yaml en remplaçant les valeurs par défaut avec vos propres informations. Assurez-vous de bien lire la description de chaque paramètre pour une configuration optimale du service. ## Exemple de configuration de base -```json -{ - "SERVEUR_IP": "IP.DE.TON.SERVER", - "SERVEUR_HOSTNAME": "HOST.DE.TON.SERVER", - "SERVEUR_LINK": "LINK.DE.TON.SERVER", - "SERVEUR_PORT": 6901, - "SERVEUR_PASSWORD": "MOT_DE_PASS_DE_TON_LINK", - "SERVEUR_ID": "10Z", - "SERVEUR_SSL": true, +```yaml +configuration: + SERVEUR_IP: "YOUR.SERVER.IP" + SERVEUR_HOSTNAME: "YOUR.SERVER.HOST" + SERVEUR_LINK: "LINK.DE.TON.SERVER" + SERVEUR_PORT: 7002 + SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD" + SERVEUR_ID: "006" + SERVEUR_SSL: true - "SERVICE_NAME": "defender", - "SERVICE_NICKNAME": "PyDefender", - "SERVICE_REALNAME": "Python Defender Security", - "SERVICE_USERNAME": "PyDefender", - "SERVICE_HOST": "HOST.DE.TON.DEFENDER", + SERVICE_NAME: "defender" + SERVICE_NICKNAME: "PyDefender" + SERVICE_REALNAME: "Python Defender Security" + SERVICE_USERNAME: "PyDefender" + SERVICE_HOST: "HOST.DE.TON.DEFENDER" + SERVICE_INFO: "Network IRC Service" + SERVICE_CHANLOG: "#services" + SERVICE_SMODES: "+ioqBS" + SERVICE_CMODES: "ntsOP" + SERVICE_UMODES: "o" + SERVICE_PREFIX: "!" - "OWNER": "TON_NICK_NAME", - "PASSWORD": "TON_PASSWORD" - -} + OWNER: "TON_NICK_NAME" + PASSWORD: "TON_PASSWORD" ``` ## Exemple complet de configuration -```json -{ - "SERVEUR_IP": "YOUR.SERVER.IP", - "SERVEUR_HOSTNAME": "YOUR.SERVER.HOST", - "SERVEUR_LINK": "LINK.DE.TON.SERVER", - "SERVEUR_PORT": 6901, - "SERVEUR_PASSWORD": "YOUR_LINK_PASSWORD", - "SERVEUR_ID": "10Z", - "SERVEUR_SSL": true, +```yaml +configuration: + SERVEUR_IP: "YOUR.SERVER.IP" + SERVEUR_HOSTNAME: "YOUR.SERVER.HOST" + SERVEUR_LINK: "LINK.DE.TON.SERVER" + SERVEUR_PORT: 7002 + SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD" + SERVEUR_ID: "006" + SERVEUR_SSL: true - "SERVICE_NAME": "defender", - "SERVICE_NICKNAME": "PyDefender", - "SERVICE_REALNAME": "Python Defender Security", - "SERVICE_USERNAME": "PyDefender", - "SERVICE_HOST": "HOST.DE.TON.DEFENDER", - "SERVICE_INFO": "Network IRC Service", - "SERVICE_CHANLOG": "#services", - "SERVICE_SMODES": "+ioqBS", - "SERVICE_CMODES": "ntsOP", - "SERVICE_UMODES": "o", - "SERVICE_PREFIX": "!", + SERVICE_NAME: "defender" + SERVICE_NICKNAME: "PyDefender" + SERVICE_REALNAME: "Python Defender Security" + SERVICE_USERNAME: "PyDefender" + SERVICE_HOST: "HOST.DE.TON.DEFENDER" + SERVICE_INFO: "Network IRC Service" + SERVICE_CHANLOG: "#services" + SERVICE_SMODES: "+ioqBS" + SERVICE_CMODES: "ntsOP" + SERVICE_UMODES: "o" + SERVICE_PREFIX: "!" - "OWNER": "TON_NICK_NAME", - "PASSWORD": "TON_PASSWORD", + OWNER: "TON_NICK_NAME" + PASSWORD: "TON_PASSWORD" - "JSONRPC_URL": "https://your.domaine.com:8600/api", - "JSONRPC_PATH_TO_SOCKET_FILE": "/PATH/TO/YOUR/IRCD/data/rpc.socket", - "JSONRPC_METHOD": "socket", - "JSONRPC_USER": "YOUR_RPC_USER", - "JSONRPC_PASSWORD": "YOUR_RPC_PASSWORD", + JSONRPC_URL: "https://your.domaine.com:8600/api" + JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket" + JSONRPC_METHOD: "unixsocket" + JSONRPC_USER: "YOUR_RPC_USER" + JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD" - "SALON_JAIL": "#jail", - "SALON_JAIL_MODES": "sS", - "SALON_LIBERER": "#welcome", + SALON_JAIL: "#jail" + SALON_JAIL_MODES: "sS" + SALON_LIBERER: "#welcome" - "CLONE_CHANNEL": "#clones", - "CLONE_CMODES": "+nts", - "CLONE_LOG_HOST_EXEMPT": ["HOST.TO.SKIP"], - "CLONE_CHANNEL_PASSWORD": "YOUR_CHANNEL_PASSWORD", + CLONE_CHANNEL: "#clones" + CLONE_CMODES: "+nts" + CLONE_LOG_HOST_EXEMPT: ["HOST.TO.SKIP"] + CLONE_CHANNEL_PASSWORD: "YOUR_CHANNEL_PASSWORD" - "API_TIMEOUT": 2, + API_TIMEOUT: 2 - "PORTS_TO_SCAN": [3028, 8080, 1080, 1085, 4145, 9050], - "WHITELISTED_IP": ["127.0.0.1"], - "GLINE_DURATION": "30", + PORTS_TO_SCAN: [3028 8080 1080 1085 4145 9050] + WHITELISTED_IP: ["127.0.0.1"] + GLINE_DURATION: "30" - "DEBUG_LEVEL": 20 - -} + DEBUG_LEVEL: 20 + DEBUG_HARD: true ``` # \\!/ Attention \\!/ @@ -192,7 +197,7 @@ Le mot de passe de l'administrateur et le mot de passe du service doivent être Ne partagez pas vos informations de connexion au serveur IRC avec des tiers. a votre premiere connexion vous devez tapez ``` - /msg [NomDuService] auth [nickname] [password] + /msg [NomDuService] firstauth [nickname] [password] -- Une fois identifié tapez la commande suivante /msg [NomDuService] editaccess [nickname] [Nouveau-Password] 5 ``` diff --git a/config/exemple_configuration.yaml b/config/exemple_configuration.yaml index 6bd50a6..0f40bfc 100644 --- a/config/exemple_configuration.yaml +++ b/config/exemple_configuration.yaml @@ -24,7 +24,7 @@ configuration: JSONRPC_URL: "https://your.domaine.com:8600/api" JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket" - JSONRPC_METHOD: "socket" + JSONRPC_METHOD: "unixsocket" JSONRPC_USER: "YOUR_RPC_USER" JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD" diff --git a/core/install.py b/core/install.py index dd5457c..8ca3b78 100644 --- a/core/install.py +++ b/core/install.py @@ -1,23 +1,99 @@ import argparse import os import sys +import json +from dataclasses import dataclass +from subprocess import check_call, CalledProcessError, check_output from pathlib import Path from platform import python_version_tuple +import traceback parser = argparse.ArgumentParser(description="Python Installation Code") parser.add_argument('--check-version', action='store_true', help='Check if the python version is ok!') parser.add_argument('--install', action='store_true', help='Run the installation') +parser.add_argument('--git-update', action='store_true', help='Update from git (main repository)') args = parser.parse_args() PYTHON_REQUIRED_VERSION = (3, 10, 0) PYTHON_SYSTEM_VERSION = tuple(map(int, python_version_tuple())) ROOT_PATH = os.getcwd() -PYENV = Path(f'{ROOT_PATH}/.pyenv/bin/python') +PYENV = Path(ROOT_PATH).joinpath('.pyenv/bin/python') if os.name != 'nt' else Path(ROOT_PATH).joinpath('.pyenv/Scripts/python.exe') +PIPENV = Path(f'{ROOT_PATH}/.pyenv/bin/pip') if os.name != 'nt' else Path(f'{ROOT_PATH}/.pyenv/Scripts/pip.exe') USER_HOME_DIRECTORY = Path.home() SYSTEMD_PATH = Path(USER_HOME_DIRECTORY).joinpath('.config', 'systemd', 'user') PY_EXEC = 'defender.py' SERVICE_FILE_NAME = 'defender.service' +@dataclass +class Package: + name: str = None + version: str = None + +def __load_required_package_versions() -> list[Package]: + """This will create Package model with package names and required version + """ + try: + DB_PACKAGES: list[Package] = [] + version_filename = Path(ROOT_PATH).joinpath('version.json') # f'.{os.sep}version.json' + with open(version_filename, 'r') as version_data: + package_info:dict[str, str] = json.load(version_data) + + for name, version in package_info.items(): + if name == 'version': + continue + DB_PACKAGES.append( + Package(name=name, version=version) + ) + + return DB_PACKAGES + + except FileNotFoundError as fe: + print(f"File not found: {fe}") + except Exception as err: + print(f"General Error: {err}") + +def update_packages() -> None: + try: + newVersion = False + db_packages = __load_required_package_versions() + print(ROOT_PATH) + if sys.prefix not in PYENV.__str__(): + print(f"You are probably running a new installation or you are not using your virtual env {PYENV}") + return newVersion + + print(f"> Checking for dependencies versions ==> WAIT") + for package in db_packages: + newVersion = False + _required_version = package.version + _installed_version: str = None + output = check_output([PIPENV, 'show', package.name]) + for line in output.decode().splitlines(): + if line.startswith('Version:'): + _installed_version = line.split(':')[1].strip() + break + + required_version = tuple(map(int, _required_version.split('.'))) + installed_version = tuple(map(int, _installed_version.split('.'))) + + if required_version > installed_version: + print(f'> New version of {package.name} is available {installed_version} ==> {required_version}') + newVersion = True + + if newVersion: + check_call([PIPENV, 'install', '--upgrade', package.name]) + + print(f"> Dependencies versions ==> OK") + return newVersion + + except CalledProcessError: + print(f"[!] Package {package.name} not installed [!]") + except Exception as err: + print(f"UpdatePackage Error: {err}") + traceback.print_exc() + +def run_git_update() -> None: + check_call(['git', 'pull', 'origin', 'main']) + def check_python_requirement(): if PYTHON_SYSTEM_VERSION < PYTHON_REQUIRED_VERSION: raise RuntimeError(f"Your Python Version is not meeting the requirement, System Version: {PYTHON_SYSTEM_VERSION} < Required Version {PYTHON_REQUIRED_VERSION}") @@ -64,6 +140,10 @@ def main(): if args.install: create_service_file() sys.exit(0) + + if args.git_update: + run_git_update() + sys.exit(0) if __name__ == "__main__": diff --git a/core/installation.py b/core/installation.py deleted file mode 100644 index dcbe1e4..0000000 --- a/core/installation.py +++ /dev/null @@ -1,314 +0,0 @@ -import os -import json -from sys import exit, prefix -from dataclasses import dataclass -from subprocess import check_call, run, CalledProcessError, PIPE, check_output -from platform import python_version, python_version_tuple - -class Install: - - @dataclass - class CoreConfig: - install_log_file: str - unix_systemd_folder: str - service_file_name: str - service_cmd_executable: list - service_cmd_daemon_reload: list - defender_main_executable: str - python_min_version: str - python_current_version_tuple: tuple[int, int, int] - python_current_version: tuple[int, int, int] - defender_install_folder: str - venv_folder: str - venv_cmd_installation: list - venv_cmd_requirements: list[str] - venv_pip_executable: str - venv_python_executable: str - - @dataclass - class Package: - name: str = None - version: str = None - - DB_PACKAGES: list[Package] = [] - - def __init__(self) -> None: - - self.set_configuration() - - if self.skip_install: - self.install_dependencies() - self.check_packages_version() - return None - - self.check_packages_version() - - # Sinon tester les dependances python et les installer avec pip - if self.do_install(): - - self.install_dependencies() - - self.create_service_file() - - self.print_final_message() - - return None - - def set_configuration(self): - - self.skip_install = False - defender_install_folder = os.getcwd() - venv_folder = '.pyenv' - unix_user_home_directory = os.path.expanduser("~") - unix_systemd_folder = os.path.join(unix_user_home_directory, '.config', 'systemd', 'user') - defender_main_executable = os.path.join(defender_install_folder, 'defender.py') - - self.config = self.CoreConfig( - install_log_file='install.log', - unix_systemd_folder=unix_systemd_folder, - service_file_name='defender.service', - service_cmd_executable=['systemctl', '--user', 'start', 'defender'], - service_cmd_daemon_reload=['systemctl', '--user', 'daemon-reload'], - defender_main_executable=defender_main_executable, - python_min_version=(3, 10, 0), - python_current_version_tuple=tuple(map(int, python_version_tuple())), - python_current_version=python_version(), - defender_install_folder=defender_install_folder, - venv_folder=venv_folder, - venv_cmd_installation=['python3', '-m', 'venv', venv_folder], - venv_cmd_requirements=['sqlalchemy','psutil','requests','faker','pyyaml','unrealircd_rpc_py'], - venv_pip_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}pip', - venv_python_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}python' - ) - - if not self.check_python_version(): - # 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, 'config', 'configuration.yaml')): - # If configuration file do not exist - exit("[!] Configuration file (core/configuration.yaml) doesn't exist! please create it [!]") - - # Exclude Windows OS from the installation - if os.name == 'nt': - # If windows, modify pip and python virtual environment executable - self.config.venv_pip_executable = f'{os.path.join(defender_install_folder, venv_folder, "Scripts")}{os.sep}pip.exe' - self.config.venv_python_executable = f'{os.path.join(defender_install_folder, venv_folder, "Scripts")}{os.sep}python.exe' - self.skip_install = True - return False - - if self.is_root(): - exit(f'[!] I highly not recommend running Defender as root [!]') - self.skip_install = True - return False - - def is_root(self) -> bool: - - if os.geteuid() != 0: - print('> User without privileges ==> OK') - return False - elif os.geteuid() == 0: - print('[!] Do not use root to install Defender [!]') - exit("Do not use root to install Defender") - return True - - def do_install(self) -> bool: - - full_service_file_path = os.path.join(self.config.unix_systemd_folder, self.config.service_file_name) - - if not os.path.exists(full_service_file_path): - print(f'[!] Service file does not exist [!]') - return True - - # Check if virtual env exist - if not os.path.exists(f'{os.path.join(self.config.defender_install_folder, self.config.venv_folder)}'): - self.run_subprocess(self.config.venv_cmd_installation) - print(f'[!] Virtual env does not exist run the install [!]') - return True - - def run_subprocess(self, command:list) -> None: - - print(f'> {command}') - try: - check_call(command) - print("The command completed successfully.") - except CalledProcessError as e: - print(f"The command failed with the return code: {e.returncode}") - print(f"Try to install dependencies ...") - exit(5) - - def get_packages_version_from_json(self) -> None: - """This will create Package model with package names and required version - """ - try: - - version_filename = f'.{os.sep}version.json' - with open(version_filename, 'r') as version_data: - package_info:dict[str, str] = json.load(version_data) - - for name, version in package_info.items(): - if name == 'version': - continue - - self.DB_PACKAGES.append( - self.Package(name=name, version=version) - ) - - return None - except FileNotFoundError as fe: - print(f"File not found: {fe}") - except Exception as err: - print(f"General Error: {err}") - - def check_packages_version(self) -> bool: - - try: - newVersion = False - self.get_packages_version_from_json() - - if not self.config.venv_folder in prefix: - print(f"You are probably running a new installation or you are not using your virtual env {self.config.venv_folder}") - return newVersion - - print(f"> Checking for dependencies versions ==> WAIT") - for package in self.DB_PACKAGES: - newVersion = False - _required_version = package.version - _installed_version: str = None - - output = check_output([self.config.venv_pip_executable, 'show', package.name]) - for line in output.decode().splitlines(): - if line.startswith('Version:'): - _installed_version = line.split(':')[1].strip() - break - - required_version = tuple(map(int, _required_version.split('.'))) - installed_version = tuple(map(int, _installed_version.split('.'))) - - if required_version > installed_version: - print(f'> New version of {package.name} is available {installed_version} ==> {required_version}') - newVersion = True - - if newVersion: - self.run_subprocess([self.config.venv_pip_executable, 'install', '--upgrade', package.name]) - - print(f"> Dependencies versions ==> OK") - return newVersion - - except CalledProcessError: - print(f"[!] Package {package.name} not installed [!]") - except Exception as err: - print(f"General Error: {err}") - - def check_python_version(self) -> bool: - """Test si la version de python est autorisée ou non - - Returns: - bool: True si la version de python est autorisé sinon False - """ - if self.config.python_current_version_tuple < self.config.python_min_version: - print(f"## Your python version must be greather than or equal to {self.config.python_min_version} ##") - return False - - print(f"> Version of python : {self.config.python_current_version} ==> OK") - return True - - def check_package(self, package_name) -> bool: - - try: - # Run a command in the virtual environment's Python to check if the package is installed - run([self.config.venv_python_executable, '-c', f'import {package_name}'], check=True, stdout=PIPE, stderr=PIPE) - return True - except CalledProcessError as cpe: - print(cpe) - return False - - def install_dependencies(self) -> None: - """### Verifie les dépendances si elles sont installées - - Test si les modules sont installés - - Met a jour pip - - Install les modules manquants - """ - do_install = False - - # Check if virtual env exist - if not os.path.exists(f'{os.path.join(self.config.defender_install_folder, self.config.venv_folder)}'): - self.run_subprocess(self.config.venv_cmd_installation) - do_install = True - - for module in self.config.venv_cmd_requirements: - module = module.replace('pyyaml', 'yaml') - if not self.check_package(module): - do_install = True - - if not do_install: - return None - - print("===> Clean pip cache") - self.run_subprocess([self.config.venv_pip_executable, 'cache', 'purge']) - - print("===> Check if pip is up to date") - self.run_subprocess([self.config.venv_python_executable, '-m', 'pip', 'install', '--upgrade', 'pip']) - - if not self.check_package('greenlet'): - self.run_subprocess([self.config.venv_pip_executable, 'install', '--only-binary', ':all:', 'greenlet']) - print('====> Greenlet installed') - - for module in self.config.venv_cmd_requirements: - if not self.check_package(module): - print("### Trying to install missing python packages ###") - self.run_subprocess([self.config.venv_pip_executable, 'install', module]) - print(f"====> Module {module} installed!") - else: - print(f"==> {module} already installed") - - def create_service_file(self) -> None: - - full_service_file_path = os.path.join(self.config.unix_systemd_folder, self.config.service_file_name) - - if os.path.exists(full_service_file_path): - print(f'[!] Service file already exist [!]') - self.run_subprocess(self.config.service_cmd_executable) - return None - - contain = f'''[Unit] -Description=Defender IRC Service - -[Service] -ExecStart={self.config.venv_python_executable} {self.config.defender_main_executable} -WorkingDirectory={self.config.defender_install_folder} -SyslogIdentifier=Defender -Restart=on-failure - -[Install] -WantedBy=default.target -''' - # Check if user systemd is available (.config/systemd/user/) - if not os.path.exists(self.config.unix_systemd_folder): - self.run_subprocess(['mkdir', '-p', self.config.unix_systemd_folder]) - - with open(full_service_file_path, 'w+') as servicefile: - servicefile.write(contain) - servicefile.close() - print('Service file generated with current configuration') - print('Running IRC Service ...') - self.run_subprocess(self.config.service_cmd_daemon_reload) - self.run_subprocess(self.config.service_cmd_executable) - - else: - with open(full_service_file_path, 'w+') as servicefile: - servicefile.write(contain) - servicefile.close() - print('Service file generated with current configuration') - print('Running IRC Service ...') - self.run_subprocess(self.config.service_cmd_daemon_reload) - self.run_subprocess(self.config.service_cmd_executable) - - def print_final_message(self) -> None: - - print(f"#"*24) - print("Installation complete ...") - print("If the configuration is correct, then you must see your service connected to your irc server") - print(f"If any issue, you can see the log file for debug {self.config.defender_install_folder}{os.sep}logs{os.sep}defender.log") - print(f"#"*24) - exit(1) diff --git a/defender.py b/defender.py index 10577d2..6fc06f2 100644 --- a/defender.py +++ b/defender.py @@ -1,4 +1,4 @@ -from core import installation +from core import install ############################################# # @Version : 6.3 # @@ -10,7 +10,7 @@ from core import installation ############################################# try: - installation.Install() + install.update_packages() from core.loader import Loader loader = Loader() loader.Irc.init_irc() diff --git a/requirements.txt b/requirements.txt index f8c2d3a..005b826 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -Faker==33.1.2 -psutil==6.1.1 -PyYAML==6.0.2 -requests==2.32.3 -SQLAlchemy==2.0.36 +Faker==37.12.0 +psutil==7.1.2 +PyYAML==6.0.3 +requests==2.32.5 +SQLAlchemy==2.0.44 unrealircd_rpc_py==3.0.2 \ No newline at end of file diff --git a/version.json b/version.json index b0b4b2f..257fd31 100644 --- a/version.json +++ b/version.json @@ -1,10 +1,10 @@ { "version": "6.3.2", - "requests": "2.32.3", - "psutil": "6.0.0", + "requests": "2.32.5", + "psutil": "7.1.2", "unrealircd_rpc_py": "3.0.1", - "sqlalchemy": "2.0.35", - "faker": "30.1.0", - "pyyaml": "6.0.2" + "sqlalchemy": "2.0.44", + "faker": "37.12.0", + "pyyaml": "6.0.3" } From b182aa8bcb7ff9da636d089305fc60b6adaa2b86 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Wed, 29 Oct 2025 00:02:57 +0100 Subject: [PATCH 03/56] Fix mod_jsonrpc module! Selecting the correct parameter based on the JSONRPC_METHOD value in the configruation.yaml --- mods/jsonrpc/mod_jsonrpc.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mods/jsonrpc/mod_jsonrpc.py b/mods/jsonrpc/mod_jsonrpc.py index 1b7bcea..34803a2 100644 --- a/mods/jsonrpc/mod_jsonrpc.py +++ b/mods/jsonrpc/mod_jsonrpc.py @@ -88,9 +88,20 @@ class Jsonrpc(): try: self.Rpc = ConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) self.LiveRpc = LiveConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) - self.Rpc.setup({'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD}) - self.LiveRpc.setup({'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD, - 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'}) + + sync_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE} + sync_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD} + + live_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE, + 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} + live_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD, + 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} + + sync_param = sync_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else sync_http + live_param = live_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else live_http + + self.Rpc.setup(sync_param) + self.LiveRpc.setup(live_param) if self.ModConfig.jsonrpc == 1: self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True) From 1a71a6eb4db496ed7360761a42d13efb47b7070e Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:35:50 +0100 Subject: [PATCH 04/56] 1st version of module interface! --- core/classes/interfaces/imodule.py | 122 +++++++++++++++++++++++++++++ mods/test/mod_test.py | 91 +++------------------ 2 files changed, 134 insertions(+), 79 deletions(-) create mode 100644 core/classes/interfaces/imodule.py diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py new file mode 100644 index 0000000..c719e3f --- /dev/null +++ b/core/classes/interfaces/imodule.py @@ -0,0 +1,122 @@ +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +from mods.clone.schemas import ModConfModel + +if TYPE_CHECKING: + from core.irc import Irc + +class IModule(ABC): + + @abstractmethod + @dataclass + class ModConfModel: + """The Model containing the module parameters + """ + + def __init__(self, uplink: 'Irc') -> None: + + # Module name (Mandatory) + self.module_name = 'mod_' + str(self.__class__.__name__).lower() + + # Add Irc Object to the module (Mandatory) + self.Irc = uplink + + # Add Protocol to the module (Mandatory) + self.Protocol = uplink.Protocol + + # Add Global Configuration to the module (Mandatory) + self.Config = uplink.Config + + # Add Base object to the module (Mandatory) + self.Base = uplink.Base + + # Add Main Utils (Mandatory) + self.MainUtils = uplink.Utils + + # Add logs object to the module (Mandatory) + self.Logs = uplink.Loader.Logs + + # Add User object to the module (Mandatory) + self.User = uplink.User + + # Add Channel object to the module (Mandatory) + self.Channel = uplink.Channel + + # Add Reputation object to the module (Optional) + self.Reputation = uplink.Reputation + + self.ModConfig = ModConfModel() + + self.load_module_configuration() + """Load module configuration""" + + self.create_tables() + """Create custom module tables""" + + # Sync the configuration with core configuration (Mandatory) + uplink.Base.db_sync_core_config(self.module_name, self.ModConfig) + + # Log the module + self.Logs.debug(f'Module {self.module_name} loaded ...') + + def update_configuration(self, param_key: str, param_value: str) -> None: + """Update the local and core configuration + + Args: + param_key (str): The parameter key + param_value (str): The parameter value + """ + self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) + + @abstractmethod + def create_tables(self) -> None: + """Methode qui va créer la base de donnée si elle n'existe pas. + Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module + Args: + database_name (str): Nom de la base de données ( pas d'espace dans le nom ) + + Returns: + None: Aucun retour n'es attendu + """ + + @abstractmethod + def load_module_configuration(self) -> None: + """### Load Module Configuration + """ + try: + # Build the default configuration model (Mandatory) + self.ModConfig = self.ModConfModel(jsonrpc=0) + + # Sync the configuration with core configuration (Mandatory) + self.Base.db_sync_core_config(self.module_name, self.ModConfig) + + return None + + except TypeError as te: + self.Logs.critical(te) + + @abstractmethod + def unload(self) -> None: + """This method is executed when the module is unloaded or reloaded. + """ + + @abstractmethod + def cmd(self, data: list) -> None: + """When recieving server messages. + + Args: + data (list): The recieved message + """ + + @abstractmethod + def hcmds(self, user: str, channel: Optional[str], cmd: list, fullcmd: list = []) -> None: + """These are the commands recieved from a client + + Args: + user (str): The client + channel (str|None): The channel if available + cmd (list): The user command sent + fullcmd (list, optional): The full server message. Defaults to []. + """ \ No newline at end of file diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 4fa746f..8f79be5 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -1,10 +1,7 @@ -from typing import TYPE_CHECKING -from dataclasses import dataclass, fields +from core.classes.interfaces.imodule import IModule +from dataclasses import dataclass -if TYPE_CHECKING: - from core.irc import Irc - -class Test(): +class Test(IModule): @dataclass class ModConfModel: @@ -13,37 +10,9 @@ class Test(): param_exemple1: str param_exemple2: int - def __init__(self, ircInstance: 'Irc') -> None: - - # Module name (Mandatory) - self.module_name = 'mod_' + str(self.__class__.__name__).lower() - - # 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 - - # Add Base object to the module (Mandatory) - self.Base = ircInstance.Base - - # Add logs object to the module (Mandatory) - self.Logs = ircInstance.Loader.Logs - - # Add User object to the module (Mandatory) - self.User = ircInstance.User - - # Add Channel object to the module (Mandatory) - self.Channel = ircInstance.Channel - - # Add Reputation object to the module (Optional) - self.Reputation = ircInstance.Reputation + def load_module_configuration(self) -> None: + """### Load Module Configuration + """ # Create module commands (Mandatory) self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command') @@ -51,25 +20,12 @@ class Test(): self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command') self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command') - - # Init the module - self.__init_module() - - # Log the module - self.Logs.debug(f'Module {self.module_name} loaded ...') - - def __init_module(self) -> None: - - # Create you own tables (Mandatory) - self.__create_tables() - - # Load module configuration and sync with core one (Mandatory) - self.__load_module_configuration() - # End of mandatory methods you can start your customization # + # Build the default configuration model (Mandatory) + self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) return None - def __create_tables(self) -> None: + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module Args: @@ -86,33 +42,9 @@ class Test(): ) ''' - self.Base.db_execute_query(table_logs) + # self.Base.db_execute_query(table_logs) return None - def __load_module_configuration(self) -> None: - """### Load Module Configuration - """ - try: - # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel(param_exemple1='param value 1', param_exemple2=1) - - # Sync the configuration with core configuration (Mandatory) - self.Base.db_sync_core_config(self.module_name, self.ModConfig) - - return None - - except TypeError as te: - self.Logs.critical(te) - - def __update_configuration(self, param_key: str, param_value: str): - """Update the local and core configuration - - Args: - param_key (str): The parameter key - param_value (str): The parameter value - """ - self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) - def unload(self) -> None: self.Irc.Commands.drop_command_by_module(self.module_name) return None @@ -148,7 +80,8 @@ class Test(): self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=fromchannel) # How to update your module configuration - self.__update_configuration('param_exemple2', 7) + self.update_configuration('param_exemple2', 7) + self.update_configuration('param_exemple1', 'my_value') # Log if you want the result self.Logs.debug(f"Test logs ready") From 8abae5df3eb39fa15af3eb2eab38c11f3677cacd Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:57:46 +0100 Subject: [PATCH 05/56] fix db_patch, the table name is no more hard coded! --- core/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/base.py b/core/base.py index 2755125..d56959d 100644 --- a/core/base.py +++ b/core/base.py @@ -599,8 +599,8 @@ class Base: def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool: if not self.db_is_column_exist(table_name, column_name): - patch = f"ALTER TABLE {self.Config.TABLE_ADMIN} ADD COLUMN {column_name} {column_type}" - update_row = f"UPDATE {self.Config.TABLE_ADMIN} SET language = 'EN' WHERE language is null" + patch = f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}" + update_row = f"UPDATE {table_name} SET language = 'EN' WHERE language is null" self.db_execute_query(patch) self.db_execute_query(update_row) self.logs.debug(f"The patch has been applied") From 2fbe75b83ec105c30ebc0f63b348d7e921231fbd Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 1 Nov 2025 17:39:16 +0100 Subject: [PATCH 06/56] update module management --- core/classes/interfaces/imodule.py | 47 +++++---- core/module.py | 16 ++- mods/command/mod_command.py | 155 ++++++++--------------------- mods/test/mod_test.py | 30 +++--- 4 files changed, 93 insertions(+), 155 deletions(-) diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index c719e3f..9bff628 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -1,7 +1,6 @@ from abc import ABC, abstractmethod from typing import TYPE_CHECKING, Optional from dataclasses import dataclass - from mods.clone.schemas import ModConfModel if TYPE_CHECKING: @@ -23,6 +22,9 @@ class IModule(ABC): # Add Irc Object to the module (Mandatory) self.Irc = uplink + # Add Loader object to the module (Mandatory) + self.Loader = uplink.Loader + # Add Protocol to the module (Mandatory) self.Protocol = uplink.Protocol @@ -41,19 +43,25 @@ class IModule(ABC): # Add User object to the module (Mandatory) self.User = uplink.User + # Add Client object to the module (Mandatory) + self.Client = uplink.Client + # Add Channel object to the module (Mandatory) self.Channel = uplink.Channel # Add Reputation object to the module (Optional) self.Reputation = uplink.Reputation - self.ModConfig = ModConfModel() + # Load the child classes + self.load() - self.load_module_configuration() - """Load module configuration""" + # Inspect child classes + self.inspect_class() + + # Init the ModConfig model object. + self.ModConfig:ModConfModel = ModConfModel() self.create_tables() - """Create custom module tables""" # Sync the configuration with core configuration (Mandatory) uplink.Base.db_sync_core_config(self.module_name, self.ModConfig) @@ -70,32 +78,27 @@ class IModule(ABC): """ self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) + def inspect_class(self): + if not hasattr(self, 'ModConfig'): + raise AttributeError("The Module must init ModConfig attribute in the load method!") + @abstractmethod def create_tables(self) -> None: - """Methode qui va créer la base de donnée si elle n'existe pas. - Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module + """ + Method that will create the database if it does not exist. + A single Session for this class will be created, which will be used within this class/module. + Args: - database_name (str): Nom de la base de données ( pas d'espace dans le nom ) + database_name (str): Name of the database (no spaces allowed in the name) Returns: - None: Aucun retour n'es attendu + None: No return is expected """ @abstractmethod - def load_module_configuration(self) -> None: - """### Load Module Configuration + def load(self) -> None: + """This method is executed when the module is loaded or reloaded. """ - try: - # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel(jsonrpc=0) - - # Sync the configuration with core configuration (Mandatory) - self.Base.db_sync_core_config(self.module_name, self.ModConfig) - - return None - - except TypeError as te: - self.Logs.critical(te) @abstractmethod def unload(self) -> None: diff --git a/core/module.py b/core/module.py index e4317e4..967a437 100644 --- a/core/module.py +++ b/core/module.py @@ -66,9 +66,19 @@ class Module: return self.reload_one_module(uplink, module_name, nickname) # Charger le module - loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') - my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe - create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe + try: + loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') + my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe + create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe + except AttributeError as attr: + red = uplink.Config.COLORS.red + nogc = uplink.Config.COLORS.nogc + uplink.Protocol.send_priv_msg( + nick_from=self.__Config.SERVICE_NICKNAME, + msg=f"[{red}MODULE ERROR{nogc}] Module {module_name} is facing issues ! {attr}", + channel=self.__Config.SERVICE_CHANLOG + ) + return False if not hasattr(create_instance_of_the_class, 'cmd'): uplink.Protocol.send_priv_msg( diff --git a/mods/command/mod_command.py b/mods/command/mod_command.py index d125914..2d41148 100644 --- a/mods/command/mod_command.py +++ b/mods/command/mod_command.py @@ -1,13 +1,12 @@ from typing import Optional, TYPE_CHECKING from dataclasses import dataclass +from core.classes.interfaces.imodule import IModule import mods.command.utils as utils if TYPE_CHECKING: - from core.irc import Irc from core.definition import MUser - from sqlalchemy import CursorResult, Row, Sequence -class Command: +class Command(IModule): @dataclass class ModConfModel: @@ -15,44 +14,44 @@ class Command: """ pass - def __init__(self, ircInstance: 'Irc') -> None: + def create_tables(self) -> None: + """Methode qui va créer la base de donnée si elle n'existe pas. + Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module + Args: + database_name (str): Nom de la base de données ( pas d'espace dans le nom ) - # Module name (Mandatory) - self.module_name = 'mod_' + str(self.__class__.__name__).lower() + Returns: + None: Aucun retour n'es attendu + """ - # Add Irc Object to the module (Mandatory) - self.Irc = ircInstance + table_automode = '''CREATE TABLE IF NOT EXISTS command_automode ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created_on TEXT, + updated_on TEXT, + nickname TEXT, + channel TEXT, + mode TEXT + ) + ''' - # Add Loader Object to the module (Mandatory) - self.Loader = ircInstance.Loader - - # Add Protocol object to the module (Mandatory) - self.Protocol = ircInstance.Protocol - - # Add Global Configuration to the module (Mandatory) - self.Config = ircInstance.Config - - # Add Base object to the module (Mandatory) - self.Base = ircInstance.Base - - # Add main Utils to the module - self.MainUtils = ircInstance.Utils - - # Add logs object to the module (Mandatory) - self.Logs = ircInstance.Loader.Logs - - # Add User object to the module (Mandatory) - self.User = ircInstance.User - - # Add Client object to the module (Mandatory) - self.Client = ircInstance.Client - - # Add Channel object to the module (Mandatory) - self.Channel = ircInstance.Channel + self.Base.db_execute_query(table_automode) + return None + def load(self) -> None: # Module Utils self.mod_utils = utils + # Build the default configuration model (Mandatory) + self.ModConfig = self.ModConfModel() + + self.user_to_notice: str = '' + self.show_219: bool = True + + # Register new commands into the protocol + new_cmds = {'403', '401', '006', '018', '219', '223'} + for c in new_cmds: + self.Irc.Protocol.known_protocol.add(c) + self.Irc.build_command(2, self.module_name, 'join', 'Join a channel') self.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task') self.Irc.build_command(2, self.module_name, 'part', 'Leave a channel') @@ -104,73 +103,6 @@ class Command: self.Irc.build_command(2, self.module_name, 'klinelist', 'List all K-line bans') self.Irc.build_command(3, self.module_name, 'map', 'Show the server network map') - # Init the module - self.__init_module() - - # Log the module - self.Logs.debug(f'-- Module {self.module_name} loaded ...') - - def __init_module(self) -> None: - - # Create you own tables (Mandatory) - self.__create_tables() - - # Load module configuration and sync with core one (Mandatory) - self.__load_module_configuration() - # End of mandatory methods you can start your customization # - - self.user_to_notice: str = '' - self.show_219: bool = True - - return None - - def __create_tables(self) -> None: - """Methode qui va créer la base de donnée si elle n'existe pas. - Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module - Args: - database_name (str): Nom de la base de données ( pas d'espace dans le nom ) - - Returns: - None: Aucun retour n'es attendu - """ - - table_automode = '''CREATE TABLE IF NOT EXISTS command_automode ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - created_on TEXT, - updated_on TEXT, - nickname TEXT, - channel TEXT, - mode TEXT - ) - ''' - - self.Base.db_execute_query(table_automode) - return None - - def __load_module_configuration(self) -> None: - """### Load Module Configuration - """ - try: - # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel() - - # Sync the configuration with core configuration (Mandatory) - self.Base.db_sync_core_config(self.module_name, self.ModConfig) - - return None - - except TypeError as te: - self.Logs.critical(te) - - def __update_configuration(self, param_key: str, param_value: str): - """Update the local and core configuration - - Args: - param_key (str): The parameter key - param_value (str): The parameter value - """ - self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) - def unload(self) -> None: self.Irc.Commands.drop_command_by_module(self.module_name) return None @@ -186,10 +118,12 @@ class Command: nogc = self.Config.COLORS.nogc cmd = list(data).copy() - if len(cmd) < 2: + pos, parsed_cmd = self.Irc.Protocol.get_ircd_protocol_poisition(cmd=cmd, log=True) + + if pos == -1: return None - match cmd[1]: + match parsed_cmd: # [':irc.deb.biz.st', '403', 'Dev-PyDefender', '#Z', ':No', 'such', 'channel'] case '403' | '401': try: @@ -260,22 +194,10 @@ class Command: except Exception as err: self.Logs.warning(f'Unknown Error: {str(err)}') - case _: - pass - - if len(cmd) < 3: - return None - - match cmd[2]: - case 'SJOIN': # ['@msgid=yldTlbwAGbzCGUcCIHi3ku;time=2024-11-11T17:56:24.297Z', ':001', 'SJOIN', '1728815963', '#znc', ':001LQ0L0C'] # Check if the user has an automode try: - - if len(cmd) < 6: - return None - user_uid = self.User.clean_uid(cmd[5]) userObj: MUser = self.User.get_user(user_uid) channel_name = cmd[4] if self.Channel.is_valid_channel(cmd[4]) else None @@ -301,6 +223,9 @@ class Command: except KeyError as ke: self.Logs.error(f"Key Error: {err}") + case _: + pass + except Exception as err: self.Logs.error(f"General Error: {err}") diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 8f79be5..b59c9d4 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -6,25 +6,12 @@ class Test(IModule): @dataclass class ModConfModel: """The Model containing the module parameters + you can leave it without params. + just use pass | if you leave it empty, in the load() method just init empty object ==> self.ModConfig = ModConfModel() """ param_exemple1: str param_exemple2: int - def load_module_configuration(self) -> None: - """### Load Module Configuration - """ - - # Create module commands (Mandatory) - self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command') - self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command') - self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command') - self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command') - - # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) - - return None - def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -45,6 +32,19 @@ class Test(IModule): # self.Base.db_execute_query(table_logs) return None + def load(self) -> None: + """### Load Module Configuration + """ + + # Create module commands (Mandatory) + self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command') + self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command') + self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command') + self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command') + + # Build the default configuration model (Mandatory) + self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) + def unload(self) -> None: self.Irc.Commands.drop_command_by_module(self.module_name) return None From 769ab8b6324065dbed1edd96c0aeb18f15ca95f5 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:00:08 +0100 Subject: [PATCH 07/56] update rest of modules to fit requirements --- core/classes/interfaces/imodule.py | 9 +- core/module.py | 1 + mods/defender/mod_defender.py | 205 +++++++++++------------------ mods/defender/schemas.py | 1 + mods/defender/utils.py | 10 +- mods/jsonrpc/mod_jsonrpc.py | 196 ++++++++------------------- mods/test/mod_test.py | 1 + mods/votekick/mod_votekick.py | 113 ++++++---------- mods/votekick/votekick_manager.py | 2 +- 9 files changed, 187 insertions(+), 351 deletions(-) diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 9bff628..6005c6b 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -31,6 +31,9 @@ class IModule(ABC): # Add Global Configuration to the module (Mandatory) self.Config = uplink.Config + # Add Settings to the module (Mandatory) + self.Settings = uplink.Settings + # Add Base object to the module (Mandatory) self.Base = uplink.Base @@ -46,6 +49,9 @@ class IModule(ABC): # Add Client object to the module (Mandatory) self.Client = uplink.Client + # Add Admin object to the module (Mandatory) + self.Admin = uplink.Admin + # Add Channel object to the module (Mandatory) self.Channel = uplink.Channel @@ -58,9 +64,6 @@ class IModule(ABC): # Inspect child classes self.inspect_class() - # Init the ModConfig model object. - self.ModConfig:ModConfModel = ModConfModel() - self.create_tables() # Sync the configuration with core configuration (Mandatory) diff --git a/core/module.py b/core/module.py index 967a437..881810a 100644 --- a/core/module.py +++ b/core/module.py @@ -78,6 +78,7 @@ class Module: msg=f"[{red}MODULE ERROR{nogc}] Module {module_name} is facing issues ! {attr}", channel=self.__Config.SERVICE_CHANLOG ) + self.__Logs.error(msg=attr, exc_info=True) return False if not hasattr(create_instance_of_the_class, 'cmd'): diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index d727f9c..a390d6e 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -1,54 +1,49 @@ -from typing import TYPE_CHECKING +from dataclasses import dataclass +from core.classes.interfaces.imodule import IModule import mods.defender.schemas as schemas import mods.defender.utils as utils import mods.defender.threads as thds from core.utils import tr -if TYPE_CHECKING: - from core.irc import Irc +class Defender(IModule): -class Defender: + @dataclass + class ModConfModel(schemas.ModConfModel): + ... - def __init__(self, irc_instance: 'Irc') -> None: + def create_tables(self) -> None: + """Methode qui va créer la base de donnée si elle n'existe pas. + Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module + Args: + database_name (str): Nom de la base de données ( pas d'espace dans le nom ) - # Module name (Mandatory) - self.module_name = 'mod_' + str(self.__class__.__name__).lower() + Returns: + None: Aucun retour n'es attendu + """ - # Add Irc Object to the module (Mandatory) - self.Irc = irc_instance + # table_autoop = '''CREATE TABLE IF NOT EXISTS defender_autoop ( + # id INTEGER PRIMARY KEY AUTOINCREMENT, + # datetime TEXT, + # nickname TEXT, + # channel TEXT + # ) + # ''' - # Add Loader Object to the module (Mandatory) - self.Loader = irc_instance.Loader - - # Add server protocol Object to the module (Mandatory) - self.Protocol = irc_instance.Protocol - - # Add Global Configuration to the module (Mandatory) - self.Config = irc_instance.Config - - # Add Base object to the module (Mandatory) - self.Base = irc_instance.Base - - # Add logs object to the module (Mandatory) - self.Logs = irc_instance.Loader.Logs - - # Add User object to the module (Mandatory) - self.User = irc_instance.User - - # Add Channel object to the module (Mandatory) - self.Channel = irc_instance.Channel - - # Add Settings object to save objects when reloading modules (Mandatory) - self.Settings = irc_instance.Settings - - # Add Reputation object to the module (Optional) - self.Reputation = irc_instance.Reputation + # self.Base.db_execute_query(table_autoop) + # self.Base.db_execute_query(table_config) + # self.Base.db_execute_query(table_trusted) + return None + def load(self): + # Add module schemas self.Schemas = schemas # Add utils functions self.Utils = utils + + # Variable qui va contenir les options de configuration du module Defender + self.ModConfig: schemas.ModConfModel = self.ModConfModel() # Create module commands (Mandatory) self.Irc.build_command(0, self.module_name, 'code', 'Display the code or key for access') @@ -62,38 +57,16 @@ class Defender: self.Irc.build_command(3, self.module_name, 'show_reputation', 'Display reputation information') self.Irc.build_command(3, self.module_name, 'sentinel', 'Monitor and guard the channel or server') - # Init the module (Mandatory) - self.__init_module() - - # Log the module - self.Logs.debug(f'-- Module {self.module_name} V2 loaded ...') - - def __init_module(self) -> None: - - # Create you own tables if needed (Mandatory) - self.__create_tables() - - # Load module configuration (Mandatory) - self.__load_module_configuration() - # End of mandatory methods you can start your customization # - self.timeout = self.Config.API_TIMEOUT # Listes qui vont contenir les ip a scanner avec les différentes API - self.Schemas.DB_ABUSEIPDB_USERS = [] - self.Schemas.DB_FREEIPAPI_USERS = [] - self.Schemas.DB_CLOUDFILT_USERS = [] - self.Schemas.DB_PSUTIL_USERS = [] - self.Schemas.DB_LOCALSCAN_USERS = [] + self.Schemas.DB_ABUSEIPDB_USERS = self.Schemas.DB_FREEIPAPI_USERS = self.Schemas.DB_CLOUDFILT_USERS = [] + self.Schemas.DB_PSUTIL_USERS = self.Schemas.DB_LOCALSCAN_USERS = [] # Variables qui indique que les threads sont en cours d'éxecutions - self.abuseipdb_isRunning:bool = True - self.freeipapi_isRunning:bool = True - self.cloudfilt_isRunning:bool = True - self.psutil_isRunning:bool = True - self.localscan_isRunning:bool = True - self.reputationTimer_isRunning:bool = True - self.autolimit_isRunning: bool = True + self.abuseipdb_isRunning = self.freeipapi_isRunning= self.cloudfilt_isRunning = True + self.psutil_isRunning = self.localscan_isRunning = self.reputationTimer_isRunning = True + self.autolimit_isRunning = True # Variable qui va contenir les users self.flood_system = {} @@ -121,46 +94,6 @@ class Defender: self.Protocol.send_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 - - def __create_tables(self) -> None: - """Methode qui va créer la base de donnée si elle n'existe pas. - Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module - Args: - database_name (str): Nom de la base de données ( pas d'espace dans le nom ) - - Returns: - None: Aucun retour n'es attendu - """ - - # table_autoop = '''CREATE TABLE IF NOT EXISTS defender_autoop ( - # id INTEGER PRIMARY KEY AUTOINCREMENT, - # datetime TEXT, - # nickname TEXT, - # channel TEXT - # ) - # ''' - - # self.Base.db_execute_query(table_autoop) - # self.Base.db_execute_query(table_config) - # self.Base.db_execute_query(table_trusted) - return None - - def __load_module_configuration(self) -> None: - """### Load Module Configuration - """ - # Variable qui va contenir les options de configuration du module Defender - self.ModConfig = self.Schemas.ModConfModel() - - # Sync the configuration with core configuration (Mandatory) - self.Base.db_sync_core_config(self.module_name, self.ModConfig) - - return None - - def __update_configuration(self, param_key: str, param_value: str): - - self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) - def __onload(self): abuseipdb = self.Settings.get_cache('ABUSEIPDB') @@ -431,7 +364,7 @@ class Defender: match arg: case 'on': if self.ModConfig.autolimit == 0: - self.__update_configuration('autolimit', 1) + self.update_configuration('autolimit', 1) self.autolimit_isRunning = True self.Base.create_thread(func=thds.thread_autolimit, func_args=(self, )) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Activated", channel=self.Config.SERVICE_CHANLOG) @@ -440,7 +373,7 @@ class Defender: case 'off': if self.ModConfig.autolimit == 1: - self.__update_configuration('autolimit', 0) + self.update_configuration('autolimit', 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Deactivated", channel=self.Config.SERVICE_CHANLOG) else: self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already Deactivated", channel=self.Config.SERVICE_CHANLOG) @@ -449,8 +382,8 @@ class Defender: amount = int(cmd[2]) interval = int(cmd[3]) - self.__update_configuration('autolimit_amount', amount) - self.__update_configuration('autolimit_interval', interval) + self.update_configuration('autolimit_amount', amount) + self.update_configuration('autolimit_interval', interval) self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Amount set to ({amount}) | Interval set to ({interval})", @@ -489,7 +422,7 @@ class Defender: return False # self.update_db_configuration('reputation', 1) - self.__update_configuration(key, 1) + self.update_configuration(key, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) @@ -515,7 +448,7 @@ class Defender: ) return False - self.__update_configuration(key, 0) + self.update_configuration(key, 0) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -604,7 +537,7 @@ class Defender: return False # self.update_db_configuration(key, 1) - self.__update_configuration(key, 1) + self.update_configuration(key, 1) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -622,7 +555,7 @@ class Defender: return False # self.update_db_configuration(key, 0) - self.__update_configuration(key, 0) + self.update_configuration(key, 0) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -635,7 +568,7 @@ class Defender: key = 'reputation_seuil' # self.update_db_configuration(key, reputation_seuil) - self.__update_configuration(key, reputation_seuil) + self.update_configuration(key, reputation_seuil) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -647,7 +580,7 @@ class Defender: case 'timer': reputation_timer = int(cmd[3]) key = 'reputation_timer' - self.__update_configuration(key, reputation_timer) + self.update_configuration(key, reputation_timer) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -659,7 +592,7 @@ class Defender: 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.update_configuration(key, reputation_score_after_release) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -671,7 +604,7 @@ class Defender: case 'security_group': reputation_sg = int(cmd[3]) key = 'reputation_sg' - self.__update_configuration(key, reputation_sg) + self.update_configuration(key, reputation_sg) self.Protocol.send_priv_msg( nick_from=dnickname, @@ -733,7 +666,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': @@ -741,7 +674,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) @@ -751,7 +684,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': @@ -759,7 +692,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) @@ -769,7 +702,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': @@ -777,7 +710,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) @@ -787,7 +720,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': @@ -795,7 +728,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) @@ -805,7 +738,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) elif action == 'off': @@ -813,7 +746,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(option, 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) @@ -846,7 +779,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(key, 1) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) @@ -855,7 +788,7 @@ class Defender: self.Protocol.send_priv_msg(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.update_configuration(key, 0) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog) @@ -867,7 +800,7 @@ class Defender: case 'flood_message': key = 'flood_message' set_value = int(cmd[3]) - self.__update_configuration(key, set_value) + self.update_configuration(key, set_value) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood message set to {set_value} by {fromuser}", @@ -876,7 +809,7 @@ class Defender: case 'flood_time': key = 'flood_time' set_value = int(cmd[3]) - self.__update_configuration(key, set_value) + self.update_configuration(key, set_value) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood time set to {set_value} by {fromuser}", @@ -885,7 +818,7 @@ class Defender: case 'flood_timer': key = 'flood_timer' set_value = int(cmd[3]) - self.__update_configuration(key, set_value) + self.update_configuration(key, set_value) self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood timer set to {set_value} by {fromuser}", @@ -922,6 +855,7 @@ class Defender: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.ModConfig.flood_message}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.ModConfig.flood_time}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.ModConfig.flood_timer}') + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Sentinel{nogc}] ==> {self.ModConfig.sentinel}') except KeyError as ke: self.Logs.error(f"Key Error : {ke}") @@ -963,14 +897,27 @@ class Defender: channel_to_dont_quit = [self.Config.SALON_JAIL, self.Config.SERVICE_CHANLOG] if activation == 'on': + result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}") + channels = result.fetchall() + channel_in_db = [channel[0] for channel in channels] + channel_to_dont_quit.extend(channel_in_db) + + self.update_configuration('sentinel', 1) for chan in self.Channel.UID_CHANNEL_DB: if chan.name not in channel_to_dont_quit: self.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name) + self.Protocol.send_priv_msg(dnickname, f"Sentinel mode activated on {channel}", channel=chan.name) return None if activation == 'off': + result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}") + channels = result.fetchall() + channel_in_db = [channel[0] for channel in channels] + channel_to_dont_quit.extend(channel_in_db) + self.update_configuration('sentinel', 0) for chan in self.Channel.UID_CHANNEL_DB: if chan.name not in channel_to_dont_quit: self.Protocol.send_part_chan(uidornickname=dnickname, channel=chan.name) + self.Protocol.send_priv_msg(dnickname, f"Sentinel mode deactivated on {channel}", channel=chan.name) self.join_saved_channels() return None diff --git a/mods/defender/schemas.py b/mods/defender/schemas.py index b404685..a7d7a78 100644 --- a/mods/defender/schemas.py +++ b/mods/defender/schemas.py @@ -20,6 +20,7 @@ class ModConfModel(MainModel): autolimit: int = 0 autolimit_amount: int = 3 autolimit_interval: int = 3 + sentinel: int = 0 @dataclass class FloodUser(MainModel): diff --git a/mods/defender/utils.py b/mods/defender/utils.py index 32fb911..826e636 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -62,6 +62,14 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]): # ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg'] + sender = srvmsg[1].replace(':','') + channel = srvmsg[3] + message = srvmsg[4:] + message[0] = message[0].replace(':', '') + + if uplink.ModConfig.sentinel == 1 and srvmsg[3] != uplink.Config.SERVICE_CHANLOG: + uplink.Protocol.send_priv_msg(uplink.Config.SERVICE_NICKNAME, f"{sender} say on {channel}: {' '.join(message)}", uplink.Config.SERVICE_CHANLOG) + action_on_flood(uplink, srvmsg) return None @@ -385,7 +393,7 @@ def action_apply_reputation_santions(uplink: 'Defender') -> None: salon_jail = gconfig.SALON_JAIL uid_to_clean = [] - if reputation_flag == 0 or reputation_timer == 0: + if reputation_flag == 0 or reputation_timer == 0 or not irc.Reputation.UID_REPUTATION_DB: return None for user in irc.Reputation.UID_REPUTATION_DB: diff --git a/mods/jsonrpc/mod_jsonrpc.py b/mods/jsonrpc/mod_jsonrpc.py index 34803a2..b0fc88b 100644 --- a/mods/jsonrpc/mod_jsonrpc.py +++ b/mods/jsonrpc/mod_jsonrpc.py @@ -1,18 +1,13 @@ import logging -import asyncio from unrealircd_rpc_py.objects.Definition import LiveRPCResult +from core.classes.interfaces.imodule import IModule import mods.jsonrpc.utils as utils import mods.jsonrpc.threads as thds -from time import sleep -from typing import TYPE_CHECKING from dataclasses import dataclass from unrealircd_rpc_py.ConnectionFactory import ConnectionFactory from unrealircd_rpc_py.LiveConnectionFactory import LiveConnectionFactory -if TYPE_CHECKING: - from core.irc import Irc - -class Jsonrpc(): +class Jsonrpc(IModule): @dataclass class ModConfModel: @@ -20,121 +15,6 @@ class Jsonrpc(): """ jsonrpc: int = 0 - def __init__(self, ircInstance: 'Irc') -> None: - - # Module name (Mandatory) - self.module_name = 'mod_' + str(self.__class__.__name__).lower() - - # 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 - - # Add Base object to the module (Mandatory) - self.Base = ircInstance.Base - - # Add Main Utils (Mandatory) - self.MainUtils = ircInstance.Utils - - # Add logs object to the module (Mandatory) - self.Logs = ircInstance.Loader.Logs - - # Add User object to the module (Mandatory) - self.User = ircInstance.User - - # Add Channel object to the module (Mandatory) - self.Channel = ircInstance.Channel - - # Is RPC Active? - self.is_streaming = False - - # Module Utils - self.Utils = utils - - # Module threads - self.Threads = thds - - # Run Garbage collector. - self.Base.create_timer(10, self.MainUtils.run_python_garbage_collector) - - # Create module commands (Mandatory) - self.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]') - self.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC') - self.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances') - - # Init the module - self.__init_module() - - # Log the module - self.Logs.debug(f'Module {self.module_name} loaded ...') - - def __init_module(self) -> None: - - logging.getLogger('websockets').setLevel(logging.WARNING) - logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL) - logging.getLogger('unrealircd-liverpc-py').setLevel(logging.CRITICAL) - - # Create you own tables (Mandatory) - # self.__create_tables() - - # Load module configuration and sync with core one (Mandatory) - self.__load_module_configuration() - # End of mandatory methods you can start your customization # - - try: - self.Rpc = ConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) - self.LiveRpc = LiveConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) - - sync_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE} - sync_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD} - - live_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE, - 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} - live_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD, - 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} - - sync_param = sync_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else sync_http - live_param = live_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else live_http - - self.Rpc.setup(sync_param) - self.LiveRpc.setup(live_param) - - if self.ModConfig.jsonrpc == 1: - self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True) - - return None - except Exception as err: - self.Protocol.send_priv_msg( - nick_from=self.Config.SERVICE_NICKNAME, - msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {err.__str__()}", - channel=self.Config.SERVICE_CHANLOG - ) - self.Logs.error(f"JSONRPC ERROR: {err.__str__()}") - - def __create_tables(self) -> None: - """Methode qui va créer la base de donnée si elle n'existe pas. - Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module - Args: - database_name (str): Nom de la base de données ( pas d'espace dans le nom ) - - Returns: - None: Aucun retour n'es attendu - """ - - table_logs = '''CREATE TABLE IF NOT EXISTS test_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - datetime TEXT, - server_msg TEXT - ) - ''' - - self.Base.db_execute_query(table_logs) - return None - def callback_sent_to_irc(self, response: LiveRPCResult) -> None: dnickname = self.Config.SERVICE_NICKNAME @@ -169,29 +49,63 @@ class Jsonrpc(): return None - def __load_module_configuration(self) -> None: - """### Load Module Configuration - """ + def create_tables(self) -> None: + return None + + def load(self) -> None: + + logging.getLogger('websockets').setLevel(logging.WARNING) + logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL) + logging.getLogger('unrealircd-liverpc-py').setLevel(logging.CRITICAL) + + self.ModConfig = self.ModConfModel(jsonrpc=0) + + # Is RPC Active? + self.is_streaming = False + + # Module Utils + self.Utils = utils + + # Module threads + self.Threads = thds + + # Run Garbage collector. + self.Base.create_timer(10, self.MainUtils.run_python_garbage_collector) + + # Create module commands (Mandatory) + self.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]') + self.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC') + self.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances') + try: - # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel(jsonrpc=0) + self.Rpc = ConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) + self.LiveRpc = LiveConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) + + sync_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE} + sync_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD} + + live_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE, + 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} + live_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD, + 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} - # Sync the configuration with core configuration (Mandatory) - self.Base.db_sync_core_config(self.module_name, self.ModConfig) + sync_param = sync_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else sync_http + live_param = live_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else live_http + self.Rpc.setup(sync_param) + self.LiveRpc.setup(live_param) + + if self.ModConfig.jsonrpc == 1: + self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True) + return None - - except TypeError as te: - self.Logs.critical(te) - - def update_configuration(self, param_key: str, param_value: str) -> None: - """Update the local and core configuration - - Args: - param_key (str): The parameter key - param_value (str): The parameter value - """ - self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) + except Exception as err: + self.Protocol.send_priv_msg( + nick_from=self.Config.SERVICE_NICKNAME, + msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {err.__str__()}", + channel=self.Config.SERVICE_CHANLOG + ) + self.Logs.error(f"JSONRPC ERROR: {err.__str__()}") def unload(self) -> None: if self.is_streaming: diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index b59c9d4..6c9cf22 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -45,6 +45,7 @@ class Test(IModule): # Build the default configuration model (Mandatory) self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) + def unload(self) -> None: self.Irc.Commands.drop_command_by_module(self.module_name) return None diff --git a/mods/votekick/mod_votekick.py b/mods/votekick/mod_votekick.py index 3da9f5b..cd896be 100644 --- a/mods/votekick/mod_votekick.py +++ b/mods/votekick/mod_votekick.py @@ -1,95 +1,29 @@ """ File : mod_votekick.py - Version : 1.0.0 + Version : 1.0.2 Description : Manages votekick sessions for multiple channels. Handles activation, ongoing vote checks, and cleanup. Author : adator Created : 2025-08-16 - Last Updated: 2025-08-16 + Last Updated: 2025-11-01 ----------------------------------------- """ +from dataclasses import dataclass import re +from core.classes.interfaces.imodule import IModule import mods.votekick.schemas as schemas import mods.votekick.utils as utils from mods.votekick.votekick_manager import VotekickManager import mods.votekick.threads as thds from typing import TYPE_CHECKING, Any, Optional -if TYPE_CHECKING: - from core.irc import Irc +class Votekick(IModule): + @dataclass + class ModConfModel(schemas.VoteChannelModel): + ... -class Votekick: - - def __init__(self, uplink: 'Irc') -> None: - - # Module name (Mandatory) - self.module_name = 'mod_' + str(self.__class__.__name__).lower() - - # Add Irc Object to the module - self.Irc = uplink - - # Add Loader Object to the module (Mandatory) - self.Loader = uplink.Loader - - # Add server protocol Object to the module (Mandatory) - self.Protocol = uplink.Protocol - - # Add Global Configuration to the module - self.Config = uplink.Config - - # Add Base object to the module - self.Base = uplink.Base - - # Add logs object to the module - self.Logs = uplink.Logs - - # Add User object to the module - self.User = uplink.User - - # Add Channel object to the module - self.Channel = uplink.Channel - - # Add Utils. - self.Utils = uplink.Utils - - # Add Utils module - self.ModUtils = utils - - # Add Schemas module - self.Schemas = schemas - - # Add Threads module - self.Threads = thds - - # Add VoteKick Manager - self.VoteKickManager = VotekickManager(self) - - metadata = uplink.Loader.Settings.get_cache('VOTEKICK') - - if metadata is not None: - self.VoteKickManager.VOTE_CHANNEL_DB = metadata - # self.VOTE_CHANNEL_DB = metadata - - # Créer les nouvelles commandes du module - self.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module') - - # Init the module - self.__init_module() - - # Log the module - self.Logs.debug(f'-- Module {self.module_name} loaded ...') - - def __init_module(self) -> None: - - # Add admin object to retrieve admin users - self.Admin = self.Irc.Admin - self.__create_tables() - self.ModUtils.join_saved_channels(self) - - return None - - def __create_tables(self) -> None: + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -115,10 +49,37 @@ class Votekick: self.Base.db_execute_query(table_vote) return None + def load(self) -> None: + + self.ModConfig = self.ModConfModel() + + # Add VoteKick Manager + self.VoteKickManager = VotekickManager(self) + + # Add Utils module + self.ModUtils = utils + + # Add Schemas module + self.Schemas = schemas + + # Add Threads module + self.Threads = thds + + self.ModUtils.join_saved_channels(self) + + metadata = self.Settings.get_cache('VOTEKICK') + + if metadata is not None: + self.VoteKickManager.VOTE_CHANNEL_DB = metadata + # self.VOTE_CHANNEL_DB = metadata + + # Créer les nouvelles commandes du module + self.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module') + def unload(self) -> None: try: # Cache the local DB with current votes. - self.Loader.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB) + self.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB) for chan in self.VoteKickManager.VOTE_CHANNEL_DB: self.Protocol.send_part_chan(uidornickname=self.Config.SERVICE_ID, channel=chan.channel_name) diff --git a/mods/votekick/votekick_manager.py b/mods/votekick/votekick_manager.py index d61fed0..aaef559 100644 --- a/mods/votekick/votekick_manager.py +++ b/mods/votekick/votekick_manager.py @@ -11,7 +11,7 @@ class VotekickManager: def __init__(self, uplink: 'Votekick'): self.uplink = uplink self.Logs = uplink.Logs - self.Utils = uplink.Utils + self.Utils = uplink.MainUtils def activate_new_channel(self, channel_name: str) -> bool: """Activate a new channel in the votekick systeme From fb41a13d0ace725ed7632e32fdca95c98dade0ad Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:11:15 +0100 Subject: [PATCH 08/56] Move mod_clone to use the module interface. --- mods/clone/mod_clone.py | 112 ++++++++++------------------------------ mods/test/mod_test.py | 1 - 2 files changed, 26 insertions(+), 87 deletions(-) diff --git a/mods/clone/mod_clone.py b/mods/clone/mod_clone.py index ee73e63..15ee7e0 100644 --- a/mods/clone/mod_clone.py +++ b/mods/clone/mod_clone.py @@ -1,4 +1,6 @@ +from dataclasses import dataclass from typing import TYPE_CHECKING, Optional, Any +from core.classes.interfaces.imodule import IModule import mods.clone.utils as utils import mods.clone.threads as thds import mods.clone.schemas as schemas @@ -8,83 +10,13 @@ if TYPE_CHECKING: from core.irc import Irc from faker import Faker -class Clone: +class Clone(IModule): - def __init__(self, irc_instance: 'Irc') -> None: + @dataclass + class ModConfModel(schemas.ModConfModel): + ... - # Module name (Mandatory) - self.module_name = 'mod_' + str(self.__class__.__name__).lower() - - # Add Irc Object to the module (Mandatory) - self.Irc = irc_instance - - # Add Irc Protocol Object to the module (Mandatory) - self.Protocol = irc_instance.Protocol - - # Add Global Configuration to the module (Mandatory) - self.Config = irc_instance.Config - - # Add Base object to the module (Mandatory) - self.Base = irc_instance.Base - - # Add logs object to the module (Mandatory) - self.Logs = irc_instance.Loader.Logs - - # Add User object to the module (Mandatory) - self.User = irc_instance.User - - # Add Channel object to the module (Mandatory) - self.Channel = irc_instance.Channel - - # Add global definitions - self.Definition = irc_instance.Loader.Definition - - # The Global Settings - self.Settings = irc_instance.Loader.Settings - - self.Schemas = schemas - - self.Utils = utils - - self.Threads = thds - - self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB') - - self.Clone = CloneManager(self) - - metadata = self.Settings.get_cache('UID_CLONE_DB') - - if metadata is not None: - self.Clone.UID_CLONE_DB = metadata - self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}") - - # Créer les nouvelles commandes du module - self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones') - - # Init the module (Mandatory) - self.__init_module() - - # Log the module - self.Logs.debug(f'Module {self.module_name} loaded ...') - - def __init_module(self) -> None: - - # Créer les tables necessaire a votre module (ce n'es pas obligatoire) - self.__create_tables() - - self.stop = False - - # Load module configuration (Mandatory) - self.__load_module_configuration() - - self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_sjoin(self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('+o', nickname=self.Config.SERVICE_NICKNAME, channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('+nts', channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('+k', channel_name=self.Config.CLONE_CHANNEL, params=self.Config.CLONE_CHANNEL_PASSWORD) - - - def __create_tables(self) -> None: + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -104,20 +36,28 @@ class Clone: return None - def __load_module_configuration(self) -> None: - """### Load Module Configuration - """ - try: - # Variable qui va contenir les options de configuration du module Defender - self.ModConfig = self.Schemas.ModConfModel() + def load(self) -> None: + self.ModConfig = self.ModConfModel() + self.stop = False + self.Schemas = schemas + self.Utils = utils + self.Threads = thds + self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB') + self.Clone = CloneManager(self) + metadata = self.Settings.get_cache('UID_CLONE_DB') - # Sync the configuration with core configuration (Mandatory) - # self.Base.db_sync_core_config(self.module_name, self.ModConfig) + if metadata is not None: + self.Clone.UID_CLONE_DB = metadata + self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}") - return None + # Créer les nouvelles commandes du module + self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones') - except TypeError as te: - self.Logs.critical(te) + self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) + self.Protocol.send_sjoin(self.Config.CLONE_CHANNEL) + self.Protocol.send_set_mode('+o', nickname=self.Config.SERVICE_NICKNAME, channel_name=self.Config.CLONE_CHANNEL) + self.Protocol.send_set_mode('+nts', channel_name=self.Config.CLONE_CHANNEL) + self.Protocol.send_set_mode('+k', channel_name=self.Config.CLONE_CHANNEL, params=self.Config.CLONE_CHANNEL_PASSWORD) def unload(self) -> None: """Cette methode sera executée a chaque désactivation ou diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 6c9cf22..b59c9d4 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -45,7 +45,6 @@ class Test(IModule): # Build the default configuration model (Mandatory) self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) - def unload(self) -> None: self.Irc.Commands.drop_command_by_module(self.module_name) return None From 29f049b3c31b1a7fd47e3057d3216e9d16cbe312 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:20:49 +0100 Subject: [PATCH 09/56] Update the protocol interface, no more __init__ constructor needed in the child class! --- core/classes/protocols/interface.py | 28 +- core/classes/protocols/unreal6.py | 610 ++++++++++++++-------------- 2 files changed, 325 insertions(+), 313 deletions(-) diff --git a/core/classes/protocols/interface.py b/core/classes/protocols/interface.py index dc3546d..e5ab6b6 100644 --- a/core/classes/protocols/interface.py +++ b/core/classes/protocols/interface.py @@ -4,12 +4,38 @@ from core.classes.protocols.command_handler import CommandHandler if TYPE_CHECKING: from core.definition import MClient, MSasl - + from core.irc import Irc class IProtocol(ABC): Handler: Optional[CommandHandler] = None + def __init__(self, uplink: 'Irc'): + self.name: Optional[str] = None + self.protocol_version: int = -1 + self.known_protocol: set[str] = {} + + self._Irc = uplink + self._Config = uplink.Config + self._Base = uplink.Base + self._Settings = uplink.Base.Settings + self._Utils = uplink.Loader.Utils + self._Logs = uplink.Loader.Logs + + self.Handler = CommandHandler(uplink.Loader) + + self.init_protocol() + + self._Logs.info(f"[PROTOCOL] Protocol [{self.__class__.__name__}] loaded!") + + @abstractmethod + def init_protocol(self): + """_summary_ + + Returns: + _type_: _description_ + """ + @abstractmethod def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]: """Get the position of known commands diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 66933de..f68a817 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -3,29 +3,18 @@ from re import match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional from ssl import SSLEOFError, SSLError - -from core.classes.protocols.command_handler import CommandHandler from core.classes.protocols.interface import IProtocol from core.utils import tr if TYPE_CHECKING: - from core.irc import Irc from core.classes.sasl import Sasl from core.definition import MClient, MSasl class Unrealircd6(IProtocol): - def __init__(self, ircInstance: 'Irc'): + def init_protocol(self) -> None: self.name = 'UnrealIRCD-6' self.protocol_version = 6100 - - self.__Irc = ircInstance - self.__Config = ircInstance.Config - self.__Base = ircInstance.Base - self.__Settings = ircInstance.Base.Settings - self.__Utils = ircInstance.Loader.Utils - self.__Logs = ircInstance.Loader.Logs - self.known_protocol: set[str] = {'SJOIN', 'UID', 'MD', 'QUIT', 'SQUIT', 'EOS', 'PRIVMSG', 'MODE', 'UMODE2', 'VERSION', 'REPUTATION', 'SVS2MODE', @@ -33,9 +22,6 @@ class Unrealircd6(IProtocol): 'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO', '006', '007', '018'} - self.Handler = CommandHandler(ircInstance.Loader) - - self.__Logs.info(f"[PROTOCOL] Protocol [{__name__}] loaded!") def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]: """Get the position of known commands @@ -52,12 +38,12 @@ class Unrealircd6(IProtocol): return index, token.upper() if log: - self.__Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") + self._Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") return (-1, None) def register_command(self) -> None: - m = self.__Irc.Loader.Definition.MIrcdCommand + m = self._Irc.Loader.Definition.MIrcdCommand self.Handler.register(m(command_name="PING", func=self.on_server_ping)) self.Handler.register(m(command_name="UID", func=self.on_uid)) self.Handler.register(m(command_name="QUIT", func=self.on_quit)) @@ -121,27 +107,27 @@ class Unrealircd6(IProtocol): 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])) + with self._Base.lock: + self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[0])) if print_log: - self.__Logs.debug(f'<< {message}') + self._Logs.debug(f'<< {message}') except UnicodeDecodeError as ude: - self.__Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') - self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace')) + self._Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') + self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) except UnicodeEncodeError as uee: - self.__Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') - self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace')) + self._Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') + self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) except AssertionError as ae: - self.__Logs.warning(f'Assertion Error {ae} - message: {message}') + self._Logs.warning(f'Assertion Error {ae} - message: {message}') except SSLEOFError as soe: - self.__Logs.error(f"SSLEOFError: {soe} - {message}") + self._Logs.error(f"SSLEOFError: {soe} - {message}") except SSLError as se: - self.__Logs.error(f"SSLError: {se} - {message}") + self._Logs.error(f"SSLError: {se} - {message}") except OSError as oe: - self.__Logs.error(f"OSError: {oe} - {message}") + self._Logs.error(f"OSError: {oe} - {message}") except AttributeError as ae: - self.__Logs.critical(f"Attribute Error: {ae}") + self._Logs.critical(f"Attribute Error: {ae}") def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): """Sending PRIVMSG to a channel or to a nickname by batches @@ -153,12 +139,12 @@ class Unrealircd6(IProtocol): 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 not nick_to is None else None + 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 not nick_to is None else None if User_from is None: - self.__Logs.error(f"The sender nickname [{nick_from}] do not exist") + self._Logs.error(f"The sender nickname [{nick_from}] do not exist") return None if not channel is None: @@ -172,8 +158,8 @@ class Unrealircd6(IProtocol): self.send2socket(f":{nick_from} PRIVMSG {User_to.uid} :{batch}") except Exception as err: - self.__Logs.error(f"General Error: {err}") - self.__Logs.error(f"General Error: {nick_from} - {channel} - {nick_to}") + self._Logs.error(f"General Error: {err}") + self._Logs.error(f"General Error: {nick_from} - {channel} - {nick_to}") def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: """Sending NOTICE by batches @@ -184,12 +170,12 @@ class Unrealircd6(IProtocol): 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) + 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.__Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist") + self._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): @@ -197,31 +183,31 @@ class Unrealircd6(IProtocol): self.send2socket(f":{User_from.uid} NOTICE {User_to.uid} :{batch}") except Exception as err: - self.__Logs.error(f"General Error: {err}") + self._Logs.error(f"General Error: {err}") def send_link(self): """Créer le link et envoyer les informations nécessaires pour la connexion au serveur. """ - service_id = self.__Config.SERVICE_ID - service_nickname = self.__Config.SERVICE_NICKNAME - service_username = self.__Config.SERVICE_USERNAME - service_realname = self.__Config.SERVICE_REALNAME - service_channel_log = self.__Config.SERVICE_CHANLOG - service_info = self.__Config.SERVICE_INFO - service_smodes = self.__Config.SERVICE_SMODES - service_cmodes = self.__Config.SERVICE_CMODES - service_umodes = self.__Config.SERVICE_UMODES - service_hostname = self.__Config.SERVICE_HOST - service_name = self.__Config.SERVICE_NAME + service_id = self._Config.SERVICE_ID + service_nickname = self._Config.SERVICE_NICKNAME + service_username = self._Config.SERVICE_USERNAME + service_realname = self._Config.SERVICE_REALNAME + service_channel_log = self._Config.SERVICE_CHANLOG + service_info = self._Config.SERVICE_INFO + service_smodes = self._Config.SERVICE_SMODES + service_cmodes = self._Config.SERVICE_CMODES + service_umodes = self._Config.SERVICE_UMODES + service_hostname = self._Config.SERVICE_HOST + service_name = self._Config.SERVICE_NAME protocolversion = self.protocol_version - server_password = self.__Config.SERVEUR_PASSWORD - server_link = self.__Config.SERVEUR_LINK - server_id = self.__Config.SERVEUR_ID + server_password = self._Config.SERVEUR_PASSWORD + server_link = self._Config.SERVEUR_LINK + server_id = self._Config.SERVEUR_ID - version = self.__Config.CURRENT_VERSION - unixtime = self.__Utils.get_unixtime() + version = self._Config.CURRENT_VERSION + unixtime = self._Utils.get_unixtime() self.send2socket(f":{server_id} PASS :{server_password}", print_log=False) self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS") @@ -236,7 +222,7 @@ class Unrealircd6(IProtocol): self.send2socket(f":{server_id} TKL + Q * {service_nickname} {service_hostname} 0 {unixtime} :Reserved for services") self.send2socket(f":{service_id} MODE {service_channel_log} {service_cmodes}") - self.__Logs.debug(f'>> {__name__} Link information sent to the server') + self._Logs.debug(f'>> {__name__} Link information sent to the server') def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: """Send a gline command to the server @@ -251,7 +237,7 @@ class Unrealircd6(IProtocol): """ # 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}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None @@ -261,10 +247,10 @@ class Unrealircd6(IProtocol): Args: newnickname (str): New nickname of the server """ - self.send2socket(f":{self.__Config.SERVICE_NICKNAME} NICK {newnickname}") + self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") - userObj = self.__Irc.User.get_user(self.__Config.SERVICE_NICKNAME) - self.__Irc.User.update_nickname(userObj.uid, newnickname) + userObj = self._Irc.User.get_user(self._Config.SERVICE_NICKNAME) + self._Irc.User.update_nickname(userObj.uid, newnickname) return None def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: @@ -276,16 +262,16 @@ class Unrealircd6(IProtocol): channel_name (Optional[str]): The channel name params (Optional[str]): Parameters like password. """ - service_id = self.__Config.SERVICE_ID + service_id = self._Config.SERVICE_ID if modes[0] not in ['+', '-']: - self.__Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") + self._Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") return None if nickname and channel_name: # :98KAAAAAB MODE #services +o defenderdev - if not self.__Irc.Channel.is_valid_channel(channel_name): - self.__Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._Irc.Channel.is_valid_channel(channel_name): + self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") return None @@ -295,8 +281,8 @@ class Unrealircd6(IProtocol): return None if nickname is None and channel_name: - if not self.__Irc.Channel.is_valid_channel(channel_name): - self.__Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._Irc.Channel.is_valid_channel(channel_name): + self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") return None @@ -313,20 +299,20 @@ class Unrealircd6(IProtocol): def send_ungline(self, nickname:str, hostname: str) -> None: - self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") return None def send_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}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None def send_unkline(self, nickname:str, hostname: str) -> None: - self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") return None @@ -336,15 +322,15 @@ class Unrealircd6(IProtocol): Args: channel (str): Channel to join """ - if not self.__Irc.Channel.is_valid_channel(channel): - self.__Logs.error(f"The channel [{channel}] is not valid") + if not self._Irc.Channel.is_valid_channel(channel): + self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{self.__Config.SERVEUR_ID} SJOIN {self.__Utils.get_unixtime()} {channel} {self.__Config.SERVICE_UMODES} :{self.__Config.SERVICE_ID}") - self.send2socket(f":{self.__Config.SERVICE_ID} MODE {channel} {self.__Config.SERVICE_UMODES} {self.__Config.SERVICE_ID}") + self.send2socket(f":{self._Config.SERVEUR_ID} SJOIN {self._Utils.get_unixtime()} {channel} {self._Config.SERVICE_UMODES} :{self._Config.SERVICE_ID}") + self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {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])) + self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[self._Config.SERVICE_ID])) return None def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: @@ -357,20 +343,20 @@ class Unrealircd6(IProtocol): """ try: - userObj = self.__Irc.User.get_user(uidornickname=nick_to_sapart) - chanObj = self.__Irc.Channel.get_channel(channel_name) - service_uid = self.__Config.SERVICE_ID + userObj = self._Irc.User.get_user(uidornickname=nick_to_sapart) + chanObj = self._Irc.Channel.get_channel(channel_name) + service_uid = self._Config.SERVICE_ID if userObj is None or chanObj is None: return None self.send2socket(f":{service_uid} SAPART {userObj.nickname} {chanObj.name}") - self.__Irc.Channel.delete_user_from_channel(chanObj.name, userObj.uid) + self._Irc.Channel.delete_user_from_channel(chanObj.name, userObj.uid) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: """_summary_ @@ -381,9 +367,9 @@ class Unrealircd6(IProtocol): """ try: - userObj = self.__Irc.User.get_user(uidornickname=nick_to_sajoin) - chanObj = self.__Irc.Channel.get_channel(channel_name) - service_uid = self.__Config.SERVICE_ID + userObj = self._Irc.User.get_user(uidornickname=nick_to_sajoin) + chanObj = self._Irc.Channel.get_channel(channel_name) + service_uid = self._Config.SERVICE_ID if userObj is None: # User not exist: leave @@ -391,53 +377,53 @@ class Unrealircd6(IProtocol): if chanObj is None: # Channel not exist - if not self.__Irc.Channel.is_valid_channel(channel_name): + if not self._Irc.Channel.is_valid_channel(channel_name): # Incorrect channel: leave return None # Create the new channel with the uid - newChanObj = self.__Irc.Loader.Definition.MChannel(name=channel_name, uids=[userObj.uid]) - self.__Irc.Channel.insert(newChanObj) + newChanObj = self._Irc.Loader.Definition.MChannel(name=channel_name, uids=[userObj.uid]) + self._Irc.Channel.insert(newChanObj) self.send2socket(f":{service_uid} SAJOIN {userObj.nickname} {newChanObj.name}") else: - self.__Irc.Channel.add_user_to_a_channel(channel_name=channel_name, uid=userObj.uid) + self._Irc.Channel.add_user_to_a_channel(channel_name=channel_name, uid=userObj.uid) self.send2socket(f":{service_uid} SAJOIN {userObj.nickname} {chanObj.name}") return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: - user_obj = self.__Irc.User.get_user(nick_to_part) + user_obj = self._Irc.User.get_user(nick_to_part) if user_obj is None: - self.__Logs.debug(f"[SVSPART] The nickname {nick_to_part} do not exist!") + self._Logs.debug(f"[SVSPART] The nickname {nick_to_part} do not exist!") return None - channels_list = ','.join([channel for channel in channels if self.__Irc.Channel.is_valid_channel(channel)]) - service_id = self.__Config.SERVICE_ID + channels_list = ','.join([channel for channel in channels if self._Irc.Channel.is_valid_channel(channel)]) + service_id = self._Config.SERVICE_ID self.send2socket(f':{service_id} SVSPART {user_obj.nickname} {channels_list} {reason}') return None def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: - user_obj = self.__Irc.User.get_user(nick_to_part) + user_obj = self._Irc.User.get_user(nick_to_part) if user_obj is None: - self.__Logs.debug(f"[SVSJOIN] The nickname {nick_to_part} do not exist!") + self._Logs.debug(f"[SVSJOIN] The nickname {nick_to_part} do not exist!") return None - channels_list = ','.join([channel for channel in channels if self.__Irc.Channel.is_valid_channel(channel)]) + channels_list = ','.join([channel for channel in channels if self._Irc.Channel.is_valid_channel(channel)]) keys_list = ','.join([key for key in keys]) - service_id = self.__Config.SERVICE_ID + service_id = self._Config.SERVICE_ID self.send2socket(f':{service_id} SVSJOIN {user_obj.nickname} {channels_list} {keys_list}') return None def send_svsmode(self, nickname: str, user_mode: str) -> None: try: - user_obj = self.__Irc.User.get_user(uidornickname=nickname) - service_uid = self.__Config.SERVICE_ID + user_obj = self._Irc.User.get_user(uidornickname=nickname) + service_uid = self._Config.SERVICE_ID if user_obj is None: return None @@ -445,16 +431,16 @@ class Unrealircd6(IProtocol): self.send2socket(f':{service_uid} SVSMODE {nickname} {user_mode}') # Update new mode - self.__Irc.User.update_mode(user_obj.uid, user_mode) + self._Irc.User.update_mode(user_obj.uid, user_mode) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def send_svs2mode(self, nickname: str, user_mode: str) -> None: try: - user_obj = self.__Irc.User.get_user(uidornickname=nickname) - service_uid = self.__Config.SERVICE_ID + user_obj = self._Irc.User.get_user(uidornickname=nickname) + service_uid = self._Config.SERVICE_ID if user_obj is None: return None @@ -462,11 +448,11 @@ class Unrealircd6(IProtocol): self.send2socket(f':{service_uid} SVS2MODE {nickname} {user_mode}') # Update new mode - self.__Irc.User.update_mode(user_obj.uid, user_mode) + self._Irc.User.update_mode(user_obj.uid, user_mode) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def send_svslogin(self, client_uid: str, user_account: str) -> None: """Log a client into his account. @@ -476,9 +462,9 @@ class Unrealircd6(IProtocol): user_account (str): The account of the user """ try: - self.send2socket(f":{self.__Irc.Config.SERVEUR_LINK} SVSLOGIN {self.__Settings.MAIN_SERVER_HOSTNAME} {client_uid} {user_account}") + self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {client_uid} {user_account}") except Exception as err: - self.__Logs.error(f'General Error: {err}') + self._Logs.error(f'General Error: {err}') def send_svslogout(self, client_obj: 'MClient') -> None: """Logout a client from his account @@ -489,11 +475,11 @@ class Unrealircd6(IProtocol): try: c_uid = client_obj.uid c_nickname = client_obj.nickname - self.send2socket(f":{self.__Irc.Config.SERVEUR_LINK} SVSLOGIN {self.__Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0") + self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0") self.send_svs2mode(c_nickname, '-r') except Exception as err: - self.__Logs.error(f'General Error: {err}') + self._Logs.error(f'General Error: {err}') def send_quit(self, uid: str, reason: str, print_log: True) -> None: """Send quit message @@ -504,18 +490,18 @@ class Unrealircd6(IProtocol): uidornickname (str): The UID or the Nickname reason (str): The reason for the quit """ - user_obj = self.__Irc.User.get_user(uidornickname=uid) - reputationObj = self.__Irc.Reputation.get_reputation(uidornickname=uid) + user_obj = self._Irc.User.get_user(uidornickname=uid) + reputationObj = self._Irc.Reputation.get_reputation(uidornickname=uid) if not user_obj is None: self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) - self.__Irc.User.delete(user_obj.uid) + self._Irc.User.delete(user_obj.uid) if not reputationObj is None: - self.__Irc.Reputation.delete(reputationObj.uid) + self._Irc.Reputation.delete(reputationObj.uid) - if not self.__Irc.Channel.delete_user_from_all_channel(uid): - self.__Logs.error(f"The UID [{uid}] has not been deleted from all channels") + if not self._Irc.Channel.delete_user_from_all_channel(uid): + self._Logs.error(f"The UID [{uid}] has not been deleted from all channels") return None @@ -534,28 +520,28 @@ class Unrealircd6(IProtocol): print_log (bool, optional): print logs if true. Defaults to True. """ # {self.Config.SERVEUR_ID} UID - # {clone.nickname} 1 {self.__Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} + # {clone.nickname} 1 {self._Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} try: - unixtime = self.__Utils.get_unixtime() - encoded_ip = self.__Base.encode_ip(remote_ip) + unixtime = self._Utils.get_unixtime() + encoded_ip = self._Base.encode_ip(remote_ip) # Create the user - self.__Irc.User.insert( - self.__Irc.Loader.Definition.MUser( + self._Irc.User.insert( + self._Irc.Loader.Definition.MUser( uid=uid, nickname=nickname, username=username, realname=realname,hostname=hostname, umodes=umodes, vhost=vhost, remote_ip=remote_ip ) ) - uid_msg = f":{self.__Config.SERVEUR_ID} UID {nickname} 1 {unixtime} {username} {hostname} {uid} * {umodes} {vhost} * {encoded_ip} :{realname}" + uid_msg = f":{self._Config.SERVEUR_ID} UID {nickname} 1 {unixtime} {username} {hostname} {uid} * {umodes} {vhost} * {encoded_ip} :{realname}" self.send2socket(uid_msg, print_log=print_log) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: """Joining a channel @@ -567,34 +553,34 @@ class Unrealircd6(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - userObj = self.__Irc.User.get_user(uidornickname) + 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_valid_channel(channel): - self.__Logs.error(f"The channel [{channel}] is not valid") + if not self._Irc.Channel.is_valid_channel(channel): + self._Logs.error(f"The channel [{channel}] is not valid") return None self.send2socket(f":{userObj.uid} JOIN {channel} {passwordChannel}", print_log=print_log) - if uidornickname == self.__Config.SERVICE_NICKNAME or uidornickname == self.__Config.SERVICE_ID: - self.send2socket(f":{self.__Config.SERVICE_ID} MODE {channel} {self.__Config.SERVICE_UMODES} {self.__Config.SERVICE_ID}") + if uidornickname == self._Config.SERVICE_NICKNAME or uidornickname == self._Config.SERVICE_ID: + self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") # Add defender to the channel uids list - self.__Irc.Channel.insert(self.__Irc.Loader.Definition.MChannel(name=channel, uids=[userObj.uid])) + self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[userObj.uid])) # Set the automode to the user if 'r' not in userObj.umodes and 'o' not in userObj.umodes: return None db_data: dict[str, str] = {"nickname": userObj.nickname, "channel": channel} - db_query = self.__Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data) + db_query = self._Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data) db_result = db_query.fetchone() if db_result is not None: id, mode = db_result - self.send2socket(f":{self.__Config.SERVICE_ID} MODE {channel} {mode} {userObj.nickname}") + self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {mode} {userObj.nickname}") return None @@ -607,35 +593,35 @@ class Unrealircd6(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - userObj = self.__Irc.User.get_user(uidornickname) + userObj = self._Irc.User.get_user(uidornickname) if userObj is None: - self.__Logs.error(f"The user [{uidornickname}] is not valid") + self._Logs.error(f"The user [{uidornickname}] is not valid") return None - if not self.__Irc.Channel.is_valid_channel(channel): - self.__Logs.error(f"The channel [{channel}] is not valid") + if not self._Irc.Channel.is_valid_channel(channel): + self._Logs.error(f"The channel [{channel}] is not valid") 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) + self._Irc.Channel.delete_user_from_channel(channel, userObj.uid) return None def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: - channel = self.__Irc.Channel.is_valid_channel(channel_name) + channel = self._Irc.Channel.is_valid_channel(channel_name) if not channel: - self.__Logs.error(f'The channel [{channel_name}] is not correct') + self._Logs.error(f'The channel [{channel_name}] is not correct') return None - self.send2socket(f":{self.__Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}") + self.send2socket(f":{self._Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}") return None def send_raw(self, raw_command: str) -> None: - self.send2socket(f":{self.__Config.SERVICE_NICKNAME} {raw_command}") + self.send2socket(f":{self._Config.SERVICE_NICKNAME} {raw_command}") return None @@ -650,7 +636,7 @@ class Unrealircd6(IProtocol): serverMsg (list[str]): The UID ircd response """ umodes = str(serverMsg[10]) - remote_ip = self.__Base.decode_ip(str(serverMsg[13])) if 'S' not in umodes else '127.0.0.1' + remote_ip = self._Base.decode_ip(str(serverMsg[13])) if 'S' not in umodes else '127.0.0.1' # Extract Geoip information pattern = r'^.*geoip=cc=(\S{2}).*$' @@ -732,8 +718,8 @@ class Unrealircd6(IProtocol): response = { "uid_sender": scopy[0].replace(':', ''), - "uid_reciever": self.__Irc.User.get_uid(scopy[2]), - "channel": scopy[2] if self.__Irc.Channel.is_valid_channel(scopy[2]) else None, + "uid_reciever": self._Irc.User.get_uid(scopy[2]), + "channel": scopy[2] if self._Irc.Channel.is_valid_channel(scopy[2]) else None, "message": " ".join(scopy[3:]) } return response @@ -755,19 +741,19 @@ class Unrealircd6(IProtocol): uid_user_to_edit = serverMsg[2] umode = serverMsg[3] - userObj = self.__Irc.User.get_user(uid_user_to_edit) + userObj = self._Irc.User.get_user(uid_user_to_edit) if userObj is None: return None - if self.__Irc.User.update_mode(userObj.uid, umode): + if self._Irc.User.update_mode(userObj.uid, umode): return None return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_mode(self, serverMsg: list[str]) -> None: """Handle mode coming from a server @@ -790,7 +776,7 @@ class Unrealircd6(IProtocol): try: # [':adator_', 'UMODE2', '-iwx'] - userObj = self.__Irc.User.get_user(str(serverMsg[0]).lstrip(':')) + userObj = self._Irc.User.get_user(str(serverMsg[0]).lstrip(':')) userMode = serverMsg[2] if userObj is None: # If user is not created @@ -800,16 +786,16 @@ class Unrealircd6(IProtocol): old_umodes = userObj.umodes # TODO : User object should be able to update user modes - if self.__Irc.User.update_mode(userObj.uid, userMode): + if self._Irc.User.update_mode(userObj.uid, userMode): return None - # self.__Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") + # self._Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_quit(self, serverMsg: list[str]) -> None: """Handle quit coming from a server @@ -822,18 +808,18 @@ class Unrealircd6(IProtocol): uid_who_quit = str(serverMsg[1]).lstrip(':') - self.__Irc.Channel.delete_user_from_all_channel(uid_who_quit) - self.__Irc.User.delete(uid_who_quit) - self.__Irc.Client.delete(uid_who_quit) - self.__Irc.Reputation.delete(uid_who_quit) - self.__Irc.Admin.delete(uid_who_quit) + self._Irc.Channel.delete_user_from_all_channel(uid_who_quit) + self._Irc.User.delete(uid_who_quit) + self._Irc.Client.delete(uid_who_quit) + self._Irc.Reputation.delete(uid_who_quit) + self._Irc.Admin.delete(uid_who_quit) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_squit(self, serverMsg: list[str]) -> None: """Handle squit coming from a server @@ -845,15 +831,15 @@ class Unrealircd6(IProtocol): server_hostname = serverMsg[2] uid_to_delete = None - for s_user in self.__Irc.User.UID_DB: + for s_user in self._Irc.User.UID_DB: if s_user.hostname == server_hostname and 'S' in s_user.umodes: uid_to_delete = s_user.uid if uid_to_delete is None: return None - self.__Irc.User.delete(uid_to_delete) - self.__Irc.Channel.delete_user_from_all_channel(uid_to_delete) + self._Irc.User.delete(uid_to_delete) + self._Irc.Channel.delete_user_from_all_channel(uid_to_delete) return None @@ -887,9 +873,9 @@ class Unrealircd6(IProtocol): if user_modes is None or prefix is None or host_server_id is None: return None - self.__Config.HSID = host_server_id - self.__Settings.PROTOCTL_USER_MODES = list(user_modes) - self.__Settings.PROTOCTL_PREFIX = list(prefix) + self._Config.HSID = host_server_id + self._Settings.PROTOCTL_USER_MODES = list(user_modes) + self._Settings.PROTOCTL_PREFIX = list(prefix) return None @@ -906,17 +892,17 @@ class Unrealircd6(IProtocol): uid = str(serverMsg[1]).lstrip(':') newnickname = serverMsg[3] - self.__Irc.User.update_nickname(uid, newnickname) - self.__Irc.Client.update_nickname(uid, newnickname) - self.__Irc.Admin.update_nickname(uid, newnickname) - self.__Irc.Reputation.update(uid, newnickname) + self._Irc.User.update_nickname(uid, newnickname) + self._Irc.Client.update_nickname(uid, newnickname) + self._Irc.Admin.update_nickname(uid, newnickname) + self._Irc.Reputation.update(uid, newnickname) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_sjoin(self, serverMsg: list[str]) -> None: """Handle sjoin coming from a server @@ -953,13 +939,13 @@ class Unrealircd6(IProtocol): # Boucle qui va ajouter l'ensemble des users (UID) for i in range(start_boucle, len(serverMsg_copy)): parsed_UID = str(serverMsg_copy[i]) - clean_uid = self.__Utils.clean_uid(parsed_UID) + clean_uid = self._Utils.clean_uid(parsed_UID) if not clean_uid is None and len(clean_uid) == 9: list_users.append(clean_uid) if list_users: - self.__Irc.Channel.insert( - self.__Irc.Loader.Definition.MChannel( + self._Irc.Channel.insert( + self._Irc.Loader.Definition.MChannel( name=channel, uids=list_users ) @@ -967,9 +953,9 @@ class Unrealircd6(IProtocol): return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_part(self, serverMsg: list[str]) -> None: """Handle part coming from a server @@ -981,13 +967,13 @@ class Unrealircd6(IProtocol): # ['@unrealircd.org', ':001EPFBRD', 'PART', '#welcome', ':WEB', 'IRC', 'Paris'] uid = str(serverMsg[1]).lstrip(':') channel = str(serverMsg[3]).lower() - self.__Irc.Channel.delete_user_from_channel(channel, uid) + self._Irc.Channel.delete_user_from_channel(channel, uid) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_eos(self, serverMsg: list[str]) -> None: """Handle EOS coming from a server @@ -999,69 +985,69 @@ class Unrealircd6(IProtocol): # [':001', 'EOS'] server_msg_copy = serverMsg.copy() hsid = str(server_msg_copy[0]).replace(':','') - 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): + 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: version = f'{current_version}' print(f"################### DEFENDER ###################") print(f"# SERVICE CONNECTE ") - 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.__Config.SSL_VERSION} ") - print(f"# NICKNAME : {self.__Config.SERVICE_NICKNAME} ") - print(f"# CHANNEL : {self.__Config.SERVICE_CHANLOG} ") + 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._Config.SSL_VERSION} ") + print(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") + print(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") print(f"# VERSION : {version} ") print(f"################################################") - self.__Logs.info(f"################### DEFENDER ###################") - self.__Logs.info(f"# SERVICE CONNECTE ") - self.__Logs.info(f"# SERVEUR : {self.__Config.SERVEUR_IP} ") - self.__Logs.info(f"# PORT : {self.__Config.SERVEUR_PORT} ") - self.__Logs.info(f"# SSL : {self.__Config.SERVEUR_SSL} ") - self.__Logs.info(f"# SSL VER : {self.__Config.SSL_VERSION} ") - self.__Logs.info(f"# NICKNAME : {self.__Config.SERVICE_NICKNAME} ") - self.__Logs.info(f"# CHANNEL : {self.__Config.SERVICE_CHANLOG} ") - self.__Logs.info(f"# VERSION : {version} ") - self.__Logs.info(f"################################################") + self._Logs.info(f"################### DEFENDER ###################") + self._Logs.info(f"# SERVICE CONNECTE ") + self._Logs.info(f"# SERVEUR : {self._Config.SERVEUR_IP} ") + self._Logs.info(f"# PORT : {self._Config.SERVEUR_PORT} ") + self._Logs.info(f"# SSL : {self._Config.SERVEUR_SSL} ") + self._Logs.info(f"# SSL VER : {self._Config.SSL_VERSION} ") + self._Logs.info(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") + self._Logs.info(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") + self._Logs.info(f"# VERSION : {version} ") + self._Logs.info(f"################################################") - self.send_sjoin(self.__Config.SERVICE_CHANLOG) + self.send_sjoin(self._Config.SERVICE_CHANLOG) - if self.__Base.check_for_new_version(False): + if self._Base.check_for_new_version(False): self.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + nick_from=self._Config.SERVICE_NICKNAME, msg=f" New Version available {version}", - channel=self.__Config.SERVICE_CHANLOG + channel=self._Config.SERVICE_CHANLOG ) # Initialisation terminé aprés le premier PING self.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, - msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self.__Config.COLORS.green, self.__Config.COLORS.nogc, self.__Config.SERVICE_NICKNAME), - channel=self.__Config.SERVICE_CHANLOG + nick_from=self._Config.SERVICE_NICKNAME, + msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._Config.COLORS.green, self._Config.COLORS.nogc, self._Config.SERVICE_NICKNAME), + channel=self._Config.SERVICE_CHANLOG ) - self.__Config.DEFENDER_INIT = 0 + self._Config.DEFENDER_INIT = 0 # Send EOF to other modules - for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(server_msg_copy) # Join saved channels & load existing modules - self.__Irc.join_saved_channels() - self.__Irc.ModuleUtils.db_load_all_existing_modules(self.__Irc) + self._Irc.join_saved_channels() + self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Key Error: {ie}") + self._Logs.error(f"{__name__} - Key Error: {ie}") except KeyError as ke: - self.__Logs.error(f"{__name__} - Key Error: {ke}") + self._Logs.error(f"{__name__} - Key Error: {ke}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_reputation(self, serverMsg: list[str]) -> None: """Handle REPUTATION coming from a server @@ -1072,27 +1058,27 @@ class Unrealircd6(IProtocol): try: # :001 REPUTATION 127.0.0.1 118 server_msg_copy = serverMsg.copy() - self.__Irc.first_connexion_ip = server_msg_copy[2] - self.__Irc.first_score = 0 + self._Irc.first_connexion_ip = server_msg_copy[2] + self._Irc.first_score = 0 if str(server_msg_copy[3]).find('*') != -1: # If * available, it means that an ircop changed the repurtation score # means also that the user exist will try to update all users with same IP - self.__Irc.first_score = int(str(server_msg_copy[3]).replace('*','')) - for user in self.__Irc.User.UID_DB: - if user.remote_ip == self.__Irc.first_connexion_ip: - user.score_connexion = self.__Irc.first_score + self._Irc.first_score = int(str(server_msg_copy[3]).replace('*','')) + for user in self._Irc.User.UID_DB: + if user.remote_ip == self._Irc.first_connexion_ip: + user.score_connexion = self._Irc.first_score else: - self.__Irc.first_score = int(server_msg_copy[3]) + self._Irc.first_score = int(server_msg_copy[3]) # Possibilité de déclancher les bans a ce niveau. except IndexError as ie: - self.__Logs.error(f'Index Error {__name__}: {ie}') + self._Logs.error(f'Index Error {__name__}: {ie}') except ValueError as ve: - self.__Irc.first_score = 0 - self.__Logs.error(f'Value Error {__name__}: {ve}') + self._Irc.first_score = 0 + self._Logs.error(f'Value Error {__name__}: {ve}') except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_uid(self, serverMsg: list[str]) -> None: """Handle uid message coming from the server @@ -1116,7 +1102,7 @@ class Unrealircd6(IProtocol): vhost = str(serverMsg[11]) if not 'S' in umodes: - remote_ip = self.__Base.decode_ip(str(serverMsg[13])) + remote_ip = self._Base.decode_ip(str(serverMsg[13])) else: remote_ip = '127.0.0.1' @@ -1142,10 +1128,10 @@ class Unrealircd6(IProtocol): else: geoip = None - score_connexion = self.__Irc.first_score + score_connexion = self._Irc.first_score - self.__Irc.User.insert( - self.__Irc.Loader.Definition.MUser( + self._Irc.User.insert( + self._Irc.Loader.Definition.MUser( uid=uid, nickname=nickname, username=username, @@ -1165,13 +1151,13 @@ class Unrealircd6(IProtocol): ) # Auto Auth admin via fingerprint - dnickname = self.__Config.SERVICE_NICKNAME - dchanlog = self.__Config.SERVICE_CHANLOG - GREEN = self.__Config.COLORS.green - RED = self.__Config.COLORS.red - NOGC = self.__Config.COLORS.nogc + dnickname = self._Config.SERVICE_NICKNAME + dchanlog = self._Config.SERVICE_CHANLOG + GREEN = self._Config.COLORS.green + RED = self._Config.COLORS.red + NOGC = self._Config.COLORS.nogc - for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(serverMsg) # SASL authentication @@ -1179,10 +1165,10 @@ class Unrealircd6(IProtocol): uid = serverMsg[8] nickname = serverMsg[3] - sasl_obj = self.__Irc.Sasl.get_sasl_obj(uid) + sasl_obj = self._Irc.Sasl.get_sasl_obj(uid) if sasl_obj: if sasl_obj.auth_success: - self.__Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) + self._Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, sasl_obj.username, dnickname), channel=dchanlog) @@ -1194,12 +1180,12 @@ class Unrealircd6(IProtocol): self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) # Delete sasl object! - self.__Irc.Sasl.delete_sasl_client(uid) + self._Irc.Sasl.delete_sasl_client(uid) return None # If no sasl authentication then auto connect via fingerprint - if self.__Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): - admin = self.__Irc.Admin.get_admin(uid) + if self._Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): + admin = self._Irc.Admin.get_admin(uid) account = admin.account if admin else '' self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, account, dnickname), @@ -1208,9 +1194,9 @@ class Unrealircd6(IProtocol): return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_privmsg(self, serverMsg: list[str]) -> None: """Handle PRIVMSG message coming from the server @@ -1226,32 +1212,32 @@ class Unrealircd6(IProtocol): cmd.pop(0) get_uid_or_nickname = str(cmd[0].replace(':','')) - user_trigger = self.__Irc.User.get_nickname(get_uid_or_nickname) - dnickname = self.__Config.SERVICE_NICKNAME - pattern = fr'(:\{self.__Config.SERVICE_PREFIX})(.*)$' + user_trigger = self._Irc.User.get_nickname(get_uid_or_nickname) + dnickname = self._Config.SERVICE_NICKNAME + pattern = fr'(:\{self._Config.SERVICE_PREFIX})(.*)$' hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . if hcmds: # Commande qui commencent par le point liste_des_commandes = list(hcmds.groups()) convert_to_string = ' '.join(liste_des_commandes) arg = convert_to_string.split() - arg.remove(f':{self.__Config.SERVICE_PREFIX}') - if not self.__Irc.Commands.is_command_exist(arg[0]): - self.__Logs.debug(f"This command {arg[0]} is not available") + arg.remove(f':{self._Config.SERVICE_PREFIX}') + if not self._Irc.Commands.is_command_exist(arg[0]): + self._Logs.debug(f"This command {arg[0]} is not available") self.send_notice( - nick_from=self.__Config.SERVICE_NICKNAME, + 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" + 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) + self._Base.log_cmd(user_trigger, cmd_to_send) - fromchannel = str(cmd[2]).lower() if self.__Irc.Channel.is_valid_channel(cmd[2]) else None - self.__Irc.hcmds(user_trigger, fromchannel, arg, cmd) + fromchannel = str(cmd[2]).lower() if self._Irc.Channel.is_valid_channel(cmd[2]) else None + self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) - if cmd[2] == self.__Config.SERVICE_ID: + if cmd[2] == self._Config.SERVICE_ID: pattern = fr'^:.*?:(.*)$' hcmds = search(pattern, ' '.join(cmd)) @@ -1275,30 +1261,30 @@ class Unrealircd6(IProtocol): self.on_ping(srv_msg) return None - if not self.__Irc.Commands.is_command_exist(arg[0]): - self.__Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + if not self._Irc.Commands.is_command_exist(arg[0]): + self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") return None - # if not arg[0].lower() in self.__Irc.module_commands_list: - # self.__Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + # if not arg[0].lower() in self._Irc.module_commands_list: + # self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") # return False cmd_to_send = convert_to_string.replace(':','') - self.__Base.log_cmd(user_trigger, cmd_to_send) + self._Base.log_cmd(user_trigger, cmd_to_send) fromchannel = None if len(arg) >= 2: - fromchannel = str(arg[1]).lower() if self.__Irc.Channel.is_valid_channel(arg[1]) else None + fromchannel = str(arg[1]).lower() if self._Irc.Channel.is_valid_channel(arg[1]) else None - self.__Irc.hcmds(user_trigger, fromchannel, arg, cmd) + self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) return None except KeyError as ke: - self.__Logs.error(f"Key Error: {ke}") + self._Logs.error(f"Key Error: {ke}") except AttributeError as ae: - self.__Logs.error(f"Attribute Error: {ae}") + self._Logs.error(f"Attribute Error: {ae}") except Exception as err: - self.__Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True) + self._Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True) def on_server_ping(self, serverMsg: list[str]) -> None: """Send a PONG message to the server @@ -1312,7 +1298,7 @@ class Unrealircd6(IProtocol): return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_server(self, serverMsg: list[str]) -> None: """_summary_ @@ -1323,9 +1309,9 @@ class Unrealircd6(IProtocol): try: # ['SERVER', 'irc.local.org', '1', ':U6100-Fhn6OoE-001', 'Local', 'Server'] sCopy = serverMsg.copy() - self.__Irc.Settings.MAIN_SERVER_HOSTNAME = sCopy[1] + self._Irc.Settings.MAIN_SERVER_HOSTNAME = sCopy[1] except Exception as err: - self.__Logs.error(f'General Error: {err}') + self._Logs.error(f'General Error: {err}') def on_version(self, serverMsg: list[str]) -> None: """Sending Server Version to the server @@ -1337,19 +1323,19 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1])) - dnickname = self.__Config.SERVICE_NICKNAME + nickname = self._Irc.User.get_nickname(self._Utils.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') + 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.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_time(self, serverMsg: list[str]) -> None: """Sending TIME answer to a requestor @@ -1361,10 +1347,10 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1])) - dnickname = self.__Config.SERVICE_NICKNAME + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(serverMsg[1])) + dnickname = self._Config.SERVICE_NICKNAME arg = serverMsg[4].replace(':', '') - current_datetime = self.__Utils.get_sdatetime() + current_datetime = self._Utils.get_sdatetime() if nickname is None: return None @@ -1374,7 +1360,7 @@ class Unrealircd6(IProtocol): return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_ping(self, serverMsg: list[str]) -> None: """Sending a PING answer to requestor @@ -1386,30 +1372,30 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1])) - dnickname = self.__Config.SERVICE_NICKNAME + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(serverMsg[1])) + dnickname = self._Config.SERVICE_NICKNAME arg = serverMsg[4].replace(':', '') if nickname is None: - self.__Logs.debug(serverMsg) + self._Logs.debug(serverMsg) return None if arg == '\x01PING': recieved_unixtime = int(serverMsg[5].replace('\x01','')) - current_unixtime = self.__Utils.get_unixtime() + current_unixtime = self._Utils.get_unixtime() ping_response = current_unixtime - recieved_unixtime - # self.__Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') + # self._Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') self.send_notice( nick_from=dnickname, nick_to=nickname, msg=f"\x01PING {ping_response} secs\x01" ) - self.__Logs.debug(serverMsg) + self._Logs.debug(serverMsg) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_version_msg(self, serverMsg: list[str]) -> None: """Handle version coming from the server @@ -1423,25 +1409,25 @@ class Unrealircd6(IProtocol): if '@' in list(serverMsg_copy[0])[0]: serverMsg_copy.pop(0) - getUser = self.__Irc.User.get_user(self.__Utils.clean_uid(serverMsg_copy[0])) + getUser = self._Irc.User.get_user(self._Utils.clean_uid(serverMsg_copy[0])) if getUser is None: return None - response_351 = f"{self.__Config.SERVICE_NAME.capitalize()}-{self.__Config.CURRENT_VERSION} {self.__Config.SERVICE_HOST} {self.name}" - self.send2socket(f':{self.__Config.SERVICE_HOST} 351 {getUser.nickname} {response_351}') + response_351 = f"{self._Config.SERVICE_NAME.capitalize()}-{self._Config.CURRENT_VERSION} {self._Config.SERVICE_HOST} {self.name}" + self.send2socket(f':{self._Config.SERVICE_HOST} 351 {getUser.nickname} {response_351}') - modules = self.__Irc.ModuleUtils.get_all_available_modules() + modules = self._Irc.ModuleUtils.get_all_available_modules() response_005 = ' | '.join(modules) - self.send2socket(f':{self.__Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server') + self.send2socket(f':{self._Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server') - response_005 = ''.join(self.__Settings.PROTOCTL_USER_MODES) - self.send2socket(f":{self.__Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server") + response_005 = ''.join(self._Settings.PROTOCTL_USER_MODES) + self.send2socket(f":{self._Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server") return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_smod(self, serverMsg: list[str]) -> None: """Handle SMOD message coming from the server @@ -1456,11 +1442,11 @@ class Unrealircd6(IProtocol): for smod in modules: smod_split = smod.split(':') - sModObj = self.__Irc.Loader.Definition.MSModule(type=smod_split[0], name=smod_split[1], version=smod_split[2]) - self.__Settings.SMOD_MODULES.append(sModObj) + sModObj = self._Irc.Loader.Definition.MSModule(type=smod_split[0], name=smod_split[1], version=smod_split[2]) + self._Settings.SMOD_MODULES.append(sModObj) except Exception as err: - self.__Logs.error(f'General Error: {err}') + self._Logs.error(f'General Error: {err}') def on_sasl(self, serverMsg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server @@ -1475,9 +1461,9 @@ class Unrealircd6(IProtocol): # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey'] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey=='] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A'] - psasl = self.__Irc.Sasl + psasl = self._Irc.Sasl sasl_enabled = False - for smod in self.__Settings.SMOD_MODULES: + for smod in self._Settings.SMOD_MODULES: if smod.name == 'sasl': sasl_enabled = True break @@ -1489,7 +1475,7 @@ class Unrealircd6(IProtocol): client_uid = sCopy[3] if len(sCopy) >= 6 else None sasl_obj = None sasl_message_type = sCopy[4] if len(sCopy) >= 6 else None - psasl.insert_sasl_client(self.__Irc.Loader.Definition.MSasl(client_uid=client_uid)) + psasl.insert_sasl_client(self._Irc.Loader.Definition.MSasl(client_uid=client_uid)) sasl_obj = psasl.get_sasl_obj(client_uid) if sasl_obj is None: @@ -1507,13 +1493,13 @@ class Unrealircd6(IProtocol): sasl_obj.mechanisme = str(sCopy[5]) if sasl_obj.mechanisme == "PLAIN": - self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") + self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") elif sasl_obj.mechanisme == "EXTERNAL": if str(sCopy[5]) == "+": return None sasl_obj.fingerprint = str(sCopy[6]) - self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") + self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") self.on_sasl_authentication_process(sasl_obj) return sasl_obj @@ -1537,7 +1523,7 @@ class Unrealircd6(IProtocol): return sasl_obj except Exception as err: - self.__Logs.error(f'General Error: {err}', exc_info=True) + self._Logs.error(f'General Error: {err}', exc_info=True) def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool: s = sasl_model @@ -1545,12 +1531,12 @@ class Unrealircd6(IProtocol): def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: if fingerprint: mes_donnees = {'fingerprint': fingerprint} - query = f"SELECT user, level, language FROM {self.__Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint" + query = f"SELECT user, level, language FROM {self._Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint" else: - mes_donnees = {'user': username, 'password': self.__Utils.hash_password(password)} - query = f"SELECT user, level, language FROM {self.__Config.TABLE_ADMIN} WHERE user = :user AND password = :password" + mes_donnees = {'user': username, 'password': self._Utils.hash_password(password)} + query = f"SELECT user, level, language FROM {self._Config.TABLE_ADMIN} WHERE user = :user AND password = :password" - result = self.__Base.db_execute_query(query, mes_donnees) + result = self._Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if user_from_db: return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]} @@ -1564,11 +1550,11 @@ class Unrealircd6(IProtocol): s.auth_success = True s.level = admin_info.get('level', 0) s.language = admin_info.get('language', 'EN') - self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - self.send2socket(f":{self.__Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: - self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - self.send2socket(f":{self.__Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL': # Connection using fingerprints @@ -1579,12 +1565,12 @@ class Unrealircd6(IProtocol): s.level = admin_info.get('level', 0) s.username = admin_info.get('user', None) s.language = admin_info.get('language', 'EN') - self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - self.send2socket(f":{self.__Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: # "904 :SASL authentication failed" - self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - self.send2socket(f":{self.__Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") def on_md(self, serverMsg: list[str]) -> None: """Handle MD responses @@ -1600,7 +1586,7 @@ class Unrealircd6(IProtocol): var = str(scopy[4]).lower() value = str(scopy[5]).replace(':', '') - user_obj = self.__Irc.User.get_user(uid) + user_obj = self._Irc.User.get_user(uid) if user_obj is None: return None @@ -1614,7 +1600,7 @@ class Unrealircd6(IProtocol): ... except Exception as e: - self.__Logs.error(f"General Error: {e}") + self._Logs.error(f"General Error: {e}") def on_kick(self, serverMsg: list[str]) -> None: """When a user is kicked out from a channel @@ -1628,5 +1614,5 @@ class Unrealircd6(IProtocol): channel = scopy[3] # Delete the user from the channel. - self.__Irc.Channel.delete_user_from_channel(channel, uid) + self._Irc.Channel.delete_user_from_channel(channel, uid) return None \ No newline at end of file From deb76baf3024ce04255d4f436cddb05833e4dc72 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:24:57 +0100 Subject: [PATCH 10/56] Update the version of defender 6.3.2>>6.3.3 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 257fd31..f8598c8 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "6.3.2", + "version": "6.3.3", "requests": "2.32.5", "psutil": "7.1.2", From 0117e1dd3a48a0c1a7c5fa9208842ef8fa12254c Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:14:36 +0100 Subject: [PATCH 11/56] Update the protocol inspircd to work with the protocol interfaces. --- core/classes/protocols/inspircd.py | 493 ++++++++++++++--------------- 1 file changed, 239 insertions(+), 254 deletions(-) diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index a4957b2..e628a14 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -4,32 +4,18 @@ from re import match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional from ssl import SSLEOFError, SSLError -from core.classes.protocols.command_handler import CommandHandler from core.classes.protocols.interface import IProtocol from core.utils import tr if TYPE_CHECKING: - from core.irc import Irc from core.definition import MSasl, MClient class Inspircd(IProtocol): - def __init__(self, uplink: 'Irc'): - """ - - Args: - uplink (Irc): The Irc object - """ + def init_protocol(self): self.name = 'InspIRCd-4' self.protocol_version = 1206 - self.__Irc = uplink - self.__Config = uplink.Config - self.__Base = uplink.Base - self.__Utils = uplink.Loader.Utils - self.__Settings = uplink.Settings - self.__Logs = uplink.Loader.Logs - self.known_protocol: set[str] = {'UID', 'ERROR', 'PRIVMSG', 'SINFO', 'FJOIN', 'PING', 'PONG', 'SASL', 'PART', 'CAPAB', 'ENDBURST', @@ -37,10 +23,6 @@ class Inspircd(IProtocol): 'MODE', 'QUIT', 'SQUIT', 'VERSION'} - self.Handler = CommandHandler(uplink.Loader) - - self.__Logs.info(f"[PROTOCOL] Protocol [{__name__}] loaded!") - def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]: """Get the position of known commands @@ -56,12 +38,12 @@ class Inspircd(IProtocol): return index, token.upper() if log: - self.__Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") + self._Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") return -1, None def register_command(self): - m = self.__Irc.Loader.Definition.MIrcdCommand + m = self._Irc.Loader.Definition.MIrcdCommand self.Handler.register(m('PING', self.on_server_ping)) self.Handler.register(m('NICK', self.on_nick)) self.Handler.register(m('SASL', self.on_sasl)) @@ -84,29 +66,29 @@ class Inspircd(IProtocol): print_log (bool): if True print the log. """ try: - with self.__Base.lock: - self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[0])) + with self._Base.lock: + self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[0])) if print_log: - self.__Logs.debug(f'<< {message}') + self._Logs.debug(f'<< {message}') except UnicodeDecodeError as ude: - self.__Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') - self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace')) + self._Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') + self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) except UnicodeEncodeError as uee: - self.__Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') - self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace')) + self._Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') + self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) except AssertionError as ae: - self.__Logs.warning(f'Assertion Error {ae} - message: {message}') + self._Logs.warning(f'Assertion Error {ae} - message: {message}') except SSLEOFError as soe: - self.__Logs.error(f"SSLEOFError: {soe} - {message}") + self._Logs.error(f"SSLEOFError: {soe} - {message}") except SSLError as se: - self.__Logs.error(f"SSLError: {se} - {message}") + self._Logs.error(f"SSLError: {se} - {message}") except OSError as oe: - self.__Logs.error(f"OSError: {oe} - {message}") + self._Logs.error(f"OSError: {oe} - {message}") if oe.errno == 10053: sys.exit(oe.__str__()) except AttributeError as ae: - self.__Logs.critical(f"Attribute Error: {ae}") + self._Logs.critical(f"Attribute Error: {ae}") def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): """Sending PRIVMSG to a channel or to a nickname by batches @@ -118,12 +100,12 @@ class Inspircd(IProtocol): 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 not None else None + 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 not None else None if user_from is None: - self.__Logs.error(f"The sender nickname [{nick_from}] do not exist") + self._Logs.error(f"The sender nickname [{nick_from}] do not exist") return None if not channel is None: @@ -136,7 +118,7 @@ class Inspircd(IProtocol): batch = str(msg)[i:i+batch_size] self.send2socket(f":{nick_from} PRIVMSG {user_to.uid} :{batch}") except Exception as err: - self.__Logs.error(f"General Error: {err}") + self._Logs.error(f"General Error: {err}") def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: """Sending NOTICE by batches @@ -147,12 +129,12 @@ class Inspircd(IProtocol): 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) + 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.__Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist") + self._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): @@ -160,28 +142,28 @@ class Inspircd(IProtocol): self.send2socket(f":{user_from.uid} NOTICE {user_to.uid} :{batch}") except Exception as err: - self.__Logs.error(f"General Error: {err}") + self._Logs.error(f"General Error: {err}") def send_link(self): """Créer le link et envoyer les informations nécessaires pour la connexion au serveur. """ - service_id = self.__Config.SERVICE_ID - service_nickname = self.__Config.SERVICE_NICKNAME - service_username = self.__Config.SERVICE_USERNAME - service_realname = self.__Config.SERVICE_REALNAME - service_info = self.__Config.SERVICE_INFO - service_smodes = self.__Config.SERVICE_SMODES - service_hostname = self.__Config.SERVICE_HOST - service_name = self.__Config.SERVICE_NAME + service_id = self._Config.SERVICE_ID + service_nickname = self._Config.SERVICE_NICKNAME + service_username = self._Config.SERVICE_USERNAME + service_realname = self._Config.SERVICE_REALNAME + service_info = self._Config.SERVICE_INFO + service_smodes = self._Config.SERVICE_SMODES + service_hostname = self._Config.SERVICE_HOST + service_name = self._Config.SERVICE_NAME - server_password = self.__Config.SERVEUR_PASSWORD - server_link = self.__Config.SERVEUR_LINK - server_id = self.__Config.SERVEUR_ID - server_hostname = self.__Settings.MAIN_SERVER_HOSTNAME = self.__Config.SERVEUR_HOSTNAME + server_password = self._Config.SERVEUR_PASSWORD + server_link = self._Config.SERVEUR_LINK + server_id = self._Config.SERVEUR_ID + server_hostname = self._Settings.MAIN_SERVER_HOSTNAME = self._Config.SERVEUR_HOSTNAME - version = self.__Config.CURRENT_VERSION - unixtime = self.__Utils.get_unixtime() + version = self._Config.CURRENT_VERSION + unixtime = self._Utils.get_unixtime() self.send2socket(f"CAPAB START {self.protocol_version}") self.send2socket(f"CAPAB MODULES :services") @@ -197,18 +179,18 @@ class Inspircd(IProtocol): self.send2socket(f":{server_id} ENDBURST") # self.send_sjoin(chan) - self.__Logs.debug(f'>> {__name__} Link information sent to the server') + self._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}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None def send_set_nick(self, newnickname: str) -> None: - self.send2socket(f":{self.__Config.SERVICE_NICKNAME} NICK {newnickname}") + self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") return None def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: @@ -220,21 +202,21 @@ class Inspircd(IProtocol): channel_name (Optional[str]): The channel name params (Optional[str]): Params to pass to the mode """ - service_id = self.__Config.SERVICE_ID + service_id = self._Config.SERVICE_ID params = '' if params is None else params if modes[0] not in ['+', '-']: - self.__Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") + self._Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") return None if nickname and channel_name: # :98KAAAAAB MODE #services +o defenderdev - if not self.__Irc.Channel.is_valid_channel(channel_name): - self.__Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._Irc.Channel.is_valid_channel(channel_name): + self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None - if not all(mode in self.__Settings.PROTOCTL_PREFIX_MODES_SIGNES for mode in list(modes.replace('+','').replace('-',''))): - self.__Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') + if not all(mode in self._Settings.PROTOCTL_PREFIX_MODES_SIGNES for mode in list(modes.replace('+','').replace('-',''))): + self._Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') return None self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") @@ -242,8 +224,8 @@ class Inspircd(IProtocol): if nickname and channel_name is None: # :98KAAAAAB MODE nickname +o - if not all(mode in self.__Settings.PROTOCTL_USER_MODES for mode in list(modes.replace('+','').replace('-',''))): - self.__Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') + if not all(mode in self._Settings.PROTOCTL_USER_MODES for mode in list(modes.replace('+','').replace('-',''))): + self._Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') return None self.send2socket(f":{service_id} MODE {nickname} {modes}") @@ -251,12 +233,12 @@ class Inspircd(IProtocol): if nickname is None and channel_name: # :98KAAAAAB MODE #channel +o - if not all(mode in self.__Settings.PROTOCTL_CHANNEL_MODES for mode in list(modes.replace('+','').replace('-',''))): - self.__Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') + if not all(mode in self._Settings.PROTOCTL_CHANNEL_MODES for mode in list(modes.replace('+','').replace('-',''))): + self._Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') return None - if not self.__Irc.Channel.is_valid_channel(channel_name): - self.__Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._Irc.Channel.is_valid_channel(channel_name): + self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") @@ -274,14 +256,14 @@ class Inspircd(IProtocol): def send_ungline(self, nickname:str, hostname: str) -> None: - self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") return None def send_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}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None @@ -291,20 +273,20 @@ class Inspircd(IProtocol): Args: channel (str): The channel name. """ - server_id = self.__Config.SERVEUR_ID - service_nickname = self.__Config.SERVICE_NICKNAME - service_modes = self.__Config.SERVICE_UMODES - service_id = self.__Config.SERVICE_ID + server_id = self._Config.SERVEUR_ID + service_nickname = self._Config.SERVICE_NICKNAME + service_modes = self._Config.SERVICE_UMODES + service_id = self._Config.SERVICE_ID - if not self.__Irc.Channel.is_valid_channel(channel): - self.__Logs.error(f"The channel [{channel}] is not valid") + if not self._Irc.Channel.is_valid_channel(channel): + self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{server_id} FJOIN {channel} {self.__Utils.get_unixtime()} :o, {service_id}") + self.send2socket(f":{server_id} FJOIN {channel} {self._Utils.get_unixtime()} :o, {service_id}") self.send_set_mode(service_modes, nickname=service_nickname, channel_name=channel) # Add defender to the channel uids list - self.__Irc.Channel.insert(self.__Irc.Loader.Definition.MChannel(name=channel, uids=[service_id])) + self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[service_id])) return None def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: @@ -315,18 +297,18 @@ class Inspircd(IProtocol): reason (str): The reason for the quit print_log (bool): If True then print logs """ - user_obj = self.__Irc.User.get_user(uidornickname=uid) - reputation_obj = self.__Irc.Reputation.get_reputation(uidornickname=uid) + user_obj = self._Irc.User.get_user(uidornickname=uid) + reputation_obj = self._Irc.Reputation.get_reputation(uidornickname=uid) if not user_obj is None: self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) - self.__Irc.User.delete(user_obj.uid) + self._Irc.User.delete(user_obj.uid) if not reputation_obj is None: - self.__Irc.Reputation.delete(reputation_obj.uid) + self._Irc.Reputation.delete(reputation_obj.uid) - if not self.__Irc.Channel.delete_user_from_all_channel(uid): - self.__Logs.error(f"The UID [{uid}] has not been deleted from all channels") + if not self._Irc.Channel.delete_user_from_all_channel(uid): + self._Logs.error(f"The UID [{uid}] has not been deleted from all channels") return None @@ -345,20 +327,20 @@ class Inspircd(IProtocol): print_log (bool, optional): print logs if true. Defaults to True. """ # {self.Config.SERVEUR_ID} UID - # {clone.nickname} 1 {self.__Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} + # {clone.nickname} 1 {self._Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} try: - unixtime = self.__Utils.get_unixtime() - # encoded_ip = self.__Base.encode_ip(remote_ip) + unixtime = self._Utils.get_unixtime() + # encoded_ip = self._Base.encode_ip(remote_ip) new_umodes = [] for mode in list(umodes.replace('+', '').replace('-', '')): - if mode in self.__Settings.PROTOCTL_USER_MODES: + if mode in self._Settings.PROTOCTL_USER_MODES: new_umodes.append(mode) final_umodes = '+' + ''.join(new_umodes) # Create the user - self.__Irc.User.insert( - self.__Irc.Loader.Definition.MUser( + self._Irc.User.insert( + self._Irc.Loader.Definition.MUser( uid=uid, nickname=nickname, username=username, realname=realname,hostname=hostname, umodes=final_umodes, vhost=vhost, remote_ip=remote_ip @@ -368,13 +350,13 @@ class Inspircd(IProtocol): # [:] UID []+ : # :98K UID 98KAAAAAB 1756932359 defenderdev defenderdev.deb.biz.st defenderdev.deb.biz.st Dev-PyDefender 127.0.0.1 1756932359 + :Dev Python Security # [':97K', 'UID', '97KAAAAAA', '1756926679', 'adator', '172.18.128.1', 'attila.example.org', '...', '...', '172.18.128.1', '1756926678', '+o', ':...'] - uid_msg = f":{self.__Config.SERVEUR_ID} UID {uid} {unixtime} {nickname} {hostname} {vhost} {username} {username} {remote_ip} {unixtime} {final_umodes} :{realname}" + uid_msg = f":{self._Config.SERVEUR_ID} UID {uid} {unixtime} {nickname} {hostname} {vhost} {username} {username} {remote_ip} {unixtime} {final_umodes} :{realname}" self.send2socket(uid_msg, print_log=print_log) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: """Joining a channel @@ -386,20 +368,20 @@ class Inspircd(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - user_obj = self.__Irc.User.get_user(uidornickname) + user_obj = self._Irc.User.get_user(uidornickname) password_channel = password if not password is None else '' if user_obj is None: return None - if not self.__Irc.Channel.is_valid_channel(channel): - self.__Logs.error(f"The channel [{channel}] is not valid") + if not self._Irc.Channel.is_valid_channel(channel): + self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{user_obj.uid} FJOIN {channel} {self.__Utils.get_unixtime()} :,{user_obj.uid} {password_channel}", print_log=print_log) + self.send2socket(f":{user_obj.uid} FJOIN {channel} {self._Utils.get_unixtime()} :,{user_obj.uid} {password_channel}", print_log=print_log) # Add defender to the channel uids list - self.__Irc.Channel.insert(self.__Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) + self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) return None def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None: @@ -411,31 +393,31 @@ class Inspircd(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - user_obj = self.__Irc.User.get_user(uidornickname) + user_obj = self._Irc.User.get_user(uidornickname) if user_obj is None: - self.__Logs.error(f"The user [{uidornickname}] is not valid") + self._Logs.error(f"The user [{uidornickname}] is not valid") return None - if not self.__Irc.Channel.is_valid_channel(channel): - self.__Logs.error(f"The channel [{channel}] is not valid") + if not self._Irc.Channel.is_valid_channel(channel): + self._Logs.error(f"The channel [{channel}] is not valid") return None self.send2socket(f":{user_obj.uid} PART {channel}", print_log=print_log) # Add defender to the channel uids list - self.__Irc.Channel.delete_user_from_channel(channel, user_obj.uid) + self._Irc.Channel.delete_user_from_channel(channel, user_obj.uid) return None def send_unkline(self, nickname:str, hostname: str) -> None: - self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}") + self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") return None def send_raw(self, raw_command: str) -> None: - self.send2socket(f":{self.__Config.SERVEUR_ID} {raw_command}") + self.send2socket(f":{self._Config.SERVEUR_ID} {raw_command}") return None # ------------------------------------------------------------------------ @@ -451,23 +433,23 @@ class Inspircd(IProtocol): try: # [':adator_', 'UMODE2', '-iwx'] - user_obj = self.__Irc.User.get_user(str(server_msg[0]).lstrip(':')) + user_obj = self._Irc.User.get_user(str(server_msg[0]).lstrip(':')) user_mode = server_msg[2] if user_obj is None: # If user is not created return None # TODO : User object should be able to update user modes - if self.__Irc.User.update_mode(user_obj.uid, user_mode): + if self._Irc.User.update_mode(user_obj.uid, user_mode): return None - # self.__Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") + # self._Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server @@ -479,16 +461,16 @@ class Inspircd(IProtocol): uid_who_quit = str(server_msg[0]).lstrip(':') - self.__Irc.Channel.delete_user_from_all_channel(uid_who_quit) - self.__Irc.User.delete(uid_who_quit) - self.__Irc.Reputation.delete(uid_who_quit) + self._Irc.Channel.delete_user_from_all_channel(uid_who_quit) + self._Irc.User.delete(uid_who_quit) + self._Irc.Reputation.delete(uid_who_quit) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server @@ -500,15 +482,15 @@ class Inspircd(IProtocol): server_hostname = server_msg[2] uid_to_delete = None - for s_user in self.__Irc.User.UID_DB: + for s_user in self._Irc.User.UID_DB: if s_user.hostname == server_hostname and 'S' in s_user.umodes: uid_to_delete = s_user.uid if uid_to_delete is None: return None - self.__Irc.User.delete(uid_to_delete) - self.__Irc.Channel.delete_user_from_all_channel(uid_to_delete) + self._Irc.User.delete(uid_to_delete) + self._Irc.Channel.delete_user_from_all_channel(uid_to_delete) return None @@ -541,9 +523,9 @@ class Inspircd(IProtocol): channel_modes.append(cmode) - self.__Settings.PROTOCTL_PREFIX_SIGNES_MODES = sign_mode - self.__Settings.PROTOCTL_PREFIX_MODES_SIGNES = mode_sign - self.__Settings.PROTOCTL_CHANNEL_MODES = list(set(channel_modes)) + self._Settings.PROTOCTL_PREFIX_SIGNES_MODES = sign_mode + self._Settings.PROTOCTL_PREFIX_MODES_SIGNES = mode_sign + self._Settings.PROTOCTL_CHANNEL_MODES = list(set(channel_modes)) # ['CAPAB', 'USERMODES', ':param-set:snomask=s', 'simple:bot=B', 'simple:invisible=i', 'simple:oper=o', 'simple:servprotect=k', # 'simple:sslqueries=z', 'simple:u_registered=r', 'simple:wallops=w'] @@ -555,7 +537,7 @@ class Inspircd(IProtocol): umode = prefix.split('=')[1] if len(prefix.split('=')) > 1 else None user_modes.append(umode) - self.__Settings.PROTOCTL_USER_MODES = list(set(user_modes)) + self._Settings.PROTOCTL_USER_MODES = list(set(user_modes)) return None @@ -576,16 +558,16 @@ class Inspircd(IProtocol): uid = str(scopy[0]).replace(':','') newnickname = scopy[2] - self.__Irc.User.update_nickname(uid, newnickname) - self.__Irc.Client.update_nickname(uid, newnickname) - self.__Irc.Admin.update_nickname(uid, newnickname) + self._Irc.User.update_nickname(uid, newnickname) + self._Irc.Client.update_nickname(uid, newnickname) + self._Irc.Admin.update_nickname(uid, newnickname) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server @@ -607,8 +589,8 @@ class Inspircd(IProtocol): list_users = list(set(list_users)) if list_users: - self.__Irc.Channel.insert( - self.__Irc.Loader.Definition.MChannel( + self._Irc.Channel.insert( + self._Irc.Loader.Definition.MChannel( name=channel, uids=list_users ) @@ -616,9 +598,9 @@ class Inspircd(IProtocol): return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_endburst(self, server_msg: list[str]) -> None: """Handle EOS coming from a server @@ -630,69 +612,69 @@ class Inspircd(IProtocol): # [':97K', 'ENDBURST'] scopy = server_msg.copy() hsid = str(scopy[0]).replace(':','') - 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): + 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: version = f'{current_version}' print(f"################### DEFENDER ###################") print(f"# SERVICE CONNECTE ") - 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.__Config.SSL_VERSION} ") - print(f"# NICKNAME : {self.__Config.SERVICE_NICKNAME} ") - print(f"# CHANNEL : {self.__Config.SERVICE_CHANLOG} ") + 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._Config.SSL_VERSION} ") + print(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") + print(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") print(f"# VERSION : {version} ") print(f"################################################") - self.__Logs.info(f"################### DEFENDER ###################") - self.__Logs.info(f"# SERVICE CONNECTE ") - self.__Logs.info(f"# SERVEUR : {self.__Config.SERVEUR_IP} ") - self.__Logs.info(f"# PORT : {self.__Config.SERVEUR_PORT} ") - self.__Logs.info(f"# SSL : {self.__Config.SERVEUR_SSL} ") - self.__Logs.info(f"# SSL VER : {self.__Config.SSL_VERSION} ") - self.__Logs.info(f"# NICKNAME : {self.__Config.SERVICE_NICKNAME} ") - self.__Logs.info(f"# CHANNEL : {self.__Config.SERVICE_CHANLOG} ") - self.__Logs.info(f"# VERSION : {version} ") - self.__Logs.info(f"################################################") + self._Logs.info(f"################### DEFENDER ###################") + self._Logs.info(f"# SERVICE CONNECTE ") + self._Logs.info(f"# SERVEUR : {self._Config.SERVEUR_IP} ") + self._Logs.info(f"# PORT : {self._Config.SERVEUR_PORT} ") + self._Logs.info(f"# SSL : {self._Config.SERVEUR_SSL} ") + self._Logs.info(f"# SSL VER : {self._Config.SSL_VERSION} ") + self._Logs.info(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") + self._Logs.info(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") + self._Logs.info(f"# VERSION : {version} ") + self._Logs.info(f"################################################") - self.send_sjoin(self.__Config.SERVICE_CHANLOG) + self.send_sjoin(self._Config.SERVICE_CHANLOG) - if self.__Base.check_for_new_version(False): + if self._Base.check_for_new_version(False): self.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + nick_from=self._Config.SERVICE_NICKNAME, msg=f" New Version available {version}", - channel=self.__Config.SERVICE_CHANLOG + channel=self._Config.SERVICE_CHANLOG ) # Initialisation terminé aprés le premier PING self.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, - msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self.__Config.COLORS.green, self.__Config.COLORS.nogc, self.__Config.SERVICE_NICKNAME), - channel=self.__Config.SERVICE_CHANLOG + nick_from=self._Config.SERVICE_NICKNAME, + msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._Config.COLORS.green, self._Config.COLORS.nogc, self._Config.SERVICE_NICKNAME), + channel=self._Config.SERVICE_CHANLOG ) - self.__Config.DEFENDER_INIT = 0 + self._Config.DEFENDER_INIT = 0 # Send EOF to other modules - for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(scopy) # Join saved channels & load existing modules - self.__Irc.join_saved_channels() - self.__Irc.ModuleUtils.db_load_all_existing_modules(self.__Irc) + self._Irc.join_saved_channels() + self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Key Error: {ie}") + self._Logs.error(f"{__name__} - Key Error: {ie}") except KeyError as ke: - self.__Logs.error(f"{__name__} - Key Error: {ke}") + self._Logs.error(f"{__name__} - Key Error: {ke}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server @@ -706,14 +688,14 @@ class Inspircd(IProtocol): uid = str(server_msg[0]).lstrip(':') channel = str(server_msg[2]).lower() # reason = str(' '.join(server_msg[3:])) - self.__Irc.Channel.delete_user_from_channel(channel, uid) + self._Irc.Channel.delete_user_from_channel(channel, uid) return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server @@ -723,9 +705,9 @@ class Inspircd(IProtocol): server_msg (list[str]): Original server message """ try: - red = self.__Config.COLORS.red - green = self.__Config.COLORS.green - nogc = self.__Config.COLORS.nogc + red = self._Config.COLORS.red + green = self._Config.COLORS.green + nogc = self._Config.COLORS.nogc is_webirc = True if 'webirc' in server_msg[0] else False is_websocket = True if 'websocket' in server_msg[0] else False @@ -737,7 +719,7 @@ class Inspircd(IProtocol): vhost = str(server_msg[6]) if not 'S' in umodes: - # remote_ip = self.__Base.decode_ip(str(serverMsg[9])) + # remote_ip = self._Base.decode_ip(str(serverMsg[9])) remote_ip = str(server_msg[9]) else: remote_ip = '127.0.0.1' @@ -756,8 +738,8 @@ class Inspircd(IProtocol): score_connexion = 0 - self.__Irc.User.insert( - self.__Irc.Loader.Definition.MUser( + self._Irc.User.insert( + self._Irc.Loader.Definition.MUser( uid=uid, nickname=nickname, username=username, @@ -774,18 +756,18 @@ class Inspircd(IProtocol): ) ) - for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(server_msg) # SASL authentication - dnickname = self.__Config.SERVICE_NICKNAME - dchanlog = self.__Config.SERVICE_CHANLOG + dnickname = self._Config.SERVICE_NICKNAME + dchanlog = self._Config.SERVICE_CHANLOG # uid = serverMsg[8] # nickname = serverMsg[3] - sasl_obj = self.__Irc.Sasl.get_sasl_obj(uid) + sasl_obj = self._Irc.Sasl.get_sasl_obj(uid) if sasl_obj: if sasl_obj.auth_success: - self.__Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) + self._Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, sasl_obj.username, dnickname), channel=dchanlog) @@ -797,14 +779,14 @@ class Inspircd(IProtocol): self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) # Delete sasl object! - self.__Irc.Sasl.delete_sasl_client(uid) + self._Irc.Sasl.delete_sasl_client(uid) return None return None except IndexError as ie: - self.__Logs.error(f"{__name__} - Index Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}", exc_info=True) + self._Logs.error(f"{__name__} - General Error: {err}", exc_info=True) def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server @@ -820,32 +802,32 @@ class Inspircd(IProtocol): cmd.pop(0) get_uid_or_nickname = str(cmd[0].replace(':','')) - user_trigger = self.__Irc.User.get_nickname(get_uid_or_nickname) - # dnickname = self.__Config.SERVICE_NICKNAME - pattern = fr'(:\{self.__Config.SERVICE_PREFIX})(.*)$' + user_trigger = self._Irc.User.get_nickname(get_uid_or_nickname) + # dnickname = self._Config.SERVICE_NICKNAME + pattern = fr'(:\{self._Config.SERVICE_PREFIX})(.*)$' hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . if hcmds: # Commande qui commencent par le point liste_des_commandes = list(hcmds.groups()) convert_to_string = ' '.join(liste_des_commandes) arg = convert_to_string.split() - arg.remove(f":{self.__Config.SERVICE_PREFIX}") - if not self.__Irc.Commands.is_command_exist(arg[0]): - self.__Logs.debug(f"This command {arg[0]} is not available") + arg.remove(f":{self._Config.SERVICE_PREFIX}") + if not self._Irc.Commands.is_command_exist(arg[0]): + self._Logs.debug(f"This command {arg[0]} is not available") self.send_notice( - nick_from=self.__Config.SERVICE_NICKNAME, + 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" + 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) + self._Base.log_cmd(user_trigger, cmd_to_send) - fromchannel = str(cmd[2]).lower() if self.__Irc.Channel.is_valid_channel(cmd[2]) else None - self.__Irc.hcmds(user_trigger, fromchannel, arg, cmd) + fromchannel = str(cmd[2]).lower() if self._Irc.Channel.is_valid_channel(cmd[2]) else None + self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) - if cmd[2] == self.__Config.SERVICE_ID: + if cmd[2] == self._Config.SERVICE_ID: pattern = fr'^:.*?:(.*)$' hcmds = search(pattern, ' '.join(cmd)) @@ -869,30 +851,30 @@ class Inspircd(IProtocol): self.on_ping(srv_msg) return None - if not self.__Irc.Commands.is_command_exist(arg[0]): - self.__Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + if not self._Irc.Commands.is_command_exist(arg[0]): + self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") return None - # if not arg[0].lower() in self.__Irc.module_commands_list: - # self.__Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + # if not arg[0].lower() in self._Irc.module_commands_list: + # self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") # return False cmd_to_send = convert_to_string.replace(':','') - self.__Base.log_cmd(user_trigger, cmd_to_send) + self._Base.log_cmd(user_trigger, cmd_to_send) fromchannel = None if len(arg) >= 2: - fromchannel = str(arg[1]).lower() if self.__Irc.Channel.is_valid_channel(arg[1]) else None + fromchannel = str(arg[1]).lower() if self._Irc.Channel.is_valid_channel(arg[1]) else None - self.__Irc.hcmds(user_trigger, fromchannel, arg, cmd) + self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) return None except KeyError as ke: - self.__Logs.error(f"Key Error: {ke}") + self._Logs.error(f"Key Error: {ke}") except AttributeError as ae: - self.__Logs.error(f"Attribute Error: {ae}") + self._Logs.error(f"Attribute Error: {ae}") except Exception as err: - self.__Logs.error(f"General Error: {err}", exc_info=True) + self._Logs.error(f"General Error: {err}", exc_info=True) def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server @@ -906,11 +888,11 @@ class Inspircd(IProtocol): # -> :808 PONG 3IN hsid = str(server_msg[0]).replace(':','') - self.send2socket(f":{self.__Config.SERVEUR_ID} PONG {hsid}", print_log=False) + self.send2socket(f":{self._Config.SERVEUR_ID} PONG {hsid}", print_log=False) return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_server(self, server_msg: list[str]) -> None: """_summary_ @@ -922,14 +904,14 @@ class Inspircd(IProtocol): """ try: param = str(server_msg[2]) - self.__Config.HSID = self.__Settings.MAIN_SERVER_ID = str(server_msg[0]).replace(':', '') + self._Config.HSID = self._Settings.MAIN_SERVER_ID = str(server_msg[0]).replace(':', '') if param == 'rawversion': - self.__Logs.debug(f">> Server Version: {server_msg[3].replace(':', '')}") + self._Logs.debug(f">> Server Version: {server_msg[3].replace(':', '')}") elif param == 'rawbranch': - self.__Logs.debug(f">> Branch Version: {server_msg[3].replace(':', '')}") + self._Logs.debug(f">> Branch Version: {server_msg[3].replace(':', '')}") except Exception as err: - self.__Logs.error(f'General Error: {err}') + self._Logs.error(f'General Error: {err}') def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server @@ -941,19 +923,19 @@ class Inspircd(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(server_msg[1])) - dnickname = self.__Config.SERVICE_NICKNAME + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(server_msg[1])) + dnickname = self._Config.SERVICE_NICKNAME arg = server_msg[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') + 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.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor @@ -965,10 +947,10 @@ class Inspircd(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(server_msg[1])) - dnickname = self.__Config.SERVICE_NICKNAME + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(server_msg[1])) + dnickname = self._Config.SERVICE_NICKNAME arg = server_msg[4].replace(':', '') - current_datetime = self.__Utils.get_sdatetime() + current_datetime = self._Utils.get_sdatetime() if nickname is None: return None @@ -978,7 +960,7 @@ class Inspircd(IProtocol): return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor @@ -990,8 +972,8 @@ class Inspircd(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(server_msg[1])) - dnickname = self.__Config.SERVICE_NICKNAME + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(server_msg[1])) + dnickname = self._Config.SERVICE_NICKNAME arg = server_msg[4].replace(':', '') if nickname is None: @@ -999,10 +981,10 @@ class Inspircd(IProtocol): if arg == '\x01PING': recieved_unixtime = int(server_msg[5].replace('\x01','')) - current_unixtime = self.__Utils.get_unixtime() + current_unixtime = self._Utils.get_unixtime() ping_response = current_unixtime - recieved_unixtime - # self.__Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') + # self._Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') self.send_notice( nick_from=dnickname, nick_to=nickname, @@ -1011,7 +993,7 @@ class Inspircd(IProtocol): return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server @@ -1021,22 +1003,22 @@ class Inspircd(IProtocol): """ try: # ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender'] - user_obj = self.__Irc.User.get_user(self.__Utils.clean_uid(server_msg[1])) + user_obj = self._Irc.User.get_user(self._Utils.clean_uid(server_msg[1])) if user_obj is None: return None - response_351 = f"{self.__Config.SERVICE_NAME.capitalize()}-{self.__Config.CURRENT_VERSION} {self.__Config.SERVICE_HOST} {self.name}" - self.send2socket(f':{self.__Config.SERVICE_HOST} 351 {user_obj.nickname} {response_351}') + response_351 = f"{self._Config.SERVICE_NAME.capitalize()}-{self._Config.CURRENT_VERSION} {self._Config.SERVICE_HOST} {self.name}" + self.send2socket(f':{self._Config.SERVICE_HOST} 351 {user_obj.nickname} {response_351}') - modules = self.__Irc.ModuleUtils.get_all_available_modules() + modules = self._Irc.ModuleUtils.get_all_available_modules() response_005 = ' | '.join(modules) - self.send2socket(f':{self.__Config.SERVICE_HOST} 005 {user_obj.nickname} {response_005} are supported by this server') + self.send2socket(f':{self._Config.SERVICE_HOST} 005 {user_obj.nickname} {response_005} are supported by this server') return None except Exception as err: - self.__Logs.error(f"{__name__} - General Error: {err}") + self._Logs.error(f"{__name__} - General Error: {err}") def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server @@ -1053,9 +1035,9 @@ class Inspircd(IProtocol): # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey'] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey=='] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A'] - psasl = self.__Irc.Sasl + psasl = self._Irc.Sasl sasl_enabled = True # Should be False - for smod in self.__Settings.SMOD_MODULES: + for smod in self._Settings.SMOD_MODULES: if smod.name == 'sasl': sasl_enabled = True break @@ -1067,7 +1049,7 @@ class Inspircd(IProtocol): client_uid = scopy[4] if len(scopy) >= 6 else None # sasl_obj = None sasl_message_type = scopy[6] if len(scopy) >= 6 else None - psasl.insert_sasl_client(self.__Irc.Loader.Definition.MSasl(client_uid=client_uid)) + psasl.insert_sasl_client(self._Irc.Loader.Definition.MSasl(client_uid=client_uid)) sasl_obj = psasl.get_sasl_obj(client_uid) if sasl_obj is None: @@ -1085,13 +1067,13 @@ class Inspircd(IProtocol): sasl_obj.mechanisme = str(scopy[7]) if sasl_obj.mechanisme == "PLAIN": - self.send2socket(f":{self.__Config.SERVEUR_ID} SASL {self.__Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") + self.send2socket(f":{self._Config.SERVEUR_ID} SASL {self._Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") elif sasl_obj.mechanisme == "EXTERNAL": if str(scopy[7]) == "+": return None sasl_obj.fingerprint = str(scopy[8]) - self.send2socket(f":{self.__Config.SERVEUR_ID} SASL {self.__Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") + self.send2socket(f":{self._Config.SERVEUR_ID} SASL {self._Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") self.on_sasl_authentication_process(sasl_obj) return sasl_obj @@ -1114,23 +1096,23 @@ class Inspircd(IProtocol): return sasl_obj except Exception as err: - self.__Logs.error(f'General Error: {err}', exc_info=True) + self._Logs.error(f'General Error: {err}', exc_info=True) def on_sasl_authentication_process(self, sasl_model: 'MSasl'): s = sasl_model - server_id = self.__Config.SERVEUR_ID - main_server_hostname = self.__Settings.MAIN_SERVER_HOSTNAME - db_admin_table = self.__Config.TABLE_ADMIN + server_id = self._Config.SERVEUR_ID + main_server_hostname = self._Settings.MAIN_SERVER_HOSTNAME + db_admin_table = self._Config.TABLE_ADMIN if sasl_model: def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: if fingerprint: mes_donnees = {'fingerprint': fingerprint} query = f"SELECT user, level, language FROM {db_admin_table} WHERE fingerprint = :fingerprint" else: - mes_donnees = {'user': username, 'password': self.__Utils.hash_password(password)} + mes_donnees = {'user': username, 'password': self._Utils.hash_password(password)} query = f"SELECT user, level, language FROM {db_admin_table} WHERE user = :user AND password = :password" - result = self.__Base.db_execute_query(query, mes_donnees) + result = self._Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if user_from_db: return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]} @@ -1167,7 +1149,7 @@ class Inspircd(IProtocol): self.send2socket(f":{server_id} SASL {s.username} :SASL authentication failed") def on_error(self, server_msg: list[str]) -> None: - self.__Logs.debug(f"{server_msg}") + self._Logs.debug(f"{server_msg}") def on_metedata(self, server_msg: list[str]) -> None: """_summary_ @@ -1178,25 +1160,28 @@ class Inspircd(IProtocol): # [':97K', 'METADATA', '97KAAAAAA', 'ssl_cert', ':vTrSe', 'fingerprint90753683519522875', # '/C=FR/OU=Testing/O=Test', 'Sasl/CN=localhost', '/C=FR/OU=Testing/O=Test', 'Sasl/CN=localhost'] scopy = server_msg.copy() - dnickname = self.__Config.SERVICE_NICKNAME - dchanlog = self.__Config.SERVICE_CHANLOG - green = self.__Config.COLORS.green - nogc = self.__Config.COLORS.nogc + dnickname = self._Config.SERVICE_NICKNAME + dchanlog = self._Config.SERVICE_CHANLOG + green = self._Config.COLORS.green + nogc = self._Config.COLORS.nogc if 'ssl_cert' in scopy: fingerprint = scopy[5] uid = scopy[2] - user_obj = self.__Irc.User.get_user(uid) + user_obj = self._Irc.User.get_user(uid) if user_obj: user_obj.fingerprint = fingerprint - if self.__Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): - admin = self.__Irc.Admin.get_admin(uid) + if self._Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): + admin = self._Irc.Admin.get_admin(uid) account = admin.account if admin else '' self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTO AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, user_obj.nickname, account, dnickname), channel=dchanlog) self.send_notice(nick_from=dnickname, nick_to=user_obj.nickname, msg=tr("Successfuly connected to %s", dnickname)) + def on_kick(self, server_msg: list[str]) -> None: + ... + # ------------------------------------------------------------------------ # COMMON IRC PARSER # ------------------------------------------------------------------------ @@ -1289,8 +1274,8 @@ class Inspircd(IProtocol): response = { "uid_sender": scopy[0].replace(':', ''), - "uid_reciever": self.__Irc.User.get_uid(scopy[2]), - "channel": scopy[2] if self.__Irc.Channel.is_valid_channel(scopy[2]) else None, + "uid_reciever": self._Irc.User.get_uid(scopy[2]), + "channel": scopy[2] if self._Irc.Channel.is_valid_channel(scopy[2]) else None, "message": " ".join(scopy[3:]) } return response From 9f2da13f8836cb6f4fe13ab621521efe0a02c415 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:15:43 +0100 Subject: [PATCH 12/56] Unload the module when the protocol is not unreal6 --- mods/jsonrpc/mod_jsonrpc.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mods/jsonrpc/mod_jsonrpc.py b/mods/jsonrpc/mod_jsonrpc.py index b0fc88b..9960e5b 100644 --- a/mods/jsonrpc/mod_jsonrpc.py +++ b/mods/jsonrpc/mod_jsonrpc.py @@ -60,6 +60,10 @@ class Jsonrpc(IModule): self.ModConfig = self.ModConfModel(jsonrpc=0) + if self.Config.SERVEUR_PROTOCOL != 'unreal6': + self.Loader.ModuleUtils.unload_one_module(self.Irc, self.module_name, False) + return None + # Is RPC Active? self.is_streaming = False @@ -108,6 +112,11 @@ class Jsonrpc(IModule): self.Logs.error(f"JSONRPC ERROR: {err.__str__()}") def unload(self) -> None: + + if self.Config.SERVEUR_PROTOCOL != 'unreal6': + self.Loader.ModuleUtils.unload_one_module(self.Irc, self.module_name, False) + return None + if self.is_streaming: self.Protocol.send_priv_msg( nick_from=self.Config.SERVICE_NICKNAME, From 645041885934de1c1ad33d3439ca88b81019c7f4 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:16:04 +0100 Subject: [PATCH 13/56] Update docstring --- core/module.py | 1 + 1 file changed, 1 insertion(+) diff --git a/core/module.py b/core/module.py index 881810a..94f4c72 100644 --- a/core/module.py +++ b/core/module.py @@ -204,6 +204,7 @@ class Module: """Unload a module Args: + uplink (Irc): The Irc instance mod_name (str): Module name ex mod_defender Returns: From ff58cbb022fd0f4de02cdb5c8855a8be4afe2298 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:16:42 +0100 Subject: [PATCH 14/56] Adding serveur_protocol to the configuration exemple. --- config/exemple_configuration.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/exemple_configuration.yaml b/config/exemple_configuration.yaml index 0f40bfc..5a26500 100644 --- a/config/exemple_configuration.yaml +++ b/config/exemple_configuration.yaml @@ -6,6 +6,7 @@ configuration: SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD" SERVEUR_ID: "006" SERVEUR_SSL: true + SERVEUR_PROTOCOL: "unreal6" # unreal6 or inspircd SERVICE_NAME: "defender" SERVICE_NICKNAME: "PyDefender" @@ -39,8 +40,8 @@ configuration: API_TIMEOUT: 2 - PORTS_TO_SCAN: [3028 8080 1080 1085 4145 9050] - WHITELISTED_IP: ["127.0.0.1"] + PORTS_TO_SCAN: [3028, 8080, 1080, 1085, 4145, 9050] + WHITELISTED_IP: ["127.0.0.1", "192.168.1.1"] GLINE_DURATION: "30" DEBUG_LEVEL: 20 From 34b5b4204eabca1101eb08bbb5c4757db81ec762 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 20:58:56 +0100 Subject: [PATCH 15/56] Update parse_privmsg, now it returns sender, reciever, channel objects and the message --- core/classes/protocols/inspircd.py | 20 +++++++++++--------- core/classes/protocols/interface.py | 15 +++++---------- core/classes/protocols/unreal6.py | 23 +++++++++++++---------- mods/clone/utils.py | 8 +++----- mods/defender/utils.py | 9 +++------ 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index e628a14..09d4bf1 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -8,7 +8,7 @@ from core.classes.protocols.interface import IProtocol from core.utils import tr if TYPE_CHECKING: - from core.definition import MSasl, MClient + from core.definition import MSasl, MClient, MUser, MChannel class Inspircd(IProtocol): @@ -1257,7 +1257,7 @@ class Inspircd(IProtocol): } return response - def parse_privmsg(self, server_msg: list[str]) -> dict[str, str]: + def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] >>> [':97KAAAAAF', 'PRIVMSG', '98KAAAAAB', ':My','Message','...'] @@ -1272,13 +1272,15 @@ class Inspircd(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - response = { - "uid_sender": scopy[0].replace(':', ''), - "uid_reciever": self._Irc.User.get_uid(scopy[2]), - "channel": scopy[2] if self._Irc.Channel.is_valid_channel(scopy[2]) else None, - "message": " ".join(scopy[3:]) - } - return response + sender = self._User.get_user(self._Utils.clean_uid(scopy[0])) + reciever = self._User.get_user(self._Utils.clean_uid(scopy[2])) + channel = self._Channel.get_channel(scopy[2]) if self._Channel.is_valid_channel(scopy[2]) else None + + tmp_message = scopy[3:] + tmp_message = tmp_message[0].replace(':', '') + message = ' '.join(tmp_message) + + return sender, reciever, channel, message # ------------------------------------------------------------------------ diff --git a/core/classes/protocols/interface.py b/core/classes/protocols/interface.py index e5ab6b6..9de8f54 100644 --- a/core/classes/protocols/interface.py +++ b/core/classes/protocols/interface.py @@ -3,7 +3,7 @@ from typing import Optional, TYPE_CHECKING from core.classes.protocols.command_handler import CommandHandler if TYPE_CHECKING: - from core.definition import MClient, MSasl + from core.definition import MClient, MSasl, MUser, MChannel from core.irc import Irc class IProtocol(ABC): @@ -21,6 +21,8 @@ class IProtocol(ABC): self._Settings = uplink.Base.Settings self._Utils = uplink.Loader.Utils self._Logs = uplink.Loader.Logs + self._User = uplink.User + self._Channel = uplink.Channel self.Handler = CommandHandler(uplink.Loader) @@ -348,7 +350,7 @@ class IProtocol(ABC): """ @abstractmethod - def parse_privmsg(self, serverMsg: list[str]) -> dict[str, str]: + def parse_privmsg(self, serverMsg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] @@ -356,14 +358,7 @@ class IProtocol(ABC): serverMsg (list[str]): The server message to parse Returns: - dict[str, str]: The response as dictionary. - ```python - response = { - "uid": '97KAAAAAE', - "channel": '#welcome', - "message": 'This is my public message' - } - ``` + tuple[MUser(Sender), MUser(Reciever), MChannel, str]: Sender user model, reciever user model, Channel model, messgae. """ # ------------------------------------------------------------------------ diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index f68a817..3658188 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -8,7 +8,8 @@ from core.utils import tr if TYPE_CHECKING: from core.classes.sasl import Sasl - from core.definition import MClient, MSasl + from core.definition import MClient, MSasl, MUser, MChannel + from core.loader import Loader class Unrealircd6(IProtocol): @@ -701,7 +702,7 @@ class Unrealircd6(IProtocol): } return response - def parse_privmsg(self, serverMsg: list[str]) -> dict[str, str]: + def parse_privmsg(self, serverMsg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> ['@....', ':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] >>> [':97KAAAAAF', 'PRIVMSG', '98KAAAAAB', ':sasa'] @@ -710,19 +711,21 @@ class Unrealircd6(IProtocol): serverMsg (list[str]): The server message to parse Returns: - dict[str, str]: The response as dictionary. + tuple[MUser(Sender), MUser(Reciever), MChannel, str]: Sender user model, reciever user model, Channel model, messgae . """ scopy = serverMsg.copy() if scopy[0].startswith('@'): scopy.pop(0) - response = { - "uid_sender": scopy[0].replace(':', ''), - "uid_reciever": self._Irc.User.get_uid(scopy[2]), - "channel": scopy[2] if self._Irc.Channel.is_valid_channel(scopy[2]) else None, - "message": " ".join(scopy[3:]) - } - return response + sender = self._User.get_user(self._Utils.clean_uid(scopy[0])) + reciever = self._User.get_user(self._Utils.clean_uid(scopy[2])) + channel = self._Channel.get_channel(scopy[2]) if self._Channel.is_valid_channel(scopy[2]) else None + + tmp_message = scopy[3:] + tmp_message = tmp_message[0].replace(':', '') + message = ' '.join(tmp_message) + + return sender, reciever, channel, message ##################### # HANDLE EVENTS # diff --git a/mods/clone/utils.py b/mods/clone/utils.py index 495252e..b371ea1 100644 --- a/mods/clone/utils.py +++ b/mods/clone/utils.py @@ -176,15 +176,13 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None: - parser = uplink.Protocol.parse_privmsg(srvmsg) - uid_sender = uplink.Irc.Utils.clean_uid(parser.get('uid_sender', None)) - senderObj = uplink.User.get_user(uid_sender) + senderObj, recieverObj, channel, message = uplink.Protocol.parse_privmsg(srvmsg) if senderObj is not None: if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT: return - senderMsg = parser.get('message', None) - clone_obj = uplink.Clone.get_clone(parser.get('uid_reciever', None)) + senderMsg = message + clone_obj = recieverObj if clone_obj is None: return diff --git a/mods/defender/utils.py b/mods/defender/utils.py index 826e636..d9e9be4 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -62,13 +62,10 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]): # ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg'] - sender = srvmsg[1].replace(':','') - channel = srvmsg[3] - message = srvmsg[4:] - message[0] = message[0].replace(':', '') - if uplink.ModConfig.sentinel == 1 and srvmsg[3] != uplink.Config.SERVICE_CHANLOG: - uplink.Protocol.send_priv_msg(uplink.Config.SERVICE_NICKNAME, f"{sender} say on {channel}: {' '.join(message)}", uplink.Config.SERVICE_CHANLOG) + sender, reciever, channel, message = uplink.Protocol.parse_privmsg(srvmsg) + if uplink.ModConfig.sentinel == 1 and channel.name != uplink.Config.SERVICE_CHANLOG: + uplink.Protocol.send_priv_msg(uplink.Config.SERVICE_NICKNAME, f"{sender.nickname} say on {channel.name}: {' '.join(message)}", uplink.Config.SERVICE_CHANLOG) action_on_flood(uplink, srvmsg) return None From 5a1432c1e604e59d13a15f39c543de44e02a9d35 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 21:17:15 +0100 Subject: [PATCH 16/56] Update parse_uid, now it returns MUser object. --- core/classes/protocols/inspircd.py | 30 +++++------------------------ core/classes/protocols/interface.py | 4 ++-- core/classes/protocols/unreal6.py | 29 ++++++---------------------- mods/defender/utils.py | 6 ++---- 4 files changed, 15 insertions(+), 54 deletions(-) diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index 09d4bf1..d59055d 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -1186,35 +1186,15 @@ class Inspircd(IProtocol): # COMMON IRC PARSER # ------------------------------------------------------------------------ - def parse_uid(self, server_msg: list[str]) -> dict[str, str]: + def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. - + >>> [':97K', 'UID', '97KAAAAAC', '1762113659', 'adator_', '172.18.128.1', '172.18.128.1', '...', '...', '172.18.128.1', '1762113659', '+', ':...'] Args: server_msg (list[str]): _description_ """ - umodes = str(server_msg[11]) - remote_ip = server_msg[9] if 'S' not in umodes else '127.0.0.1' - - # Extract Geoip information - pattern = r'^.*geoip=cc=(\S{2}).*$' - geoip_match = match(pattern, server_msg[0]) - geoip = geoip_match.group(1) if geoip_match else None - - response = { - 'uid': str(server_msg[2]), - 'nickname': str(server_msg[4]), - 'username': str(server_msg[7]), - 'hostname': str(server_msg[5]), - 'umodes': umodes, - 'vhost': str(server_msg[6]), - 'ip': remote_ip, - 'realname': ' '.join(server_msg[12:]).lstrip(':'), - 'geoip': geoip, - 'reputation_score': 0, - 'iswebirc': True if 'webirc' in server_msg[0] else False, - 'iswebsocket': True if 'websocket' in server_msg[0] else False - } - return response + scopy = server_msg.copy() + uid = scopy[2] + return self._User.get_user(uid) def parse_quit(self, server_msg: list[str]) -> dict[str, str]: """Parse quit and return dictionary. diff --git a/core/classes/protocols/interface.py b/core/classes/protocols/interface.py index 9de8f54..9be3b84 100644 --- a/core/classes/protocols/interface.py +++ b/core/classes/protocols/interface.py @@ -316,14 +316,14 @@ class IProtocol(ABC): # ------------------------------------------------------------------------ @abstractmethod - def parse_uid(self, serverMsg: list[str]) -> dict[str, str]: + def parse_uid(self, serverMsg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. Args: serverMsg (list[str]): The UID IRCD message Returns: - dict[str, str]: The response as dictionary. + Optional[MUser]: The MUser object or None """ @abstractmethod diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 3658188..222a218 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -630,35 +630,18 @@ class Unrealircd6(IProtocol): # COMMON IRC PARSER # ------------------------------------------------------------------------ - def parse_uid(self, serverMsg: list[str]) -> dict[str, str]: + def parse_uid(self, serverMsg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. >>> ['@s2s-md/geoip=cc=GBtag...', ':001', 'UID', 'albatros', '0', '1721564597', 'albatros', 'hostname...', '001HB8G04', '0', '+iwxz', 'hostname-vhost', 'hostname-vhost', 'MyZBwg==', ':...'] Args: serverMsg (list[str]): The UID ircd response """ - umodes = str(serverMsg[10]) - remote_ip = self._Base.decode_ip(str(serverMsg[13])) if 'S' not in umodes else '127.0.0.1' + scopy = serverMsg.copy() + if '@' in scopy[0]: + scopy.pop(0) - # Extract Geoip information - pattern = r'^.*geoip=cc=(\S{2}).*$' - geoip_match = match(pattern, serverMsg[0]) - geoip = geoip_match.group(1) if geoip_match else None - - response = { - 'uid': str(serverMsg[8]), - 'nickname': str(serverMsg[3]), - 'username': str(serverMsg[6]), - 'hostname': str(serverMsg[7]), - 'umodes': umodes, - 'vhost': str(serverMsg[11]), - 'ip': remote_ip, - 'realname': ' '.join(serverMsg[12:]).lstrip(':'), - 'geoip': geoip, - 'reputation_score': 0, - 'iswebirc': True if 'webirc' in serverMsg[0] else False, - 'iswebsocket': True if 'websocket' in serverMsg[0] else False - } - return response + uid = scopy[7] + return self._User.get_user(uid) def parse_quit(self, serverMsg: list[str]) -> dict[str, str]: """Parse quit and return dictionary. diff --git a/mods/defender/utils.py b/mods/defender/utils.py index d9e9be4..03f481b 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -212,7 +212,7 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): uplink (Defender): The Defender instance srvmsg (list[str]): The Server MSG """ - parser_uid = uplink.Protocol.parse_uid(srvmsg) + _User = uplink.Protocol.parse_uid(srvmsg) gconfig = uplink.Config irc = uplink.Irc confmodel = uplink.ModConfig @@ -222,10 +222,8 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): return None # Get User information - _User = irc.User.get_user(parser_uid.get('uid', None)) - if _User is None: - irc.Logs.warning(f'This UID: [{parser_uid.get("uid", None)}] is not available please check why') + irc.Logs.warning(f'Error when parsing UID', exc_info=True) return # If user is not service or IrcOp then scan them From 79c1b94a92aab01a376fcca80dd09d2aa23cb73c Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 21:28:44 +0100 Subject: [PATCH 17/56] Update parse_quit, now it returns MUser object and the reason. --- core/classes/protocols/inspircd.py | 15 ++++++++------- core/classes/protocols/interface.py | 4 ++-- core/classes/protocols/unreal6.py | 20 +++++++++++--------- mods/defender/utils.py | 11 +++++++---- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index d59055d..1e6ae90 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -1196,25 +1196,26 @@ class Inspircd(IProtocol): uid = scopy[2] return self._User.get_user(uid) - def parse_quit(self, server_msg: list[str]) -> dict[str, str]: + def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] Args: server_msg (list[str]): The server message to parse Returns: - dict[str, str]: The dictionary. + tuple[MUser, str]: The User Who Quit Object and the reason. """ scopy = server_msg.copy() if scopy[0].startswith('@'): scopy.pop(0) + + user_obj = self._User.get_user(self._Utils.clean_uid(scopy[0])) + tmp_reason = scopy[3:] + tmp_reason[0] = tmp_reason[0].replace(':', '') + reason = ' '.join(tmp_reason) - response = { - "uid": scopy[0].replace(':', ''), - "reason": " ".join(scopy[3:]) - } - return response + return user_obj, reason def parse_nick(self, server_msg: list[str]) -> dict[str, str]: """Parse nick changes. diff --git a/core/classes/protocols/interface.py b/core/classes/protocols/interface.py index 9be3b84..d730097 100644 --- a/core/classes/protocols/interface.py +++ b/core/classes/protocols/interface.py @@ -327,14 +327,14 @@ class IProtocol(ABC): """ @abstractmethod - def parse_quit(self, serverMsg: list[str]) -> dict[str, str]: + def parse_quit(self, serverMsg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] Args: serverMsg (list[str]): The server message to parse Returns: - dict[str, str]: The response as dictionary. + tuple[MUser, str]: The User Who Quit Object and the reason. """ @abstractmethod diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 222a218..7970c80 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -1,4 +1,5 @@ from base64 import b64decode +from optparse import Option from re import match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional @@ -637,30 +638,31 @@ class Unrealircd6(IProtocol): serverMsg (list[str]): The UID ircd response """ scopy = serverMsg.copy() - if '@' in scopy[0]: + if scopy[0].startswith('@'): scopy.pop(0) uid = scopy[7] return self._User.get_user(uid) - def parse_quit(self, serverMsg: list[str]) -> dict[str, str]: + def parse_quit(self, serverMsg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> # ['@unrealtag...', ':001JKNY0N', 'QUIT', ':Quit:', '....'] Args: serverMsg (list[str]): The server message to parse Returns: - dict[str, str]: The dictionary. + tuple[MUser, str]: The User Who Quit Object and the reason. """ scopy = serverMsg.copy() if scopy[0].startswith('@'): scopy.pop(0) + + user_obj = self._User.get_user(self._Utils.clean_uid(scopy[0])) + tmp_reason = scopy[3:] + tmp_reason[0] = tmp_reason[0].replace(':', '') + reason = ' '.join(tmp_reason) - response = { - "uid": scopy[0].replace(':', ''), - "reason": " ".join(scopy[3:]) - } - return response + return user_obj, reason def parse_nick(self, serverMsg: list[str]) -> dict[str, str]: """Parse nick changes and return dictionary. @@ -705,7 +707,7 @@ class Unrealircd6(IProtocol): channel = self._Channel.get_channel(scopy[2]) if self._Channel.is_valid_channel(scopy[2]) else None tmp_message = scopy[3:] - tmp_message = tmp_message[0].replace(':', '') + tmp_message[0] = tmp_message[0].replace(':', '') message = ' '.join(tmp_message) return sender, reciever, channel, message diff --git a/mods/defender/utils.py b/mods/defender/utils.py index 03f481b..04d9d0a 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -184,14 +184,17 @@ def handle_on_quit(uplink: 'Defender', srvmsg: list[str]): srvmsg (list[str]): The Server MSG """ p = uplink.Protocol - parser = p.parse_quit(srvmsg) + userobj, reason = p.parse_quit(srvmsg) confmodel = uplink.ModConfig + + if userobj is None: + uplink.Logs.error("Error when parsing message QUIT", exc_info=True) + return None ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan) - final_UID = uplink.Loader.Utils.clean_uid(str(parser.get('uid', None))) jail_salon = uplink.Config.SALON_JAIL service_id = uplink.Config.SERVICE_ID - get_user_reputation = uplink.Reputation.get_reputation(final_UID) + get_user_reputation = uplink.Reputation.get_reputation(userobj.uid) if get_user_reputation is not None: final_nickname = get_user_reputation.nickname @@ -200,7 +203,7 @@ def handle_on_quit(uplink: 'Defender', srvmsg: list[str]): p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*") uplink.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}") - uplink.Reputation.delete(final_UID) + uplink.Reputation.delete(userobj.uid) uplink.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB") def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): From 0e6384c26cbe0024dae071d24ffdc6a4901f8df3 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 22:21:55 +0100 Subject: [PATCH 18/56] modify and move protocol interface to interfaces folder. refactoring all dependencies --- .../classes/{protocols/interface.py => interfaces/iprotocol.py} | 0 core/classes/protocols/factory.py | 2 +- core/classes/protocols/inspircd.py | 2 +- core/classes/protocols/unreal6.py | 2 +- core/irc.py | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename core/classes/{protocols/interface.py => interfaces/iprotocol.py} (100%) diff --git a/core/classes/protocols/interface.py b/core/classes/interfaces/iprotocol.py similarity index 100% rename from core/classes/protocols/interface.py rename to core/classes/interfaces/iprotocol.py diff --git a/core/classes/protocols/factory.py b/core/classes/protocols/factory.py index 7ccf267..6d30ffe 100644 --- a/core/classes/protocols/factory.py +++ b/core/classes/protocols/factory.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Optional from .unreal6 import Unrealircd6 from .inspircd import Inspircd -from .interface import IProtocol +from ..interfaces.iprotocol import IProtocol if TYPE_CHECKING: from core.irc import Irc diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index 1e6ae90..a921b50 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -4,7 +4,7 @@ from re import match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional from ssl import SSLEOFError, SSLError -from core.classes.protocols.interface import IProtocol +from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr if TYPE_CHECKING: diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 7970c80..ade1865 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -4,7 +4,7 @@ from re import match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional from ssl import SSLEOFError, SSLError -from core.classes.protocols.interface import IProtocol +from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr if TYPE_CHECKING: diff --git a/core/irc.py b/core/irc.py index 8ee2e96..1888b2a 100644 --- a/core/irc.py +++ b/core/irc.py @@ -7,7 +7,7 @@ from ssl import SSLSocket from datetime import datetime, timedelta from typing import TYPE_CHECKING, Any, Optional, Union from core.classes import rehash -from core.classes.protocols.interface import IProtocol +from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr if TYPE_CHECKING: From 0c6c3cd6acc8347fe737e0d103608cf2145f9117 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 2 Nov 2025 22:52:27 +0100 Subject: [PATCH 19/56] Refactoring the code, create new folder modules. --- core/base.py | 4 ---- core/classes/{ => modules}/admin.py | 0 core/classes/{ => modules}/channel.py | 0 core/classes/{ => modules}/client.py | 0 core/classes/{ => modules}/commands.py | 0 core/classes/{ => modules}/config.py | 0 core/classes/{ => modules}/rehash.py | 16 +++++++++------- core/classes/{ => modules}/reputation.py | 0 core/classes/{ => modules}/sasl.py | 0 core/classes/{ => modules}/settings.py | 0 core/classes/{ => modules}/translation.py | 0 core/classes/{ => modules}/user.py | 0 core/classes/protocols/unreal6.py | 2 +- core/irc.py | 2 +- core/loader.py | 8 ++++---- core/utils.py | 2 +- 16 files changed, 16 insertions(+), 18 deletions(-) rename core/classes/{ => modules}/admin.py (100%) rename core/classes/{ => modules}/channel.py (100%) rename core/classes/{ => modules}/client.py (100%) rename core/classes/{ => modules}/commands.py (100%) rename core/classes/{ => modules}/config.py (100%) rename core/classes/{ => modules}/rehash.py (96%) rename core/classes/{ => modules}/reputation.py (100%) rename core/classes/{ => modules}/sasl.py (100%) rename core/classes/{ => modules}/settings.py (100%) rename core/classes/{ => modules}/translation.py (100%) rename core/classes/{ => modules}/user.py (100%) diff --git a/core/base.py b/core/base.py index d56959d..77cb9cf 100644 --- a/core/base.py +++ b/core/base.py @@ -1,16 +1,12 @@ -import importlib import os import re import json -import sys import time import socket import threading import ipaddress import ast import requests -from pathlib import Path -from types import ModuleType from dataclasses import fields from typing import Any, Optional, TYPE_CHECKING from base64 import b64decode, b64encode diff --git a/core/classes/admin.py b/core/classes/modules/admin.py similarity index 100% rename from core/classes/admin.py rename to core/classes/modules/admin.py diff --git a/core/classes/channel.py b/core/classes/modules/channel.py similarity index 100% rename from core/classes/channel.py rename to core/classes/modules/channel.py diff --git a/core/classes/client.py b/core/classes/modules/client.py similarity index 100% rename from core/classes/client.py rename to core/classes/modules/client.py diff --git a/core/classes/commands.py b/core/classes/modules/commands.py similarity index 100% rename from core/classes/commands.py rename to core/classes/modules/commands.py diff --git a/core/classes/config.py b/core/classes/modules/config.py similarity index 100% rename from core/classes/config.py rename to core/classes/modules/config.py diff --git a/core/classes/rehash.py b/core/classes/modules/rehash.py similarity index 96% rename from core/classes/rehash.py rename to core/classes/modules/rehash.py index 75c5947..2f8b457 100644 --- a/core/classes/rehash.py +++ b/core/classes/modules/rehash.py @@ -11,10 +11,11 @@ if TYPE_CHECKING: REHASH_MODULES = [ 'core.definition', 'core.utils', - 'core.classes.config', + 'core.classes.modules.config', 'core.base', - 'core.classes.commands', - 'core.classes.protocols.interface', + 'core.classes.modules.commands', + 'core.classes.interfaces.iprotocol', + 'core.classes.protocols.command_handler', 'core.classes.protocols.factory', 'core.classes.protocols.unreal6', 'core.classes.protocols.inspircd' @@ -32,10 +33,6 @@ def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") - for module in uplink.ModuleUtils.model_get_loaded_modules().copy(): uplink.ModuleUtils.unload_one_module(uplink, module.module_name) - uplink.ModuleUtils.model_clear() # Clear loaded modules. - uplink.User.UID_DB.clear() # Clear User Object - uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object - uplink.Client.CLIENT_DB.clear() # Clear Client object uplink.Base.garbage_collector_thread() uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!') @@ -58,6 +55,11 @@ def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") - uplink.Protocol = uplink.Loader.PFactory.get() uplink.Protocol.register_command() + uplink.ModuleUtils.model_clear() # Clear loaded modules. + uplink.User.UID_DB.clear() # Clear User Object + uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object + uplink.Client.CLIENT_DB.clear() # Clear Client object + uplink.init_service_user() uplink.Utils.create_socket(uplink) uplink.Protocol.send_link() diff --git a/core/classes/reputation.py b/core/classes/modules/reputation.py similarity index 100% rename from core/classes/reputation.py rename to core/classes/modules/reputation.py diff --git a/core/classes/sasl.py b/core/classes/modules/sasl.py similarity index 100% rename from core/classes/sasl.py rename to core/classes/modules/sasl.py diff --git a/core/classes/settings.py b/core/classes/modules/settings.py similarity index 100% rename from core/classes/settings.py rename to core/classes/modules/settings.py diff --git a/core/classes/translation.py b/core/classes/modules/translation.py similarity index 100% rename from core/classes/translation.py rename to core/classes/modules/translation.py diff --git a/core/classes/user.py b/core/classes/modules/user.py similarity index 100% rename from core/classes/user.py rename to core/classes/modules/user.py diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index ade1865..e239a7b 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -8,7 +8,7 @@ from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr if TYPE_CHECKING: - from core.classes.sasl import Sasl + from core.classes.modules.sasl import Sasl from core.definition import MClient, MSasl, MUser, MChannel from core.loader import Loader diff --git a/core/irc.py b/core/irc.py index 1888b2a..2fd8616 100644 --- a/core/irc.py +++ b/core/irc.py @@ -6,7 +6,7 @@ import time from ssl import SSLSocket from datetime import datetime, timedelta from typing import TYPE_CHECKING, Any, Optional, Union -from core.classes import rehash +from core.classes.modules import rehash from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr diff --git a/core/loader.py b/core/loader.py index 4953940..1608d87 100644 --- a/core/loader.py +++ b/core/loader.py @@ -1,13 +1,13 @@ from logging import Logger -from core.classes.settings import global_settings -from core.classes import translation, user, admin, client, channel, reputation, settings, sasl +from core.classes.modules.settings import global_settings +from core.classes.modules import translation, user, admin, client, channel, reputation, settings, sasl import core.logs as logs import core.definition as df import core.utils as utils import core.base as base_mod import core.module as module_mod -import core.classes.commands as commands_mod -import core.classes.config as conf_mod +import core.classes.modules.commands as commands_mod +import core.classes.modules.config as conf_mod import core.irc as irc import core.classes.protocols.factory as factory diff --git a/core/utils.py b/core/utils.py index bbfca6f..bf2a397 100644 --- a/core/utils.py +++ b/core/utils.py @@ -13,7 +13,7 @@ from datetime import datetime, timedelta, timezone from time import time from random import choice from hashlib import md5, sha3_512 -from core.classes.settings import global_settings +from core.classes.modules.settings import global_settings if TYPE_CHECKING: from core.irc import Irc From 1bfd95c2917c3b7e1a6e1154baffc501c8c43592 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:12:28 +0100 Subject: [PATCH 20/56] refactoring code --- core/classes/interfaces/iprotocol.py | 115 +++++++++++++-------------- core/classes/protocols/inspircd.py | 11 +-- core/classes/protocols/unreal6.py | 94 +++++++++++----------- 3 files changed, 109 insertions(+), 111 deletions(-) diff --git a/core/classes/interfaces/iprotocol.py b/core/classes/interfaces/iprotocol.py index d730097..87b921f 100644 --- a/core/classes/interfaces/iprotocol.py +++ b/core/classes/interfaces/iprotocol.py @@ -13,7 +13,7 @@ class IProtocol(ABC): def __init__(self, uplink: 'Irc'): self.name: Optional[str] = None self.protocol_version: int = -1 - self.known_protocol: set[str] = {} + self.known_protocol: set[str] = set() self._Irc = uplink self._Config = uplink.Config @@ -32,10 +32,7 @@ class IProtocol(ABC): @abstractmethod def init_protocol(self): - """_summary_ - - Returns: - _type_: _description_ + """Init protocol """ @abstractmethod @@ -316,46 +313,46 @@ class IProtocol(ABC): # ------------------------------------------------------------------------ @abstractmethod - def parse_uid(self, serverMsg: list[str]) -> Optional['MUser']: + def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. Args: - serverMsg (list[str]): The UID IRCD message + server_msg (list[str]): The UID IRCD message Returns: Optional[MUser]: The MUser object or None """ @abstractmethod - def parse_quit(self, serverMsg: list[str]) -> tuple[Optional['MUser'], str]: + def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] Args: - serverMsg (list[str]): The server message to parse + server_msg (list[str]): The server message to parse Returns: tuple[MUser, str]: The User Who Quit Object and the reason. """ @abstractmethod - def parse_nick(self, serverMsg: list[str]) -> dict[str, str]: + def parse_nick(self, server_msg: list[str]) -> dict[str, str]: """Parse nick changes and return dictionary. >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] Args: - serverMsg (list[str]): The server message to parse + server_msg (list[str]): The server message to parse Returns: dict[str, str]: The response as dictionary. """ @abstractmethod - def parse_privmsg(self, serverMsg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: + def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] Args: - serverMsg (list[str]): The server message to parse + server_msg (list[str]): The server message to parse Returns: tuple[MUser(Sender), MUser(Reciever), MChannel, str]: Sender user model, reciever user model, Channel model, messgae. @@ -366,174 +363,174 @@ class IProtocol(ABC): # ------------------------------------------------------------------------ @abstractmethod - def on_svs2mode(self, serverMsg: list[str]) -> None: + def on_svs2mode(self, server_msg: list[str]) -> None: """Handle svs2mode coming from a server >>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_mode(self, serverMsg: list[str]) -> None: + def on_mode(self, server_msg: list[str]) -> None: """Handle mode coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_umode2(self, serverMsg: list[str]) -> None: + def on_umode2(self, server_msg: list[str]) -> None: """Handle umode2 coming from a server >>> [':adator_', 'UMODE2', '-i'] Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_quit(self, serverMsg: list[str]) -> None: + def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_squit(self, serverMsg: list[str]) -> None: + def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_protoctl(self, serverMsg: list[str]) -> None: + def on_protoctl(self, server_msg: list[str]) -> None: """Handle protoctl coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_nick(self, serverMsg: list[str]) -> None: + def on_nick(self, server_msg: list[str]) -> None: """Handle nick coming from a server new nickname Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_sjoin(self, serverMsg: list[str]) -> None: + def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_part(self, serverMsg: list[str]) -> None: + def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_eos(self, serverMsg: list[str]) -> None: + def on_eos(self, server_msg: list[str]) -> None: """Handle EOS coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_reputation(self, serverMsg: list[str]) -> None: + def on_reputation(self, server_msg: list[str]) -> None: """Handle REPUTATION coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_uid(self, serverMsg: list[str]) -> None: + def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_privmsg(self, serverMsg: list[str]) -> None: + def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_server_ping(self, serverMsg: list[str]) -> None: + def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server Args: - serverMsg (list[str]): List of str coming from the server + server_msg (list[str]): List of str coming from the server """ @abstractmethod - def on_server(self, serverMsg: list[str]) -> None: + def on_server(self, server_msg: list[str]) -> None: """_summary_ Args: - serverMsg (list[str]): _description_ + server_msg (list[str]): _description_ """ @abstractmethod - def on_version(self, serverMsg: list[str]) -> None: + def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server Args: - serverMsg (list[str]): List of str coming from the server + server_msg (list[str]): List of str coming from the server """ @abstractmethod - def on_time(self, serverMsg: list[str]) -> None: + def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor Args: - serverMsg (list[str]): List of str coming from the server + server_msg (list[str]): List of str coming from the server """ @abstractmethod - def on_ping(self, serverMsg: list[str]) -> None: + def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor Args: - serverMsg (list[str]): List of str coming from the server + server_msg (list[str]): List of str coming from the server """ @abstractmethod - def on_version_msg(self, serverMsg: list[str]) -> None: + def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server \n ex. /version Defender Args: - serverMsg (list[str]): Original message from the server + server_msg (list[str]): Original message from the server """ @abstractmethod - def on_smod(self, serverMsg: list[str]) -> None: + def on_smod(self, server_msg: list[str]) -> None: """Handle SMOD message coming from the server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ @abstractmethod - def on_sasl(self, serverMsg: list[str]) -> Optional['MSasl']: + def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message Returns: @@ -551,18 +548,18 @@ class IProtocol(ABC): """ @abstractmethod - def on_md(self, serverMsg: list[str]) -> None: + def on_md(self, server_msg: list[str]) -> None: """Handle MD responses [':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...'] Args: - serverMsg (list[str]): The server reply + server_msg (list[str]): The server reply """ @abstractmethod - def on_kick(self, serverMsg: list[str]) -> None: + def on_kick(self, server_msg: list[str]) -> None: """When a user is kicked out from a channel Eg. ['@unrealircd.org...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User'] Args: - serverMsg (list[str]): The server message + server_msg (list[str]): The server message """ diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index a921b50..7ff0e54 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -254,7 +254,7 @@ class Inspircd(IProtocol): self.send2socket(f":{server_id} SQUIT {server_link} :{reason}") return None - def send_ungline(self, nickname:str, hostname: str) -> None: + def send_ungline(self, nickname: str, hostname: str) -> None: self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") @@ -312,7 +312,9 @@ class Inspircd(IProtocol): return None - def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: + def send_uid(self, nickname: str, username: str, hostname: str, + uid:str, umodes: str, vhost: str, remote_ip: str, + realname: str, print_log: bool = True) -> None: """Send UID to the server [:] UID []+ : Args: @@ -384,7 +386,7 @@ class Inspircd(IProtocol): self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) return None - def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None: + def send_part_chan(self, uidornickname: str, channel: str, print_log: bool = True) -> None: """Part from a channel Args: @@ -409,7 +411,7 @@ class Inspircd(IProtocol): self._Irc.Channel.delete_user_from_channel(channel, user_obj.uid) return None - def send_unkline(self, nickname:str, hostname: str) -> None: + def send_unkline(self, nickname: str, hostname: str) -> None: self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") @@ -1263,7 +1265,6 @@ class Inspircd(IProtocol): return sender, reciever, channel, message - # ------------------------------------------------------------------------ # IRC SENDER METHODS # ------------------------------------------------------------------------ diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index e239a7b..c80552e 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -1,5 +1,4 @@ from base64 import b64decode -from optparse import Option from re import match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional @@ -10,7 +9,6 @@ from core.utils import tr if TYPE_CHECKING: from core.classes.modules.sasl import Sasl from core.definition import MClient, MSasl, MUser, MChannel - from core.loader import Loader class Unrealircd6(IProtocol): @@ -106,7 +104,8 @@ class Unrealircd6(IProtocol): """Envoit les commandes à envoyer au serveur. Args: - string (Str): contient la commande à envoyer au serveur. + message (str): contient la commande à envoyer au serveur. + print_log (bool): True print log message in the console """ try: with self._Base.lock: @@ -142,22 +141,22 @@ class Unrealircd6(IProtocol): """ 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 not nick_to is None else None + user_from = self._Irc.User.get_user(nick_from) + user_to = self._Irc.User.get_user(nick_to) if not nick_to is None else None - if User_from is None: + if user_from is None: self._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}") + 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}") + self.send2socket(f":{nick_from} PRIVMSG {user_to.uid} :{batch}") except Exception as err: self._Logs.error(f"General Error: {err}") @@ -173,16 +172,16 @@ class Unrealircd6(IProtocol): """ 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) + 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: + if user_from is None or user_to is None: self._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}") + self.send2socket(f":{user_from.uid} NOTICE {user_to.uid} :{batch}") except Exception as err: self._Logs.error(f"General Error: {err}") @@ -199,7 +198,7 @@ class Unrealircd6(IProtocol): service_info = self._Config.SERVICE_INFO service_smodes = self._Config.SERVICE_SMODES service_cmodes = self._Config.SERVICE_CMODES - service_umodes = self._Config.SERVICE_UMODES + # service_umodes = self._Config.SERVICE_UMODES service_hostname = self._Config.SERVICE_HOST service_name = self._Config.SERVICE_NAME protocolversion = self.protocol_version @@ -251,8 +250,8 @@ class Unrealircd6(IProtocol): """ self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") - userObj = self._Irc.User.get_user(self._Config.SERVICE_NICKNAME) - self._Irc.User.update_nickname(userObj.uid, newnickname) + user_obj = self._Irc.User.get_user(self._Config.SERVICE_NICKNAME) + self._Irc.User.update_nickname(user_obj.uid, newnickname) return None def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: @@ -339,21 +338,20 @@ class Unrealircd6(IProtocol): """_summary_ Args: - from_nick (str): _description_ - nick_to (str): _description_ + nick_to_sapart (str): _description_ channel_name (str): _description_ """ try: - userObj = self._Irc.User.get_user(uidornickname=nick_to_sapart) - chanObj = self._Irc.Channel.get_channel(channel_name) + user_obj = self._Irc.User.get_user(uidornickname=nick_to_sapart) + chan_obj = self._Irc.Channel.get_channel(channel_name) service_uid = self._Config.SERVICE_ID - if userObj is None or chanObj is None: + if user_obj is None or chan_obj is None: return None - self.send2socket(f":{service_uid} SAPART {userObj.nickname} {chanObj.name}") - self._Irc.Channel.delete_user_from_channel(chanObj.name, userObj.uid) + self.send2socket(f":{service_uid} SAPART {user_obj.nickname} {chan_obj.name}") + self._Irc.Channel.delete_user_from_channel(chan_obj.name, user_obj.uid) return None @@ -369,28 +367,28 @@ class Unrealircd6(IProtocol): """ try: - userObj = self._Irc.User.get_user(uidornickname=nick_to_sajoin) - chanObj = self._Irc.Channel.get_channel(channel_name) + user_obj = self._Irc.User.get_user(uidornickname=nick_to_sajoin) + chan_obj = self._Irc.Channel.get_channel(channel_name) service_uid = self._Config.SERVICE_ID - if userObj is None: + if user_obj is None: # User not exist: leave return None - if chanObj is None: + if chan_obj is None: # Channel not exist if not self._Irc.Channel.is_valid_channel(channel_name): # Incorrect channel: leave return None # Create the new channel with the uid - newChanObj = self._Irc.Loader.Definition.MChannel(name=channel_name, uids=[userObj.uid]) - self._Irc.Channel.insert(newChanObj) - self.send2socket(f":{service_uid} SAJOIN {userObj.nickname} {newChanObj.name}") + new_chan_obj = self._Irc.Loader.Definition.MChannel(name=channel_name, uids=[user_obj.uid]) + self._Irc.Channel.insert(new_chan_obj) + self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {new_chan_obj.name}") else: - self._Irc.Channel.add_user_to_a_channel(channel_name=channel_name, uid=userObj.uid) - self.send2socket(f":{service_uid} SAJOIN {userObj.nickname} {chanObj.name}") + self._Irc.Channel.add_user_to_a_channel(channel_name=channel_name, uid=user_obj.uid) + self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {chan_obj.name}") return None @@ -472,7 +470,7 @@ class Unrealircd6(IProtocol): """Logout a client from his account Args: - client_uid (str): The Client UID + client_obj (MClient): The Client object """ try: c_uid = client_obj.uid @@ -483,31 +481,33 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f'General Error: {err}') - def send_quit(self, uid: str, reason: str, print_log: True) -> None: + def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: """Send quit message - Delete uid from User object - Delete uid from Reputation object Args: - uidornickname (str): The UID or the Nickname + uid (str): The UID or the Nickname reason (str): The reason for the quit + print_log (bool): Print the log """ user_obj = self._Irc.User.get_user(uidornickname=uid) - reputationObj = self._Irc.Reputation.get_reputation(uidornickname=uid) + reputation_obj = self._Irc.Reputation.get_reputation(uidornickname=uid) if not user_obj is None: self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) self._Irc.User.delete(user_obj.uid) - if not reputationObj is None: - self._Irc.Reputation.delete(reputationObj.uid) + if not reputation_obj is None: + self._Irc.Reputation.delete(reputation_obj.uid) if not self._Irc.Channel.delete_user_from_all_channel(uid): self._Logs.error(f"The UID [{uid}] has not been deleted from all channels") return None - def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: + def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, + vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: """Send UID to the server - Insert User to User Object Args: @@ -555,34 +555,34 @@ class Unrealircd6(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - userObj = self._Irc.User.get_user(uidornickname) - passwordChannel = password if not password is None else '' + user_obj = self._Irc.User.get_user(uidornickname) + pwd_channel = password if not password is None else '' - if userObj is None: + if user_obj is None: return None if not self._Irc.Channel.is_valid_channel(channel): self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{userObj.uid} JOIN {channel} {passwordChannel}", print_log=print_log) + self.send2socket(f":{user_obj.uid} JOIN {channel} {pwd_channel}", print_log=print_log) if uidornickname == self._Config.SERVICE_NICKNAME or uidornickname == self._Config.SERVICE_ID: self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") # Add defender to the channel uids list - self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[userObj.uid])) + self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) # Set the automode to the user - if 'r' not in userObj.umodes and 'o' not in userObj.umodes: + if 'r' not in user_obj.umodes and 'o' not in user_obj.umodes: return None - db_data: dict[str, str] = {"nickname": userObj.nickname, "channel": channel} + db_data: dict[str, str] = {"nickname": user_obj.nickname, "channel": channel} db_query = self._Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data) db_result = db_query.fetchone() if db_result is not None: - id, mode = db_result - self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {mode} {userObj.nickname}") + id_cmd_automode, mode = db_result + self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {mode} {user_obj.nickname}") return None From b52a57f95a2343ca2c0c4f9e6d8443bb3e5747f7 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Fri, 7 Nov 2025 22:46:09 +0100 Subject: [PATCH 21/56] Fix library path in settings.py --- core/classes/modules/settings.py | 2 +- core/irc.py | 17 ++++++----------- core/language/fr/core-fr.yaml | 2 ++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/core/classes/modules/settings.py b/core/classes/modules/settings.py index 913fbbc..3026359 100644 --- a/core/classes/modules/settings.py +++ b/core/classes/modules/settings.py @@ -7,7 +7,7 @@ from typing import Any, Optional, TYPE_CHECKING from core.definition import MSModule, MAdmin if TYPE_CHECKING: - from core.classes.user import User + from core.classes.modules.user import User class Settings: """This Class will never be reloaded. diff --git a/core/irc.py b/core/irc.py index 2fd8616..7efe779 100644 --- a/core/irc.py +++ b/core/irc.py @@ -129,7 +129,6 @@ class Irc: # Define the IrcSocket object self.IrcSocket: Optional[Union[socket.socket, SSLSocket]] = None - self.__create_table() self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, )) ############################################## @@ -353,11 +352,6 @@ class Irc: self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") - def __create_table(self) -> None: - """## Create core tables - """ - pass - def get_defender_uptime(self) -> str: """Savoir depuis quand Defender est connecté @@ -526,6 +520,7 @@ class Irc: RED = self.Config.COLORS.red GREEN = self.Config.COLORS.green + BLACK = self.Config.COLORS.black NOGC = self.Config.COLORS.nogc # Defender information @@ -596,7 +591,7 @@ class Irc: nick_to=fromuser, msg=tr("You can't use this command anymore ! Please use [%sauth] instead", self.Config.SERVICE_PREFIX) ) - return False + return None if current_nickname is None: self.Logs.critical(f"This nickname [{fromuser}] don't exist") @@ -641,7 +636,7 @@ class Irc: self.Base.db_create_first_admin() self.insert_db_admin(current_uid, cmd_owner, 5, self.Config.LANG) self.Protocol.send_priv_msg( - 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}", + msg=f"[ {GREEN}{str(current_command).upper()} {NOGC}] - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}", nick_from=dnickname, channel=dchanlog ) @@ -649,11 +644,11 @@ class Irc: self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f"Connexion a {dnickname} réussie!" + msg=tr("Successfuly connected to %s", dnickname) ) else: self.Protocol.send_priv_msg( - 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", + msg=f"[ {RED}{str(current_command).upper()} {NOGC}] - {self.User.get_nickname(fromuser)} a tapé un mauvais mot de pass", nick_from=dnickname, channel=dchanlog ) @@ -661,7 +656,7 @@ class Irc: self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f"Mot de passe incorrecte" + msg=tr("Wrong password!") ) case 'auth': diff --git a/core/language/fr/core-fr.yaml b/core/language/fr/core-fr.yaml index d879cfb..2f491d0 100644 --- a/core/language/fr/core-fr.yaml +++ b/core/language/fr/core-fr.yaml @@ -2,6 +2,8 @@ traduction: # Message help - orig: "Access denied!" trad: "Accès refusé." + - orig: "Wrong password!" + tard: "Mot de passe incorrect!" - orig: "%s - %sLoaded%s by %s on %s" trad: "%s - %sChargé%s par %s le %s" - orig: "%s - %sNot Loaded%s" From 17cb2ada5ff0b682d958a32a3a66febbcdebbba9 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sat, 8 Nov 2025 21:21:38 +0100 Subject: [PATCH 22/56] Fix server response, fix ircd parser aswell, update first setup on base.py --- Makefile | 3 ++ core/base.py | 8 +++- core/classes/modules/rehash.py | 1 + core/classes/protocols/unreal6.py | 6 +-- core/irc.py | 62 ++++++++++++++++++++++--------- core/language/fr/core-fr.yaml | 2 +- core/loader.py | 2 + mods/clone/mod_clone.py | 1 - 8 files changed, 61 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index ed7516b..8ddf336 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,9 @@ endif clean: ifeq ($(OS), Linux) + @export echo $DBUS_SESSION_BUS_ADDRESS && \ + systemctl --user stop defender + $(info Defender has been stopped...) @if [ -e .pyenv ]; then \ rm -rf .pyenv; \ echo "Virtual Env has been removed!"; \ diff --git a/core/base.py b/core/base.py index 77cb9cf..2392ebe 100644 --- a/core/base.py +++ b/core/base.py @@ -45,7 +45,10 @@ class Base: 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 - self.__create_db() # Initialisation de la base de données + # self.__create_db() # Initialisation de la base de données + + def init(self) -> None: + self.__create_db() def __set_current_defender_version(self) -> None: """This will put the current version of Defender @@ -481,7 +484,7 @@ class Base: engine = create_engine(f'sqlite:///{full_path_db}.db', echo=False) cursor = engine.connect() - self.logs.info("-- database connexion has been initiated") + self.logs.info("-- Database connexion has been initiated") return engine, cursor def __create_db(self) -> None: @@ -535,6 +538,7 @@ class Base: vhost TEXT, password TEXT, fingerprint TEXT, + language TEXT, level INTEGER ) ''' diff --git a/core/classes/modules/rehash.py b/core/classes/modules/rehash.py index 2f8b457..aa842f8 100644 --- a/core/classes/modules/rehash.py +++ b/core/classes/modules/rehash.py @@ -15,6 +15,7 @@ REHASH_MODULES = [ 'core.base', 'core.classes.modules.commands', 'core.classes.interfaces.iprotocol', + 'core.classes.interfaces.imodule', 'core.classes.protocols.command_handler', 'core.classes.protocols.factory', 'core.classes.protocols.unreal6', diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index c80552e..606062b 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -34,7 +34,7 @@ class Unrealircd6(IProtocol): tuple[int, Optional[str]]: The position and the command. """ for index, token in enumerate(cmd): - if token.upper() in self.known_protocol: + if token.upper() in self.known_protocol and index < 3: return index, token.upper() if log: @@ -216,9 +216,9 @@ class Unrealircd6(IProtocol): self.send2socket(f":{server_id} PROTOCTL SID={server_id}") self.send2socket(f":{server_id} PROTOCTL BOOTED={unixtime}") self.send2socket(f":{server_id} SERVER {server_link} 1 :{service_info}") - self.send2socket("EOS") self.send2socket(f":{server_id} {service_nickname} :Reserved for services") self.send2socket(f":{server_id} UID {service_nickname} 1 {unixtime} {service_username} {service_hostname} {service_id} * {service_smodes} * * fwAAAQ== :{service_realname}") + self.send2socket("EOS") self.send_sjoin(service_channel_log) self.send2socket(f":{server_id} TKL + Q * {service_nickname} {service_hostname} 0 {unixtime} :Reserved for services") self.send2socket(f":{service_id} MODE {service_channel_log} {service_cmodes}") @@ -1064,7 +1064,7 @@ class Unrealircd6(IProtocol): self._Logs.error(f'Index Error {__name__}: {ie}') except ValueError as ve: self._Irc.first_score = 0 - self._Logs.error(f'Value Error {__name__}: {ve}') + self._Logs.error(f'Value Error {__name__}: {ve}', exc_info=True) except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") diff --git a/core/irc.py b/core/irc.py index 7efe779..a2edc41 100644 --- a/core/irc.py +++ b/core/irc.py @@ -6,6 +6,7 @@ import time from ssl import SSLSocket from datetime import datetime, timedelta from typing import TYPE_CHECKING, Any, Optional, Union +from xml.etree.ElementInclude import DEFAULT_MAX_INCLUSION_DEPTH from core.classes.modules import rehash from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr @@ -178,14 +179,21 @@ class Irc: # 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 + eol = True + if data_in_bytes[-2:] != b"\r\n": + eol = False + + while not eol: new_data = self.IrcSocket.recv(buffer_size) data_in_bytes += new_data - count_bytes = len(new_data) + if data_in_bytes[-2:] == eol: + eol = False + + # 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) @@ -441,7 +449,7 @@ class Irc: # Check if the user already exist if not self.Admin.db_is_admin_exist(nickname): - mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level, 'language': 'EN'} + mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level, 'language': self.Config.LANG} self.Base.db_execute_query(f'''INSERT INTO {self.Config.TABLE_ADMIN} (createdOn, user, password, hostname, vhost, level, language) VALUES (:datetime, :user, :password, :hostname, :vhost, :level, :language) @@ -840,17 +848,37 @@ class Irc: case 'cert': # Syntax !cert try: + if len(cmd) < 2: + self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert add") + self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert del") + return None + admin_obj = self.Admin.get_admin(fromuser) - if admin_obj: - if admin_obj.fingerprint is not None: - query = f'UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user = :user' - r = self.Base.db_execute_query(query, {'fingerprint': admin_obj.fingerprint, 'user': admin_obj.account}) - if r.rowcount > 0: - self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your new fingerprint has been attached to your account. {admin_obj.fingerprint}') - else: - self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to add your fingerprint.{admin_obj.fingerprint}') - else: - self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] There is no fingerprint to add.') + param = cmd[1] # add or del + match param: + case 'add': + if admin_obj: + if admin_obj.fingerprint is not None: + query = f'UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user = :user' + r = self.Base.db_execute_query(query, {'fingerprint': admin_obj.fingerprint, 'user': admin_obj.account}) + if r.rowcount > 0: + self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your new fingerprint has been attached to your account. {admin_obj.fingerprint}') + else: + self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to add your fingerprint.{admin_obj.fingerprint}') + else: + self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] There is no fingerprint to add.') + case 'del': + if admin_obj: + query = f"UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user =:user" + r = self.Base.db_execute_query(query, {'fingerprint': None, 'user': admin_obj.account}) + if r.rowcount > 0: + self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your fingerprint has been removed from your account. {admin_obj.fingerprint}') + else: + self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to remove your fingerprint.{admin_obj.fingerprint}') + case _: + self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert add") + self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert del") + return None except Exception as e: self.Logs.error(e) diff --git a/core/language/fr/core-fr.yaml b/core/language/fr/core-fr.yaml index 2f491d0..b49ef8a 100644 --- a/core/language/fr/core-fr.yaml +++ b/core/language/fr/core-fr.yaml @@ -3,7 +3,7 @@ traduction: - orig: "Access denied!" trad: "Accès refusé." - orig: "Wrong password!" - tard: "Mot de passe incorrect!" + trad: "Mot de passe incorrect!" - orig: "%s - %sLoaded%s by %s on %s" trad: "%s - %sChargé%s par %s le %s" - orig: "%s - %sNot Loaded%s" diff --git a/core/loader.py b/core/loader.py index 1608d87..8cdbfd8 100644 --- a/core/loader.py +++ b/core/loader.py @@ -69,4 +69,6 @@ class Loader: self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc) + self.Base.init() + self.Logs.debug(self.Utils.tr("Loader %s success", __name__)) diff --git a/mods/clone/mod_clone.py b/mods/clone/mod_clone.py index 15ee7e0..e016718 100644 --- a/mods/clone/mod_clone.py +++ b/mods/clone/mod_clone.py @@ -7,7 +7,6 @@ import mods.clone.schemas as schemas from mods.clone.clone_manager import CloneManager if TYPE_CHECKING: - from core.irc import Irc from faker import Faker class Clone(IModule): From f9eb37479855020ea41bc5538f8ac81dc4b5e3ec Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 20:53:30 +0100 Subject: [PATCH 23/56] When fp is None, return False. log when login via fingerprint. --- core/classes/modules/admin.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/classes/modules/admin.py b/core/classes/modules/admin.py index 7479e36..117c60c 100644 --- a/core/classes/modules/admin.py +++ b/core/classes/modules/admin.py @@ -190,6 +190,9 @@ class Admin: Returns: bool: True if found """ + if fp is None: + return False + query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp" data = {'fp': fp} exe = self.Base.db_execute_query(query, data) @@ -200,12 +203,13 @@ class Admin: language = result[2] user_obj = self.User.get_user(uidornickname) if user_obj: - admin_obj = self.Definition.MAdmin(**user_obj.to_dict(),account=account, level=level, language=language) + admin_obj = self.Definition.MAdmin(**user_obj.to_dict(), account=account, level=level, language=language) if self.insert(admin_obj): self.Setting.current_admin = admin_obj + self.Logs.debug(f"[Fingerprint login] {user_obj.nickname} ({admin_obj.account}) has been logged in successfully!") return True - return False + return False def db_is_admin_exist(self, admin_nickname: str) -> bool: """Verify if the admin exist in the database! From 445cbc27b0f0b84144ba27227ba081a629574fc9 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:32:21 +0100 Subject: [PATCH 24/56] exclude users.txt file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index efaa5e4..9f02bfe 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ configuration.yaml configuration_inspircd.json configuration_unreal6.json *.log -test.py \ No newline at end of file +test.py +users.txt \ No newline at end of file From a6cf11ae2a08275d53c26d960f98943049f5d277 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:33:17 +0100 Subject: [PATCH 25/56] Update the log level when userobj is not found! --- mods/defender/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/defender/utils.py b/mods/defender/utils.py index 04d9d0a..d0be159 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -188,7 +188,7 @@ def handle_on_quit(uplink: 'Defender', srvmsg: list[str]): confmodel = uplink.ModConfig if userobj is None: - uplink.Logs.error("Error when parsing message QUIT", exc_info=True) + uplink.Logs.debug(f"This UID do not exist anymore: {srvmsg}") return None ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan) From 371645149d3343495c00a143b798dbb936dd8e36 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:35:27 +0100 Subject: [PATCH 26/56] Refactoring the Code, clean unsused methods. avoid multi calls to get_user, get_nickname ... --- mods/defender/mod_defender.py | 60 ++++++++++------------------------- 1 file changed, 16 insertions(+), 44 deletions(-) diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index a390d6e..601246b 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from typing import Any from core.classes.interfaces.imodule import IModule import mods.defender.schemas as schemas import mods.defender.utils as utils @@ -53,7 +54,6 @@ class Defender(IModule): self.Irc.build_command(3, self.module_name, 'proxy_scan', 'Scan users for proxy connections') self.Irc.build_command(3, self.module_name, 'flood', 'Handle flood detection and mitigation') self.Irc.build_command(3, self.module_name, 'status', 'Check the status of the server or bot') - self.Irc.build_command(3, self.module_name, 'timer', 'Set or manage timers') self.Irc.build_command(3, self.module_name, 'show_reputation', 'Display reputation information') self.Irc.build_command(3, self.module_name, 'sentinel', 'Monitor and guard the channel or server') @@ -64,7 +64,7 @@ class Defender(IModule): self.Schemas.DB_PSUTIL_USERS = self.Schemas.DB_LOCALSCAN_USERS = [] # Variables qui indique que les threads sont en cours d'éxecutions - self.abuseipdb_isRunning = self.freeipapi_isRunning= self.cloudfilt_isRunning = True + self.abuseipdb_isRunning = self.freeipapi_isRunning = self.cloudfilt_isRunning = True self.psutil_isRunning = self.localscan_isRunning = self.reputationTimer_isRunning = True self.autolimit_isRunning = True @@ -84,7 +84,6 @@ class Defender(IModule): self.Base.create_thread(func=thds.thread_abuseipdb_scan, func_args=(self, )) self.Base.create_thread(func=thds.thread_local_scan, func_args=(self, )) self.Base.create_thread(func=thds.thread_psutil_scan, func_args=(self, )) - self.Base.create_thread(func=thds.thread_apply_reputation_sanctions, func_args=(self, )) if self.ModConfig.autolimit == 1: @@ -140,9 +139,12 @@ class Defender(IModule): return None def insert_db_trusted(self, uid: str, nickname:str) -> None: + u = self.User.get_user(uid) + if u is None: + return None - uid = self.User.get_uid(uid) - nickname = self.User.get_nickname(nickname) + uid = u.uid + nickname = u.nickname query = "SELECT id FROM def_trusted WHERE user = ?" exec_query = self.Base.db_execute_query(query, {"user": nickname}) @@ -178,29 +180,6 @@ class Defender(IModule): except Exception as err: self.Logs.error(f"General Error: {err}") - def run_db_action_timer(self, wait_for: float = 0) -> None: - - 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.Protocol.send_priv_msg( - nick_from=service_id, - msg=f" ===> {param[0]}", - channel=dchanlog - ) - else: - self.Protocol.send_priv_msg( - nick_from=service_id, - msg=f"{param[0]}", - channel=dchanlog - ) - - return None - def cmd(self, data: list[str]) -> None: if not data or len(data) < 2: @@ -227,6 +206,7 @@ class Defender(IModule): return None case 'UID': + print(f"{self.module_name} - {cmd}") self.Utils.handle_on_uid(self, cmd) return None @@ -257,10 +237,13 @@ class Defender(IModule): except Exception as err: self.Logs.error(f"General Error: {err}", exc_info=True) - def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None: + def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: + u = self.User.get_user(user) + if u is None: + return None command = str(cmd[0]).lower() - fromuser = user + fromuser = u.nickname channel = fromchannel = channel if self.Channel.is_valid_channel(channel) else None dnickname = self.Config.SERVICE_NICKNAME # Defender nickname @@ -272,17 +255,6 @@ class Defender(IModule): match command: - case 'timer': - try: - timer_sent = self.Base.int_if_possible(cmd[1]) - timer_sent = int(timer_sent) - self.Base.create_timer(timer_sent, self.run_db_action_timer) - - except TypeError as te: - self.Logs.error(f"Type Error -> {te}") - except ValueError as ve: - self.Logs.error(f"Value Error -> {ve}") - case 'show_reputation': if not self.Reputation.UID_REPUTATION_DB: @@ -296,8 +268,8 @@ class Defender(IModule): case 'code': try: release_code = cmd[1] - jailed_nickname = self.User.get_nickname(fromuser) - jailed_UID = self.User.get_uid(fromuser) + jailed_nickname = u.nickname + jailed_UID = u.uid get_reputation = self.Reputation.get_reputation(jailed_UID) if get_reputation is None: @@ -327,7 +299,7 @@ class Defender(IModule): self.Protocol.send_sapart(nick_to_sapart=jailed_nickname, channel_name=jailed_salon) self.Protocol.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=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 + u.score_connexion = reputation_seuil + 1 self.Protocol.send_priv_msg(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) From de2b5fa8e2acaf2ae4214830a3edb56f550ce14d Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:36:58 +0100 Subject: [PATCH 27/56] Refactoring the Code, comment the code to dispatch the server response to all modules --- core/classes/protocols/unreal6.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 606062b..e1561ff 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -1088,18 +1088,15 @@ class Unrealircd6(IProtocol): hostname = str(serverMsg[7]) umodes = str(serverMsg[10]) vhost = str(serverMsg[11]) - - if not 'S' in umodes: - remote_ip = self._Base.decode_ip(str(serverMsg[13])) - else: - remote_ip = '127.0.0.1' - + remote_ip = '127.0.0.1' if 'S' in umodes else self._Base.decode_ip(str(serverMsg[13])) + # extract realname realname = ' '.join(serverMsg[14:]).lstrip(':') # Extract Geoip information pattern = r'^.*geoip=cc=(\S{2}).*$' geoip_match = match(pattern, serverMsg[0]) + geoip = geoip_match.group(1) if geoip_match else None # Extract Fingerprint information pattern = r'^.*certfp=([^;]+).*$' @@ -1110,12 +1107,6 @@ class Unrealircd6(IProtocol): pattern = r'^.*tls_cipher=([^;]+).*$' tlsc_match = match(pattern, serverMsg[0]) tls_cipher = tlsc_match.group(1) if tlsc_match else None - - if geoip_match: - geoip = geoip_match.group(1) - else: - geoip = None - score_connexion = self._Irc.first_score self._Irc.User.insert( @@ -1145,8 +1136,8 @@ class Unrealircd6(IProtocol): RED = self._Config.COLORS.red NOGC = self._Config.COLORS.nogc - for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): - module.class_instance.cmd(serverMsg) + # for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): + # module.class_instance.cmd(serverMsg) # SASL authentication # ['@s2s-md/..', ':001', 'UID', 'adator__', '0', '1755987444', '...', 'desktop-h1qck20.mshome.net', '001XLTT0U', '0', '+iwxz', '*', 'Clk-EC2256B2.mshome.net', 'rBKAAQ==', ':...'] From c05990f862f826b407d422e33eacff4c4b7a14fb Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:37:42 +0100 Subject: [PATCH 28/56] Refactoring the Code! --- core/classes/modules/admin.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/core/classes/modules/admin.py b/core/classes/modules/admin.py index 117c60c..7f59939 100644 --- a/core/classes/modules/admin.py +++ b/core/classes/modules/admin.py @@ -93,18 +93,11 @@ class Admin: Returns: bool: True if the admin has been deleted """ - - 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) - self.Logs.debug(f'UID ({record.uid}) has been deleted') - return True - if record.nickname.lower() == uidornickname.lower(): - # If the admin exist, delete and do not go further - self.UID_ADMIN_DB.remove(record) - self.Logs.debug(f'nickname ({record.nickname}) has been deleted') - return True + admin_obj = self.get_admin(uidornickname) + if admin_obj: + self.UID_ADMIN_DB.remove(admin_obj) + self.Logs.debug(f'UID ({admin_obj.uid}) has been deleted') + return True self.Logs.debug(f'The UID {uidornickname} was not deleted') From a1254c7a3991dabbdfc8b9407a27d618affe388c Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:39:19 +0100 Subject: [PATCH 29/56] Refactoring the Code, Dispatch server responses to all modules including UID, avoid multi calls to get_user, get_nickname... --- core/irc.py | 158 +++++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 75 deletions(-) diff --git a/core/irc.py b/core/irc.py index a2edc41..a4aab8c 100644 --- a/core/irc.py +++ b/core/irc.py @@ -6,7 +6,6 @@ import time from ssl import SSLSocket from datetime import datetime, timedelta from typing import TYPE_CHECKING, Any, Optional, Union -from xml.etree.ElementInclude import DEFAULT_MAX_INCLUSION_DEPTH from core.classes.modules import rehash from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr @@ -126,6 +125,7 @@ class Irc: self.build_command(3, 'core', 'cert', 'Append your new fingerprint to your account!') self.build_command(4, 'core', 'rehash', 'Reload the configuration file without restarting') self.build_command(4, 'core', 'raw', 'Send a raw command directly to the IRC server') + self.build_command(4, 'core', 'print_users', 'Print users in a file.') # Define the IrcSocket object self.IrcSocket: Optional[Union[socket.socket, SSLSocket]] = None @@ -482,28 +482,26 @@ class Irc: """ try: original_response: list[str] = data.copy() - RED = self.Config.COLORS.red - GREEN = self.Config.COLORS.green - NOGC = self.Config.COLORS.nogc - if len(original_response) < 2: self.Logs.warning(f'Size ({str(len(original_response))}) - {original_response}') return None self.Logs.debug(f">> {self.Utils.hide_sensitive_data(original_response)}") - pos, parsed_protocol = self.Protocol.get_ircd_protocol_poisition(cmd=original_response, log=True) + modules = self.ModuleUtils.model_get_loaded_modules().copy() for parsed in self.Protocol.Handler.get_ircd_commands(): if parsed.command_name.upper() == parsed_protocol: parsed.func(original_response) - - if len(original_response) > 2: - if original_response[2] != 'UID': - # Envoyer la commande aux classes dynamiquement chargées - for module in self.ModuleUtils.model_get_loaded_modules().copy(): + for module in modules: module.class_instance.cmd(original_response) + # if len(original_response) > 2: + # if original_response[2] != 'UID': + # # Envoyer la commande aux classes dynamiquement chargées + # for module in self.ModuleUtils.model_get_loaded_modules().copy(): + # module.class_instance.cmd(original_response) + except IndexError as ie: self.Logs.error(f"IndexError: {ie}") except Exception as err: @@ -521,9 +519,16 @@ class Irc: Returns: None: Nothing to return """ + u = self.User.get_user(user) + """The User Object""" + if u is None: + return None - fromuser = self.User.get_nickname(user) # Nickname qui a lancé la commande - uid = self.User.get_uid(user) # Récuperer le uid de l'utilisateur + c = self.Client.get_Client(u.uid) + """The Client Object""" + + fromuser = u.nickname + uid = u.uid self.Settings.current_admin = self.Admin.get_admin(user) # set Current admin if any. RED = self.Config.COLORS.red @@ -571,7 +576,7 @@ class Irc: case 'deauth': current_command = str(cmd[0]).upper() - uid_to_deauth = self.User.get_uid(fromuser) + uid_to_deauth = uid self.delete_db_admin(uid_to_deauth) self.Protocol.send_priv_msg( @@ -584,11 +589,20 @@ class Irc: return None case 'firstauth': - # firstauth OWNER_NICKNAME OWNER_PASSWORD - current_nickname = self.User.get_nickname(fromuser) - current_uid = self.User.get_uid(fromuser) + # Syntax. /msg defender firstauth OWNER_NICKNAME OWNER_PASSWORD + # Check command + current_nickname = fromuser + current_uid = uid current_command = str(cmd[0]) + if current_nickname is None: + self.Logs.critical(f"This nickname [{fromuser}] don't exist") + return None + + if len(cmd) < 3: + self.Protocol.send_notice(dnickname,fromuser, tr("Syntax. /msg %s %s [OWNER_NICKNAME] [OWNER_PASSWORD]", self.Config.SERVICE_NICKNAME, current_command)) + return None + query = f"SELECT count(id) as c FROM {self.Config.TABLE_ADMIN}" result = self.Base.db_execute_query(query) result_db = result.fetchone() @@ -601,10 +615,6 @@ class Irc: ) return None - if current_nickname is None: - self.Logs.critical(f"This nickname [{fromuser}] don't exist") - return False - # Credentials sent from the user cmd_owner = str(cmd[1]) cmd_password = str(cmd[2]) @@ -613,59 +623,33 @@ class Irc: config_owner = self.Config.OWNER config_password = self.Config.PASSWORD - if current_nickname != cmd_owner: - self.Logs.critical(f"The current nickname [{fromuser}] is different than the nickname sent [{cmd_owner}] !") - self.Protocol.send_notice( - 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.Logs.critical(f"The current nickname [{current_nickname}] is different than the configuration owner [{config_owner}] !") - self.Protocol.send_notice( - 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.Logs.critical(f"The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !") self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f"The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !" + msg=tr("The nickname sent [%s] is different than the one set in the configuration file !", cmd_owner) ) - return False + return None if cmd_owner == config_owner and cmd_password == config_password: self.Base.db_create_first_admin() self.insert_db_admin(current_uid, cmd_owner, 5, self.Config.LANG) self.Protocol.send_priv_msg( - msg=f"[ {GREEN}{str(current_command).upper()} {NOGC}] - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}", + msg=tr("[%s %s %s] - %s is now connected to %s", GREEN, current_command.upper(), NOGC, fromuser, dnickname), nick_from=dnickname, channel=dchanlog ) - self.Protocol.send_notice( - nick_from=dnickname, - nick_to=fromuser, - msg=tr("Successfuly connected to %s", dnickname) - ) + self.Protocol.send_notice(dnickname, fromuser, tr("Successfuly connected to %s", dnickname)) else: self.Protocol.send_priv_msg( - msg=f"[ {RED}{str(current_command).upper()} {NOGC}] - {self.User.get_nickname(fromuser)} a tapé un mauvais mot de pass", + msg=tr("[ %s %s %s ] - %s provided a wrong password!", RED, current_command.upper(), NOGC, current_nickname), nick_from=dnickname, channel=dchanlog ) - self.Protocol.send_notice( - nick_from=dnickname, - nick_to=fromuser, - msg=tr("Wrong password!") - ) + self.Protocol.send_notice(dnickname, fromuser, tr("Wrong password!")) case 'auth': # Syntax. !auth nickname password @@ -673,22 +657,21 @@ class Irc: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [password]") return None - current_command = cmd[0] user_to_log = cmd[1] password = cmd[2] - current_client = self.User.get_user(fromuser) + current_client = u admin_obj = self.Admin.get_admin(fromuser) if current_client is None: # This case should never happen self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - Nickname {fromuser} is trying to connect to defender wrongly", + msg=f"[ {RED}{str(command).upper()} FAIL{NOGC} ] - Nickname {fromuser} is trying to connect to defender wrongly", channel=dchanlog) return None if admin_obj: self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - {fromuser} is already connected to {dnickname}", + msg=f"[ {GREEN}{str(command).upper()}{NOGC} ] - {fromuser} is already connected to {dnickname}", channel=dchanlog) self.Protocol.send_notice(dnickname, fromuser, tr("You are already connected to %s", dnickname)) return None @@ -704,15 +687,15 @@ class Irc: language = str(user_from_db[3]) self.insert_db_admin(current_client.uid, account, level, language) self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - {current_client.nickname} ({account}) est désormais connecté a {dnickname}", + msg=f"[ {GREEN}{str(command).upper()} SUCCESS{NOGC} ] - {current_client.nickname} ({account}) est désormais connecté a {dnickname}", channel=dchanlog) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Connexion a {dnickname} réussie!") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=tr("Successfuly connected to %s", dnickname)) return None else: self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {RED}{str(current_command).upper()}{NOGC} ] - {current_client.nickname} a tapé un mauvais mot de pass", + msg=f"[ {RED}{str(command).upper()} FAIL{NOGC} ] - {current_client.nickname} a tapé un mauvais mot de pass", channel=dchanlog) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Mot de passe incorrecte") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=tr("Wrong password!")) return None case 'addaccess': @@ -738,7 +721,7 @@ class Irc: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") case 'editaccess': - # .editaccess [USER] [PASSWORD] [LEVEL] + # .editaccess [USER] [NEW_PASSWORD] [LEVEL] try: if len(cmd) < 3: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} editaccess [nickname] [NEWPASSWORD] [NEWLEVEL]") @@ -753,8 +736,8 @@ class Irc: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no Admin access") return None - current_user = self.User.get_nickname(fromuser) - current_uid = self.User.get_uid(fromuser) + current_user = fromuser + current_uid = uid current_user_level = get_admin.level user_new_level = int(cmd[3]) if len(cmd) == 4 else get_admin.level @@ -818,8 +801,8 @@ class Irc: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no admin access") return None - current_user = self.User.get_nickname(fromuser) - current_uid = self.User.get_uid(fromuser) + current_user = fromuser + current_uid = uid current_user_level = get_admin.level # Rechercher le user dans la base de données. @@ -906,7 +889,7 @@ class Irc: ) return None - user_obj = self.User.get_user(fromuser) + user_obj = u if user_obj is None: self.Logs.error(f"Nickname ({fromuser}) doesn't exist, it is impossible to register this nickname") @@ -961,8 +944,8 @@ class Irc: account = str(cmd[1]) # account encrypted_password = self.Loader.Utils.hash_password(cmd[2]) - user_obj = self.User.get_user(fromuser) - client_obj = self.Client.get_Client(user_obj.uid) + user_obj = u + client_obj = c if client_obj is not None: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are already logged in") @@ -1002,19 +985,18 @@ class Irc: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") return None - user_obj = self.User.get_user(fromuser) + user_obj = u if user_obj is None: self.Logs.error(f"The User [{fromuser}] is not available in the database") return None - client_obj = self.Client.get_Client(user_obj.uid) + client_obj = c if client_obj is None: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nothing to logout. please login first") return None self.Protocol.send_svslogout(client_obj) - # self.Protocol.send_svsmode(nickname=fromuser, user_mode='-r') self.Client.delete(user_obj.uid) self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You have been logged out successfully") @@ -1034,6 +1016,10 @@ class Irc: case 'load': try: # Load a module ex: .load mod_defender + if len(cmd) < 2: + self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) + return None + mod_name = str(cmd[1]) self.ModuleUtils.load_one_module(self, mod_name, fromuser) return None @@ -1046,6 +1032,9 @@ class Irc: # unload mod_defender try: # The module name. exemple: mod_defender + if len(cmd) < 2: + self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) + return None module_name = str(cmd[1]).lower() self.ModuleUtils.unload_one_module(self, module_name, False) return None @@ -1056,6 +1045,10 @@ class Irc: # reload mod_defender try: # ==> mod_defender + if len(cmd) < 2: + self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) + return None + module_name = str(cmd[1]).lower() self.ModuleUtils.reload_one_module(self, module_name, fromuser) return None @@ -1098,8 +1091,12 @@ class Irc: case 'restart': final_reason = ' '.join(cmd[1:]) self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{dnickname.capitalize()} is going to restart!") - 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 + + # Set restart status to 1 saying that the service will restart + self.Config.DEFENDER_RESTART = 1 + + # set init to 1 saying that the service will be re initiated + self.Config.DEFENDER_INIT = 1 case 'rehash': rehash.rehash_service(self, fromuser) @@ -1235,7 +1232,7 @@ class Irc: self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f"{uptime}" + msg=uptime ) return None @@ -1256,5 +1253,16 @@ class Irc: self.Protocol.send_raw(raw_command) return None + case 'print_users': + with open('users.txt', 'w') as fw: + i = 1 + for u in self.User.UID_DB: + w = fw.write(u.to_dict().__str__() + "\n") + self.Logs.debug(f" {i} - chars written {w}") + i += 1 + self.Protocol.send_priv_msg(dnickname, "Data written in users.txt file", dchanlog) + + return None + case _: pass From a7efede75e851f96e4536a92e3f0f5b5467002f1 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 10 Nov 2025 00:13:35 +0100 Subject: [PATCH 30/56] Introduce MOD_HEADER constante in all modules as mandatory constante. --- core/classes/interfaces/imodule.py | 4 +++- mods/clone/mod_clone.py | 8 ++++++++ mods/command/mod_command.py | 8 ++++++++ mods/defender/mod_defender.py | 8 ++++++++ mods/jsonrpc/mod_jsonrpc.py | 8 ++++++++ mods/test/mod_test.py | 8 ++++++++ mods/votekick/mod_votekick.py | 10 +++++++++- 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 6005c6b..7860c19 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -1,4 +1,4 @@ -from abc import ABC, abstractmethod +from abc import ABC, abstractmethod, abstractproperty from typing import TYPE_CHECKING, Optional from dataclasses import dataclass from mods.clone.schemas import ModConfModel @@ -84,6 +84,8 @@ class IModule(ABC): def inspect_class(self): if not hasattr(self, 'ModConfig'): raise AttributeError("The Module must init ModConfig attribute in the load method!") + if not hasattr(self, 'MOD_HEADER'): + raise NotImplementedError(f"You must declare the header of the module in {self.__class__.__name__}!") @abstractmethod def create_tables(self) -> None: diff --git a/mods/clone/mod_clone.py b/mods/clone/mod_clone.py index e016718..4eb698f 100644 --- a/mods/clone/mod_clone.py +++ b/mods/clone/mod_clone.py @@ -15,6 +15,14 @@ class Clone(IModule): class ModConfModel(schemas.ModConfModel): ... + MOD_HEADER: set[str] = { + 'Clone', + '1.0.0', + 'Connect thousands of clones to your IRCD, by group. You can use them as security moderation.', + 'Defender Team', + 'Defender-6' + } + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module diff --git a/mods/command/mod_command.py b/mods/command/mod_command.py index 2d41148..0f74106 100644 --- a/mods/command/mod_command.py +++ b/mods/command/mod_command.py @@ -14,6 +14,14 @@ class Command(IModule): """ pass + MOD_HEADER: set[str] = { + 'Command', + '1.0.0', + 'Module contains all IRC commands', + 'Defender Team', + 'Defender-6' + } + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index 601246b..f42da02 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -12,6 +12,14 @@ class Defender(IModule): class ModConfModel(schemas.ModConfModel): ... + MOD_HEADER: set[str] = { + 'Defender', + '1.0.0', + 'Defender main module that uses the reputation security.', + 'Defender Team', + 'Defender-6' + } + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module diff --git a/mods/jsonrpc/mod_jsonrpc.py b/mods/jsonrpc/mod_jsonrpc.py index 9960e5b..6086d94 100644 --- a/mods/jsonrpc/mod_jsonrpc.py +++ b/mods/jsonrpc/mod_jsonrpc.py @@ -15,6 +15,14 @@ class Jsonrpc(IModule): """ jsonrpc: int = 0 + MOD_HEADER: set[str] = { + 'JsonRPC', + '1.0.0', + 'Module using the unrealircd-rpc-py library', + 'Defender Team', + 'Defender-6' + } + def callback_sent_to_irc(self, response: LiveRPCResult) -> None: dnickname = self.Config.SERVICE_NICKNAME diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index b59c9d4..290cf1b 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -12,6 +12,14 @@ class Test(IModule): param_exemple1: str param_exemple2: int + MOD_HEADER: set[str] = { + 'Test', + '1.0.0', + 'The test module', + 'Defender Team', + 'Defender-6' + } + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module diff --git a/mods/votekick/mod_votekick.py b/mods/votekick/mod_votekick.py index cd896be..de65fe9 100644 --- a/mods/votekick/mod_votekick.py +++ b/mods/votekick/mod_votekick.py @@ -15,7 +15,7 @@ import mods.votekick.schemas as schemas import mods.votekick.utils as utils from mods.votekick.votekick_manager import VotekickManager import mods.votekick.threads as thds -from typing import TYPE_CHECKING, Any, Optional +from typing import Any, Optional class Votekick(IModule): @@ -23,6 +23,14 @@ class Votekick(IModule): class ModConfModel(schemas.VoteChannelModel): ... + MOD_HEADER: set[str] = { + 'votekick', + '1.0.2', + 'Channel Democraty', + 'Defender Team', + 'Defender-6' + } + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module From 401e78538342a1e8045cc59606bbfb360a7958f4 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 10 Nov 2025 00:15:53 +0100 Subject: [PATCH 31/56] Remove deprecated class (abstractproperty). --- core/classes/interfaces/imodule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 7860c19..901c3d2 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -1,4 +1,4 @@ -from abc import ABC, abstractmethod, abstractproperty +from abc import ABC, abstractmethod from typing import TYPE_CHECKING, Optional from dataclasses import dataclass from mods.clone.schemas import ModConfModel From 371c8fb5f163bc2219a7f6a3de6a3ec44e8a4d92 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 10 Nov 2025 23:08:18 +0100 Subject: [PATCH 32/56] Exclude modules.txt files from the commit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9f02bfe..dfc11aa 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ configuration_inspircd.json configuration_unreal6.json *.log test.py -users.txt \ No newline at end of file +users.txt +modules.txt \ No newline at end of file From 511e0c0715a1b9c2bdffdb2a30fcd27bcbbd66b8 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 10 Nov 2025 23:09:13 +0100 Subject: [PATCH 33/56] Introduce MOD_HEADER in all modules. impact modules.py, definition.py, unreal6 protocol. --- core/classes/protocols/unreal6.py | 4 ++- core/definition.py | 8 +++++ core/irc.py | 12 ++++++-- core/module.py | 49 ++++++++++++++++++++++++++++--- mods/clone/mod_clone.py | 12 ++++---- mods/command/mod_command.py | 12 ++++---- mods/defender/mod_defender.py | 14 ++++----- mods/jsonrpc/mod_jsonrpc.py | 12 ++++---- mods/test/mod_test.py | 12 ++++---- mods/votekick/mod_votekick.py | 16 +++++----- 10 files changed, 104 insertions(+), 47 deletions(-) diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index e1561ff..28adbe0 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -1029,9 +1029,11 @@ class Unrealircd6(IProtocol): self._Irc.join_saved_channels() self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) + self.send2socket(f":{self._Config.SERVEUR_ID} SMOD :L:Defender:1.0.0 :L:Command:1.0.0") + return None except IndexError as ie: - self._Logs.error(f"{__name__} - Key Error: {ie}") + self._Logs.error(f"{__name__} - Index Error: {ie}") except KeyError as ke: self._Logs.error(f"{__name__} - Key Error: {ke}") except Exception as err: diff --git a/core/definition.py b/core/definition.py index d8a6e05..d7016e3 100644 --- a/core/definition.py +++ b/core/definition.py @@ -349,6 +349,14 @@ class MModule(MainModel): class_name: str = None class_instance: Optional[Any] = None +@dataclass +class DefenderModuleHeader(MainModel): + name: str = '' + version: str = '' + description: str = '' + author: str = '' + core_version: str = '' + @dataclass class MSModule: """Server Modules model""" diff --git a/core/irc.py b/core/irc.py index a4aab8c..43aa828 100644 --- a/core/irc.py +++ b/core/irc.py @@ -125,7 +125,7 @@ class Irc: self.build_command(3, 'core', 'cert', 'Append your new fingerprint to your account!') self.build_command(4, 'core', 'rehash', 'Reload the configuration file without restarting') self.build_command(4, 'core', 'raw', 'Send a raw command directly to the IRC server') - self.build_command(4, 'core', 'print_users', 'Print users in a file.') + self.build_command(4, 'core', 'print_vars', 'Print users in a file.') # Define the IrcSocket object self.IrcSocket: Optional[Union[socket.socket, SSLSocket]] = None @@ -1253,7 +1253,7 @@ class Irc: self.Protocol.send_raw(raw_command) return None - case 'print_users': + case 'print_vars': with open('users.txt', 'w') as fw: i = 1 for u in self.User.UID_DB: @@ -1261,6 +1261,14 @@ class Irc: self.Logs.debug(f" {i} - chars written {w}") i += 1 self.Protocol.send_priv_msg(dnickname, "Data written in users.txt file", dchanlog) + + with open('modules.txt', 'w') as fw: + i = 1 + for u in self.ModuleUtils.DB_MODULE_HEADERS: + w = fw.write(u.to_dict().__str__() + "\n") + self.Logs.debug(f" {i} - chars written {w}") + i += 1 + self.Protocol.send_priv_msg(dnickname, "Data written in modules.txt file", dchanlog) return None diff --git a/core/module.py b/core/module.py index 94f4c72..b1e1596 100644 --- a/core/module.py +++ b/core/module.py @@ -1,12 +1,13 @@ ''' This is the main operational file to handle modules ''' +from optparse import Option from pathlib import Path import sys import importlib from types import ModuleType from typing import TYPE_CHECKING, Optional -from core.definition import MModule +from core.definition import DefenderModuleHeader, MModule if TYPE_CHECKING: from core.loader import Loader @@ -15,6 +16,7 @@ if TYPE_CHECKING: class Module: DB_MODULES: list[MModule] = [] + DB_MODULE_HEADERS: list[DefenderModuleHeader] = [] def __init__(self, loader: 'Loader') -> None: self.__Loader = loader @@ -38,11 +40,46 @@ class Module: if not module_name.lower().startswith('mod_'): return None, None, None - module_name = module_name.lower() + module_name = module_name.lower() # --> mod_defender module_folder = module_name.split('_')[1].lower() # --> defender class_name = module_name.split('_')[1].capitalize() # --> Defender return module_folder, module_name, class_name + def get_module_header(self, module_name: str) -> Optional[DefenderModuleHeader]: + + for mod_h in self.DB_MODULE_HEADERS: + if module_name.lower() == mod_h.name.lower(): + return mod_h + + return None + + def create_module_header(self, module_header: dict[str, str]) -> bool: + """Create a new module header into DB_MODULE_HEADERS + + Args: + module_header (dict[str, str]): The module header + + Returns: + bool: True if the module header has been created. + """ + mod_header = DefenderModuleHeader(**module_header) + if self.get_module_header(mod_header.name) is None: + self.__Logs.debug(f"[MOD_HEADER] The module header has been created! ({mod_header.name} v{mod_header.version})") + self.DB_MODULE_HEADERS.append(mod_header) + return True + + return False + + def delete_module_header(self, module_name: str) -> bool: + mod_header = self.get_module_header(module_name) + if mod_header is not None: + self.__Logs.debug(f"[MOD_HEADER] The module header has been deleted ({mod_header.name} v{mod_header.version})") + self.DB_MODULE_HEADERS.remove(mod_header) + return True + + self.__Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})") + return False + def load_one_module(self, uplink: 'Irc', module_name: str, nickname: str, is_default: bool = False) -> bool: module_folder, module_name, class_name = self.get_module_information(module_name) @@ -70,6 +107,7 @@ class Module: loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe + self.create_module_header(create_instance_of_the_class.MOD_HEADER) except AttributeError as attr: red = uplink.Config.COLORS.red nogc = uplink.Config.COLORS.nogc @@ -124,6 +162,7 @@ class Module: if self.is_module_exist_in_sys_module(module_name): module_model = self.model_get_module(module_name) if module_model: + self.delete_module_header(module_model.class_instance.MOD_HEADER['name']) module_model.class_instance.unload() else: uplink.Protocol.send_priv_msg( @@ -141,6 +180,7 @@ class Module: importlib.reload(the_module) my_class = getattr(the_module, class_name, None) new_instance = my_class(uplink) + self.create_module_header(new_instance.MOD_HEADER) module_model.class_instance = new_instance # Créer le module dans la base de données @@ -163,7 +203,7 @@ class Module: return False except (TypeError, AttributeError, KeyError, Exception) as err: - self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}") + self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True) uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=f"[RELOAD MODULE ERROR]: {err}", @@ -227,6 +267,7 @@ class Module: return False if module: + self.delete_module_header(module.class_instance.MOD_HEADER['name']) module.class_instance.unload() self.DB_MODULES.remove(module) @@ -253,7 +294,7 @@ class Module: return False except Exception as err: - self.__Logs.error(f"General Error: {err}") + self.__Logs.error(f"General Error: {err}", exc_info=True) return False def unload_all_modules(self) -> bool: diff --git a/mods/clone/mod_clone.py b/mods/clone/mod_clone.py index 4eb698f..999dd3b 100644 --- a/mods/clone/mod_clone.py +++ b/mods/clone/mod_clone.py @@ -15,12 +15,12 @@ class Clone(IModule): class ModConfModel(schemas.ModConfModel): ... - MOD_HEADER: set[str] = { - 'Clone', - '1.0.0', - 'Connect thousands of clones to your IRCD, by group. You can use them as security moderation.', - 'Defender Team', - 'Defender-6' + MOD_HEADER: dict[str, str] = { + 'name':'Clone', + 'version':'1.0.0', + 'description':'Connect thousands of clones to your IRCD, by group. You can use them as security moderation.', + 'author':'Defender Team', + 'core_version':'Defender-6' } def create_tables(self) -> None: diff --git a/mods/command/mod_command.py b/mods/command/mod_command.py index 0f74106..083b199 100644 --- a/mods/command/mod_command.py +++ b/mods/command/mod_command.py @@ -14,12 +14,12 @@ class Command(IModule): """ pass - MOD_HEADER: set[str] = { - 'Command', - '1.0.0', - 'Module contains all IRC commands', - 'Defender Team', - 'Defender-6' + MOD_HEADER: dict[str, str] = { + 'name':'Command', + 'version':'1.0.0', + 'description':'Module contains all IRC commands', + 'author':'Defender Team', + 'core_version':'Defender-6' } def create_tables(self) -> None: diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index f42da02..93cf86a 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -12,12 +12,12 @@ class Defender(IModule): class ModConfModel(schemas.ModConfModel): ... - MOD_HEADER: set[str] = { - 'Defender', - '1.0.0', - 'Defender main module that uses the reputation security.', - 'Defender Team', - 'Defender-6' + MOD_HEADER: dict[str, str] = { + 'name':'Defender', + 'version':'1.0.0', + 'description':'Defender main module that uses the reputation security.', + 'author':'Defender Team', + 'core_version':'Defender-6' } def create_tables(self) -> None: @@ -214,12 +214,10 @@ class Defender(IModule): return None case 'UID': - print(f"{self.module_name} - {cmd}") self.Utils.handle_on_uid(self, cmd) return None case 'SJOIN': - self.Utils.handle_on_sjoin(self, cmd) return None diff --git a/mods/jsonrpc/mod_jsonrpc.py b/mods/jsonrpc/mod_jsonrpc.py index 6086d94..bc8fd33 100644 --- a/mods/jsonrpc/mod_jsonrpc.py +++ b/mods/jsonrpc/mod_jsonrpc.py @@ -15,12 +15,12 @@ class Jsonrpc(IModule): """ jsonrpc: int = 0 - MOD_HEADER: set[str] = { - 'JsonRPC', - '1.0.0', - 'Module using the unrealircd-rpc-py library', - 'Defender Team', - 'Defender-6' + MOD_HEADER: dict[str, str] = { + 'name':'JsonRPC', + 'version':'1.0.0', + 'description':'Module using the unrealircd-rpc-py library', + 'author':'Defender Team', + 'core_version':'Defender-6' } def callback_sent_to_irc(self, response: LiveRPCResult) -> None: diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 290cf1b..d3c7aec 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -12,12 +12,12 @@ class Test(IModule): param_exemple1: str param_exemple2: int - MOD_HEADER: set[str] = { - 'Test', - '1.0.0', - 'The test module', - 'Defender Team', - 'Defender-6' + MOD_HEADER: dict[str, str] = { + 'name':'Test', + 'version':'1.0.0', + 'description':'The test module', + 'author':'Defender Team', + 'core_version':'Defender-6' } def create_tables(self) -> None: diff --git a/mods/votekick/mod_votekick.py b/mods/votekick/mod_votekick.py index de65fe9..b6307e6 100644 --- a/mods/votekick/mod_votekick.py +++ b/mods/votekick/mod_votekick.py @@ -23,12 +23,12 @@ class Votekick(IModule): class ModConfModel(schemas.VoteChannelModel): ... - MOD_HEADER: set[str] = { - 'votekick', - '1.0.2', - 'Channel Democraty', - 'Defender Team', - 'Defender-6' + MOD_HEADER: dict[str, str] = { + 'name':'votekick', + 'version':'1.0.2', + 'description':'Channel Democraty', + 'author':'Defender Team', + 'core_version':'Defender-6' } def create_tables(self) -> None: @@ -79,7 +79,6 @@ class Votekick(IModule): if metadata is not None: self.VoteKickManager.VOTE_CHANNEL_DB = metadata - # self.VOTE_CHANNEL_DB = metadata # Créer les nouvelles commandes du module self.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module') @@ -87,7 +86,8 @@ class Votekick(IModule): def unload(self) -> None: try: # Cache the local DB with current votes. - self.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB) + if self.VoteKickManager.VOTE_CHANNEL_DB: + self.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB) for chan in self.VoteKickManager.VOTE_CHANNEL_DB: self.Protocol.send_part_chan(uidornickname=self.Config.SERVICE_ID, channel=chan.channel_name) From 9cee758b6fba056c62c70668e0074a8ec92e98d0 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 10 Nov 2025 23:13:17 +0100 Subject: [PATCH 34/56] Remove unused imported library! --- core/module.py | 1 - 1 file changed, 1 deletion(-) diff --git a/core/module.py b/core/module.py index b1e1596..a73c132 100644 --- a/core/module.py +++ b/core/module.py @@ -1,7 +1,6 @@ ''' This is the main operational file to handle modules ''' -from optparse import Option from pathlib import Path import sys import importlib From 8932e1441a5342af5f3b83cbc866b069e431d958 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 10 Nov 2025 23:38:19 +0100 Subject: [PATCH 35/56] Update docstring of the test module. --- mods/test/mod_test.py | 46 +++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index d3c7aec..480d763 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -1,3 +1,4 @@ +from typing import Any from core.classes.interfaces.imodule import IModule from dataclasses import dataclass @@ -5,7 +6,7 @@ class Test(IModule): @dataclass class ModConfModel: - """The Model containing the module parameters + """The Model containing the module parameters (Mandatory) you can leave it without params. just use pass | if you leave it empty, in the load() method just init empty object ==> self.ModConfig = ModConfModel() """ @@ -19,6 +20,7 @@ class Test(IModule): 'author':'Defender Team', 'core_version':'Defender-6' } + """Module Header (Mandatory)""" def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. @@ -41,7 +43,7 @@ class Test(IModule): return None def load(self) -> None: - """### Load Module Configuration + """### Load Module Configuration (Mandatory) """ # Create module commands (Mandatory) @@ -54,38 +56,48 @@ class Test(IModule): self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) def unload(self) -> None: + """### This method is called when you unload or you reload the module (Mandatory)""" self.Irc.Commands.drop_command_by_module(self.module_name) return None - def cmd(self, data:list) -> None: - try: - cmd = list(data).copy() + def cmd(self, data: list[str]) -> None: + """All messages coming from the IRCD server will be handled using this method (Mandatory) + Args: + data (list): Messages coming from the IRCD server. + """ + cmd = list(data).copy() + try: return None - except KeyError as ke: - self.Logs.error(f"Key Error: {ke}") - except IndexError as ie: - self.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}") except Exception as err: self.Logs.error(f"General Error: {err}") - def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None: + def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: + """All messages coming from the user commands (Mandatory) + + Args: + user (str): The user who send the request. + channel (Any): The channel from where is coming the message (could be None). + cmd (list): The messages coming from the IRCD server. + fullcmd (list, optional): The full messages coming from the IRCD server. Defaults to []. + """ + u = self.User.get_user(user) + c = self.Channel.get_channel(channel) if self.Channel.is_valid_channel(channel) else None + if u is None: + return None command = str(cmd[0]).lower() dnickname = self.Config.SERVICE_NICKNAME - fromuser = user - fromchannel = str(channel) if not channel is None else None match command: case 'test-command': try: + self.Protocol.send_notice(nick_from=dnickname, nick_to=u.nickname, msg="This is a notice to the sender ...") + self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=u.nickname) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This is a notice to the sender ...") - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=fromuser) - - if not fromchannel is None: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=fromchannel) + if c is not None: + self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name) # How to update your module configuration self.update_configuration('param_exemple2', 7) From 999072a88a3b79074638399ac12559834770ad6d Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:47:02 +0100 Subject: [PATCH 36/56] Refactoring unreal6 code! --- core/classes/protocols/unreal6.py | 336 +++++++++++++++--------------- 1 file changed, 165 insertions(+), 171 deletions(-) diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 28adbe0..4886816 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -7,7 +7,6 @@ from core.classes.interfaces.iprotocol import IProtocol from core.utils import tr if TYPE_CHECKING: - from core.classes.modules.sasl import Sasl from core.definition import MClient, MSasl, MUser, MChannel class Unrealircd6(IProtocol): @@ -40,7 +39,7 @@ class Unrealircd6(IProtocol): if log: self._Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") - return (-1, None) + return -1, None def register_command(self) -> None: m = self._Irc.Loader.Definition.MIrcdCommand @@ -595,9 +594,9 @@ class Unrealircd6(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - userObj = self._Irc.User.get_user(uidornickname) + u = self._Irc.User.get_user(uidornickname) - if userObj is None: + if u is None: self._Logs.error(f"The user [{uidornickname}] is not valid") return None @@ -605,10 +604,10 @@ class Unrealircd6(IProtocol): self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{userObj.uid} PART {channel}", print_log=print_log) + self.send2socket(f":{u.uid} PART {channel}", print_log=print_log) # Add defender to the channel uids list - self._Irc.Channel.delete_user_from_channel(channel, userObj.uid) + self._Irc.Channel.delete_user_from_channel(channel, u.uid) return None def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: @@ -631,29 +630,29 @@ class Unrealircd6(IProtocol): # COMMON IRC PARSER # ------------------------------------------------------------------------ - def parse_uid(self, serverMsg: list[str]) -> Optional['MUser']: + def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. >>> ['@s2s-md/geoip=cc=GBtag...', ':001', 'UID', 'albatros', '0', '1721564597', 'albatros', 'hostname...', '001HB8G04', '0', '+iwxz', 'hostname-vhost', 'hostname-vhost', 'MyZBwg==', ':...'] Args: - serverMsg (list[str]): The UID ircd response + server_msg (list[str]): The UID ircd response """ - scopy = serverMsg.copy() + scopy = server_msg.copy() if scopy[0].startswith('@'): scopy.pop(0) uid = scopy[7] return self._User.get_user(uid) - def parse_quit(self, serverMsg: list[str]) -> tuple[Optional['MUser'], str]: + def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> # ['@unrealtag...', ':001JKNY0N', 'QUIT', ':Quit:', '....'] Args: - serverMsg (list[str]): The server message to parse + server_msg (list[str]): The server message to parse Returns: tuple[MUser, str]: The User Who Quit Object and the reason. """ - scopy = serverMsg.copy() + scopy = server_msg.copy() if scopy[0].startswith('@'): scopy.pop(0) @@ -664,19 +663,19 @@ class Unrealircd6(IProtocol): return user_obj, reason - def parse_nick(self, serverMsg: list[str]) -> dict[str, str]: + def parse_nick(self, server_msg: list[str]) -> dict[str, str]: """Parse nick changes and return dictionary. >>> ['@unrealircd.org/geoip=FR;unrealircd.org/', ':001OOU2H3', 'NICK', 'WebIrc', '1703795844'] Args: - serverMsg (list[str]): The server message to parse + server_msg (list[str]): The server message to parse Returns: dict: The response as dictionary. >>> {"uid": "", "newnickname": "", "timestamp": ""} """ - scopy = serverMsg.copy() + scopy = server_msg.copy() if scopy[0].startswith('@'): scopy.pop(0) @@ -687,18 +686,18 @@ class Unrealircd6(IProtocol): } return response - def parse_privmsg(self, serverMsg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: + def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> ['@....', ':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] >>> [':97KAAAAAF', 'PRIVMSG', '98KAAAAAB', ':sasa'] Args: - serverMsg (list[str]): The server message to parse + server_msg (list[str]): The server message to parse Returns: tuple[MUser(Sender), MUser(Reciever), MChannel, str]: Sender user model, reciever user model, Channel model, messgae . """ - scopy = serverMsg.copy() + scopy = server_msg.copy() if scopy[0].startswith('@'): scopy.pop(0) @@ -716,25 +715,25 @@ class Unrealircd6(IProtocol): # HANDLE EVENTS # ##################### - def on_svs2mode(self, serverMsg: list[str]) -> None: + def on_svs2mode(self, server_msg: list[str]) -> None: """Handle svs2mode coming from a server >>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # >> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] + scopy = server_msg.copy() + uid_user_to_edit = scopy[2] + umode = scopy[3] - uid_user_to_edit = serverMsg[2] - umode = serverMsg[3] + u = self._Irc.User.get_user(uid_user_to_edit) - userObj = self._Irc.User.get_user(uid_user_to_edit) - - if userObj is None: + if u is None: return None - if self._Irc.User.update_mode(userObj.uid, umode): + if self._Irc.User.update_mode(u.uid, umode): return None return None @@ -743,38 +742,35 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_mode(self, serverMsg: list[str]) -> None: + def on_mode(self, server_msg: list[str]) -> None: """Handle mode coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ #['@msgid=d0ySx56Yd0nc35oHts2SkC-/J9mVUA1hfM6...', ':001', 'MODE', '#a', '+nt', '1723207536'] #['@unrealircd.org/userhost=adator@localhost;...', ':001LQ0L0C', 'MODE', '#services', '-l'] return None - def on_umode2(self, serverMsg: list[str]) -> None: + def on_umode2(self, server_msg: list[str]) -> None: """Handle umode2 coming from a server >>> [':adator_', 'UMODE2', '-i'] Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # [':adator_', 'UMODE2', '-iwx'] + scopy = server_msg.copy() + u = self._Irc.User.get_user(str(scopy[0]).lstrip(':')) + user_mode = scopy[2] - userObj = self._Irc.User.get_user(str(serverMsg[0]).lstrip(':')) - userMode = serverMsg[2] - - if userObj is None: # If user is not created + if u is None: # If user is not created return None - # save previous user modes - old_umodes = userObj.umodes - # TODO : User object should be able to update user modes - if self._Irc.User.update_mode(userObj.uid, userMode): + if self._Irc.User.update_mode(u.uid, user_mode): return None # self._Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") @@ -785,16 +781,16 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_quit(self, serverMsg: list[str]) -> None: + def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # ['@unrealircd.org/userhost=...@192.168.1.10;unrealircd.org/userip=...@192.168.1.10;msgid=CssUrV08BzekYuq7BfvPHn;time=2024-11-02T15:03:33.182Z', ':001JKNY0N', 'QUIT', ':Quit:', '....'] - - uid_who_quit = str(serverMsg[1]).lstrip(':') + scopy = server_msg.copy() + uid_who_quit = str(scopy[1]).lstrip(':') self._Irc.Channel.delete_user_from_all_channel(uid_who_quit) self._Irc.User.delete(uid_who_quit) @@ -809,15 +805,15 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_squit(self, serverMsg: list[str]) -> None: + def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ # ['@msgid=QOEolbRxdhpVW5c8qLkbAU;time=2024-09-21T17:33:16.547Z', 'SQUIT', 'defender.deb.biz.st', ':Connection', 'closed'] - - server_hostname = serverMsg[2] + scopy = server_msg.copy() + server_hostname = scopy[2] uid_to_delete = None for s_user in self._Irc.User.UID_DB: if s_user.hostname == server_hostname and 'S' in s_user.umodes: @@ -831,19 +827,19 @@ class Unrealircd6(IProtocol): return None - def on_protoctl(self, serverMsg: list[str]) -> None: + def on_protoctl(self, server_msg: list[str]) -> None: """Handle protoctl coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ # ['PROTOCTL', 'CHANMODES=beI,fkL,lFH,cdimnprstzCDGKMNOPQRSTVZ', 'USERMODES=diopqrstwxzBDGHIRSTWZ', 'BOOTED=1728815798', 'PREFIX=(qaohv)~&@%+', 'SID=001', 'MLOCK', 'TS=1730662755', 'EXTSWHOIS'] - user_modes: str = None - prefix: str = None - host_server_id: str = None + user_modes: Optional[str] = None + prefix: Optional[str] = None + host_server_id: Optional[str] = None + + for msg in server_msg: - for msg in serverMsg: - pattern = None if msg.startswith('PREFIX='): pattern = r'^PREFIX=\((.*)\).*$' find_match = match(pattern, msg) @@ -855,6 +851,7 @@ class Unrealircd6(IProtocol): pattern = r'^USERMODES=(.*)$' find_match = match(pattern, msg) user_modes = find_match.group(1) if find_match else None + elif msg.startswith('SID='): host_server_id = msg.split('=')[1] @@ -867,19 +864,19 @@ class Unrealircd6(IProtocol): return None - def on_nick(self, serverMsg: list[str]) -> None: + def on_nick(self, server_msg: list[str]) -> None: """Handle nick coming from a server new nickname Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # ['@unrealircd.org/geoip=FR;unrealircd.org/', ':001OOU2H3', 'NICK', 'WebIrc', '1703795844'] # Changement de nickname - uid = str(serverMsg[1]).lstrip(':') - newnickname = serverMsg[3] + uid = str(server_msg[1]).lstrip(':') + newnickname = server_msg[3] self._Irc.User.update_nickname(uid, newnickname) self._Irc.Client.update_nickname(uid, newnickname) self._Irc.Admin.update_nickname(uid, newnickname) @@ -892,11 +889,11 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_sjoin(self, serverMsg: list[str]) -> None: + def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # ['@msgid=5sTwGdj349D82L96p749SY;time=2024-08-15T09:50:23.528Z', ':001', 'SJOIN', '1721564574', '#welcome', ':001JD94QH'] @@ -906,28 +903,28 @@ class Unrealircd6(IProtocol): # '001F16WGR', '001X9YMGQ', '*+001DYPFGP', '@00BAAAAAJ', '001AAGOG9', '001FMFVG8', '001DAEEG7', # '&~G:unknown-users', '"~G:websocket-users', '"~G:known-users', '"~G:webirc-users'] # [':00B', 'SJOIN', '1731872579', '#services', '+', ':00BAAAAAB'] - serverMsg_copy = serverMsg.copy() - if serverMsg_copy[0].startswith('@'): - serverMsg_copy.pop(0) + scopy = server_msg.copy() + if scopy[0].startswith('@'): + scopy.pop(0) - channel = str(serverMsg_copy[3]).lower() - len_cmd = len(serverMsg_copy) + channel = str(scopy[3]).lower() + len_cmd = len(scopy) list_users:list = [] occurence = 0 start_boucle = 0 # Trouver le premier user for i in range(len_cmd): - s: list = findall(fr':', serverMsg_copy[i]) + s: list = findall(fr':', scopy[i]) if s: occurence += 1 if occurence == 2: start_boucle = i # Boucle qui va ajouter l'ensemble des users (UID) - for i in range(start_boucle, len(serverMsg_copy)): - parsed_UID = str(serverMsg_copy[i]) - clean_uid = self._Utils.clean_uid(parsed_UID) + for i in range(start_boucle, len(scopy)): + parsed_uid = str(scopy[i]) + clean_uid = self._Utils.clean_uid(parsed_uid) if not clean_uid is None and len(clean_uid) == 9: list_users.append(clean_uid) @@ -945,16 +942,16 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_part(self, serverMsg: list[str]) -> None: + def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # ['@unrealircd.org', ':001EPFBRD', 'PART', '#welcome', ':WEB', 'IRC', 'Paris'] - uid = str(serverMsg[1]).lstrip(':') - channel = str(serverMsg[3]).lower() + uid = str(server_msg[1]).lstrip(':') + channel = str(server_msg[3]).lower() self._Irc.Channel.delete_user_from_channel(channel, uid) return None @@ -963,15 +960,15 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_eos(self, serverMsg: list[str]) -> None: + def on_eos(self, server_msg: list[str]) -> None: """Handle EOS coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # [':001', 'EOS'] - server_msg_copy = serverMsg.copy() + server_msg_copy = server_msg.copy() hsid = str(server_msg_copy[0]).replace(':','') if hsid == self._Config.HSID: if self._Config.DEFENDER_INIT == 1: @@ -1039,15 +1036,15 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_reputation(self, serverMsg: list[str]) -> None: + def on_reputation(self, server_msg: list[str]) -> None: """Handle REPUTATION coming from a server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # :001 REPUTATION 127.0.0.1 118 - server_msg_copy = serverMsg.copy() + server_msg_copy = server_msg.copy() self._Irc.first_connexion_ip = server_msg_copy[2] self._Irc.first_score = 0 @@ -1070,44 +1067,44 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_uid(self, serverMsg: list[str]) -> None: + def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ # ['@s2s-md/geoip=cc=GB|cd=United\\sKingdom|asn=16276|asname=OVH\\sSAS;s2s-md/tls_cipher=TLSv1.3-TLS_CHACHA20_POLY1305_SHA256;s2s-md/creationtime=1721564601', # ':001', 'UID', 'albatros', '0', '1721564597', 'albatros', 'vps-91b2f28b.vps.ovh.net', # '001HB8G04', '0', '+iwxz', 'Clk-A62F1D18.vps.ovh.net', 'Clk-A62F1D18.vps.ovh.net', 'MyZBwg==', ':...'] try: + scopy = server_msg.copy() + is_webirc = True if 'webirc' in scopy[0] else False + is_websocket = True if 'websocket' in scopy[0] else False - isWebirc = True if 'webirc' in serverMsg[0] else False - isWebsocket = True if 'websocket' in serverMsg[0] else False - - uid = str(serverMsg[8]) - nickname = str(serverMsg[3]) - username = str(serverMsg[6]) - hostname = str(serverMsg[7]) - umodes = str(serverMsg[10]) - vhost = str(serverMsg[11]) - remote_ip = '127.0.0.1' if 'S' in umodes else self._Base.decode_ip(str(serverMsg[13])) + uid = str(scopy[8]) + nickname = str(scopy[3]) + username = str(scopy[6]) + hostname = str(scopy[7]) + umodes = str(scopy[10]) + vhost = str(scopy[11]) + remote_ip = '127.0.0.1' if 'S' in umodes else self._Base.decode_ip(str(scopy[13])) # extract realname - realname = ' '.join(serverMsg[14:]).lstrip(':') + realname = ' '.join(scopy[14:]).lstrip(':') # Extract Geoip information pattern = r'^.*geoip=cc=(\S{2}).*$' - geoip_match = match(pattern, serverMsg[0]) + geoip_match = match(pattern, scopy[0]) geoip = geoip_match.group(1) if geoip_match else None # Extract Fingerprint information pattern = r'^.*certfp=([^;]+).*$' - fp_match = match(pattern, serverMsg[0]) + fp_match = match(pattern, scopy[0]) fingerprint = fp_match.group(1) if fp_match else None # Extract tls_cipher information pattern = r'^.*tls_cipher=([^;]+).*$' - tlsc_match = match(pattern, serverMsg[0]) + tlsc_match = match(pattern, scopy[0]) tls_cipher = tlsc_match.group(1) if tlsc_match else None score_connexion = self._Irc.first_score @@ -1122,8 +1119,8 @@ class Unrealircd6(IProtocol): vhost=vhost, fingerprint=fingerprint, tls_cipher=tls_cipher, - isWebirc=isWebirc, - isWebsocket=isWebsocket, + isWebirc=is_webirc, + isWebsocket=is_websocket, remote_ip=remote_ip, geoip=geoip, score_connexion=score_connexion, @@ -1134,9 +1131,9 @@ class Unrealircd6(IProtocol): # Auto Auth admin via fingerprint dnickname = self._Config.SERVICE_NICKNAME dchanlog = self._Config.SERVICE_CHANLOG - GREEN = self._Config.COLORS.green - RED = self._Config.COLORS.red - NOGC = self._Config.COLORS.nogc + green = self._Config.COLORS.green + red = self._Config.COLORS.red + nogc = self._Config.COLORS.nogc # for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): # module.class_instance.cmd(serverMsg) @@ -1144,19 +1141,17 @@ class Unrealircd6(IProtocol): # SASL authentication # ['@s2s-md/..', ':001', 'UID', 'adator__', '0', '1755987444', '...', 'desktop-h1qck20.mshome.net', '001XLTT0U', '0', '+iwxz', '*', 'Clk-EC2256B2.mshome.net', 'rBKAAQ==', ':...'] - uid = serverMsg[8] - nickname = serverMsg[3] sasl_obj = self._Irc.Sasl.get_sasl_obj(uid) if sasl_obj: if sasl_obj.auth_success: self._Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) self.send_priv_msg(nick_from=dnickname, - msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, sasl_obj.username, dnickname), + msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, sasl_obj.username, dnickname), channel=dchanlog) self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) else: self.send_priv_msg(nick_from=dnickname, - msg=tr("[ %sSASL AUTH%s ] - %s provided a wrong password for this username %s", RED, NOGC, nickname, sasl_obj.username), + msg=tr("[ %sSASL AUTH%s ] - %s provided a wrong password for this username %s", red, nogc, nickname, sasl_obj.username), channel=dchanlog) self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) @@ -1169,7 +1164,7 @@ class Unrealircd6(IProtocol): admin = self._Irc.Admin.get_admin(uid) account = admin.account if admin else '' self.send_priv_msg(nick_from=dnickname, - msg=tr("[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, account, dnickname), + msg=tr("[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, account, dnickname), channel=dchanlog) self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) @@ -1179,22 +1174,22 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_privmsg(self, serverMsg: list[str]) -> None: + def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ + srv_msg = server_msg.copy() + cmd = server_msg.copy() try: - srv_msg = serverMsg.copy() - cmd = serverMsg.copy() + # Supprimer la premiere valeur si MTAGS activé if cmd[0].startswith('@'): cmd.pop(0) get_uid_or_nickname = str(cmd[0].replace(':','')) user_trigger = self._Irc.User.get_nickname(get_uid_or_nickname) - dnickname = self._Config.SERVICE_NICKNAME pattern = fr'(:\{self._Config.SERVICE_PREFIX})(.*)$' hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . @@ -1267,46 +1262,47 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True) - def on_server_ping(self, serverMsg: list[str]) -> None: + def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server Args: - serverMsg (list[str]): List of str coming from the server + server_msg (list[str]): List of str coming from the server """ try: - pong = str(serverMsg[1]).replace(':','') + scopy = server_msg.copy() + pong = str(scopy[1]).replace(':','') self.send2socket(f"PONG :{pong}", print_log=False) return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_server(self, serverMsg: list[str]) -> None: + def on_server(self, server_msg: list[str]) -> None: """_summary_ Args: - serverMsg (list[str]): _description_ + server_msg (list[str]): _description_ """ try: # ['SERVER', 'irc.local.org', '1', ':U6100-Fhn6OoE-001', 'Local', 'Server'] - sCopy = serverMsg.copy() - self._Irc.Settings.MAIN_SERVER_HOSTNAME = sCopy[1] + scopy = server_msg.copy() + self._Irc.Settings.MAIN_SERVER_HOSTNAME = scopy[1] except Exception as err: self._Logs.error(f'General Error: {err}') - def on_version(self, serverMsg: list[str]) -> None: + def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server Args: - serverMsg (list[str]): List of str coming from the server + server_msg (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._Utils.clean_uid(serverMsg[1])) + scopy = server_msg.copy() + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(scopy[1])) dnickname = self._Config.SERVICE_NICKNAME - arg = serverMsg[4].replace(':', '') + arg = scopy[4].replace(':', '') if nickname is None: return None @@ -1318,19 +1314,19 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_time(self, serverMsg: list[str]) -> None: + def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor Args: - serverMsg (list[str]): List of str coming from the server + server_msg (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._Utils.clean_uid(serverMsg[1])) + scopy = server_msg.copy() + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(scopy[1])) dnickname = self._Config.SERVICE_NICKNAME - arg = serverMsg[4].replace(':', '') + arg = scopy[4].replace(':', '') current_datetime = self._Utils.get_sdatetime() if nickname is None: @@ -1343,26 +1339,26 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_ping(self, serverMsg: list[str]) -> None: + def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor Args: - serverMsg (list[str]): List of str coming from the server + server_msg (list[str]): List of str coming from the server """ # ['@unrealircd.org/...', ':001INC60B', 'PRIVMSG', '12ZAAAAAB', ':\x01PING', '762382207\x01'] # Réponse a un CTCP VERSION try: - - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(serverMsg[1])) + scopy = server_msg.copy() + nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(scopy[1])) dnickname = self._Config.SERVICE_NICKNAME - arg = serverMsg[4].replace(':', '') + arg = scopy[4].replace(':', '') if nickname is None: - self._Logs.debug(serverMsg) + self._Logs.debug(scopy) return None if arg == '\x01PING': - recieved_unixtime = int(serverMsg[5].replace('\x01','')) + recieved_unixtime = int(scopy[5].replace('\x01','')) current_unixtime = self._Utils.get_unixtime() ping_response = current_unixtime - recieved_unixtime @@ -1372,69 +1368,68 @@ class Unrealircd6(IProtocol): nick_to=nickname, msg=f"\x01PING {ping_response} secs\x01" ) - self._Logs.debug(serverMsg) + self._Logs.debug(scopy) return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_version_msg(self, serverMsg: list[str]) -> None: + def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server \n ex. /version Defender Args: - serverMsg (list[str]): Original message from the server + server_msg (list[str]): Original message from the server """ try: # ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender'] - serverMsg_copy = serverMsg.copy() - if '@' in list(serverMsg_copy[0])[0]: - serverMsg_copy.pop(0) + scopy = server_msg.copy() + if '@' in list(scopy[0])[0]: + scopy.pop(0) - getUser = self._Irc.User.get_user(self._Utils.clean_uid(serverMsg_copy[0])) + u = self._Irc.User.get_user(self._Utils.clean_uid(scopy[0])) - if getUser is None: + if u is None: return None response_351 = f"{self._Config.SERVICE_NAME.capitalize()}-{self._Config.CURRENT_VERSION} {self._Config.SERVICE_HOST} {self.name}" - self.send2socket(f':{self._Config.SERVICE_HOST} 351 {getUser.nickname} {response_351}') + self.send2socket(f':{self._Config.SERVICE_HOST} 351 {u.nickname} {response_351}') modules = self._Irc.ModuleUtils.get_all_available_modules() response_005 = ' | '.join(modules) - self.send2socket(f':{self._Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server') + self.send2socket(f':{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server') response_005 = ''.join(self._Settings.PROTOCTL_USER_MODES) - self.send2socket(f":{self._Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server") + self.send2socket(f":{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server") return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_smod(self, serverMsg: list[str]) -> None: + def on_smod(self, server_msg: list[str]) -> None: """Handle SMOD message coming from the server Args: - serverMsg (list[str]): Original server message + server_msg (list[str]): Original server message """ try: # [':001', 'SMOD', ':L:history_backend_mem:2.0', 'L:channeldb:1.0', 'L:tkldb:1.10', 'L:staff:3.8', 'L:ircops:3.71', ...] - sCopy = serverMsg.copy() - modules = [m.lstrip(':') for m in sCopy[2:]] + scopy = server_msg.copy() + modules = [m.lstrip(':') for m in scopy[2:]] for smod in modules: smod_split = smod.split(':') - sModObj = self._Irc.Loader.Definition.MSModule(type=smod_split[0], name=smod_split[1], version=smod_split[2]) - self._Settings.SMOD_MODULES.append(sModObj) + smodobj = self._Irc.Loader.Definition.MSModule(type=smod_split[0], name=smod_split[1], version=smod_split[2]) + self._Settings.SMOD_MODULES.append(smodobj) except Exception as err: self._Logs.error(f'General Error: {err}') - def on_sasl(self, serverMsg: list[str]) -> Optional['MSasl']: + def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server Args: - serverMsg (list[str]): Original server message - psasl (Sasl): The SASL process object + server_msg (list[str]): Original server message """ try: # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'H', '172.18.128.1', '172.18.128.1'] @@ -1442,6 +1437,7 @@ class Unrealircd6(IProtocol): # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey'] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey=='] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A'] + scopy = server_msg.copy() psasl = self._Irc.Sasl sasl_enabled = False for smod in self._Settings.SMOD_MODULES: @@ -1452,10 +1448,8 @@ class Unrealircd6(IProtocol): if not sasl_enabled: return None - sCopy = serverMsg.copy() - client_uid = sCopy[3] if len(sCopy) >= 6 else None - sasl_obj = None - sasl_message_type = sCopy[4] if len(sCopy) >= 6 else None + client_uid = scopy[3] if len(scopy) >= 6 else None + sasl_message_type = scopy[4] if len(scopy) >= 6 else None psasl.insert_sasl_client(self._Irc.Loader.Definition.MSasl(client_uid=client_uid)) sasl_obj = psasl.get_sasl_obj(client_uid) @@ -1464,22 +1458,22 @@ class Unrealircd6(IProtocol): match sasl_message_type: case 'H': - sasl_obj.remote_ip = str(sCopy[5]) + sasl_obj.remote_ip = str(scopy[5]) sasl_obj.message_type = sasl_message_type return sasl_obj case 'S': sasl_obj.message_type = sasl_message_type - if str(sCopy[5]) in ['PLAIN', 'EXTERNAL']: - sasl_obj.mechanisme = str(sCopy[5]) + if str(scopy[5]) in ['PLAIN', 'EXTERNAL']: + sasl_obj.mechanisme = str(scopy[5]) if sasl_obj.mechanisme == "PLAIN": self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") elif sasl_obj.mechanisme == "EXTERNAL": - if str(sCopy[5]) == "+": + if str(scopy[5]) == "+": return None - sasl_obj.fingerprint = str(sCopy[6]) + sasl_obj.fingerprint = str(scopy[6]) self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") self.on_sasl_authentication_process(sasl_obj) @@ -1487,7 +1481,7 @@ class Unrealircd6(IProtocol): case 'C': if sasl_obj.mechanisme == "PLAIN": - credentials = sCopy[5] + credentials = scopy[5] decoded_credentials = b64decode(credentials).decode() user, username, password = decoded_credentials.split('\0') @@ -1506,7 +1500,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f'General Error: {err}', exc_info=True) - def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool: + def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> None: s = sasl_model if sasl_model: def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: @@ -1553,15 +1547,15 @@ class Unrealircd6(IProtocol): self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") - def on_md(self, serverMsg: list[str]) -> None: + def on_md(self, server_msg: list[str]) -> None: """Handle MD responses [':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...'] Args: - serverMsg (list[str]): The server reply + server_msg (list[str]): The server reply """ try: - scopy = serverMsg.copy() - available_vars = ['creationtime', 'certfp', 'tls_cipher'] + scopy = server_msg.copy() + # available_vars = ['creationtime', 'certfp', 'tls_cipher'] uid = str(scopy[3]) var = str(scopy[4]).lower() @@ -1583,14 +1577,14 @@ class Unrealircd6(IProtocol): except Exception as e: self._Logs.error(f"General Error: {e}") - def on_kick(self, serverMsg: list[str]) -> None: + def on_kick(self, server_msg: list[str]) -> None: """When a user is kicked out from a channel ['@unrealircd.org/issued-by=RPC:admin-for-test@...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User'] Args: - serverMsg (list[str]): The server message + server_msg (list[str]): The server message """ - scopy = serverMsg.copy() + scopy = server_msg.copy() uid = scopy[4] channel = scopy[3] From 10cad7cda651e79cbd36ed8837e1c697c8521380 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:48:20 +0100 Subject: [PATCH 37/56] Refactoring code! --- core/classes/interfaces/imodule.py | 9 ++------- core/utils.py | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 901c3d2..72c0c8c 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -1,7 +1,6 @@ from abc import ABC, abstractmethod from typing import TYPE_CHECKING, Optional from dataclasses import dataclass -from mods.clone.schemas import ModConfModel if TYPE_CHECKING: from core.irc import Irc @@ -89,13 +88,9 @@ class IModule(ABC): @abstractmethod def create_tables(self) -> None: - """ - Method that will create the database if it does not exist. + """Method that will create the database if it does not exist. A single Session for this class will be created, which will be used within this class/module. - Args: - database_name (str): Name of the database (no spaces allowed in the name) - Returns: None: No return is expected """ @@ -119,7 +114,7 @@ class IModule(ABC): """ @abstractmethod - def hcmds(self, user: str, channel: Optional[str], cmd: list, fullcmd: list = []) -> None: + def hcmds(self, user: str, channel: Optional[str], cmd: list[str], fullcmd: Optional[list[str]] = None) -> None: """These are the commands recieved from a client Args: diff --git a/core/utils.py b/core/utils.py index bf2a397..e79752d 100644 --- a/core/utils.py +++ b/core/utils.py @@ -1,15 +1,14 @@ -''' +""" Main utils library. -''' +""" import gc import ssl import socket import sys from pathlib import Path from re import match, sub -from base64 import b64decode from typing import Literal, Optional, Any, TYPE_CHECKING -from datetime import datetime, timedelta, timezone +from datetime import datetime from time import time from random import choice from hashlib import md5, sha3_512 @@ -84,9 +83,9 @@ def get_unixtime() -> int: Returns: int: Current time in seconds since the Epoch (int) """ - cet_offset = timezone(timedelta(hours=2)) - now_cet = datetime.now(cet_offset) - unixtime_cet = int(now_cet.timestamp()) + # cet_offset = timezone(timedelta(hours=2)) + # now_cet = datetime.now(cet_offset) + # unixtime_cet = int(now_cet.timestamp()) return int(time()) def get_sdatetime() -> str: @@ -142,9 +141,9 @@ def create_socket(uplink: 'Irc') -> None: except OSError as oe: uplink.Logs.critical(f"[OS Error]: {oe}") if 'connection refused' in str(oe).lower(): - sys.exit(oe) + sys.exit(oe.__str__()) if oe.errno == 10053: - sys.exit(oe) + sys.exit(oe.__str__()) except AttributeError as ae: uplink.Logs.critical(f"AttributeError: {ae}") @@ -225,9 +224,9 @@ def clean_uid(uid: str) -> Optional[str]: return None pattern = fr'[:|@|%|\+|~|\*]*' - parsed_UID = sub(pattern, '', uid) + parsed_uid = sub(pattern, '', uid) - return parsed_UID + return parsed_uid def hide_sensitive_data(srvmsg: list[str]) -> list[str]: try: From 7dd15f2dac7c016e8f2d59dbdcd4cd8a6855b1f4 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:48:37 +0100 Subject: [PATCH 38/56] Updating translation! --- core/language/fr/core-fr.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/language/fr/core-fr.yaml b/core/language/fr/core-fr.yaml index b49ef8a..725e866 100644 --- a/core/language/fr/core-fr.yaml +++ b/core/language/fr/core-fr.yaml @@ -6,6 +6,12 @@ traduction: trad: "Mot de passe incorrect!" - orig: "%s - %sLoaded%s by %s on %s" trad: "%s - %sChargé%s par %s le %s" + - orig: "Module %s loaded!" + trad: "Module %s chargé!" + - orig: "cmd method is not available in the module (%s)" + trad: "La méthode cmd n'est pas disponible dans le module (%s)" + - orig: "[%sMODULE ERROR%s] Module %s is facing issues! %s" + trad: "[%sMODULE ERREUR%s] Le module %s a rencontré une erreur! %s" - orig: "%s - %sNot Loaded%s" trad: "%s - %sNon chargé%s" - orig: "Successfuly connected to %s" From 6a0d4e2286955c7806832d2df8a3c69ac676cdb9 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 11 Nov 2025 03:49:16 +0100 Subject: [PATCH 39/56] Updating some translation, refactoring the code! --- core/module.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/module.py b/core/module.py index a73c132..7922053 100644 --- a/core/module.py +++ b/core/module.py @@ -7,6 +7,7 @@ import importlib from types import ModuleType from typing import TYPE_CHECKING, Optional from core.definition import DefenderModuleHeader, MModule +from core.utils import tr if TYPE_CHECKING: from core.loader import Loader @@ -32,9 +33,11 @@ class Module: list[str]: List of all module names. """ base_path = Path('mods') - return [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')] + modules_available = [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')] + self.__Logs.debug(f"Modules available: {modules_available}") + return modules_available - def get_module_information(self, module_name: str) -> tuple[str, str, str]: + def get_module_information(self, module_name: str) -> tuple[Optional[str], Optional[str], Optional[str]]: # module_name : mod_defender if not module_name.lower().startswith('mod_'): return None, None, None @@ -42,12 +45,14 @@ class Module: module_name = module_name.lower() # --> mod_defender module_folder = module_name.split('_')[1].lower() # --> defender class_name = module_name.split('_')[1].capitalize() # --> Defender + self.__Logs.debug(f"Module information Folder: {module_folder}, Name: {module_name}, Class: {class_name}") return module_folder, module_name, class_name def get_module_header(self, module_name: str) -> Optional[DefenderModuleHeader]: for mod_h in self.DB_MODULE_HEADERS: if module_name.lower() == mod_h.name.lower(): + self.__Logs.debug(f"Module Header found: {mod_h}") return mod_h return None @@ -112,7 +117,7 @@ class Module: nogc = uplink.Config.COLORS.nogc uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, - msg=f"[{red}MODULE ERROR{nogc}] Module {module_name} is facing issues ! {attr}", + msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr), channel=self.__Config.SERVICE_CHANLOG ) self.__Logs.error(msg=attr, exc_info=True) @@ -121,7 +126,7 @@ class Module: if not hasattr(create_instance_of_the_class, 'cmd'): uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, - msg=f"Module {module_name} ne contient pas de méthode cmd", + msg=tr("cmd method is not available in the module (%s)", module_name), channel=self.__Config.SERVICE_CHANLOG ) self.__Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available") @@ -134,11 +139,14 @@ class Module: self.db_register_module(module_name, nickname, is_default) uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, - msg=f"Module {module_name} chargé", + msg=tr("Module %s loaded!", module_name), channel=self.__Config.SERVICE_CHANLOG ) self.__Logs.debug(f"Module {class_name} has been loaded") + return True + + return False def load_all_modules(self) -> bool: ... @@ -244,7 +252,8 @@ class Module: Args: uplink (Irc): The Irc instance - mod_name (str): Module name ex mod_defender + module_name (str): Module name ex mod_defender + keep_in_db (bool): Keep in database Returns: bool: True if success From 7ffc58d4ff545b7f99b99df04c58a0a199d5df71 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 13:15:49 +0100 Subject: [PATCH 40/56] Trigger a thread clean-up before running a new thread --- core/base.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/base.py b/core/base.py index 2392ebe..590129b 100644 --- a/core/base.py +++ b/core/base.py @@ -324,7 +324,7 @@ class Base: self.logs.error(f'Assertion Error -> {ae}') return None - def create_thread(self, func:object, func_args: tuple = (), run_once:bool = False, daemon: bool = True) -> None: + def create_thread(self, func: object, func_args: tuple = (), run_once: bool = False, daemon: bool = True) -> None: """Create a new thread and store it into running_threads variable Args: @@ -333,6 +333,9 @@ class Base: run_once (bool, optional): If you want to ensure that this method/function run once. Defaults to False. """ try: + # Clean unused threads first + self.garbage_collector_thread() + func_name = func.__name__ if run_once: @@ -346,8 +349,8 @@ class Base: self.running_threads.append(th) self.logs.debug(f"-- Thread ID : {str(th.ident)} | Thread name : {th.name} | Running Threads : {len(threading.enumerate())}") - except AssertionError as ae: - self.logs.error(f'{ae}') + except Exception as err: + self.logs.error(err, exc_info=True) def is_thread_alive(self, thread_name: str) -> bool: """Check if the thread is still running! using the is_alive method of Threads. @@ -424,11 +427,11 @@ class Base: if thread.name != 'heartbeat': if not thread.is_alive(): self.running_threads.remove(thread) - self.logs.info(f"-- Thread {str(thread.name)} {str(thread.native_id)} removed") + self.logs.debug(f"-- Thread {str(thread.name)} {str(thread.native_id)} has been removed!") # print(threading.enumerate()) - except AssertionError as ae: - self.logs.error(f'Assertion Error -> {ae}') + except Exception as err: + self.logs.error(err, exc_info=True) def garbage_collector_sockets(self) -> None: From a3dcc20a0681641945ec6a60922493624f0d96d8 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 13:20:11 +0100 Subject: [PATCH 41/56] Handle SETHOST response to update the vhost of the user --- core/classes/interfaces/iprotocol.py | 15 +++++++++-- core/classes/protocols/inspircd.py | 20 +++++++++------ core/classes/protocols/unreal6.py | 37 +++++++++++++++++----------- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/core/classes/interfaces/iprotocol.py b/core/classes/interfaces/iprotocol.py index 87b921f..704582b 100644 --- a/core/classes/interfaces/iprotocol.py +++ b/core/classes/interfaces/iprotocol.py @@ -335,7 +335,7 @@ class IProtocol(ABC): """ @abstractmethod - def parse_nick(self, server_msg: list[str]) -> dict[str, str]: + def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: """Parse nick changes and return dictionary. >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] @@ -343,7 +343,9 @@ class IProtocol(ABC): server_msg (list[str]): The server message to parse Returns: - dict[str, str]: The response as dictionary. + tuple(MUser, newnickname(str), timestamp(str)): Tuple of the response. + + >>> MUser, newnickname, timestamp """ @abstractmethod @@ -563,3 +565,12 @@ class IProtocol(ABC): Args: server_msg (list[str]): The server message """ + + @abstractmethod + def on_sethost(self, server_msg: list[str]) -> None: + """On SETHOST command + >>> [':001DN7305', 'SETHOST', ':netadmin.example.org'] + + Args: + server_msg (list[str]): _description_ + """ \ No newline at end of file diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index 7ff0e54..52704af 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -1219,7 +1219,7 @@ class Inspircd(IProtocol): return user_obj, reason - def parse_nick(self, server_msg: list[str]) -> dict[str, str]: + def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: """Parse nick changes. >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] @@ -1233,12 +1233,10 @@ class Inspircd(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - response = { - "uid": scopy[0].replace(':', ''), - "newnickname": scopy[2], - "timestamp": scopy[3] - } - return response + user_obj = self._User.get_user(self._User.clean_uid(scopy[0])) + newnickname = scopy[2] + timestamp = scopy[3] + return user_obj, newnickname, timestamp def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. @@ -1412,3 +1410,11 @@ class Inspircd(IProtocol): server_msg (list[str]): Original server message """ ... + + def on_sethost(self, server_msg: list[str]) -> None: + """On SETHOST command + + Args: + server_msg (list[str]): _description_ + """ + ... diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 4886816..4f53a7e 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -19,8 +19,7 @@ class Unrealircd6(IProtocol): 'VERSION', 'REPUTATION', 'SVS2MODE', 'SLOG', 'NICK', 'PART', 'PONG', 'SASL', 'PING', 'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO', - '006', '007', '018'} - + 'SETHOST', '006', '007', '018'} def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]: """Get the position of known commands @@ -62,6 +61,7 @@ class Unrealircd6(IProtocol): self.Handler.register(m(command_name="MD", func=self.on_md)) self.Handler.register(m(command_name="PRIVMSG", func=self.on_privmsg)) self.Handler.register(m(command_name="KICK", func=self.on_kick)) + self.Handler.register(m(command_name="SETHOST", func=self.on_sethost)) return None @@ -663,7 +663,7 @@ class Unrealircd6(IProtocol): return user_obj, reason - def parse_nick(self, server_msg: list[str]) -> dict[str, str]: + def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: """Parse nick changes and return dictionary. >>> ['@unrealircd.org/geoip=FR;unrealircd.org/', ':001OOU2H3', 'NICK', 'WebIrc', '1703795844'] @@ -671,20 +671,18 @@ class Unrealircd6(IProtocol): server_msg (list[str]): The server message to parse Returns: - dict: The response as dictionary. + tuple(MUser, newnickname(str), timestamp(str)): Tuple of the response. - >>> {"uid": "", "newnickname": "", "timestamp": ""} + >>> MUser, newnickname, timestamp """ scopy = server_msg.copy() if scopy[0].startswith('@'): scopy.pop(0) - response = { - "uid": scopy[0].replace(':', ''), - "newnickname": scopy[2], - "timestamp": scopy[3] - } - return response + user_obj = self._User.get_user(self._User.clean_uid(scopy[0])) + newnickname = scopy[2] + timestamp = scopy[3] + return user_obj, newnickname, timestamp def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. @@ -772,7 +770,6 @@ class Unrealircd6(IProtocol): # TODO : User object should be able to update user modes if self._Irc.User.update_mode(u.uid, user_mode): return None - # self._Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") return None @@ -1573,7 +1570,6 @@ class Unrealircd6(IProtocol): case _: return None - ... except Exception as e: self._Logs.error(f"General Error: {e}") @@ -1590,4 +1586,17 @@ class Unrealircd6(IProtocol): # Delete the user from the channel. self._Irc.Channel.delete_user_from_channel(channel, uid) - return None \ No newline at end of file + return None + + def on_sethost(self, server_msg: list[str]) -> None: + """On SETHOST command + >>> [':001DN7305', 'SETHOST', ':netadmin.example.org'] + + Args: + server_msg (list[str]): _description_ + """ + scopy = server_msg.copy() + uid = self._User.clean_uid(scopy[0]) + vhost = scopy[2].lstrip(':') + user = self._User.get_user(uid) + user.vhost = vhost From fc01de34b2f61e083dd685506934c0aa62153bb2 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 13:21:57 +0100 Subject: [PATCH 42/56] Adding new debug messages when module exist or not --- core/module.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/module.py b/core/module.py index 7922053..199b713 100644 --- a/core/module.py +++ b/core/module.py @@ -319,7 +319,9 @@ class Module: """ module_folder, module_name, class_name = self.get_module_information(module_name) if "mods." + module_folder + "." + module_name in sys.modules: + self.__Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) found in sys.modules") return True + self.__Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules") return False ''' From ba989b7f265e20794178245bb95d0697c6a5ee20 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 13:22:33 +0100 Subject: [PATCH 43/56] Update debug message. --- core/classes/interfaces/imodule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 72c0c8c..95a8e47 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -69,7 +69,7 @@ class IModule(ABC): uplink.Base.db_sync_core_config(self.module_name, self.ModConfig) # Log the module - self.Logs.debug(f'Module {self.module_name} loaded ...') + self.Logs.debug(f'Loading Module {self.module_name} ...') def update_configuration(self, param_key: str, param_value: str) -> None: """Update the local and core configuration From 2e422c93e5ef49efd9ab4045c03b647ea7989cba Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 13:35:09 +0100 Subject: [PATCH 44/56] Base.py refactoring. Nothing fancy. --- core/base.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/base.py b/core/base.py index 590129b..fbb404a 100644 --- a/core/base.py +++ b/core/base.py @@ -26,7 +26,8 @@ class Base: self.Utils = loader.Utils self.logs = loader.Logs - self.check_for_new_version(True) # Verifier si une nouvelle version est disponible + # Check if new Defender version is available + self.check_for_new_version(True) # Liste des timers en cours self.running_timers: list[threading.Timer] = self.Settings.RUNNING_TIMERS @@ -43,9 +44,14 @@ class Base: # 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 - # self.__create_db() # Initialisation de la base de données + # Init install variable + self.install: bool = False + + # Init database connection + self.engine, self.cursor = self.db_init() + + # Create the database + # self.__create_db() def init(self) -> None: self.__create_db() From c37191006619646b537901fc5c4ee06e5ee12f2a Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:13:26 +0100 Subject: [PATCH 45/56] Creating JSONRPC Server --- core/classes/modules/rehash.py | 7 +- core/classes/modules/rpc/rpc.py | 240 ++++++++++++++++++++++++ core/classes/modules/rpc/rpc_channel.py | 12 ++ core/classes/modules/rpc/rpc_command.py | 21 +++ core/classes/modules/rpc/rpc_user.py | 30 +++ core/definition.py | 9 +- core/irc.py | 10 +- core/loader.py | 5 + core/utils.py | 14 +- defender.py | 2 +- mods/defender/utils.py | 11 +- 11 files changed, 347 insertions(+), 14 deletions(-) create mode 100644 core/classes/modules/rpc/rpc.py create mode 100644 core/classes/modules/rpc/rpc_channel.py create mode 100644 core/classes/modules/rpc/rpc_command.py create mode 100644 core/classes/modules/rpc/rpc_user.py diff --git a/core/classes/modules/rehash.py b/core/classes/modules/rehash.py index aa842f8..6b96998 100644 --- a/core/classes/modules/rehash.py +++ b/core/classes/modules/rehash.py @@ -14,6 +14,7 @@ REHASH_MODULES = [ 'core.classes.modules.config', 'core.base', 'core.classes.modules.commands', + 'core.classes.modules.rpc', 'core.classes.interfaces.iprotocol', 'core.classes.interfaces.imodule', 'core.classes.protocols.command_handler', @@ -69,6 +70,8 @@ def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") - def rehash_service(uplink: 'Irc', nickname: str) -> None: need_a_restart = ["SERVEUR_ID"] uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS) + uplink.Loader.RpcServer.stop_server() + restart_flag = False config_model_bakcup = uplink.Config mods = REHASH_MODULES @@ -80,7 +83,7 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None: channel=uplink.Config.SERVICE_CHANLOG ) uplink.Utils = sys.modules['core.utils'] - uplink.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model + uplink.Config = uplink.Loader.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model uplink.Config.HSID = config_model_bakcup.HSID uplink.Config.DEFENDER_INIT = config_model_bakcup.DEFENDER_INIT uplink.Config.DEFENDER_RESTART = config_model_bakcup.DEFENDER_RESTART @@ -113,6 +116,8 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None: # Reload Main Commands Module uplink.Commands = uplink.Loader.CommandModule.Command(uplink.Loader) + uplink.Loader.RpcServer = uplink.Loader.RpcServerModule.JSONRPCServer(uplink.Loader) + uplink.Loader.RpcServer.start_server() uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands') uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader) diff --git a/core/classes/modules/rpc/rpc.py b/core/classes/modules/rpc/rpc.py new file mode 100644 index 0000000..95170a0 --- /dev/null +++ b/core/classes/modules/rpc/rpc.py @@ -0,0 +1,240 @@ +import base64 +import json +import logging +from enum import Enum +from http.server import BaseHTTPRequestHandler, HTTPServer +from typing import TYPE_CHECKING, Any, Optional +from core.classes.modules.rpc.rpc_user import RPCUser +from core.classes.modules.rpc.rpc_channel import RPCChannel +from core.classes.modules.rpc.rpc_command import RPCCommand + +if TYPE_CHECKING: + from core.loader import Loader + +ProxyLoader: Optional['Loader'] = None + +class RPCRequestHandler(BaseHTTPRequestHandler): + + def log_message(self, format, *args): + pass + + def do_POST(self): + logs = ProxyLoader.Logs + self.server_version = 'Defender6' + self.sys_version = ProxyLoader.Config.CURRENT_VERSION + content_length = int(self.headers['Content-Length']) + body = self.rfile.read(content_length) + request_data: dict = json.loads(body) + rip, rport = self.client_address + + if not self.authenticate(request_data): + return None + + response_data = { + 'jsonrpc': '2.0', + 'id': request_data.get('id', 123) + } + + method = request_data.get("method") + params: dict[str, Any] = request_data.get("params", {}) + response_data['method'] = method + http_code = 200 + + match method: + case 'user.list': + user = RPCUser(ProxyLoader) + response_data['result'] = user.user_list() + logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') + del user + + case 'user.get': + user = RPCUser(ProxyLoader) + uid_or_nickname = params.get('uid_or_nickname', None) + response_data['result'] = user.user_get(uid_or_nickname) + logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') + del user + + case 'channel.list': + channel = RPCChannel(ProxyLoader) + response_data['result'] = channel.channel_list() + logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') + del channel + + case 'command.list': + command = RPCCommand(ProxyLoader) + response_data['result'] = command.command_list() + logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') + del command + + case 'command.get.by.module': + command = RPCCommand(ProxyLoader) + module_name = params.get('name', None) + response_data['result'] = command.command_get_by_module(module_name) + logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') + del command + + case 'command.get.by.name': + command = RPCCommand(ProxyLoader) + command_name = params.get('name', None) + response_data['result'] = command.command_get_by_name(command_name) + logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') + del command + + case _: + response_data['error'] = create_error_response(JSONRPCErrorCode.METHOD_NOT_FOUND) + logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}') + http_code = 404 + + self.send_response(http_code) + self.send_header('Content-Type', 'application/json') + self.end_headers() + self.wfile.write(json.dumps(response_data).encode('utf-8')) + + return None + + def do_GET(self): + self.server_version = 'Defender6' + self.sys_version = ProxyLoader.Config.CURRENT_VERSION + content_length = int(self.headers['Content-Length']) + body = self.rfile.read(content_length) + request_data: dict = json.loads(body) + + if not self.authenticate(request_data): + return None + + response_data = {'jsonrpc': '2.0', 'id': request_data.get('id', 321), + 'error': create_error_response(JSONRPCErrorCode.INVALID_REQUEST)} + + self.send_response(404) + self.send_header('Content-Type', 'application/json') + self.end_headers() + self.wfile.write(json.dumps(response_data).encode('utf-8')) + + return None + + + def authenticate(self, request_data: dict) -> bool: + logs = ProxyLoader.Logs + auth = self.headers.get('Authorization', None) + if auth is None: + self.send_auth_error(request_data) + return False + + # Authorization header format: Basic base64(username:password) + auth_type, auth_string = auth.split(' ', 1) + if auth_type.lower() != 'basic': + self.send_auth_error(request_data) + return False + + try: + # Decode the base64-encoded username:password + decoded_credentials = base64.b64decode(auth_string).decode('utf-8') + username, password = decoded_credentials.split(":", 1) + + # Check the username and password. + for rpcuser in ProxyLoader.Irc.Config.RPC_USERS: + if rpcuser.get('USERNAME', None) == username and rpcuser.get('PASSWORD', None) == password: + return True + + self.send_auth_error(request_data) + return False + + except Exception as e: + self.send_auth_error(request_data) + logs.error(e) + return False + + def send_auth_error(self, request_data: dict) -> None: + + response_data = { + 'jsonrpc': '2.0', + 'id': request_data.get('id', 123), + 'error': create_error_response(JSONRPCErrorCode.AUTHENTICATION_ERROR) + } + + self.send_response(401) + self.send_header('WWW-Authenticate', 'Basic realm="Authorization Required"') + self.end_headers() + self.wfile.write(json.dumps(response_data).encode('utf-8')) + +class JSONRPCServer: + def __init__(self, loader: 'Loader'): + global ProxyLoader + + ProxyLoader = loader + self._Loader = loader + self._Base = loader.Base + self._Logs = loader.Logs + self.rpc_server: Optional[HTTPServer] = None + self.connected: bool = False + + def start_server(self, server_class=HTTPServer, handler_class=RPCRequestHandler, *, hostname: str = 'localhost', port: int = 5000): + logging.getLogger('http.server').setLevel(logging.CRITICAL) + server_address = (hostname, port) + self.rpc_server = server_class(server_address, handler_class) + self._Logs.debug(f"Server ready on http://{hostname}:{port}...") + self._Base.create_thread(self.thread_start_rpc_server, (), True) + + def thread_start_rpc_server(self) -> None: + self._Loader.Irc.Protocol.send_priv_msg( + self._Loader.Config.SERVICE_NICKNAME, "Defender RPC Server has started successfuly!", self._Loader.Config.SERVICE_CHANLOG + ) + self.connected = True + self.rpc_server.serve_forever() + ProxyLoader.Logs.debug(f"RPC Server down!") + + def stop_server(self): + self._Base.create_thread(self.thread_stop_rpc_server) + + def thread_stop_rpc_server(self): + self.rpc_server.shutdown() + ProxyLoader.Logs.debug(f"RPC Server shutdown!") + self.rpc_server.server_close() + ProxyLoader.Logs.debug(f"RPC Server clean-up!") + self._Base.garbage_collector_thread() + self._Loader.Irc.Protocol.send_priv_msg( + self._Loader.Config.SERVICE_NICKNAME, "Defender RPC Server has stopped successfuly!", self._Loader.Config.SERVICE_CHANLOG + ) + self.connected = False + +class JSONRPCErrorCode(Enum): + PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON) + INVALID_REQUEST = -32600 # Invalid Request (incorrect structure or missing fields) + METHOD_NOT_FOUND = -32601 # Method not found (the requested method does not exist) + INVALID_PARAMS = -32602 # Invalid Params (the parameters provided are incorrect) + INTERNAL_ERROR = -32603 # Internal Error (an internal server error occurred) + + # Custom application-specific errors (beyond standard JSON-RPC codes) + CUSTOM_ERROR = 1001 # Custom application-defined error (e.g., user not found) + AUTHENTICATION_ERROR = 1002 # Authentication failure (e.g., invalid credentials) + PERMISSION_ERROR = 1003 # Permission error (e.g., user does not have access to this method) + RESOURCE_NOT_FOUND = 1004 # Resource not found (e.g., the requested resource does not exist) + DUPLICATE_REQUEST = 1005 # Duplicate request (e.g., a similar request has already been processed) + + def description(self): + """Returns a description associated with each error code""" + descriptions = { + JSONRPCErrorCode.PARSE_ERROR: "The JSON request is malformed.", + JSONRPCErrorCode.INVALID_REQUEST: "The request is invalid (missing or incorrect fields).", + JSONRPCErrorCode.METHOD_NOT_FOUND: "The requested method could not be found.", + JSONRPCErrorCode.INVALID_PARAMS: "The parameters provided are invalid.", + JSONRPCErrorCode.INTERNAL_ERROR: "An internal error occurred on the server.", + JSONRPCErrorCode.CUSTOM_ERROR: "A custom error defined by the application.", + JSONRPCErrorCode.AUTHENTICATION_ERROR: "User authentication failed.", + JSONRPCErrorCode.PERMISSION_ERROR: "User does not have permission to access this method.", + JSONRPCErrorCode.RESOURCE_NOT_FOUND: "The requested resource could not be found.", + JSONRPCErrorCode.DUPLICATE_REQUEST: "The request is a duplicate or is already being processed.", + } + return descriptions.get(self, "Unknown error") + +def create_error_response(error_code: JSONRPCErrorCode, details: dict = None) -> dict[str, str]: + """Create a JSON-RPC error!""" + response = { + "code": error_code.value, + "message": error_code.description(), + } + + if details: + response["data"] = details + + return response \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_channel.py b/core/classes/modules/rpc/rpc_channel.py new file mode 100644 index 0000000..e45e782 --- /dev/null +++ b/core/classes/modules/rpc/rpc_channel.py @@ -0,0 +1,12 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from core.loader import Loader + +class RPCChannel: + def __init__(self, loader: 'Loader'): + self._Loader = loader + self._Channel = loader.Channel + + def channel_list(self) -> list[dict]: + return [chan.to_dict() for chan in self._Channel.UID_CHANNEL_DB] \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_command.py b/core/classes/modules/rpc/rpc_command.py new file mode 100644 index 0000000..1c2025d --- /dev/null +++ b/core/classes/modules/rpc/rpc_command.py @@ -0,0 +1,21 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from core.loader import Loader + +class RPCCommand: + def __init__(self, loader: 'Loader'): + self._Loader = loader + self._Command = loader.Commands + + def command_list(self) -> list[dict]: + return [command.to_dict() for command in self._Command.DB_COMMANDS] + + def command_get_by_module(self, module_name: str) -> list[dict]: + return [command.to_dict() for command in self._Command.DB_COMMANDS if command.module_name.lower() == module_name.lower()] + + def command_get_by_name(self, command_name: str) -> dict: + for command in self._Command.DB_COMMANDS: + if command.command_name.lower() == command_name.lower(): + return command.to_dict() + return {} \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_user.py b/core/classes/modules/rpc/rpc_user.py new file mode 100644 index 0000000..b9e014b --- /dev/null +++ b/core/classes/modules/rpc/rpc_user.py @@ -0,0 +1,30 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from core.loader import Loader + from core.definition import MUser + +class RPCUser: + def __init__(self, loader: 'Loader'): + self._Loader = loader + self._User = loader.User + + def user_list(self) -> list[dict]: + users = self._User.UID_DB.copy() + copy_users: list['MUser'] = [] + + for user in users: + copy_user = user.copy() + copy_user.connexion_datetime = copy_user.connexion_datetime.strftime('%d-%m-%Y') + copy_users.append(copy_user) + + return [user.to_dict() for user in copy_users] + + def user_get(self, uidornickname: str) -> Optional[dict]: + user = self._User.get_user(uidornickname) + if user: + user_copy = user.copy() + user_copy.connexion_datetime = user_copy.connexion_datetime.strftime('%d-%m-%Y') + return user_copy.to_dict() + + return None \ No newline at end of file diff --git a/core/definition.py b/core/definition.py index d7016e3..72f9062 100644 --- a/core/definition.py +++ b/core/definition.py @@ -1,6 +1,6 @@ from datetime import datetime from json import dumps -from dataclasses import dataclass, field, asdict, fields +from dataclasses import dataclass, field, asdict, fields, replace from typing import Literal, Any, Optional from os import sep @@ -14,6 +14,10 @@ class MainModel: def to_json(self) -> str: """Return the object of a dataclass a json str.""" return dumps(self.to_dict()) + + def copy(self): + """Return the object of a dataclass a json str.""" + return replace(self) def get_attributes(self) -> list[str]: """Return a list of attributes name""" @@ -205,6 +209,9 @@ class MConfig(MainModel): PASSWORD: str = "password" """The password of the admin of the service""" + RPC_USERS: list[dict] = field(default_factory=list) + """The Defender rpc users""" + JSONRPC_URL: str = None """The RPC url, if local https://127.0.0.1:PORT/api should be fine""" diff --git a/core/irc.py b/core/irc.py index 43aa828..18a8fbe 100644 --- a/core/irc.py +++ b/core/irc.py @@ -126,6 +126,8 @@ class Irc: self.build_command(4, 'core', 'rehash', 'Reload the configuration file without restarting') self.build_command(4, 'core', 'raw', 'Send a raw command directly to the IRC server') self.build_command(4, 'core', 'print_vars', 'Print users in a file.') + self.build_command(4, 'core', 'start_rpc', 'Start defender jsonrpc server') + self.build_command(4, 'core', 'stop_rpc', 'Stop defender jsonrpc server') # Define the IrcSocket object self.IrcSocket: Optional[Union[socket.socket, SSLSocket]] = None @@ -372,7 +374,7 @@ class Irc: return uptime - def heartbeat(self, beat:float) -> None: + def heartbeat(self, beat: float) -> None: """Execute certaines commandes de nettoyage toutes les x secondes x étant définit a l'initialisation de cette class (self.beat) @@ -1272,5 +1274,11 @@ class Irc: return None + case 'start_rpc': + self.Loader.RpcServer.start_server() + + case 'stop_rpc': + self.Loader.RpcServer.stop_server() + case _: pass diff --git a/core/loader.py b/core/loader.py index 8cdbfd8..c254552 100644 --- a/core/loader.py +++ b/core/loader.py @@ -8,6 +8,7 @@ import core.base as base_mod import core.module as module_mod import core.classes.modules.commands as commands_mod import core.classes.modules.config as conf_mod +import core.classes.modules.rpc.rpc as rpc_mod import core.irc as irc import core.classes.protocols.factory as factory @@ -26,6 +27,8 @@ class Loader: self.LoggingModule: logs = logs + self.RpcServerModule: rpc_mod = rpc_mod + self.Utils: utils = utils # Load Classes @@ -69,6 +72,8 @@ class Loader: self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc) + self.RpcServer: rpc_mod.JSONRPCServer = rpc_mod.JSONRPCServer(self) + self.Base.init() self.Logs.debug(self.Utils.tr("Loader %s success", __name__)) diff --git a/core/utils.py b/core/utils.py index e79752d..0abd02d 100644 --- a/core/utils.py +++ b/core/utils.py @@ -177,7 +177,7 @@ def generate_random_string(lenght: int) -> str: return randomize -def hash_password(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') -> str: +def hash_password(password: str, algorithm: Literal["md5", "sha3_512"] = 'md5') -> str: """Return the crypted password following the selected algorithm Args: @@ -190,16 +190,16 @@ def hash_password(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') -> match algorithm: case 'md5': - password = md5(password.encode()).hexdigest() - return password + hashed_password = md5(password.encode()).hexdigest() + return hashed_password case 'sha3_512': - password = sha3_512(password.encode()).hexdigest() - return password + hashed_password = sha3_512(password.encode()).hexdigest() + return hashed_password case _: - password = md5(password.encode()).hexdigest() - return password + hashed_password = md5(password.encode()).hexdigest() + return hashed_password def get_all_modules() -> list[str]: """Get list of all main modules diff --git a/defender.py b/defender.py index 6fc06f2..da46ad4 100644 --- a/defender.py +++ b/defender.py @@ -10,7 +10,7 @@ from core import install ############################################# try: - install.update_packages() + # install.update_packages() from core.loader import Loader loader = Loader() loader.Irc.init_irc() diff --git a/mods/defender/utils.py b/mods/defender/utils.py index d0be159..a930600 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -152,8 +152,13 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): confmodel (ModConfModel): The Module Configuration """ p = uplink.Protocol - parser = p.parse_nick(srvmsg) - uid = uplink.Loader.Utils.clean_uid(parser.get('uid', None)) + u, new_nickname, timestamp = p.parse_nick(srvmsg) + + if u is None: + uplink.Logs.error(f"[USER OBJ ERROR {timestamp}] - {srvmsg}") + return None + + uid = u.uid confmodel = uplink.ModConfig get_reputation = uplink.Reputation.get_reputation(uid) @@ -166,7 +171,7 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): # Update the new nickname oldnick = get_reputation.nickname - newnickname = parser.get('newnickname', None) + newnickname = new_nickname get_reputation.nickname = newnickname # If ban in all channel is ON then unban old nickname an ban the new nickname From 3926d7270d3d009f217d059d9d566668cf0f05ef Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Sun, 16 Nov 2025 22:09:40 +0100 Subject: [PATCH 46/56] First commit asyncio --- core/classes/interfaces/iprotocol.py | 110 +++++----- core/classes/protocols/unreal6.py | 278 ++++++++++++------------ core/irc.py | 88 +++++--- core/logs.py | 2 +- core/module.py | 16 +- defender.py | 27 ++- mods/defender/mod_defender.py | 310 +++++++++++++-------------- mods/votekick/utils.py | 6 +- 8 files changed, 443 insertions(+), 394 deletions(-) diff --git a/core/classes/interfaces/iprotocol.py b/core/classes/interfaces/iprotocol.py index 704582b..7c7ad3b 100644 --- a/core/classes/interfaces/iprotocol.py +++ b/core/classes/interfaces/iprotocol.py @@ -53,7 +53,7 @@ class IProtocol(ABC): """ @abstractmethod - def send2socket(self, message: str, print_log: bool = True) -> None: + async def send2socket(self, message: str, print_log: bool = True) -> None: """Envoit les commandes à envoyer au serveur. Args: @@ -62,7 +62,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): + async def send_priv_msg(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: @@ -73,7 +73,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: + async def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: """Sending NOTICE by batches Args: @@ -83,13 +83,13 @@ class IProtocol(ABC): """ @abstractmethod - def send_link(self) -> None: + async def send_link(self) -> None: """Créer le link et envoyer les informations nécessaires pour la connexion au serveur. """ @abstractmethod - def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + async def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: """Send a gline command to the server Args: @@ -102,7 +102,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_set_nick(self, newnickname: str) -> None: + async def send_set_nick(self, newnickname: str) -> None: """Change nickname of the server \n This method will also update the User object Args: @@ -110,7 +110,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: + async def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: """Set a mode to channel or to a nickname or for a user in a channel Args: @@ -121,7 +121,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_squit(self, server_id: str, server_link: str, reason: str) -> None: + async def send_squit(self, server_id: str, server_link: str, reason: str) -> None: """_summary_ Args: @@ -131,7 +131,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_ungline(self, nickname:str, hostname: str) -> None: + async def send_ungline(self, nickname:str, hostname: str) -> None: """_summary_ Args: @@ -140,7 +140,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + async def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: """_summary_ Args: @@ -153,7 +153,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_unkline(self, nickname:str, hostname: str) -> None: + async def send_unkline(self, nickname:str, hostname: str) -> None: """_summary_ Args: @@ -162,7 +162,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_sjoin(self, channel: str) -> None: + async def send_sjoin(self, channel: str) -> None: """Server will join a channel with pre defined umodes Args: @@ -170,7 +170,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: + async def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: """_summary_ Args: @@ -179,7 +179,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: + async def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: """_summary_ Args: @@ -188,7 +188,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: + async def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: """_summary_ Args: @@ -198,7 +198,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: + async def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: """_summary_ Args: @@ -208,7 +208,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_svsmode(self, nickname: str, user_mode: str) -> None: + async def send_svsmode(self, nickname: str, user_mode: str) -> None: """_summary_ Args: @@ -217,7 +217,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_svs2mode(self, nickname: str, user_mode: str) -> None: + async def send_svs2mode(self, nickname: str, user_mode: str) -> None: """_summary_ Args: @@ -226,7 +226,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_svslogin(self, client_uid: str, user_account: str) -> None: + async def send_svslogin(self, client_uid: str, user_account: str) -> None: """Log a client into his account. Args: @@ -235,7 +235,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_svslogout(self, client_obj: 'MClient') -> None: + async def send_svslogout(self, client_obj: 'MClient') -> None: """Logout a client from his account Args: @@ -243,7 +243,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: + async def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: """Send quit message - Delete uid from User object - Delete uid from Reputation object @@ -255,7 +255,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: + async def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: """Send UID to the server - Insert User to User Object Args: @@ -271,7 +271,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: + async def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: """Joining a channel Args: @@ -282,7 +282,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None: + async def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None: """Part from a channel Args: @@ -292,7 +292,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: + async def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: """_summary_ Args: @@ -301,7 +301,7 @@ class IProtocol(ABC): """ @abstractmethod - def send_raw(self, raw_command: str) -> None: + async def send_raw(self, raw_command: str) -> None: """Send raw message to the server Args: @@ -313,7 +313,7 @@ class IProtocol(ABC): # ------------------------------------------------------------------------ @abstractmethod - def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: + async def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. Args: @@ -324,7 +324,7 @@ class IProtocol(ABC): """ @abstractmethod - def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: + async def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] Args: @@ -335,7 +335,7 @@ class IProtocol(ABC): """ @abstractmethod - def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: + async def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: """Parse nick changes and return dictionary. >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] @@ -349,7 +349,7 @@ class IProtocol(ABC): """ @abstractmethod - def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: + async def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] @@ -365,7 +365,7 @@ class IProtocol(ABC): # ------------------------------------------------------------------------ @abstractmethod - def on_svs2mode(self, server_msg: list[str]) -> None: + async def on_svs2mode(self, server_msg: list[str]) -> None: """Handle svs2mode coming from a server >>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] @@ -374,7 +374,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_mode(self, server_msg: list[str]) -> None: + async def on_mode(self, server_msg: list[str]) -> None: """Handle mode coming from a server Args: @@ -382,7 +382,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_umode2(self, server_msg: list[str]) -> None: + async def on_umode2(self, server_msg: list[str]) -> None: """Handle umode2 coming from a server >>> [':adator_', 'UMODE2', '-i'] @@ -391,7 +391,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_quit(self, server_msg: list[str]) -> None: + async def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server Args: @@ -399,7 +399,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_squit(self, server_msg: list[str]) -> None: + async def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server Args: @@ -407,7 +407,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_protoctl(self, server_msg: list[str]) -> None: + async def on_protoctl(self, server_msg: list[str]) -> None: """Handle protoctl coming from a server Args: @@ -415,7 +415,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_nick(self, server_msg: list[str]) -> None: + async def on_nick(self, server_msg: list[str]) -> None: """Handle nick coming from a server new nickname @@ -424,7 +424,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_sjoin(self, server_msg: list[str]) -> None: + async def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server Args: @@ -432,7 +432,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_part(self, server_msg: list[str]) -> None: + async def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server Args: @@ -440,7 +440,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_eos(self, server_msg: list[str]) -> None: + async def on_eos(self, server_msg: list[str]) -> None: """Handle EOS coming from a server Args: @@ -448,7 +448,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_reputation(self, server_msg: list[str]) -> None: + async def on_reputation(self, server_msg: list[str]) -> None: """Handle REPUTATION coming from a server Args: @@ -456,7 +456,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_uid(self, server_msg: list[str]) -> None: + async def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server Args: @@ -464,7 +464,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_privmsg(self, server_msg: list[str]) -> None: + async def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server Args: @@ -472,7 +472,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_server_ping(self, server_msg: list[str]) -> None: + async def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server Args: @@ -480,7 +480,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_server(self, server_msg: list[str]) -> None: + async def on_server(self, server_msg: list[str]) -> None: """_summary_ Args: @@ -488,7 +488,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_version(self, server_msg: list[str]) -> None: + async def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server Args: @@ -496,7 +496,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_time(self, server_msg: list[str]) -> None: + async def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor Args: @@ -504,7 +504,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_ping(self, server_msg: list[str]) -> None: + async def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor Args: @@ -512,7 +512,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_version_msg(self, server_msg: list[str]) -> None: + async def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server \n ex. /version Defender Args: @@ -520,7 +520,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_smod(self, server_msg: list[str]) -> None: + async def on_smod(self, server_msg: list[str]) -> None: """Handle SMOD message coming from the server Args: @@ -528,7 +528,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: + async def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server Args: @@ -539,7 +539,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool: + async def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool: """Finalize sasl authentication Args: @@ -550,7 +550,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_md(self, server_msg: list[str]) -> None: + async def on_md(self, server_msg: list[str]) -> None: """Handle MD responses [':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...'] Args: @@ -558,7 +558,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_kick(self, server_msg: list[str]) -> None: + async def on_kick(self, server_msg: list[str]) -> None: """When a user is kicked out from a channel Eg. ['@unrealircd.org...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User'] @@ -567,7 +567,7 @@ class IProtocol(ABC): """ @abstractmethod - def on_sethost(self, server_msg: list[str]) -> None: + async def on_sethost(self, server_msg: list[str]) -> None: """On SETHOST command >>> [':001DN7305', 'SETHOST', ':netadmin.example.org'] diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 4f53a7e..154d286 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -99,7 +99,7 @@ class Unrealircd6(IProtocol): return None - def send2socket(self, message: str, print_log: bool = True) -> None: + async def send2socket(self, message: str, print_log: bool = True) -> None: """Envoit les commandes à envoyer au serveur. Args: @@ -108,16 +108,19 @@ class Unrealircd6(IProtocol): """ try: with self._Base.lock: - self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[0])) + self._Irc.writer.write(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[0])) + await self._Irc.writer.drain() if print_log: self._Logs.debug(f'<< {message}') except UnicodeDecodeError as ude: self._Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') - self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) + self._Irc.writer.write(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) + await self._Irc.writer.drain() except UnicodeEncodeError as uee: self._Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') - self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) + self._Irc.writer.write(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) + await self._Irc.writer.drain() except AssertionError as ae: self._Logs.warning(f'Assertion Error {ae} - message: {message}') except SSLEOFError as soe: @@ -129,7 +132,7 @@ class Unrealircd6(IProtocol): except AttributeError as ae: self._Logs.critical(f"Attribute Error: {ae}") - def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): + async def send_priv_msg(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: @@ -150,18 +153,18 @@ class Unrealircd6(IProtocol): 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}") + await 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}") + await self.send2socket(f":{nick_from} PRIVMSG {user_to.uid} :{batch}") except Exception as err: self._Logs.error(f"General Error: {err}") self._Logs.error(f"General Error: {nick_from} - {channel} - {nick_to}") - def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: + async def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: """Sending NOTICE by batches Args: @@ -180,12 +183,12 @@ class Unrealircd6(IProtocol): 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}") + await self.send2socket(f":{user_from.uid} NOTICE {user_to.uid} :{batch}") except Exception as err: self._Logs.error(f"General Error: {err}") - def send_link(self): + async def send_link(self): """Créer le link et envoyer les informations nécessaires pour la connexion au serveur. """ @@ -209,22 +212,22 @@ class Unrealircd6(IProtocol): version = self._Config.CURRENT_VERSION unixtime = self._Utils.get_unixtime() - self.send2socket(f":{server_id} PASS :{server_password}", print_log=False) - self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS") - self.send2socket(f":{server_id} PROTOCTL EAUTH={server_link},{protocolversion},,{service_name}-v{version}") - self.send2socket(f":{server_id} PROTOCTL SID={server_id}") - self.send2socket(f":{server_id} PROTOCTL BOOTED={unixtime}") - self.send2socket(f":{server_id} SERVER {server_link} 1 :{service_info}") - self.send2socket(f":{server_id} {service_nickname} :Reserved for services") - self.send2socket(f":{server_id} UID {service_nickname} 1 {unixtime} {service_username} {service_hostname} {service_id} * {service_smodes} * * fwAAAQ== :{service_realname}") - self.send2socket("EOS") - self.send_sjoin(service_channel_log) - self.send2socket(f":{server_id} TKL + Q * {service_nickname} {service_hostname} 0 {unixtime} :Reserved for services") - self.send2socket(f":{service_id} MODE {service_channel_log} {service_cmodes}") + await self.send2socket(f":{server_id} PASS :{server_password}", print_log=False) + await self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS") + await self.send2socket(f":{server_id} PROTOCTL EAUTH={server_link},{protocolversion},,{service_name}-v{version}") + await self.send2socket(f":{server_id} PROTOCTL SID={server_id}") + await self.send2socket(f":{server_id} PROTOCTL BOOTED={unixtime}") + await self.send2socket(f":{server_id} SERVER {server_link} 1 :{service_info}") + await self.send2socket(f":{server_id} {service_nickname} :Reserved for services") + await self.send2socket(f":{server_id} UID {service_nickname} 1 {unixtime} {service_username} {service_hostname} {service_id} * {service_smodes} * * fwAAAQ== :{service_realname}") + await self.send2socket("EOS") + await self.send_sjoin(service_channel_log) + await self.send2socket(f":{server_id} TKL + Q * {service_nickname} {service_hostname} 0 {unixtime} :Reserved for services") + await self.send2socket(f":{service_id} MODE {service_channel_log} {service_cmodes}") self._Logs.debug(f'>> {__name__} Link information sent to the server') - def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + async def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: """Send a gline command to the server Args: @@ -237,23 +240,23 @@ class Unrealircd6(IProtocol): """ # 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}") + await self.send2socket(f":{self._Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None - def send_set_nick(self, newnickname: str) -> None: + async def send_set_nick(self, newnickname: str) -> None: """Change nickname of the server \n This method will also update the User object Args: newnickname (str): New nickname of the server """ - self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") + await self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") user_obj = self._Irc.User.get_user(self._Config.SERVICE_NICKNAME) self._Irc.User.update_nickname(user_obj.uid, newnickname) return None - def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: + async def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: """Set a mode to channel or to a nickname or for a user in a channel Args: @@ -273,50 +276,50 @@ class Unrealircd6(IProtocol): if not self._Irc.Channel.is_valid_channel(channel_name): self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None - self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") + await self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") return None if nickname and channel_name is None: - self.send2socket(f":{service_id} MODE {nickname} {modes}") + await self.send2socket(f":{service_id} MODE {nickname} {modes}") return None if nickname is None and channel_name: if not self._Irc.Channel.is_valid_channel(channel_name): self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None - self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") + await self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") return None return None - def send_squit(self, server_id: str, server_link: str, reason: str) -> None: + async def send_squit(self, server_id: str, server_link: str, reason: str) -> None: if not reason: reason = 'Service Shutdown' - self.send2socket(f":{server_id} SQUIT {server_link} :{reason}") + await self.send2socket(f":{server_id} SQUIT {server_link} :{reason}") return None - def send_ungline(self, nickname:str, hostname: str) -> None: + async def send_ungline(self, nickname:str, hostname: str) -> None: - self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") + await self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") return None - def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + async def send_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}") + await self.send2socket(f":{self._Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None - def send_unkline(self, nickname:str, hostname: str) -> None: + async def send_unkline(self, nickname:str, hostname: str) -> None: - self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") + await self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") return None - def send_sjoin(self, channel: str) -> None: + async def send_sjoin(self, channel: str) -> None: """Server will join a channel with pre defined umodes Args: @@ -326,14 +329,14 @@ class Unrealircd6(IProtocol): self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{self._Config.SERVEUR_ID} SJOIN {self._Utils.get_unixtime()} {channel} {self._Config.SERVICE_UMODES} :{self._Config.SERVICE_ID}") - self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") + await self.send2socket(f":{self._Config.SERVEUR_ID} SJOIN {self._Utils.get_unixtime()} {channel} {self._Config.SERVICE_UMODES} :{self._Config.SERVICE_ID}") + await self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {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 send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: + async def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: """_summary_ Args: @@ -349,7 +352,7 @@ class Unrealircd6(IProtocol): if user_obj is None or chan_obj is None: return None - self.send2socket(f":{service_uid} SAPART {user_obj.nickname} {chan_obj.name}") + await self.send2socket(f":{service_uid} SAPART {user_obj.nickname} {chan_obj.name}") self._Irc.Channel.delete_user_from_channel(chan_obj.name, user_obj.uid) return None @@ -357,7 +360,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: + async def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: """_summary_ Args: @@ -383,18 +386,18 @@ class Unrealircd6(IProtocol): # Create the new channel with the uid new_chan_obj = self._Irc.Loader.Definition.MChannel(name=channel_name, uids=[user_obj.uid]) self._Irc.Channel.insert(new_chan_obj) - self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {new_chan_obj.name}") + await self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {new_chan_obj.name}") else: self._Irc.Channel.add_user_to_a_channel(channel_name=channel_name, uid=user_obj.uid) - self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {chan_obj.name}") + await self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {chan_obj.name}") return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: + async def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: user_obj = self._Irc.User.get_user(nick_to_part) if user_obj is None: @@ -403,10 +406,10 @@ class Unrealircd6(IProtocol): channels_list = ','.join([channel for channel in channels if self._Irc.Channel.is_valid_channel(channel)]) service_id = self._Config.SERVICE_ID - self.send2socket(f':{service_id} SVSPART {user_obj.nickname} {channels_list} {reason}') + await self.send2socket(f':{service_id} SVSPART {user_obj.nickname} {channels_list} {reason}') return None - def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: + async def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: user_obj = self._Irc.User.get_user(nick_to_part) if user_obj is None: @@ -416,10 +419,10 @@ class Unrealircd6(IProtocol): channels_list = ','.join([channel for channel in channels if self._Irc.Channel.is_valid_channel(channel)]) keys_list = ','.join([key for key in keys]) service_id = self._Config.SERVICE_ID - self.send2socket(f':{service_id} SVSJOIN {user_obj.nickname} {channels_list} {keys_list}') + await self.send2socket(f':{service_id} SVSJOIN {user_obj.nickname} {channels_list} {keys_list}') return None - def send_svsmode(self, nickname: str, user_mode: str) -> None: + async def send_svsmode(self, nickname: str, user_mode: str) -> None: try: user_obj = self._Irc.User.get_user(uidornickname=nickname) service_uid = self._Config.SERVICE_ID @@ -427,7 +430,7 @@ class Unrealircd6(IProtocol): if user_obj is None: return None - self.send2socket(f':{service_uid} SVSMODE {nickname} {user_mode}') + await self.send2socket(f':{service_uid} SVSMODE {nickname} {user_mode}') # Update new mode self._Irc.User.update_mode(user_obj.uid, user_mode) @@ -436,7 +439,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def send_svs2mode(self, nickname: str, user_mode: str) -> None: + async def send_svs2mode(self, nickname: str, user_mode: str) -> None: try: user_obj = self._Irc.User.get_user(uidornickname=nickname) service_uid = self._Config.SERVICE_ID @@ -444,7 +447,7 @@ class Unrealircd6(IProtocol): if user_obj is None: return None - self.send2socket(f':{service_uid} SVS2MODE {nickname} {user_mode}') + await self.send2socket(f':{service_uid} SVS2MODE {nickname} {user_mode}') # Update new mode self._Irc.User.update_mode(user_obj.uid, user_mode) @@ -453,7 +456,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def send_svslogin(self, client_uid: str, user_account: str) -> None: + async def send_svslogin(self, client_uid: str, user_account: str) -> None: """Log a client into his account. Args: @@ -461,11 +464,11 @@ class Unrealircd6(IProtocol): user_account (str): The account of the user """ try: - self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {client_uid} {user_account}") + await self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {client_uid} {user_account}") except Exception as err: self._Logs.error(f'General Error: {err}') - def send_svslogout(self, client_obj: 'MClient') -> None: + async def send_svslogout(self, client_obj: 'MClient') -> None: """Logout a client from his account Args: @@ -474,13 +477,13 @@ class Unrealircd6(IProtocol): try: c_uid = client_obj.uid c_nickname = client_obj.nickname - self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0") + await self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0") self.send_svs2mode(c_nickname, '-r') except Exception as err: self._Logs.error(f'General Error: {err}') - def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: + async def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: """Send quit message - Delete uid from User object - Delete uid from Reputation object @@ -494,7 +497,7 @@ class Unrealircd6(IProtocol): reputation_obj = self._Irc.Reputation.get_reputation(uidornickname=uid) if not user_obj is None: - self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) + await self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) self._Irc.User.delete(user_obj.uid) if not reputation_obj is None: @@ -505,7 +508,7 @@ class Unrealircd6(IProtocol): return None - def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, + async def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: """Send UID to the server - Insert User to User Object @@ -537,14 +540,14 @@ class Unrealircd6(IProtocol): uid_msg = f":{self._Config.SERVEUR_ID} UID {nickname} 1 {unixtime} {username} {hostname} {uid} * {umodes} {vhost} * {encoded_ip} :{realname}" - self.send2socket(uid_msg, print_log=print_log) + await self.send2socket(uid_msg, print_log=print_log) return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: + async def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: """Joining a channel Args: @@ -564,10 +567,10 @@ class Unrealircd6(IProtocol): self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{user_obj.uid} JOIN {channel} {pwd_channel}", print_log=print_log) + await self.send2socket(f":{user_obj.uid} JOIN {channel} {pwd_channel}", print_log=print_log) if uidornickname == self._Config.SERVICE_NICKNAME or uidornickname == self._Config.SERVICE_ID: - self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") + await self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") # Add defender to the channel uids list self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) @@ -581,11 +584,11 @@ class Unrealircd6(IProtocol): db_result = db_query.fetchone() if db_result is not None: id_cmd_automode, mode = db_result - self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {mode} {user_obj.nickname}") + await self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {mode} {user_obj.nickname}") return None - def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None: + async def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None: """Part from a channel Args: @@ -604,25 +607,25 @@ class Unrealircd6(IProtocol): self._Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{u.uid} PART {channel}", print_log=print_log) + await self.send2socket(f":{u.uid} PART {channel}", print_log=print_log) # Add defender to the channel uids list self._Irc.Channel.delete_user_from_channel(channel, u.uid) return None - def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: + async def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: channel = self._Irc.Channel.is_valid_channel(channel_name) if not channel: self._Logs.error(f'The channel [{channel_name}] is not correct') return None - self.send2socket(f":{self._Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}") + await self.send2socket(f":{self._Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}") return None - def send_raw(self, raw_command: str) -> None: + async def send_raw(self, raw_command: str) -> None: - self.send2socket(f":{self._Config.SERVICE_NICKNAME} {raw_command}") + await self.send2socket(f":{self._Config.SERVICE_NICKNAME} {raw_command}") return None @@ -713,7 +716,7 @@ class Unrealircd6(IProtocol): # HANDLE EVENTS # ##################### - def on_svs2mode(self, server_msg: list[str]) -> None: + async def on_svs2mode(self, server_msg: list[str]) -> None: """Handle svs2mode coming from a server >>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] @@ -740,7 +743,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_mode(self, server_msg: list[str]) -> None: + async def on_mode(self, server_msg: list[str]) -> None: """Handle mode coming from a server Args: @@ -751,7 +754,7 @@ class Unrealircd6(IProtocol): return None - def on_umode2(self, server_msg: list[str]) -> None: + async def on_umode2(self, server_msg: list[str]) -> None: """Handle umode2 coming from a server >>> [':adator_', 'UMODE2', '-i'] @@ -778,7 +781,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_quit(self, server_msg: list[str]) -> None: + async def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server Args: @@ -802,7 +805,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_squit(self, server_msg: list[str]) -> None: + async def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server Args: @@ -824,7 +827,7 @@ class Unrealircd6(IProtocol): return None - def on_protoctl(self, server_msg: list[str]) -> None: + async def on_protoctl(self, server_msg: list[str]) -> None: """Handle protoctl coming from a server Args: @@ -861,7 +864,7 @@ class Unrealircd6(IProtocol): return None - def on_nick(self, server_msg: list[str]) -> None: + async def on_nick(self, server_msg: list[str]) -> None: """Handle nick coming from a server new nickname @@ -886,7 +889,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_sjoin(self, server_msg: list[str]) -> None: + async def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server Args: @@ -939,7 +942,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_part(self, server_msg: list[str]) -> None: + async def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server Args: @@ -957,7 +960,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_eos(self, server_msg: list[str]) -> None: + async def on_eos(self, server_msg: list[str]) -> None: """Handle EOS coming from a server Args: @@ -998,17 +1001,17 @@ class Unrealircd6(IProtocol): self._Logs.info(f"# VERSION : {version} ") self._Logs.info(f"################################################") - self.send_sjoin(self._Config.SERVICE_CHANLOG) + await self.send_sjoin(self._Config.SERVICE_CHANLOG) if self._Base.check_for_new_version(False): - self.send_priv_msg( + await self.send_priv_msg( 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.send_priv_msg( + await self.send_priv_msg( nick_from=self._Config.SERVICE_NICKNAME, msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._Config.COLORS.green, self._Config.COLORS.nogc, self._Config.SERVICE_NICKNAME), channel=self._Config.SERVICE_CHANLOG @@ -1020,10 +1023,10 @@ class Unrealircd6(IProtocol): module.class_instance.cmd(server_msg_copy) # Join saved channels & load existing modules - self._Irc.join_saved_channels() - self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) + await self._Irc.join_saved_channels() + await self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) - self.send2socket(f":{self._Config.SERVEUR_ID} SMOD :L:Defender:1.0.0 :L:Command:1.0.0") + await self.send2socket(f":{self._Config.SERVEUR_ID} SMOD :L:Defender:1.0.0 :L:Command:1.0.0") return None except IndexError as ie: @@ -1033,7 +1036,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_reputation(self, server_msg: list[str]) -> None: + async def on_reputation(self, server_msg: list[str]) -> None: """Handle REPUTATION coming from a server Args: @@ -1064,7 +1067,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_uid(self, server_msg: list[str]) -> None: + async def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server Args: @@ -1142,15 +1145,15 @@ class Unrealircd6(IProtocol): if sasl_obj: if sasl_obj.auth_success: self._Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) - self.send_priv_msg(nick_from=dnickname, + await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, sasl_obj.username, dnickname), channel=dchanlog) - self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) + await self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) else: - self.send_priv_msg(nick_from=dnickname, + await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s provided a wrong password for this username %s", red, nogc, nickname, sasl_obj.username), channel=dchanlog) - self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) + await self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) # Delete sasl object! self._Irc.Sasl.delete_sasl_client(uid) @@ -1160,10 +1163,10 @@ class Unrealircd6(IProtocol): if self._Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): admin = self._Irc.Admin.get_admin(uid) account = admin.account if admin else '' - self.send_priv_msg(nick_from=dnickname, + await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, account, dnickname), channel=dchanlog) - self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) + await self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) return None except IndexError as ie: @@ -1171,7 +1174,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_privmsg(self, server_msg: list[str]) -> None: + async def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server Args: @@ -1197,7 +1200,7 @@ class Unrealircd6(IProtocol): arg.remove(f':{self._Config.SERVICE_PREFIX}') if not self._Irc.Commands.is_command_exist(arg[0]): self._Logs.debug(f"This command {arg[0]} is not available") - self.send_notice( + await self.send_notice( 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" @@ -1208,7 +1211,7 @@ class Unrealircd6(IProtocol): self._Base.log_cmd(user_trigger, cmd_to_send) fromchannel = str(cmd[2]).lower() if self._Irc.Channel.is_valid_channel(cmd[2]) else None - self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) + await self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) if cmd[2] == self._Config.SERVICE_ID: pattern = fr'^:.*?:(.*)$' @@ -1221,35 +1224,31 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION if arg[0] == '\x01VERSION\x01': - self.on_version(srv_msg) + await self.on_version(srv_msg) return None # Réponse a un TIME if arg[0] == '\x01TIME\x01': - self.on_time(srv_msg) + await self.on_time(srv_msg) return None # Réponse a un PING if arg[0] == '\x01PING': - self.on_ping(srv_msg) + await self.on_ping(srv_msg) return None if not self._Irc.Commands.is_command_exist(arg[0]): self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") return None - # if not arg[0].lower() in self._Irc.module_commands_list: - # self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") - # return False - cmd_to_send = convert_to_string.replace(':','') self._Base.log_cmd(user_trigger, cmd_to_send) - fromchannel = None + if len(arg) >= 2: fromchannel = str(arg[1]).lower() if self._Irc.Channel.is_valid_channel(arg[1]) else None - self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) + await self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) return None except KeyError as ke: @@ -1259,7 +1258,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True) - def on_server_ping(self, server_msg: list[str]) -> None: + async def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server Args: @@ -1267,14 +1266,13 @@ class Unrealircd6(IProtocol): """ try: scopy = server_msg.copy() - pong = str(scopy[1]).replace(':','') - self.send2socket(f"PONG :{pong}", print_log=False) + await self.send2socket(' '.join(scopy).replace('PING', 'PONG'), print_log=True) return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_server(self, server_msg: list[str]) -> None: + async def on_server(self, server_msg: list[str]) -> None: """_summary_ Args: @@ -1287,7 +1285,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f'General Error: {err}') - def on_version(self, server_msg: list[str]) -> None: + async def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server Args: @@ -1305,13 +1303,13 @@ class Unrealircd6(IProtocol): return None if arg == '\x01VERSION\x01': - self.send2socket(f':{dnickname} NOTICE {nickname} :\x01VERSION Service {self._Config.SERVICE_NICKNAME} V{self._Config.CURRENT_VERSION}\x01') + await 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._Logs.error(f"{__name__} - General Error: {err}") - def on_time(self, server_msg: list[str]) -> None: + async def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor Args: @@ -1330,13 +1328,13 @@ class Unrealircd6(IProtocol): return None if arg == '\x01TIME\x01': - self.send2socket(f':{dnickname} NOTICE {nickname} :\x01TIME {current_datetime}\x01') + await self.send2socket(f':{dnickname} NOTICE {nickname} :\x01TIME {current_datetime}\x01') return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_ping(self, server_msg: list[str]) -> None: + async def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor Args: @@ -1360,7 +1358,7 @@ class Unrealircd6(IProtocol): ping_response = current_unixtime - recieved_unixtime # self._Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') - self.send_notice( + await self.send_notice( nick_from=dnickname, nick_to=nickname, msg=f"\x01PING {ping_response} secs\x01" @@ -1371,7 +1369,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_version_msg(self, server_msg: list[str]) -> None: + async def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server \n ex. /version Defender Args: @@ -1389,21 +1387,21 @@ class Unrealircd6(IProtocol): return None response_351 = f"{self._Config.SERVICE_NAME.capitalize()}-{self._Config.CURRENT_VERSION} {self._Config.SERVICE_HOST} {self.name}" - self.send2socket(f':{self._Config.SERVICE_HOST} 351 {u.nickname} {response_351}') + await self.send2socket(f':{self._Config.SERVICE_HOST} 351 {u.nickname} {response_351}') modules = self._Irc.ModuleUtils.get_all_available_modules() response_005 = ' | '.join(modules) - self.send2socket(f':{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server') + await self.send2socket(f':{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server') response_005 = ''.join(self._Settings.PROTOCTL_USER_MODES) - self.send2socket(f":{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server") + await self.send2socket(f":{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server") return None except Exception as err: self._Logs.error(f"{__name__} - General Error: {err}") - def on_smod(self, server_msg: list[str]) -> None: + async def on_smod(self, server_msg: list[str]) -> None: """Handle SMOD message coming from the server Args: @@ -1422,7 +1420,7 @@ class Unrealircd6(IProtocol): except Exception as err: self._Logs.error(f'General Error: {err}') - def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: + async def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server Args: @@ -1465,13 +1463,13 @@ class Unrealircd6(IProtocol): sasl_obj.mechanisme = str(scopy[5]) if sasl_obj.mechanisme == "PLAIN": - self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") + await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") elif sasl_obj.mechanisme == "EXTERNAL": if str(scopy[5]) == "+": return None sasl_obj.fingerprint = str(scopy[6]) - self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") + await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") self.on_sasl_authentication_process(sasl_obj) return sasl_obj @@ -1486,18 +1484,18 @@ class Unrealircd6(IProtocol): sasl_obj.username = username sasl_obj.password = password - self.on_sasl_authentication_process(sasl_obj) + await self.on_sasl_authentication_process(sasl_obj) return sasl_obj elif sasl_obj.mechanisme == "EXTERNAL": sasl_obj.message_type = sasl_message_type - self.on_sasl_authentication_process(sasl_obj) + await self.on_sasl_authentication_process(sasl_obj) return sasl_obj except Exception as err: self._Logs.error(f'General Error: {err}', exc_info=True) - def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> None: + async def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> None: s = sasl_model if sasl_model: def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: @@ -1522,11 +1520,11 @@ class Unrealircd6(IProtocol): s.auth_success = True s.level = admin_info.get('level', 0) s.language = admin_info.get('language', 'EN') - self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + await self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: - self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + await self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL': # Connection using fingerprints @@ -1537,14 +1535,14 @@ class Unrealircd6(IProtocol): s.level = admin_info.get('level', 0) s.username = admin_info.get('user', None) s.language = admin_info.get('language', 'EN') - self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + await self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: # "904 :SASL authentication failed" - self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + await self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") - def on_md(self, server_msg: list[str]) -> None: + async def on_md(self, server_msg: list[str]) -> None: """Handle MD responses [':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...'] Args: @@ -1573,7 +1571,7 @@ class Unrealircd6(IProtocol): except Exception as e: self._Logs.error(f"General Error: {e}") - def on_kick(self, server_msg: list[str]) -> None: + async def on_kick(self, server_msg: list[str]) -> None: """When a user is kicked out from a channel ['@unrealircd.org/issued-by=RPC:admin-for-test@...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User'] @@ -1588,7 +1586,7 @@ class Unrealircd6(IProtocol): self._Irc.Channel.delete_user_from_channel(channel, uid) return None - def on_sethost(self, server_msg: list[str]) -> None: + async def on_sethost(self, server_msg: list[str]) -> None: """On SETHOST command >>> [':001DN7305', 'SETHOST', ':netadmin.example.org'] diff --git a/core/irc.py b/core/irc.py index 18a8fbe..89b1811 100644 --- a/core/irc.py +++ b/core/irc.py @@ -1,3 +1,4 @@ +import asyncio import sys import socket import ssl @@ -26,6 +27,8 @@ class Irc: def __init__(self, loader: 'Loader'): + self.signal: bool = True + # Loader class self.Loader = loader @@ -132,8 +135,34 @@ class Irc: # Define the IrcSocket object self.IrcSocket: Optional[Union[socket.socket, SSLSocket]] = None + self.reader: Optional[asyncio.StreamReader] = None + self.writer: Optional[asyncio.StreamWriter] = None + self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, )) + async def connect(self): + + if self.Config.SERVEUR_SSL: + self.reader, self.writer = await asyncio.open_connection(self.Config.SERVEUR_IP, self.Config.SERVEUR_PORT, ssl=self.Utils.get_ssl_context()) + else: + self.reader, self.writer = await asyncio.open_connection(self.Config.SERVEUR_IP, self.Config.SERVEUR_PORT) + + self.init_service_user() + self.Protocol: 'IProtocol' = self.Loader.PFactory.get() + self.Protocol.register_command() + await self.Protocol.send_link() + + + async def listen(self): + + while self.signal: + data = await self.reader.readuntil(b'\r\n') + await self.send_response(data.splitlines()) + + async def run(self): + await self.connect() + await self.listen() + ############################################## # CONNEXION IRC # ############################################## @@ -232,7 +261,7 @@ class Irc: except Exception as e: self.Logs.critical(f"General Error: {e}", exc_info=True) - def join_saved_channels(self) -> None: + async def join_saved_channels(self) -> None: """## Joining saved channels""" exec_query = self.Base.db_execute_query(f'SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}') result_query = exec_query.fetchall() @@ -240,25 +269,25 @@ class Irc: if result_query: for chan_name in result_query: chan = chan_name[0] - self.Protocol.send_sjoin(channel=chan) + await self.Protocol.send_sjoin(channel=chan) - def send_response(self, responses:list[bytes]) -> None: + async def send_response(self, responses:list[bytes]) -> None: try: for data in responses: response = data.decode(self.CHARSET[0]).split() - self.cmd(response) + await self.cmd(response) except UnicodeEncodeError as ue: for data in responses: response = data.decode(self.CHARSET[1],'replace').split() - self.cmd(response) + await self.cmd(response) self.Logs.error(f'UnicodeEncodeError: {ue}') self.Logs.error(response) except UnicodeDecodeError as ud: for data in responses: response = data.decode(self.CHARSET[1],'replace').split() - self.cmd(response) + await self.cmd(response) self.Logs.error(f'UnicodeDecodeError: {ud}') self.Logs.error(response) @@ -287,7 +316,7 @@ class Irc: return None - def generate_help_menu(self, nickname: str, module: Optional[str] = None) -> None: + async def generate_help_menu(self, nickname: str, module: Optional[str] = None) -> None: # Check if the nickname is an admin p = self.Protocol @@ -300,14 +329,14 @@ class Irc: if admin_obj is not None: current_level = admin_obj.level - p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" ***************** LISTE DES COMMANDES *****************") + await p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" ***************** LISTE DES COMMANDES *****************") header = f" {'Level':<8}| {'Command':<25}| {'Module':<15}| {'Description':<35}" line = "-"*75 - p.send_notice(nick_from=dnickname,nick_to=nickname, msg=header) - p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" {line}") + await p.send_notice(nick_from=dnickname,nick_to=nickname, msg=header) + await p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" {line}") for cmd in self.Commands.get_commands_by_level(current_level): if module is None or cmd.module_name.lower() == module.lower(): - p.send_notice( + await p.send_notice( nick_from=dnickname, nick_to=nickname, msg=f" {color_black}{cmd.command_level:<8}{color_nogc}| {cmd.command_name:<25}| {cmd.module_name:<15}| {cmd.description:<35}" @@ -465,18 +494,18 @@ class Irc: self.Logs.info(f"The nickname {nickname} already exist! (sent by {sender})") return False - def thread_check_for_new_version(self, fromuser: str) -> None: + async def thread_check_for_new_version(self, fromuser: str) -> None: dnickname = self.Config.SERVICE_NICKNAME if self.Base.check_for_new_version(True): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" New Version available : {self.Config.CURRENT_VERSION} >>> {self.Config.LATEST_VERSION}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" Please run (git pull origin main) in the current folder") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" New Version available : {self.Config.CURRENT_VERSION} >>> {self.Config.LATEST_VERSION}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" Please run (git pull origin main) in the current folder") else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" You have the latest version of defender") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" You have the latest version of defender") return None - def cmd(self, data: list[str]) -> None: + async def cmd(self, data: list[str]) -> None: """Parse server response Args: @@ -494,7 +523,7 @@ class Irc: for parsed in self.Protocol.Handler.get_ircd_commands(): if parsed.command_name.upper() == parsed_protocol: - parsed.func(original_response) + await parsed.func(original_response) for module in modules: module.class_instance.cmd(original_response) @@ -509,7 +538,7 @@ class Irc: except Exception as err: self.Logs.error(f"General Error: {err}", exc_info=True) - def hcmds(self, user: str, channel: Union[str, None], cmd: list, fullcmd: list = []) -> None: + async def hcmds(self, user: str, channel: Union[str, None], cmd: list, fullcmd: list = []) -> None: """Create Args: @@ -560,13 +589,13 @@ class Irc: case 'notallowed': try: current_command = str(cmd[0]) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( msg=tr('[ %s%s%s ] - Access denied to %s', RED, current_command.upper(), NOGC, fromuser), nick_from=dnickname, channel=dchanlog ) - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=tr('Access denied!') @@ -1012,7 +1041,7 @@ class Irc: case 'help': # Syntax. !help [module_name] module_name = str(cmd[1]) if len(cmd) == 2 else None - self.generate_help_menu(nickname=fromuser, module=module_name) + await self.generate_help_menu(nickname=fromuser, module=module_name) return None case 'load': @@ -1119,14 +1148,14 @@ class Irc: loaded = True if loaded: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=tr('%s - %sLoaded%s by %s on %s', module, GREEN, NOGC, loaded_user, loaded_datetime) ) loaded = False else: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=tr('%s - %sNot Loaded%s', module, RED, NOGC) @@ -1150,11 +1179,17 @@ class Irc: case 'show_threads': for thread in self.Base.running_threads: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f">> {thread.name} ({thread.is_alive()})" ) + + asyncio.create_task(self.new_coro(), name='my_new_coro') + for task in asyncio.all_tasks(): + print(task.get_name()) + print(task) + return None case 'show_channels': @@ -1282,3 +1317,8 @@ class Irc: case _: pass + + async def new_coro(self): + self.Logs.debug("Creating new coro") + await asyncio.sleep(5) + self.Logs.debug("End of the coro") \ No newline at end of file diff --git a/core/logs.py b/core/logs.py index fbf02a7..1ed5152 100644 --- a/core/logs.py +++ b/core/logs.py @@ -15,7 +15,7 @@ class ServiceLogging: self.SERVER_PREFIX = None self.LOGGING_CONSOLE = True - self.LOG_FILTERS: list[str] = ["PING", f":{self.SERVER_PREFIX}auth", "['PASS'"] + self.LOG_FILTERS: list[str] = [f":{self.SERVER_PREFIX}auth", "['PASS'"] self.file_handler = None self.stdout_handler = None diff --git a/core/module.py b/core/module.py index 199b713..bdd6c2b 100644 --- a/core/module.py +++ b/core/module.py @@ -84,7 +84,7 @@ class Module: self.__Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})") return False - def load_one_module(self, uplink: 'Irc', module_name: str, nickname: str, is_default: bool = False) -> bool: + async def load_one_module(self, uplink: 'Irc', module_name: str, nickname: str, is_default: bool = False) -> bool: module_folder, module_name, class_name = self.get_module_information(module_name) @@ -97,7 +97,7 @@ class Module: if self.model_is_module_exist(module_name): # Si le module existe dans la variable globale retourne False self.__Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!") - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( 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 @@ -110,12 +110,12 @@ class Module: try: loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe - create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe + create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe self.create_module_header(create_instance_of_the_class.MOD_HEADER) except AttributeError as attr: red = uplink.Config.COLORS.red nogc = uplink.Config.COLORS.nogc - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr), channel=self.__Config.SERVICE_CHANLOG @@ -124,7 +124,7 @@ class Module: return False if not hasattr(create_instance_of_the_class, 'cmd'): - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=tr("cmd method is not available in the module (%s)", module_name), channel=self.__Config.SERVICE_CHANLOG @@ -137,7 +137,7 @@ class Module: if self.model_insert_module(MModule(module_name, class_name, create_instance_of_the_class)): # Enregistrer le module dans la base de données self.db_register_module(module_name, nickname, is_default) - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=tr("Module %s loaded!", module_name), channel=self.__Config.SERVICE_CHANLOG @@ -399,7 +399,7 @@ class Module: OPERATION DEDICATED TO DATABASE MANAGEMENT ''' - def db_load_all_existing_modules(self, uplink: 'Irc') -> bool: + async def db_load_all_existing_modules(self, uplink: 'Irc') -> bool: """Charge les modules qui existe déja dans la base de données Returns: @@ -408,7 +408,7 @@ class Module: self.__Logs.debug("[DB LOAD MODULE] Loading modules from the database!") result = self.__Base.db_execute_query(f"SELECT module_name FROM {self.__Config.TABLE_MODULE}") for r in result.fetchall(): - self.load_one_module(uplink, r[0], 'sys', True) + await self.load_one_module(uplink, r[0], 'sys', True) return True diff --git a/defender.py b/defender.py index da46ad4..199080f 100644 --- a/defender.py +++ b/defender.py @@ -1,3 +1,4 @@ +import asyncio from core import install ############################################# @@ -9,14 +10,24 @@ from core import install # UnrealIRCD 6.2.2 or higher # ############################################# -try: - # install.update_packages() +async def main(): from core.loader import Loader loader = Loader() - loader.Irc.init_irc() + await loader.Irc.run() -except AssertionError as ae: - print(f'Assertion Error -> {ae}') -except KeyboardInterrupt as k: - # ircInstance.Base.execute_periodic_action() - ... \ No newline at end of file +if __name__ == "__main__": + asyncio.run(main(), debug=True) + + + +# try: +# # install.update_packages() +# from core.loader import Loader +# loader = Loader() +# loader.Irc.init_irc() + +# except AssertionError as ae: +# print(f'Assertion Error -> {ae}') +# except KeyboardInterrupt as k: +# # ircInstance.Base.execute_periodic_action() +# ... \ No newline at end of file diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index 93cf86a..9065325 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -43,7 +43,7 @@ class Defender(IModule): # self.Base.db_execute_query(table_trusted) return None - def load(self): + async def load(self): # Add module schemas self.Schemas = schemas @@ -98,8 +98,8 @@ class Defender(IModule): self.Base.create_thread(func=thds.thread_autolimit, func_args=(self, )) if self.ModConfig.reputation == 1: - self.Protocol.send_sjoin(self.Config.SALON_JAIL) - self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.SALON_JAIL} +o {self.Config.SERVICE_NICKNAME}") + await self.Protocol.send_sjoin(self.Config.SALON_JAIL) + await self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.SALON_JAIL} +o {self.Config.SERVICE_NICKNAME}") def __onload(self): @@ -164,7 +164,7 @@ class Defender(IModule): exec_query = self.Base.db_execute_query(q_insert, mes_donnees) pass - def join_saved_channels(self) -> None: + async def join_saved_channels(self) -> None: """_summary_ """ try: @@ -178,10 +178,10 @@ class Defender(IModule): for channel in channels: chan = channel[0] - self.Protocol.send_sjoin(chan) + await self.Protocol.send_sjoin(chan) if chan == 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}") + await self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") + await self.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") return None @@ -243,7 +243,7 @@ class Defender(IModule): except Exception as err: self.Logs.error(f"General Error: {err}", exc_info=True) - def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: + async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: u = self.User.get_user(user) if u is None: return None @@ -264,10 +264,10 @@ class Defender(IModule): case 'show_reputation': if not self.Reputation.UID_REPUTATION_DB: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="No one is suspected") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="No one is suspected") for suspect in self.Reputation.UID_REPUTATION_DB: - self.Protocol.send_notice(nick_from=dnickname, + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Uid: {suspect.uid} | Nickname: {suspect.nickname} | Reputation: {suspect.score_connexion} | Secret code: {suspect.secret_code} | Connected on: {suspect.connexion_datetime}") @@ -279,7 +279,7 @@ class Defender(IModule): get_reputation = self.Reputation.get_reputation(jailed_UID) if get_reputation is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...") return False jailed_IP = get_reputation.remote_ip @@ -293,30 +293,30 @@ class Defender(IModule): color_black = self.Config.COLORS.black if release_code == get_reputation.secret_code: - self.Protocol.send_priv_msg(nick_from=dnickname, msg="Bon mot de passe. Allez du vent !", channel=jailed_salon) + await self.Protocol.send_priv_msg(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.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {jailed_nickname}!*@*") + await self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {jailed_nickname}!*@*") self.Reputation.delete(jailed_UID) self.Logs.debug(f'{jailed_UID} - {jailed_nickname} removed from REPUTATION_DB') - self.Protocol.send_sapart(nick_to_sapart=jailed_nickname, channel_name=jailed_salon) - self.Protocol.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=welcome_salon) - self.Protocol.send2socket(f":{link} REPUTATION {jailed_IP} {self.ModConfig.reputation_score_after_release}") + await self.Protocol.send_sapart(nick_to_sapart=jailed_nickname, channel_name=jailed_salon) + await self.Protocol.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=welcome_salon) + await self.Protocol.send2socket(f":{link} REPUTATION {jailed_IP} {self.ModConfig.reputation_score_after_release}") u.score_connexion = reputation_seuil + 1 - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg="Mauvais password", channel=jailed_salon ) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[{color_green} MAUVAIS PASSWORD {color_black}] You have typed a wrong code. for recall your password is: {self.Config.SERVICE_PREFIX}code {get_reputation.secret_code}", nick_to=jailed_nickname @@ -324,7 +324,7 @@ class Defender(IModule): except IndexError as ie: self.Logs.error(f'Index Error: {ie}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} code [code]") + await self.Protocol.send_notice(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}') @@ -333,8 +333,8 @@ class Defender(IModule): # autolimit on # autolimit set [amount] [interval] if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") return None arg = str(cmd[1]).lower() @@ -345,16 +345,16 @@ class Defender(IModule): self.update_configuration('autolimit', 1) self.autolimit_isRunning = True self.Base.create_thread(func=thds.thread_autolimit, func_args=(self, )) - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Activated", channel=self.Config.SERVICE_CHANLOG) + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Activated", channel=self.Config.SERVICE_CHANLOG) else: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already activated", channel=self.Config.SERVICE_CHANLOG) + await self.Protocol.send_priv_msg(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.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Deactivated", channel=self.Config.SERVICE_CHANLOG) + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Deactivated", channel=self.Config.SERVICE_CHANLOG) else: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already Deactivated", channel=self.Config.SERVICE_CHANLOG) + await self.Protocol.send_priv_msg(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]) @@ -362,19 +362,19 @@ class Defender(IModule): self.update_configuration('autolimit_amount', amount) self.update_configuration('autolimit_interval', interval) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( 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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") self.Logs.error(f"Value Error -> {err}") case 'reputation': @@ -396,30 +396,30 @@ class Defender(IModule): if activation == 'on': if self.ModConfig.reputation == 1: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) - self.Protocol.send_join_chan(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}") + await self.Protocol.send_join_chan(uidornickname=dnickname, channel=jail_chan) + await self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") + await 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.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") + await self.Protocol.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users") + await self.Protocol.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") self.Channel.db_query_channel('add', self.module_name, jail_chan) if activation == 'off': if self.ModConfig.reputation == 0: - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already deactivated", channel=dchanlog @@ -428,19 +428,19 @@ class Defender(IModule): self.update_configuration(key, 0) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( 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}") + await self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} -{dumodes} {dnickname}") + await self.Protocol.send2socket(f":{service_id} MODE {jail_chan} -sS") + await self.Protocol.send2socket(f":{service_id} PART {jail_chan}") for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_chan: - 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") + await self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b ~security-group:unknown-users") + await self.Protocol.send2socket(f":{service_id} MODE {chan.name} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") self.Channel.db_query_channel('del', self.module_name, jail_chan) @@ -450,7 +450,7 @@ class Defender(IModule): match get_options: case 'release': # .reputation release [nick] - p = self.Protocol + p = await self.Protocol link = self.Config.SERVEUR_LINK jailed_salon = self.Config.SALON_JAIL welcome_salon = self.Config.SALON_LIBERER @@ -507,7 +507,7 @@ class Defender(IModule): if get_value == 'on': if self.ModConfig.reputation_ban_all_chan == 1: - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already activated", channel=dchanlog @@ -517,7 +517,7 @@ class Defender(IModule): # self.update_db_configuration(key, 1) self.update_configuration(key, 1) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog @@ -525,7 +525,7 @@ class Defender(IModule): elif get_value == 'off': if self.ModConfig.reputation_ban_all_chan == 0: - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already deactivated", channel=dchanlog @@ -535,7 +535,7 @@ class Defender(IModule): # self.update_db_configuration(key, 0) self.update_configuration(key, 0) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog @@ -548,71 +548,71 @@ class Defender(IModule): # self.update_db_configuration(key, reputation_seuil) self.update_configuration(key, reputation_seuil) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( 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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation set to {reputation_seuil}") + await self.Protocol.send_notice(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.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( 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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation set to {reputation_timer}") + await self.Protocol.send_notice(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.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( 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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_score_after_release}") + await self.Protocol.send_notice(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.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( 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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_sg}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_sg}") case _: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set action [kill|None]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") + await self.Protocol.send_notice(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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set action [kill|None]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") + await self.Protocol.send_notice(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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" La valeur devrait etre un entier >= 0") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" La valeur devrait etre un entier >= 0") case 'proxy_scan': @@ -628,11 +628,11 @@ class Defender(IModule): set_key = str(cmd[1]).lower() if set_key != 'set': - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + await self.Protocol.send_notice(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 @@ -641,105 +641,105 @@ class Defender(IModule): case 'local_scan': if action == 'on': if self.ModConfig.local_scan == 1: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case _: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') case 'flood': # .flood on/off @@ -754,21 +754,21 @@ class Defender(IModule): key = 'flood' if activation == 'on': if self.ModConfig.flood == 1: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Already activated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.red}FLOOD{self.Config.COLORS.black} ] : Already Deactivated", channel=dchanlog) + await self.Protocol.send_priv_msg(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.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.Protocol.send_priv_msg(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() @@ -780,7 +780,7 @@ class Defender(IModule): set_value = int(cmd[3]) self.update_configuration(key, set_value) - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood message set to {set_value} by {fromuser}", channel=dchanlog) @@ -789,7 +789,7 @@ class Defender(IModule): set_value = int(cmd[3]) self.update_configuration(key, set_value) - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood time set to {set_value} by {fromuser}", channel=dchanlog) @@ -798,7 +798,7 @@ class Defender(IModule): set_value = int(cmd[3]) self.update_configuration(key, set_value) - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood timer set to {set_value} by {fromuser}", channel=dchanlog) @@ -814,33 +814,33 @@ class Defender(IModule): color_black = self.Config.COLORS.black nogc = self.Config.COLORS.nogc try: - self.Protocol.send_notice(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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_seuil ==> {self.ModConfig.reputation_seuil}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_after_release ==> {self.ModConfig.reputation_score_after_release}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_ban_all_chan ==> {self.ModConfig.reputation_ban_all_chan}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_timer ==> {self.ModConfig.reputation_timer}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' [Proxy_scan]') - self.Protocol.send_notice(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.send_notice(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.send_notice(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.send_notice(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.send_notice(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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit{nogc}] ==> {self.ModConfig.autolimit}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit Amount{nogc} ==> {self.ModConfig.autolimit_amount}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit Interval{nogc} ==> {self.ModConfig.autolimit_interval}') - self.Protocol.send_notice(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.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' flood_action ==> Coming soon') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.ModConfig.flood_message}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.ModConfig.flood_time}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.ModConfig.flood_timer}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Sentinel{nogc}] ==> {self.ModConfig.sentinel}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.reputation == 1 else color_red}Reputation{nogc}] ==> {self.ModConfig.reputation}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_seuil ==> {self.ModConfig.reputation_seuil}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_after_release ==> {self.ModConfig.reputation_score_after_release}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_ban_all_chan ==> {self.ModConfig.reputation_ban_all_chan}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_timer ==> {self.ModConfig.reputation_timer}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' [Proxy_scan]') + await self.Protocol.send_notice(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}') + await self.Protocol.send_notice(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}') + await self.Protocol.send_notice(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}') + await self.Protocol.send_notice(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}') + await self.Protocol.send_notice(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}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit{nogc}] ==> {self.ModConfig.autolimit}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit Amount{nogc} ==> {self.ModConfig.autolimit_amount}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit Interval{nogc} ==> {self.ModConfig.autolimit_interval}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Flood{nogc}] ==> {self.ModConfig.flood}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' flood_action ==> Coming soon') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.ModConfig.flood_message}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.ModConfig.flood_time}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.ModConfig.flood_timer}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Sentinel{nogc}] ==> {self.ModConfig.sentinel}') except KeyError as ke: self.Logs.error(f"Key Error : {ke}") case 'info': try: if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Syntax. /msg {dnickname} INFO [nickname]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Syntax. /msg {dnickname} INFO [nickname]") return None nickoruid = cmd[1] @@ -849,22 +849,22 @@ class Defender(IModule): if UserObject is not None: channels: list = [chan.name for chan in self.Channel.UID_CHANNEL_DB for uid_in_chan in chan.uids if self.Loader.Utils.clean_uid(uid_in_chan) == UserObject.uid] - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' UID : {UserObject.uid}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' NICKNAME : {UserObject.nickname}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' USERNAME : {UserObject.username}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REALNAME : {UserObject.realname}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' HOSTNAME : {UserObject.hostname}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' VHOST : {UserObject.vhost}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' IP : {UserObject.remote_ip}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Country : {UserObject.geoip}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebIrc : {UserObject.isWebirc}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {", ".join(channels)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' UID : {UserObject.uid}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' NICKNAME : {UserObject.nickname}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' USERNAME : {UserObject.username}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REALNAME : {UserObject.realname}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' HOSTNAME : {UserObject.hostname}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' VHOST : {UserObject.vhost}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' IP : {UserObject.remote_ip}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Country : {UserObject.geoip}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebIrc : {UserObject.isWebirc}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {", ".join(channels)}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {nickoruid} doesn't exist") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {nickoruid} doesn't exist") except KeyError as ke: self.Logs.warning(f"Key error info user : {ke}") @@ -883,8 +883,8 @@ class Defender(IModule): self.update_configuration('sentinel', 1) for chan in self.Channel.UID_CHANNEL_DB: if chan.name not in channel_to_dont_quit: - self.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name) - self.Protocol.send_priv_msg(dnickname, f"Sentinel mode activated on {channel}", channel=chan.name) + await self.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name) + await self.Protocol.send_priv_msg(dnickname, f"Sentinel mode activated on {channel}", channel=chan.name) return None if activation == 'off': @@ -895,7 +895,7 @@ class Defender(IModule): self.update_configuration('sentinel', 0) for chan in self.Channel.UID_CHANNEL_DB: if chan.name not in channel_to_dont_quit: - self.Protocol.send_part_chan(uidornickname=dnickname, channel=chan.name) - self.Protocol.send_priv_msg(dnickname, f"Sentinel mode deactivated on {channel}", channel=chan.name) + await self.Protocol.send_part_chan(uidornickname=dnickname, channel=chan.name) + await self.Protocol.send_priv_msg(dnickname, f"Sentinel mode deactivated on {channel}", channel=chan.name) self.join_saved_channels() return None diff --git a/mods/votekick/utils.py b/mods/votekick/utils.py index 7f28bc9..4f81bb5 100644 --- a/mods/votekick/utils.py +++ b/mods/votekick/utils.py @@ -58,7 +58,7 @@ def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool: else: return False -def join_saved_channels(uplink: 'Votekick') -> None: +async def join_saved_channels(uplink: 'Votekick') -> None: param = {'module_name': uplink.module_name} result = uplink.Base.db_execute_query(f"SELECT id, channel_name FROM {uplink.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param) @@ -68,7 +68,7 @@ def join_saved_channels(uplink: 'Votekick') -> None: for channel in channels: id_, chan = channel uplink.VoteKickManager.activate_new_channel(chan) - uplink.Protocol.send_sjoin(channel=chan) - uplink.Protocol.send2socket(f":{uplink.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.Config.SERVICE_NICKNAME}") + await uplink.Protocol.send_sjoin(channel=chan) + await uplink.Protocol.send2socket(f":{uplink.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.Config.SERVICE_NICKNAME}") return None \ No newline at end of file From af992f7721b1ffa0e3069b902c48214bdab3182b Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:34:03 +0100 Subject: [PATCH 47/56] last changes for asyncio --- core/__init__.py | 1 + core/base.py | 30 ++++++++++++- core/classes/interfaces/imodule.py | 36 ++++++++-------- core/classes/modules/settings.py | 4 ++ core/context.py | 69 ++++++++++++++++++++++++++++++ core/irc.py | 12 +++--- core/module.py | 14 +++--- defender.py | 14 ------ mods/defender/mod_defender.py | 8 +++- mods/test/mod_test.py | 28 +++++++++--- 10 files changed, 163 insertions(+), 53 deletions(-) create mode 100644 core/context.py diff --git a/core/__init__.py b/core/__init__.py index e69de29..d87fb0c 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -0,0 +1 @@ +__version__ = '6.3' \ No newline at end of file diff --git a/core/base.py b/core/base.py index fbb404a..474050b 100644 --- a/core/base.py +++ b/core/base.py @@ -1,3 +1,4 @@ +import asyncio import os import re import json @@ -8,7 +9,7 @@ import ipaddress import ast import requests from dataclasses import fields -from typing import Any, Optional, TYPE_CHECKING +from typing import Any, Callable, Iterable, Optional, TYPE_CHECKING from base64 import b64decode, b64encode from sqlalchemy import create_engine, Engine, Connection, CursorResult from sqlalchemy.sql import text @@ -35,6 +36,9 @@ class Base: # Liste des threads en cours self.running_threads: list[threading.Thread] = self.Settings.RUNNING_THREADS + # List of all async tasks + self.running_asynctasks: list[asyncio.Task] = self.Settings.RUNNING_ASYNCTASKS + # Les sockets ouvert self.running_sockets: list[socket.socket] = self.Settings.RUNNING_SOCKETS @@ -358,6 +362,30 @@ class Base: except Exception as err: self.logs.error(err, exc_info=True) + def create_asynctask(self, func: Callable, *, async_name: str = None, run_once: bool = False) -> asyncio.Task: + """Create a new asynchrone and store it into running_asynctasks variable + + Args: + func (Callable): The function you want to call in asynchrone way + async_name (str, optional): The task name. Defaults to None. + run_once (bool, optional): If true the task will be run once. Defaults to False. + + Returns: + asyncio.Task: The Task + """ + name = func.__name__ if async_name is None else async_name + + if run_once: + for task in asyncio.all_tasks(): + if task.get_name().lower() == async_name.lower(): + return None + + task = asyncio.create_task(func, name=name) + self.running_asynctasks.append(task) + + self.logs.debug(f"++ New asynchrone task created as: {task.get_name()}") + return task + def is_thread_alive(self, thread_name: str) -> bool: """Check if the thread is still running! using the is_alive method of Threads. diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 95a8e47..fa22f52 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Optional from dataclasses import dataclass if TYPE_CHECKING: - from core.irc import Irc + from core.loader import Loader class IModule(ABC): @@ -13,19 +13,19 @@ class IModule(ABC): """The Model containing the module parameters """ - def __init__(self, uplink: 'Irc') -> None: + def __init__(self, uplink: 'Loader') -> None: # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() # Add Irc Object to the module (Mandatory) - self.Irc = uplink + self.Irc = uplink.Irc # Add Loader object to the module (Mandatory) - self.Loader = uplink.Loader + self.Loader = uplink # Add Protocol to the module (Mandatory) - self.Protocol = uplink.Protocol + self.Protocol = uplink.Irc.Protocol # Add Global Configuration to the module (Mandatory) self.Config = uplink.Config @@ -40,7 +40,7 @@ class IModule(ABC): self.MainUtils = uplink.Utils # Add logs object to the module (Mandatory) - self.Logs = uplink.Loader.Logs + self.Logs = uplink.Logs # Add User object to the module (Mandatory) self.User = uplink.User @@ -57,19 +57,23 @@ class IModule(ABC): # Add Reputation object to the module (Optional) self.Reputation = uplink.Reputation - # Load the child classes + # Log the module + self.Logs.debug(f'Loading Module {self.module_name} ...') + + def init(self) -> None: self.load() - - # Inspect child classes self.inspect_class() - self.create_tables() # Sync the configuration with core configuration (Mandatory) - uplink.Base.db_sync_core_config(self.module_name, self.ModConfig) + self.Base.db_sync_core_config(self.module_name, self.ModConfig) + return None - # Log the module - self.Logs.debug(f'Loading Module {self.module_name} ...') + def inspect_class(self): + if not hasattr(self, 'ModConfig'): + raise AttributeError("The Module must init ModConfig attribute in the load method!") + if not hasattr(self, 'MOD_HEADER'): + raise NotImplementedError(f"You must declare the header of the module in {self.__class__.__name__}!") def update_configuration(self, param_key: str, param_value: str) -> None: """Update the local and core configuration @@ -80,12 +84,6 @@ class IModule(ABC): """ self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) - def inspect_class(self): - if not hasattr(self, 'ModConfig'): - raise AttributeError("The Module must init ModConfig attribute in the load method!") - if not hasattr(self, 'MOD_HEADER'): - raise NotImplementedError(f"You must declare the header of the module in {self.__class__.__name__}!") - @abstractmethod def create_tables(self) -> None: """Method that will create the database if it does not exist. diff --git a/core/classes/modules/settings.py b/core/classes/modules/settings.py index 3026359..216920e 100644 --- a/core/classes/modules/settings.py +++ b/core/classes/modules/settings.py @@ -1,7 +1,9 @@ """This class should never be reloaded. """ +import asyncio from logging import Logger from threading import Timer, Thread, RLock +from asyncio.locks import Lock from socket import socket from typing import Any, Optional, TYPE_CHECKING from core.definition import MSModule, MAdmin @@ -17,9 +19,11 @@ class Settings: RUNNING_TIMERS: list[Timer] = [] RUNNING_THREADS: list[Thread] = [] + RUNNING_ASYNCTASKS: list[asyncio.Task] = [] RUNNING_SOCKETS: list[socket] = [] PERIODIC_FUNC: dict[str, Any] = {} LOCK: RLock = RLock() + AILOCK: Lock = Lock() CONSOLE: bool = False diff --git a/core/context.py b/core/context.py new file mode 100644 index 0000000..c8f4006 --- /dev/null +++ b/core/context.py @@ -0,0 +1,69 @@ +from logging import Logger +from core.classes.modules.settings import global_settings +from core.classes.modules import translation, user, admin, client, channel, reputation, settings, sasl +import core.logs as logs +import core.definition as df +import core.utils as utils +import core.base as base_mod +import core.module as module_mod +import core.classes.modules.commands as commands_mod +import core.classes.modules.config as conf_mod +import core.classes.modules.rpc.rpc as rpc_mod +import core.irc as irc +import core.classes.protocols.factory as factory + +class IrcContext: + + def ctx_modules(self) -> None: + self.Definition: df = df + self.ConfModule: conf_mod = conf_mod + self.BaseModule: base_mod = base_mod + self.CommandModule: commands_mod = commands_mod + self.LoggingModule: logs = logs + self.RpcServerModule: rpc_mod = rpc_mod + self.Utils: utils = utils + + def ctx_system(self) -> None: + self.Settings: settings.Settings = global_settings + self.Settings.global_lang = self.Config.LANG if self.Config.LANG else "EN" + + self.ServiceLogging: logs.ServiceLogging = self.LoggingModule.ServiceLogging() + self.Logs: Logger = self.ServiceLogging.get_logger() + + self.Config: df.MConfig = self.ConfModule.Configuration(self.Logs, self.ServiceLogging).configuration_model + + self.Settings.global_logger = self.Logs + + self.Translation: translation.Translation = translation.Translation(self) + + self.Settings.global_translation = self.Translation.get_translation() + + self.Base: base_mod.Base = self.BaseModule.Base(self) + + self.User: user.User = user.User(self) + + self.Settings.global_user = self.User + + self.Client: client.Client = client.Client(self) + + self.Admin: admin.Admin = admin.Admin(self) + + self.Channel: channel.Channel = channel.Channel(self) + + self.Reputation: reputation.Reputation = reputation.Reputation(self) + + self.Commands: commands_mod.Command = commands_mod.Command(self) + + self.ModuleUtils: module_mod.Module = module_mod.Module(self) + + self.Sasl: sasl.Sasl = sasl.Sasl(self) + + self.Irc: irc.Irc = irc.Irc(self) + + self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc) + + self.RpcServer: rpc_mod.JSONRPCServer = rpc_mod.JSONRPCServer(self) + + self.Base.init() + + self.Logs.debug(self.Utils.tr("Loader %s success", __name__)) diff --git a/core/irc.py b/core/irc.py index 89b1811..5469a2b 100644 --- a/core/irc.py +++ b/core/irc.py @@ -582,7 +582,7 @@ class Irc: # Envoyer la commande aux classes dynamiquement chargées if command != 'notallowed': for module in self.ModuleUtils.DB_MODULES: - module.class_instance.hcmds(user, channel, cmd, fullcmd) + await module.class_instance.hcmds(user, channel, cmd, fullcmd) match command: @@ -1048,11 +1048,11 @@ class Irc: try: # Load a module ex: .load mod_defender if len(cmd) < 2: - self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) + await self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) return None mod_name = str(cmd[1]) - self.ModuleUtils.load_one_module(self, mod_name, fromuser) + await self.ModuleUtils.load_one_module(self, mod_name, fromuser) return None except KeyError as ke: self.Logs.error(f"Key Error: {ke} - list recieved: {cmd}") @@ -1077,15 +1077,15 @@ class Irc: try: # ==> mod_defender if len(cmd) < 2: - self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) + await self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) return None module_name = str(cmd[1]).lower() - self.ModuleUtils.reload_one_module(self, module_name, fromuser) + await self.ModuleUtils.reload_one_module(self, module_name, fromuser) return None except Exception as e: self.Logs.error(f"Something went wrong with a module you want to reload: {e}") - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"Something went wrong with the module: {e}", channel=dchanlog diff --git a/core/module.py b/core/module.py index bdd6c2b..df684dd 100644 --- a/core/module.py +++ b/core/module.py @@ -110,7 +110,7 @@ class Module: try: loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe - create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe + create_instance_of_the_class = my_class(uplink.Loader) # Créer une nouvelle instance de la classe self.create_module_header(create_instance_of_the_class.MOD_HEADER) except AttributeError as attr: red = uplink.Config.COLORS.red @@ -151,7 +151,7 @@ class Module: def load_all_modules(self) -> bool: ... - def reload_one_module(self, uplink: 'Irc', module_name: str, nickname: str) -> bool: + async def reload_one_module(self, uplink: 'Irc', module_name: str, nickname: str) -> bool: """Reloading one module and insert it into the model as well as the database Args: @@ -172,7 +172,7 @@ class Module: self.delete_module_header(module_model.class_instance.MOD_HEADER['name']) module_model.class_instance.unload() else: - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}", channel=self.__Config.SERVICE_CHANLOG @@ -186,13 +186,13 @@ class Module: the_module = sys.modules[f'mods.{module_folder}.{module_name}'] importlib.reload(the_module) my_class = getattr(the_module, class_name, None) - new_instance = my_class(uplink) + new_instance = my_class(uplink.Loader) self.create_module_header(new_instance.MOD_HEADER) module_model.class_instance = new_instance # Créer le module dans la base de données self.db_register_module(module_name, nickname) - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=f"Module [{module_folder}.{module_name}] has been reloaded!", channel=self.__Config.SERVICE_CHANLOG @@ -202,7 +202,7 @@ class Module: else: # Module is not loaded! Nothing to reload self.__Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}") - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}", channel=self.__Config.SERVICE_CHANLOG @@ -211,7 +211,7 @@ class Module: except (TypeError, AttributeError, KeyError, Exception) as err: self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True) - uplink.Protocol.send_priv_msg( + await uplink.Protocol.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, msg=f"[RELOAD MODULE ERROR]: {err}", channel=self.__Config.SERVICE_CHANLOG diff --git a/defender.py b/defender.py index 199080f..9b03d89 100644 --- a/defender.py +++ b/defender.py @@ -17,17 +17,3 @@ async def main(): if __name__ == "__main__": asyncio.run(main(), debug=True) - - - -# try: -# # install.update_packages() -# from core.loader import Loader -# loader = Loader() -# loader.Irc.init_irc() - -# except AssertionError as ae: -# print(f'Assertion Error -> {ae}') -# except KeyboardInterrupt as k: -# # ircInstance.Base.execute_periodic_action() -# ... \ No newline at end of file diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index 9065325..2a5476c 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -1,11 +1,14 @@ from dataclasses import dataclass -from typing import Any +from typing import Any, TYPE_CHECKING from core.classes.interfaces.imodule import IModule import mods.defender.schemas as schemas import mods.defender.utils as utils import mods.defender.threads as thds from core.utils import tr +if TYPE_CHECKING: + from core.loader import Loader + class Defender(IModule): @dataclass @@ -20,6 +23,9 @@ class Defender(IModule): 'core_version':'Defender-6' } + def __init__(self, context: 'Loader') -> None: + self.ctx = context + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 480d763..0425279 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -1,7 +1,11 @@ -from typing import Any +import asyncio +from typing import Any, TYPE_CHECKING from core.classes.interfaces.imodule import IModule from dataclasses import dataclass +if TYPE_CHECKING: + from core.loader import Loader + class Test(IModule): @dataclass @@ -22,6 +26,10 @@ class Test(IModule): } """Module Header (Mandatory)""" + def __init__(self, uplink: 'Loader'): + super().__init__(uplink) + self.init() + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -48,6 +56,7 @@ class Test(IModule): # Create module commands (Mandatory) self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command') + self.Irc.build_command(0, self.module_name, 'asyncio', 'Create a new asynchron task!') self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command') self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command') self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command') @@ -72,7 +81,13 @@ class Test(IModule): except Exception as err: self.Logs.error(f"General Error: {err}") - def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: + async def asyncio_func(self) -> None: + self.Logs.debug(f"Starting async method in a task: {self.__class__.__name__}") + await asyncio.sleep(2) + await asyncio.sleep(3) + self.Logs.debug(f"End of the task: {self.__class__.__name__}") + + async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: """All messages coming from the user commands (Mandatory) Args: @@ -90,14 +105,17 @@ class Test(IModule): dnickname = self.Config.SERVICE_NICKNAME match command: + + case 'asyncio': + task = self.Base.create_asynctask(self.asyncio_func()) case 'test-command': try: - self.Protocol.send_notice(nick_from=dnickname, nick_to=u.nickname, msg="This is a notice to the sender ...") - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=u.nickname) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=u.nickname, msg="This is a notice to the sender ...") + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=u.nickname) if c is not None: - self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name) + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name) # How to update your module configuration self.update_configuration('param_exemple2', 7) From 1b30b1ff4ed31e7eaa6eb813efce90262acf110f Mon Sep 17 00:00:00 2001 From: adator85 <> Date: Tue, 18 Nov 2025 16:27:42 +0100 Subject: [PATCH 48/56] Update module interface... --- core/base.py | 14 +++---- core/classes/interfaces/imodule.py | 66 +++++++----------------------- mods/test/mod_test.py | 64 +++++++++++++++++------------ 3 files changed, 59 insertions(+), 85 deletions(-) diff --git a/core/base.py b/core/base.py index 474050b..dff0d0e 100644 --- a/core/base.py +++ b/core/base.py @@ -259,20 +259,20 @@ class Base: self.logs.error(err) return False - def db_update_core_config(self, module_name:str, dataclassObj: object, param_key:str, param_value: str) -> bool: + def db_update_core_config(self, module_name:str, dataclass_obj: object, param_key:str, param_value: str) -> bool: core_table = self.Config.TABLE_CONFIG # Check if the param exist - if not hasattr(dataclassObj, param_key): + if not hasattr(dataclass_obj, param_key): self.logs.error(f"Le parametre {param_key} n'existe pas dans la variable global") return False mes_donnees = {'module_name': module_name, 'param_key': param_key, 'param_value': param_value} search_param_query = f"SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key" result = self.db_execute_query(search_param_query, mes_donnees) - isParamExist = result.fetchone() + is_param_exist = result.fetchone() - if not isParamExist is None: + if not is_param_exist is None: mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'module_name': module_name, 'param_key': param_key, @@ -282,14 +282,14 @@ class Base: update = self.db_execute_query(query, mes_donnees) updated_rows = update.rowcount if updated_rows > 0: - setattr(dataclassObj, param_key, self.int_if_possible(param_value)) + setattr(dataclass_obj, param_key, self.int_if_possible(param_value)) self.logs.debug(f'Parameter updated : {param_key} - {param_value} | Module: {module_name}') else: self.logs.error(f'Parameter NOT updated : {param_key} - {param_value} | Module: {module_name}') else: self.logs.error(f'Parameter and Module do not exist: Param ({param_key}) - Value ({param_value}) | Module ({module_name})') - self.logs.debug(dataclassObj) + self.logs.debug(dataclass_obj) return True @@ -362,7 +362,7 @@ class Base: except Exception as err: self.logs.error(err, exc_info=True) - def create_asynctask(self, func: Callable, *, async_name: str = None, run_once: bool = False) -> asyncio.Task: + def create_asynctask(self, func: Any, *, async_name: str = None, run_once: bool = False) -> asyncio.Task: """Create a new asynchrone and store it into running_asynctasks variable Args: diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index fa22f52..309b853 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Union from dataclasses import dataclass if TYPE_CHECKING: @@ -15,74 +15,38 @@ class IModule(ABC): def __init__(self, uplink: 'Loader') -> None: + # import the context + self.ctx = uplink + # Module name (Mandatory) self.module_name = 'mod_' + str(self.__class__.__name__).lower() - # Add Irc Object to the module (Mandatory) - self.Irc = uplink.Irc - - # Add Loader object to the module (Mandatory) - self.Loader = uplink - - # Add Protocol to the module (Mandatory) - self.Protocol = uplink.Irc.Protocol - - # Add Global Configuration to the module (Mandatory) - self.Config = uplink.Config - - # Add Settings to the module (Mandatory) - self.Settings = uplink.Settings - - # Add Base object to the module (Mandatory) - self.Base = uplink.Base - - # Add Main Utils (Mandatory) - self.MainUtils = uplink.Utils - - # Add logs object to the module (Mandatory) - self.Logs = uplink.Logs - - # Add User object to the module (Mandatory) - self.User = uplink.User - - # Add Client object to the module (Mandatory) - self.Client = uplink.Client - - # Add Admin object to the module (Mandatory) - self.Admin = uplink.Admin - - # Add Channel object to the module (Mandatory) - self.Channel = uplink.Channel - - # Add Reputation object to the module (Optional) - self.Reputation = uplink.Reputation - # Log the module - self.Logs.debug(f'Loading Module {self.module_name} ...') + self.ctx.Logs.debug(f'Loading Module {self.module_name} ...') def init(self) -> None: self.load() - self.inspect_class() self.create_tables() # Sync the configuration with core configuration (Mandatory) - self.Base.db_sync_core_config(self.module_name, self.ModConfig) + self.ctx.Base.db_sync_core_config(self.module_name, self.mod_config) return None - def inspect_class(self): - if not hasattr(self, 'ModConfig'): - raise AttributeError("The Module must init ModConfig attribute in the load method!") - if not hasattr(self, 'MOD_HEADER'): - raise NotImplementedError(f"You must declare the header of the module in {self.__class__.__name__}!") - - def update_configuration(self, param_key: str, param_value: str) -> None: + def update_configuration(self, param_key: str, param_value: Union[str, int]) -> None: """Update the local and core configuration Args: param_key (str): The parameter key param_value (str): The parameter value """ - self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value) + self.ctx.Base.db_update_core_config(self.module_name, self.mod_config, param_key, param_value) + + @property + @abstractmethod + def mod_config(self) -> ModConfModel: + """ + The module configuration model + """ @abstractmethod def create_tables(self) -> None: diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 0425279..4b8aac7 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -1,5 +1,5 @@ import asyncio -from typing import Any, TYPE_CHECKING +from typing import Any, TYPE_CHECKING, Optional from core.classes.interfaces.imodule import IModule from dataclasses import dataclass @@ -28,13 +28,11 @@ class Test(IModule): def __init__(self, uplink: 'Loader'): super().__init__(uplink) - self.init() + self._mod_config: Optional[Test.ModConfModel] = None def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module - Args: - database_name (str): Nom de la base de données ( pas d'espace dans le nom ) Returns: None: Aucun retour n'es attendu @@ -47,7 +45,7 @@ class Test(IModule): ) ''' - # self.Base.db_execute_query(table_logs) + # self.ctx.Base.db_execute_query(table_logs) return None def load(self) -> None: @@ -55,18 +53,25 @@ class Test(IModule): """ # Create module commands (Mandatory) - self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command') - self.Irc.build_command(0, self.module_name, 'asyncio', 'Create a new asynchron task!') - self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command') - self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command') - self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command') + self.ctx.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command') + self.ctx.Irc.build_command(0, self.module_name, 'asyncio', 'Create a new asynchron task!') + self.ctx.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command') + self.ctx.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command') + self.ctx.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command') # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel(param_exemple1='str', param_exemple2=1) + self._mod_config = self.ModConfModel(param_exemple1='str', param_exemple2=1) + + # Init the module (Mandatory) + self.init() + + @property + def mod_config(self) -> ModConfModel: + return self._mod_config def unload(self) -> None: - """### This method is called when you unload or you reload the module (Mandatory)""" - self.Irc.Commands.drop_command_by_module(self.module_name) + """### This method is called when you unload, or you reload the module (Mandatory)""" + self.ctx.Irc.Commands.drop_command_by_module(self.module_name) return None def cmd(self, data: list[str]) -> None: @@ -79,15 +84,14 @@ class Test(IModule): try: return None except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}") async def asyncio_func(self) -> None: - self.Logs.debug(f"Starting async method in a task: {self.__class__.__name__}") + self.ctx.Logs.debug(f"Starting async method in a task: {self.__class__.__name__}") await asyncio.sleep(2) - await asyncio.sleep(3) - self.Logs.debug(f"End of the task: {self.__class__.__name__}") + self.ctx.Logs.debug(f"End of the task: {self.__class__.__name__}") - async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: + async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None: """All messages coming from the user commands (Mandatory) Args: @@ -96,33 +100,39 @@ class Test(IModule): cmd (list): The messages coming from the IRCD server. fullcmd (list, optional): The full messages coming from the IRCD server. Defaults to []. """ - u = self.User.get_user(user) - c = self.Channel.get_channel(channel) if self.Channel.is_valid_channel(channel) else None + u = self.ctx.User.get_user(user) + c = self.ctx.Channel.get_channel(channel) if self.ctx.Channel.is_valid_channel(channel) else None if u is None: return None command = str(cmd[0]).lower() - dnickname = self.Config.SERVICE_NICKNAME + dnickname = self.ctx.Config.SERVICE_NICKNAME match command: case 'asyncio': - task = self.Base.create_asynctask(self.asyncio_func()) + self.ctx.Base.create_asynctask(self.asyncio_func()) + return None case 'test-command': try: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=u.nickname, msg="This is a notice to the sender ...") - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=u.nickname) + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=u.nickname, msg="This is a notice to the sender ...") + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=u.nickname) if c is not None: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name) # How to update your module configuration self.update_configuration('param_exemple2', 7) self.update_configuration('param_exemple1', 'my_value') # Log if you want the result - self.Logs.debug(f"Test logs ready") + self.ctx.Logs.debug(f"Test logs ready") + return None except Exception as err: - self.Logs.error(f"Unknown Error: {err}") \ No newline at end of file + self.ctx.Logs.error(f"Unknown Error: {err}") + return None + + case _: + return None \ No newline at end of file From aa15aea749955473401c440297f55dae61bf5e8b Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 00:29:32 +0100 Subject: [PATCH 49/56] Introduce full asyncio version (still some module to migrate). Defender JSONRPC Server ready and using with uvcorn --- core/base.py | 103 ++-- core/classes/interfaces/imodule.py | 19 +- core/classes/interfaces/iprotocol.py | 29 +- core/classes/modules/admin.py | 8 +- core/classes/modules/channel.py | 66 ++- core/classes/modules/client.py | 4 +- core/classes/modules/rehash.py | 70 +-- core/classes/modules/rpc/__init__.py | 1 + core/classes/modules/rpc/rpc.py | 243 +++----- core/classes/modules/rpc/rpc_channel.py | 4 +- core/classes/modules/rpc/rpc_command.py | 16 +- core/classes/modules/rpc/rpc_user.py | 12 +- core/classes/protocols/factory.py | 21 +- core/classes/protocols/inspircd.py | 711 +++++++++++------------ core/classes/protocols/unreal6.py | 620 ++++++++++---------- core/definition.py | 3 +- core/irc.py | 726 ++++++++++-------------- core/loader.py | 18 +- core/logs.py | 2 +- core/module.py | 239 ++++---- core/utils.py | 12 + defender.py | 1 + mods/clone/clone_manager.py | 2 +- mods/clone/mod_clone.py | 175 +++--- mods/clone/threads.py | 13 +- mods/clone/utils.py | 18 +- mods/command/mod_command.py | 647 ++++++++++----------- mods/command/utils.py | 180 +++--- mods/defender/mod_defender.py | 698 ++++++++++++----------- mods/defender/threads.py | 115 ++-- mods/defender/utils.py | 363 ++++++------ mods/test/mod_test.py | 11 +- requirements.txt | 4 +- version.json | 6 +- 34 files changed, 2533 insertions(+), 2627 deletions(-) create mode 100644 core/classes/modules/rpc/__init__.py diff --git a/core/base.py b/core/base.py index dff0d0e..6d9fbb7 100644 --- a/core/base.py +++ b/core/base.py @@ -45,9 +45,6 @@ class Base: # Liste des fonctions en attentes self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC - # Création du lock - self.lock = self.Settings.LOCK - # Init install variable self.install: bool = False @@ -57,8 +54,8 @@ class Base: # Create the database # self.__create_db() - def init(self) -> None: - self.__create_db() + async def init(self) -> None: + await self.__create_db() def __set_current_defender_version(self) -> None: """This will put the current version of Defender @@ -145,7 +142,7 @@ class Base: except Exception as err: self.logs.error(f'General Error: {err}') - def create_log(self, log_message: str) -> None: + async def create_log(self, log_message: str) -> None: """Enregiste les logs Args: @@ -156,11 +153,11 @@ class Base: """ sql_insert = f"INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)" mes_donnees = {'datetime': str(self.Utils.get_sdatetime()),'server_msg': f'{log_message}'} - self.db_execute_query(sql_insert, mes_donnees) + await self.db_execute_query(sql_insert, mes_donnees) return None - def log_cmd(self, user_cmd: str, cmd: str) -> None: + async def log_cmd(self, user_cmd: str, cmd: str) -> None: """Enregistre les commandes envoyées par les utilisateurs Args: @@ -176,11 +173,11 @@ class Base: insert_cmd_query = f"INSERT INTO {self.Config.TABLE_COMMAND} (datetime, user, commande) VALUES (:datetime, :user, :commande)" mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'commande': cmd} - self.db_execute_query(insert_cmd_query, mes_donnees) + await self.db_execute_query(insert_cmd_query, mes_donnees) return None - def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool: + async def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool: """Sync module local parameters with the database if new module then local param will be stored in the database if old module then db param will be moved to the local dataclassObj @@ -207,7 +204,7 @@ class Base: param_to_search = {'module_name': module_name, 'param_key': param_key} search_query = f'''SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key''' - excecute_search_query = self.db_execute_query(search_query, param_to_search) + excecute_search_query = await self.db_execute_query(search_query, param_to_search) result_search_query = excecute_search_query.fetchone() if result_search_query is None: @@ -219,7 +216,7 @@ class Base: insert_query = f'''INSERT INTO {core_table} (datetime, module_name, param_key, param_value) VALUES (:datetime, :module_name, :param_key, :param_value) ''' - execution = self.db_execute_query(insert_query, param_to_insert) + execution = await self.db_execute_query(insert_query, param_to_insert) if execution.rowcount > 0: self.logs.debug(f'New parameter added to the database: {param_key} --> {param_value}') @@ -227,14 +224,14 @@ class Base: # Delete from DB unused parameter query_select = f"SELECT module_name, param_key, param_value FROM {core_table} WHERE module_name = :module_name" parameter = {'module_name': module_name} - execute_query_select = self.db_execute_query(query_select, parameter) + execute_query_select = await self.db_execute_query(query_select, parameter) result_query_select = execute_query_select.fetchall() for result in result_query_select: db_mod_name, db_param_key, db_param_value = result if not hasattr(dataclassObj, db_param_key): mes_donnees = {'param_key': db_param_key, 'module_name': db_mod_name} - execute_delete = self.db_execute_query(f'DELETE FROM {core_table} WHERE module_name = :module_name and param_key = :param_key', mes_donnees) + execute_delete = await self.db_execute_query(f'DELETE FROM {core_table} WHERE module_name = :module_name and param_key = :param_key', mes_donnees) row_affected = execute_delete.rowcount if row_affected > 0: self.logs.debug(f'A parameter has been deleted from the database: {db_param_key} --> {db_param_value} | Mod: {db_mod_name}') @@ -242,7 +239,7 @@ class Base: # Sync local variable with Database query = f"SELECT param_key, param_value FROM {core_table} WHERE module_name = :module_name" parameter = {'module_name': module_name} - response = self.db_execute_query(query, parameter) + response = await self.db_execute_query(query, parameter) result = response.fetchall() for param, value in result: @@ -259,7 +256,7 @@ class Base: self.logs.error(err) return False - def db_update_core_config(self, module_name:str, dataclass_obj: object, param_key:str, param_value: str) -> bool: + async def db_update_core_config(self, module_name:str, dataclass_obj: object, param_key:str, param_value: str) -> bool: core_table = self.Config.TABLE_CONFIG # Check if the param exist @@ -269,7 +266,7 @@ class Base: mes_donnees = {'module_name': module_name, 'param_key': param_key, 'param_value': param_value} search_param_query = f"SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key" - result = self.db_execute_query(search_param_query, mes_donnees) + result = await self.db_execute_query(search_param_query, mes_donnees) is_param_exist = result.fetchone() if not is_param_exist is None: @@ -279,7 +276,7 @@ class Base: 'param_value': param_value } query = f'''UPDATE {core_table} SET datetime = :datetime, param_value = :param_value WHERE module_name = :module_name AND param_key = :param_key''' - update = self.db_execute_query(query, mes_donnees) + update = await self.db_execute_query(query, mes_donnees) updated_rows = update.rowcount if updated_rows > 0: setattr(dataclass_obj, param_key, self.int_if_possible(param_value)) @@ -293,9 +290,9 @@ class Base: return True - def db_create_first_admin(self) -> None: + async def db_create_first_admin(self) -> None: - user = self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}") + user = await self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}") if not user.fetchall(): admin = self.Config.OWNER password = self.Utils.hash_password(self.Config.PASSWORD) @@ -308,7 +305,7 @@ class Base: 'language': 'EN', 'level': 5 } - self.db_execute_query(f""" + await self.db_execute_query(f""" INSERT INTO {self.Config.TABLE_ADMIN} (createdOn, user, password, hostname, vhost, language, level) VALUES @@ -381,11 +378,28 @@ class Base: return None task = asyncio.create_task(func, name=name) + task.add_done_callback(self.asynctask_done) self.running_asynctasks.append(task) self.logs.debug(f"++ New asynchrone task created as: {task.get_name()}") return task + def asynctask_done(self, task: asyncio.Task): + """Log task when done + + Args: + task (asyncio.Task): The Asyncio Task callback + """ + try: + if task.exception(): + self.logs.error(f"[ASYNCIO] Task {task.get_name()} failed with exception: {task.exception()}") + else: + self.logs.debug(f"[ASYNCIO] Task {task.get_name()} completed successfully.") + except asyncio.CancelledError as ce: + self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with cancelled error.") + except asyncio.InvalidStateError as ie: + self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with invalid state error.") + def is_thread_alive(self, thread_name: str) -> bool: """Check if the thread is still running! using the is_alive method of Threads. @@ -429,7 +443,7 @@ class Base: Returns: int: Number of threads """ - with self.lock: + with self.Settings.LOCK: count = 0 for thr in self.running_threads: @@ -478,7 +492,7 @@ class Base: self.running_sockets.remove(soc) self.logs.debug(f"-- Socket ==> closed {str(soc.fileno())}") - def shutdown(self) -> None: + async def shutdown(self) -> None: """Methode qui va préparer l'arrêt complêt du service """ # Nettoyage des timers @@ -507,6 +521,9 @@ class Base: self.running_sockets.remove(soc) self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}") + + await self.Loader.RpcServer.stop_server() + self.db_close() return None @@ -524,7 +541,7 @@ class Base: self.logs.info("-- Database connexion has been initiated") return engine, cursor - def __create_db(self) -> None: + async def __create_db(self) -> None: table_core_log = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_LOG} ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -594,27 +611,27 @@ class Base: ) ''' - self.db_execute_query(table_core_log) - self.db_execute_query(table_core_log_command) - self.db_execute_query(table_core_module) - self.db_execute_query(table_core_admin) - self.db_execute_query(table_core_client) - self.db_execute_query(table_core_channel) - self.db_execute_query(table_core_config) + await self.db_execute_query(table_core_log) + await self.db_execute_query(table_core_log_command) + await self.db_execute_query(table_core_module) + await self.db_execute_query(table_core_admin) + await self.db_execute_query(table_core_client) + await self.db_execute_query(table_core_channel) + await self.db_execute_query(table_core_config) # Patch database - self.db_patch(self.Config.TABLE_ADMIN, "language", "TEXT") + await self.db_patch(self.Config.TABLE_ADMIN, "language", "TEXT") if self.install: - self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True) - self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True) + await self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True) + await self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True) self.install = False return None - def db_execute_query(self, query:str, params:dict = {}) -> CursorResult: + async def db_execute_query(self, query:str, params:dict = {}) -> CursorResult: - with self.lock: + async with self.Loader.Settings.AILOCK: insert_query = text(query) if not params: response = self.cursor.execute(insert_query) @@ -625,8 +642,8 @@ class Base: return response - def db_is_column_exist(self, table_name: str, column_name: str) -> bool: - q = self.db_execute_query(f"PRAGMA table_info({table_name})") + async def db_is_column_exist(self, table_name: str, column_name: str) -> bool: + q = await self.db_execute_query(f"PRAGMA table_info({table_name})") existing_columns = [col[1] for col in q.fetchall()] if column_name in existing_columns: @@ -634,12 +651,12 @@ class Base: else: return False - def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool: - if not self.db_is_column_exist(table_name, column_name): + async def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool: + if not await self.db_is_column_exist(table_name, column_name): patch = f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}" update_row = f"UPDATE {table_name} SET language = 'EN' WHERE language is null" - self.db_execute_query(patch) - self.db_execute_query(update_row) + await self.db_execute_query(patch) + await self.db_execute_query(update_row) self.logs.debug(f"The patch has been applied") self.logs.debug(f"Table name: {table_name}, Column name: {column_name}, Column type: {column_type}") return True @@ -647,9 +664,9 @@ class Base: return False def db_close(self) -> None: - try: self.cursor.close() + self.logs.debug("Database engine closed!") except AttributeError as ae: self.logs.error(f"Attribute Error : {ae}") diff --git a/core/classes/interfaces/imodule.py b/core/classes/interfaces/imodule.py index 309b853..7f8c306 100644 --- a/core/classes/interfaces/imodule.py +++ b/core/classes/interfaces/imodule.py @@ -24,22 +24,19 @@ class IModule(ABC): # Log the module self.ctx.Logs.debug(f'Loading Module {self.module_name} ...') - def init(self) -> None: - self.load() - self.create_tables() - + async def sync_db(self) -> None: # Sync the configuration with core configuration (Mandatory) - self.ctx.Base.db_sync_core_config(self.module_name, self.mod_config) + await self.ctx.Base.db_sync_core_config(self.module_name, self.mod_config) return None - def update_configuration(self, param_key: str, param_value: Union[str, int]) -> None: + async def update_configuration(self, param_key: str, param_value: Union[str, int]) -> None: """Update the local and core configuration Args: param_key (str): The parameter key param_value (str): The parameter value """ - self.ctx.Base.db_update_core_config(self.module_name, self.mod_config, param_key, param_value) + await self.ctx.Base.db_update_core_config(self.module_name, self.mod_config, param_key, param_value) @property @abstractmethod @@ -58,17 +55,17 @@ class IModule(ABC): """ @abstractmethod - def load(self) -> None: + async def load(self) -> None: """This method is executed when the module is loaded or reloaded. """ @abstractmethod - def unload(self) -> None: + async def unload(self) -> None: """This method is executed when the module is unloaded or reloaded. """ @abstractmethod - def cmd(self, data: list) -> None: + async def cmd(self, data: list) -> None: """When recieving server messages. Args: @@ -76,7 +73,7 @@ class IModule(ABC): """ @abstractmethod - def hcmds(self, user: str, channel: Optional[str], cmd: list[str], fullcmd: Optional[list[str]] = None) -> None: + async def hcmds(self, user: str, channel: Optional[str], cmd: list[str], fullcmd: Optional[list[str]] = None) -> None: """These are the commands recieved from a client Args: diff --git a/core/classes/interfaces/iprotocol.py b/core/classes/interfaces/iprotocol.py index 7c7ad3b..6ff5bfc 100644 --- a/core/classes/interfaces/iprotocol.py +++ b/core/classes/interfaces/iprotocol.py @@ -4,31 +4,20 @@ from core.classes.protocols.command_handler import CommandHandler if TYPE_CHECKING: from core.definition import MClient, MSasl, MUser, MChannel - from core.irc import Irc + from core.loader import Loader class IProtocol(ABC): Handler: Optional[CommandHandler] = None - def __init__(self, uplink: 'Irc'): + def __init__(self, context: 'Loader'): self.name: Optional[str] = None self.protocol_version: int = -1 self.known_protocol: set[str] = set() - - self._Irc = uplink - self._Config = uplink.Config - self._Base = uplink.Base - self._Settings = uplink.Base.Settings - self._Utils = uplink.Loader.Utils - self._Logs = uplink.Loader.Logs - self._User = uplink.User - self._Channel = uplink.Channel - - self.Handler = CommandHandler(uplink.Loader) - + self._ctx = context + self.Handler = CommandHandler(context) self.init_protocol() - - self._Logs.info(f"[PROTOCOL] Protocol [{self.__class__.__name__}] loaded!") + self._ctx.Logs.info(f"[PROTOCOL] Protocol [{self.__class__.__name__}] loaded!") @abstractmethod def init_protocol(self): @@ -313,7 +302,7 @@ class IProtocol(ABC): # ------------------------------------------------------------------------ @abstractmethod - async def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: + def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. Args: @@ -324,7 +313,7 @@ class IProtocol(ABC): """ @abstractmethod - async def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: + def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] Args: @@ -335,7 +324,7 @@ class IProtocol(ABC): """ @abstractmethod - async def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: + def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: """Parse nick changes and return dictionary. >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] @@ -349,7 +338,7 @@ class IProtocol(ABC): """ @abstractmethod - async def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: + def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] diff --git a/core/classes/modules/admin.py b/core/classes/modules/admin.py index 7f59939..a71a87d 100644 --- a/core/classes/modules/admin.py +++ b/core/classes/modules/admin.py @@ -173,7 +173,7 @@ class Admin: return admin.language - def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool: + async def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool: """Check the fingerprint Args: @@ -188,7 +188,7 @@ class Admin: query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp" data = {'fp': fp} - exe = self.Base.db_execute_query(query, data) + exe = await self.Base.db_execute_query(query, data) result = exe.fetchone() if result: account = result[0] @@ -204,7 +204,7 @@ class Admin: return False - def db_is_admin_exist(self, admin_nickname: str) -> bool: + async def db_is_admin_exist(self, admin_nickname: str) -> bool: """Verify if the admin exist in the database! Args: @@ -216,7 +216,7 @@ class Admin: mes_donnees = {'admin': admin_nickname} query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user = :admin" - r = self.Base.db_execute_query(query_search_user, mes_donnees) + r = await self.Base.db_execute_query(query_search_user, mes_donnees) exist_user = r.fetchone() if exist_user: return True diff --git a/core/classes/modules/channel.py b/core/classes/modules/channel.py index 0bcb0fb..0ea36d4 100644 --- a/core/classes/modules/channel.py +++ b/core/classes/modules/channel.py @@ -17,9 +17,7 @@ class Channel: Args: loader (Loader): The Loader Instance """ - self.Logs = loader.Logs - self.Base = loader.Base - self.Utils = loader.Utils + self._ctx = loader def insert(self, new_channel: 'MChannel') -> bool: """This method will insert a new channel and if the channel exist it will update the user list (uids) @@ -34,14 +32,14 @@ class Channel: exist = False if not self.is_valid_channel(new_channel.name): - self.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #") + self._ctx.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #") return False for record in self.UID_CHANNEL_DB: if record.name.lower() == new_channel.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') + # self._ctx.Logs.debug(f'{record.name} already exist') for user in new_channel.uids: record.uids.append(user) @@ -49,7 +47,7 @@ class Channel: # 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}') + # self._ctx.Logs.debug(f'Updating a new UID to the channel {record}') return result if not exist: @@ -57,10 +55,10 @@ class Channel: new_channel.name = new_channel.name.lower() self.UID_CHANNEL_DB.append(new_channel) result = True - # self.Logs.debug(f'New Channel Created: ({new_channel})') + # self._ctx.Logs.debug(f'New Channel Created: ({new_channel})') if not result: - self.Logs.critical(f'The Channel Object was not inserted {new_channel}') + self._ctx.Logs.critical(f'The Channel Object was not inserted {new_channel}') self.clean_channel() @@ -103,7 +101,7 @@ class Channel: return result for userid in chan_obj.uids: - if self.Utils.clean_uid(userid) == self.Utils.clean_uid(uid): + if self._ctx.Utils.clean_uid(userid) == self._ctx.Utils.clean_uid(uid): chan_obj.uids.remove(userid) result = True @@ -111,7 +109,7 @@ class Channel: return result except ValueError as ve: - self.Logs.error(f'{ve}') + self._ctx.Logs.error(f'{ve}') return False def delete_user_from_all_channel(self, uid:str) -> bool: @@ -128,7 +126,7 @@ class Channel: for record in self.UID_CHANNEL_DB: for user_id in record.uids: - if self.Utils.clean_uid(user_id) == self.Utils.clean_uid(uid): + if self._ctx.Utils.clean_uid(user_id) == self._ctx.Utils.clean_uid(uid): record.uids.remove(user_id) result = True @@ -136,7 +134,7 @@ class Channel: return result except ValueError as ve: - self.Logs.error(f'{ve}') + self._ctx.Logs.error(f'{ve}') return False def add_user_to_a_channel(self, channel_name: str, uid: str) -> bool: @@ -154,7 +152,7 @@ class Channel: if chan_obj is None: # Create a new channel if the channel don't exist - self.Logs.debug(f"New channel will be created ({channel_name} - {uid})") + self._ctx.Logs.debug(f"New channel will be created ({channel_name} - {uid})") return self.insert(MChannel(channel_name, uids=[uid])) chan_obj.uids.append(uid) @@ -163,7 +161,7 @@ class Channel: return True except Exception as err: - self.Logs.error(f'{err}') + self._ctx.Logs.error(f'{err}') return False def is_user_present_in_channel(self, channel_name: str, uid: str) -> bool: @@ -180,9 +178,9 @@ class Channel: if chan is None: return False - clean_uid = self.Utils.clean_uid(uid=uid) + clean_uid = self._ctx.Utils.clean_uid(uid=uid) for chan_uid in chan.uids: - if self.Utils.clean_uid(chan_uid) == clean_uid: + if self._ctx.Utils.clean_uid(chan_uid) == clean_uid: return True return False @@ -197,7 +195,7 @@ class Channel: return None except Exception as err: - self.Logs.error(f'{err}') + self._ctx.Logs.error(f'{err}') def get_channel(self, channel_name: str) -> Optional['MChannel']: """Get the channel object @@ -237,13 +235,13 @@ class Channel: else: return True except TypeError as te: - self.Logs.error(f'TypeError: [{channel_to_check}] - {te}') + self._ctx.Logs.error(f'TypeError: [{channel_to_check}] - {te}') return False except Exception as err: - self.Logs.error(f'Error Not defined: {err}') + self._ctx.Logs.error(f'Error Not defined: {err}') return False - def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool: + async def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool: """You can add a channel or delete a channel. Args: @@ -256,39 +254,49 @@ class Channel: """ try: channel_name = channel_name.lower() if self.is_valid_channel(channel_name) else None - core_table = self.Base.Config.TABLE_CHANNEL + core_table = self._ctx.Base.Config.TABLE_CHANNEL if not channel_name: - self.Logs.warning(f'The channel [{channel_name}] is not correct') + self._ctx.Logs.warning(f'The channel [{channel_name}] is not correct') return False 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) + response = await self._ctx.Base.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees) is_channel_exist = response.fetchone() if is_channel_exist is None: - mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name} - insert = self.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees) + mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name} + insert = await self._ctx.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees) if insert.rowcount: - self.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}') + self._ctx.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}') return True 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) + response = await self._ctx.Base.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes) if response.rowcount > 0: - self.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}') + self._ctx.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}') return True else: return False except Exception as err: - self.Logs.error(err) + self._ctx.Logs.error(err) return False + + async def db_join_saved_channels(self) -> None: + """## Joining saved channels""" + exec_query = await self._ctx.Base.db_execute_query(f'SELECT distinct channel_name FROM {self._ctx.Config.TABLE_CHANNEL}') + result_query = exec_query.fetchall() + + if result_query: + for chan_name in result_query: + chan = chan_name[0] + await self._ctx.Irc.Protocol.send_sjoin(channel=chan) \ No newline at end of file diff --git a/core/classes/modules/client.py b/core/classes/modules/client.py index 2ea01c3..ec422eb 100644 --- a/core/classes/modules/client.py +++ b/core/classes/modules/client.py @@ -201,7 +201,7 @@ class Client: return True - def db_is_account_exist(self, account: str) -> bool: + async def db_is_account_exist(self, account: str) -> bool: """Check if the account exist in the database Args: @@ -213,7 +213,7 @@ class Client: table_client = self.Base.Config.TABLE_CLIENT account_to_check = {'account': account.lower()} - account_to_check_query = self.Base.db_execute_query(f""" + account_to_check_query = await self.Base.db_execute_query(f""" SELECT id FROM {table_client} WHERE LOWER(account) = :account """, account_to_check) diff --git a/core/classes/modules/rehash.py b/core/classes/modules/rehash.py index 6b96998..791fe9b 100644 --- a/core/classes/modules/rehash.py +++ b/core/classes/modules/rehash.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING import socket if TYPE_CHECKING: - from core.irc import Irc + from core.loader import Loader # Modules impacted by rehashing! REHASH_MODULES = [ @@ -14,7 +14,10 @@ REHASH_MODULES = [ 'core.classes.modules.config', 'core.base', 'core.classes.modules.commands', - 'core.classes.modules.rpc', + 'core.classes.modules.rpc.rpc_channel', + 'core.classes.modules.rpc.rpc_command', + 'core.classes.modules.rpc.rpc_user', + 'core.classes.modules.rpc.rpc', 'core.classes.interfaces.iprotocol', 'core.classes.interfaces.imodule', 'core.classes.protocols.command_handler', @@ -24,66 +27,62 @@ REHASH_MODULES = [ ] -def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -> None: +async def restart_service(uplink: 'Loader', reason: str = "Restarting with no reason!") -> None: """ Args: uplink (Irc): The Irc instance reason (str): The reason of the restart. """ - # reload modules. + # unload modules. for module in uplink.ModuleUtils.model_get_loaded_modules().copy(): - uplink.ModuleUtils.unload_one_module(uplink, module.module_name) + await uplink.ModuleUtils.unload_one_module(module.module_name) uplink.Base.garbage_collector_thread() uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!') - uplink.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason) + await uplink.Irc.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason) uplink.Logs.debug('Restarting Defender ...') - uplink.IrcSocket.shutdown(socket.SHUT_RDWR) - uplink.IrcSocket.close() - - while uplink.IrcSocket.fileno() != -1: - time.sleep(0.5) - uplink.Logs.warning('-- Waiting for socket to close ...') - - # Reload configuration - uplink.Loader.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model - uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader) for mod in REHASH_MODULES: importlib.reload(sys.modules[mod]) - uplink.Protocol = uplink.Loader.PFactory.get() - uplink.Protocol.register_command() + # Reload configuration + uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model + uplink.Base = uplink.BaseModule.Base(uplink) uplink.ModuleUtils.model_clear() # Clear loaded modules. uplink.User.UID_DB.clear() # Clear User Object uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object uplink.Client.CLIENT_DB.clear() # Clear Client object + uplink.Irc.Protocol.Handler.DB_IRCDCOMMS.clear() - uplink.init_service_user() - uplink.Utils.create_socket(uplink) - uplink.Protocol.send_link() + # Reload Service modules + for module in uplink.ModuleUtils.model_get_loaded_modules().copy(): + await uplink.ModuleUtils.reload_one_module(module.module_name, uplink.Settings.current_admin) + + uplink.Irc.signal = True + await uplink.Irc.run() uplink.Config.DEFENDER_RESTART = 0 -def rehash_service(uplink: 'Irc', nickname: str) -> None: +async def rehash_service(uplink: 'Loader', nickname: str) -> None: need_a_restart = ["SERVEUR_ID"] uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS) - uplink.Loader.RpcServer.stop_server() + + await uplink.RpcServer.stop_server() restart_flag = False config_model_bakcup = uplink.Config mods = REHASH_MODULES for mod in mods: importlib.reload(sys.modules[mod]) - uplink.Protocol.send_priv_msg( + await uplink.Irc.Protocol.send_priv_msg( nick_from=uplink.Config.SERVICE_NICKNAME, msg=f'[REHASH] Module [{mod}] reloaded', channel=uplink.Config.SERVICE_CHANLOG ) uplink.Utils = sys.modules['core.utils'] - uplink.Config = uplink.Loader.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model + uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model uplink.Config.HSID = config_model_bakcup.HSID uplink.Config.DEFENDER_INIT = config_model_bakcup.DEFENDER_INIT uplink.Config.DEFENDER_RESTART = config_model_bakcup.DEFENDER_RESTART @@ -96,7 +95,7 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None: for key, value in conf_bkp_dict.items(): if config_dict[key] != value and key != 'COLORS': - uplink.Protocol.send_priv_msg( + await uplink.Irc.Protocol.send_priv_msg( nick_from=uplink.Config.SERVICE_NICKNAME, msg=f'[{key}]: {value} ==> {config_dict[key]}', channel=uplink.Config.SERVICE_CHANLOG @@ -105,27 +104,28 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None: restart_flag = True if config_model_bakcup.SERVICE_NICKNAME != uplink.Config.SERVICE_NICKNAME: - uplink.Protocol.send_set_nick(uplink.Config.SERVICE_NICKNAME) + await uplink.Irc.Protocol.send_set_nick(uplink.Config.SERVICE_NICKNAME) if restart_flag: uplink.Config.SERVEUR_ID = config_model_bakcup.SERVEUR_ID - uplink.Protocol.send_priv_msg( + await uplink.Irc.Protocol.send_priv_msg( nick_from=uplink.Config.SERVICE_NICKNAME, channel=uplink.Config.SERVICE_CHANLOG, msg='You need to restart defender !') # Reload Main Commands Module - uplink.Commands = uplink.Loader.CommandModule.Command(uplink.Loader) - uplink.Loader.RpcServer = uplink.Loader.RpcServerModule.JSONRPCServer(uplink.Loader) - uplink.Loader.RpcServer.start_server() + uplink.Commands = uplink.CommandModule.Command(uplink) uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands') - uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader) - uplink.Protocol = uplink.Loader.PFactory.get() - uplink.Protocol.register_command() + uplink.Base = uplink.BaseModule.Base(uplink) + uplink.Irc.Protocol = uplink.PFactory.get() + uplink.Irc.Protocol.register_command() + + uplink.RpcServer = uplink.RpcServerModule.JSonRpcServer(uplink) + uplink.Base.create_asynctask(uplink.RpcServer.start_server()) # Reload Service modules for module in uplink.ModuleUtils.model_get_loaded_modules().copy(): - uplink.ModuleUtils.reload_one_module(uplink, module.module_name, nickname) + await uplink.ModuleUtils.reload_one_module(module.module_name, nickname) return None \ No newline at end of file diff --git a/core/classes/modules/rpc/__init__.py b/core/classes/modules/rpc/__init__.py new file mode 100644 index 0000000..75977e6 --- /dev/null +++ b/core/classes/modules/rpc/__init__.py @@ -0,0 +1 @@ +__version__ = '1.0.0' \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc.py b/core/classes/modules/rpc/rpc.py index 95170a0..b26e34e 100644 --- a/core/classes/modules/rpc/rpc.py +++ b/core/classes/modules/rpc/rpc.py @@ -1,8 +1,11 @@ import base64 import json -import logging +from starlette.applications import Starlette +from starlette.responses import JSONResponse +from starlette.requests import Request +from starlette.routing import Route +import uvicorn from enum import Enum -from http.server import BaseHTTPRequestHandler, HTTPServer from typing import TYPE_CHECKING, Any, Optional from core.classes.modules.rpc.rpc_user import RPCUser from core.classes.modules.rpc.rpc_channel import RPCChannel @@ -11,120 +14,101 @@ from core.classes.modules.rpc.rpc_command import RPCCommand if TYPE_CHECKING: from core.loader import Loader -ProxyLoader: Optional['Loader'] = None +class JSonRpcServer: -class RPCRequestHandler(BaseHTTPRequestHandler): + def __init__(self, context: 'Loader', *, hostname: str = 'localhost', port: int = 5000): + self._ctx = context + self.live: bool = False + self.host = hostname + self.port = port + self.routes: list[Route] = [] + self.server: Optional[uvicorn.Server] = None - def log_message(self, format, *args): - pass - - def do_POST(self): - logs = ProxyLoader.Logs - self.server_version = 'Defender6' - self.sys_version = ProxyLoader.Config.CURRENT_VERSION - content_length = int(self.headers['Content-Length']) - body = self.rfile.read(content_length) - request_data: dict = json.loads(body) - rip, rport = self.client_address - - if not self.authenticate(request_data): - return None - - response_data = { - 'jsonrpc': '2.0', - 'id': request_data.get('id', 123) + self.methods: dict = { + 'user.list': RPCUser(context).user_list, + 'user.get': RPCUser(context).user_get, + 'channel.list': RPCChannel(context).channel_list, + 'command.list': RPCCommand(context).command_list, + 'command.get.by.name': RPCCommand(context).command_get_by_name, + 'command.get.by.module': RPCCommand(context).command_get_by_module } - method = request_data.get("method") + async def start_server(self): + + if not self.live: + self.routes = [Route('/api', self.request_handler, methods=['POST'])] + self.app_jsonrpc = Starlette(debug=False, routes=self.routes) + config = uvicorn.Config(self.app_jsonrpc, host=self.host, port=self.port, log_level=self._ctx.Config.DEBUG_LEVEL) + self.server = uvicorn.Server(config) + self.live = True + await self._ctx.Irc.Protocol.send_priv_msg( + self._ctx.Config.SERVICE_NICKNAME, + "[DEFENDER JSONRPC SERVER] RPC Server started!", + self._ctx.Config.SERVICE_CHANLOG + ) + await self.server.serve() + self._ctx.Logs.debug("Server is going to shutdown!") + else: + self._ctx.Logs.debug("Server already running") + + async def stop_server(self): + + if self.server: + self.server.should_exit = True + await self.server.shutdown() + self.live = False + self._ctx.Logs.debug("JSON-RPC Server off!") + await self._ctx.Irc.Protocol.send_priv_msg( + self._ctx.Config.SERVICE_NICKNAME, + "[DEFENDER JSONRPC SERVER] RPC Server Stopped!", + self._ctx.Config.SERVICE_CHANLOG + ) + + async def request_handler(self, request: Request) -> JSONResponse: + + request_data: dict = await request.json() + method = request_data.get("method", None) params: dict[str, Any] = request_data.get("params", {}) + + auth: JSONResponse = self.authenticate(request.headers, request_data) + if not json.loads(auth.body).get('result', False): + return auth + + response_data = { + "jsonrpc": "2.0", + "id": request_data.get('id', 123) + } + response_data['method'] = method + rip = request.client.host + rport = request.client.port http_code = 200 - match method: - case 'user.list': - user = RPCUser(ProxyLoader) - response_data['result'] = user.user_list() - logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') - del user - - case 'user.get': - user = RPCUser(ProxyLoader) - uid_or_nickname = params.get('uid_or_nickname', None) - response_data['result'] = user.user_get(uid_or_nickname) - logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') - del user + if method in self.methods: + response_data['result'] = self.methods[method](**params) + return JSONResponse(response_data, http_code) - case 'channel.list': - channel = RPCChannel(ProxyLoader) - response_data['result'] = channel.channel_list() - logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') - del channel + response_data['error'] = create_error_response(JSONRPCErrorCode.METHOD_NOT_FOUND) + self._ctx.Logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}') + http_code = 404 + return JSONResponse(response_data, http_code) - case 'command.list': - command = RPCCommand(ProxyLoader) - response_data['result'] = command.command_list() - logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') - del command + def authenticate(self, headers: dict, body: dict) -> JSONResponse: + ok_auth = { + 'jsonrpc': '2.0', + 'id': body.get('id', 123), + 'result': True + } - case 'command.get.by.module': - command = RPCCommand(ProxyLoader) - module_name = params.get('name', None) - response_data['result'] = command.command_get_by_module(module_name) - logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') - del command - - case 'command.get.by.name': - command = RPCCommand(ProxyLoader) - command_name = params.get('name', None) - response_data['result'] = command.command_get_by_name(command_name) - logs.debug(f'[RPC] {method} recieved from {rip}:{rport}') - del command - - case _: - response_data['error'] = create_error_response(JSONRPCErrorCode.METHOD_NOT_FOUND) - logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}') - http_code = 404 - - self.send_response(http_code) - self.send_header('Content-Type', 'application/json') - self.end_headers() - self.wfile.write(json.dumps(response_data).encode('utf-8')) - - return None - - def do_GET(self): - self.server_version = 'Defender6' - self.sys_version = ProxyLoader.Config.CURRENT_VERSION - content_length = int(self.headers['Content-Length']) - body = self.rfile.read(content_length) - request_data: dict = json.loads(body) - - if not self.authenticate(request_data): - return None - - response_data = {'jsonrpc': '2.0', 'id': request_data.get('id', 321), - 'error': create_error_response(JSONRPCErrorCode.INVALID_REQUEST)} - - self.send_response(404) - self.send_header('Content-Type', 'application/json') - self.end_headers() - self.wfile.write(json.dumps(response_data).encode('utf-8')) - - return None - - - def authenticate(self, request_data: dict) -> bool: - logs = ProxyLoader.Logs - auth = self.headers.get('Authorization', None) - if auth is None: - self.send_auth_error(request_data) - return False + logs = self._ctx.Logs + auth: str = headers.get('Authorization', '') + if not auth: + return self.send_auth_error(body) # Authorization header format: Basic base64(username:password) auth_type, auth_string = auth.split(' ', 1) if auth_type.lower() != 'basic': - self.send_auth_error(request_data) - return False + return self.send_auth_error(body) try: # Decode the base64-encoded username:password @@ -132,70 +116,25 @@ class RPCRequestHandler(BaseHTTPRequestHandler): username, password = decoded_credentials.split(":", 1) # Check the username and password. - for rpcuser in ProxyLoader.Irc.Config.RPC_USERS: + for rpcuser in self._ctx.Config.RPC_USERS: if rpcuser.get('USERNAME', None) == username and rpcuser.get('PASSWORD', None) == password: - return True + return JSONResponse(ok_auth) - self.send_auth_error(request_data) - return False + return self.send_auth_error(body) except Exception as e: - self.send_auth_error(request_data) logs.error(e) - return False + return self.send_auth_error(body) - def send_auth_error(self, request_data: dict) -> None: + def send_auth_error(self, request_data: dict) -> JSONResponse: response_data = { 'jsonrpc': '2.0', 'id': request_data.get('id', 123), 'error': create_error_response(JSONRPCErrorCode.AUTHENTICATION_ERROR) } + return JSONResponse(response_data) - self.send_response(401) - self.send_header('WWW-Authenticate', 'Basic realm="Authorization Required"') - self.end_headers() - self.wfile.write(json.dumps(response_data).encode('utf-8')) - -class JSONRPCServer: - def __init__(self, loader: 'Loader'): - global ProxyLoader - - ProxyLoader = loader - self._Loader = loader - self._Base = loader.Base - self._Logs = loader.Logs - self.rpc_server: Optional[HTTPServer] = None - self.connected: bool = False - - def start_server(self, server_class=HTTPServer, handler_class=RPCRequestHandler, *, hostname: str = 'localhost', port: int = 5000): - logging.getLogger('http.server').setLevel(logging.CRITICAL) - server_address = (hostname, port) - self.rpc_server = server_class(server_address, handler_class) - self._Logs.debug(f"Server ready on http://{hostname}:{port}...") - self._Base.create_thread(self.thread_start_rpc_server, (), True) - - def thread_start_rpc_server(self) -> None: - self._Loader.Irc.Protocol.send_priv_msg( - self._Loader.Config.SERVICE_NICKNAME, "Defender RPC Server has started successfuly!", self._Loader.Config.SERVICE_CHANLOG - ) - self.connected = True - self.rpc_server.serve_forever() - ProxyLoader.Logs.debug(f"RPC Server down!") - - def stop_server(self): - self._Base.create_thread(self.thread_stop_rpc_server) - - def thread_stop_rpc_server(self): - self.rpc_server.shutdown() - ProxyLoader.Logs.debug(f"RPC Server shutdown!") - self.rpc_server.server_close() - ProxyLoader.Logs.debug(f"RPC Server clean-up!") - self._Base.garbage_collector_thread() - self._Loader.Irc.Protocol.send_priv_msg( - self._Loader.Config.SERVICE_NICKNAME, "Defender RPC Server has stopped successfuly!", self._Loader.Config.SERVICE_CHANLOG - ) - self.connected = False class JSONRPCErrorCode(Enum): PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON) diff --git a/core/classes/modules/rpc/rpc_channel.py b/core/classes/modules/rpc/rpc_channel.py index e45e782..4f39338 100644 --- a/core/classes/modules/rpc/rpc_channel.py +++ b/core/classes/modules/rpc/rpc_channel.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING if TYPE_CHECKING: from core.loader import Loader @@ -8,5 +8,5 @@ class RPCChannel: self._Loader = loader self._Channel = loader.Channel - def channel_list(self) -> list[dict]: + def channel_list(self, **kwargs) -> list[dict]: return [chan.to_dict() for chan in self._Channel.UID_CHANNEL_DB] \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_command.py b/core/classes/modules/rpc/rpc_command.py index 1c2025d..230af53 100644 --- a/core/classes/modules/rpc/rpc_command.py +++ b/core/classes/modules/rpc/rpc_command.py @@ -8,14 +8,22 @@ class RPCCommand: self._Loader = loader self._Command = loader.Commands - def command_list(self) -> list[dict]: + def command_list(self, **kwargs) -> list[dict]: return [command.to_dict() for command in self._Command.DB_COMMANDS] - def command_get_by_module(self, module_name: str) -> list[dict]: + def command_get_by_module(self, **kwargs) -> list[dict]: + module_name = kwargs.get('module_name', None) + if module_name is None: + return [] + return [command.to_dict() for command in self._Command.DB_COMMANDS if command.module_name.lower() == module_name.lower()] - def command_get_by_name(self, command_name: str) -> dict: + def command_get_by_name(self, **kwargs) -> dict: + command_name: str = kwargs.get('command_name', '') + if not command_name: + return dict() + for command in self._Command.DB_COMMANDS: if command.command_name.lower() == command_name.lower(): return command.to_dict() - return {} \ No newline at end of file + return dict() \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_user.py b/core/classes/modules/rpc/rpc_user.py index b9e014b..bf8a323 100644 --- a/core/classes/modules/rpc/rpc_user.py +++ b/core/classes/modules/rpc/rpc_user.py @@ -6,11 +6,10 @@ if TYPE_CHECKING: class RPCUser: def __init__(self, loader: 'Loader'): - self._Loader = loader - self._User = loader.User + self._ctx = loader - def user_list(self) -> list[dict]: - users = self._User.UID_DB.copy() + def user_list(self, **kwargs) -> list[dict]: + users = self._ctx.User.UID_DB.copy() copy_users: list['MUser'] = [] for user in users: @@ -20,8 +19,9 @@ class RPCUser: return [user.to_dict() for user in copy_users] - def user_get(self, uidornickname: str) -> Optional[dict]: - user = self._User.get_user(uidornickname) + def user_get(self, **kwargs) -> Optional[dict]: + uidornickname = kwargs.get('uid_or_nickname', None) + user = self._ctx.User.get_user(uidornickname) if user: user_copy = user.copy() user_copy.connexion_datetime = user_copy.connexion_datetime.strftime('%d-%m-%Y') diff --git a/core/classes/protocols/factory.py b/core/classes/protocols/factory.py index 6d30ffe..0ae4425 100644 --- a/core/classes/protocols/factory.py +++ b/core/classes/protocols/factory.py @@ -4,30 +4,29 @@ from .inspircd import Inspircd from ..interfaces.iprotocol import IProtocol if TYPE_CHECKING: - from core.irc import Irc + from core.loader import Loader class ProtocolFactorty: - def __init__(self, uplink: 'Irc'): + def __init__(self, context: 'Loader'): """ProtocolFactory init. Args: - uplink (Irc): The Irc object + context (Loader): The Context object """ - self.__Config = uplink.Config - self.__uplink = uplink + self.__ctx = context def get(self) -> Optional[IProtocol]: - protocol = self.__Config.SERVEUR_PROTOCOL + protocol = self.__ctx.Config.SERVEUR_PROTOCOL match protocol: case 'unreal6': - self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded") - return Unrealircd6(self.__uplink) + self.__ctx.Logs.debug(f"[PROTOCOL] {protocol} has been loaded") + return Unrealircd6(self.__ctx) case 'inspircd': - self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded") - return Inspircd(self.__uplink) + self.__ctx.Logs.debug(f"[PROTOCOL] {protocol} has been loaded") + return Inspircd(self.__ctx) case _: - self.__uplink.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)") + self.__ctx.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)") raise Exception("Unknown protocol!") diff --git a/core/classes/protocols/inspircd.py b/core/classes/protocols/inspircd.py index 52704af..f8a6f71 100644 --- a/core/classes/protocols/inspircd.py +++ b/core/classes/protocols/inspircd.py @@ -1,6 +1,6 @@ import sys from base64 import b64decode -from re import match, findall, search +from re import A, match, findall, search from datetime import datetime from typing import TYPE_CHECKING, Any, Optional from ssl import SSLEOFError, SSLError @@ -12,7 +12,7 @@ if TYPE_CHECKING: class Inspircd(IProtocol): - def init_protocol(self): + async def init_protocol(self): self.name = 'InspIRCd-4' self.protocol_version = 1206 @@ -23,7 +23,7 @@ class Inspircd(IProtocol): 'MODE', 'QUIT', 'SQUIT', 'VERSION'} - def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]: + async def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]: """Get the position of known commands Args: @@ -38,12 +38,12 @@ class Inspircd(IProtocol): return index, token.upper() if log: - self._Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") + self._ctx.Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") return -1, None - def register_command(self): - m = self._Irc.Loader.Definition.MIrcdCommand + async def register_command(self): + m = self._ctx.Definition.MIrcdCommand self.Handler.register(m('PING', self.on_server_ping)) self.Handler.register(m('NICK', self.on_nick)) self.Handler.register(m('SASL', self.on_sasl)) @@ -58,7 +58,7 @@ class Inspircd(IProtocol): self.Handler.register(m('ENDBURST', self.on_endburst)) self.Handler.register(m('METADATA', self.on_metedata)) - def send2socket(self, message: str, print_log: bool = True) -> None: + async def send2socket(self, message: str, print_log: bool = True) -> None: """Envoit les commandes à envoyer au serveur. Args: @@ -66,31 +66,32 @@ class Inspircd(IProtocol): print_log (bool): if True print the log. """ try: - with self._Base.lock: - self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[0])) + with self._ctx.Settings.AILOCK: + self._ctx.Irc.writer.write(f"{message}\r\n".encode(self._ctx.Config.SERVEUR_CHARSET[0])) + await self._ctx.Irc.writer.drain() if print_log: - self._Logs.debug(f'<< {message}') + self._ctx.Logs.debug(f'<< {message}') except UnicodeDecodeError as ude: - self._Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') - self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) + self._ctx.Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') + self._ctx.Irc.writer.write(f"{message}\r\n".encode(self._ctx.Config.SERVEUR_CHARSET[1],'replace')) except UnicodeEncodeError as uee: - self._Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') - self._Irc.IrcSocket.send(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) + self._ctx.Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') + self._ctx.Irc.writer.write(f"{message}\r\n".encode(self._ctx.Config.SERVEUR_CHARSET[1],'replace')) except AssertionError as ae: - self._Logs.warning(f'Assertion Error {ae} - message: {message}') + self._ctx.Logs.warning(f'Assertion Error {ae} - message: {message}') except SSLEOFError as soe: - self._Logs.error(f"SSLEOFError: {soe} - {message}") + self._ctx.Logs.error(f"SSLEOFError: {soe} - {message}") except SSLError as se: - self._Logs.error(f"SSLError: {se} - {message}") + self._ctx.Logs.error(f"SSLError: {se} - {message}") except OSError as oe: - self._Logs.error(f"OSError: {oe} - {message}") + self._ctx.Logs.error(f"OSError: {oe} - {message}") if oe.errno == 10053: sys.exit(oe.__str__()) except AttributeError as ae: - self._Logs.critical(f"Attribute Error: {ae}") + self._ctx.Logs.critical(f"Attribute Error: {ae}") - def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): + async def send_priv_msg(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: @@ -100,27 +101,27 @@ class Inspircd(IProtocol): 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 not None else None + batch_size = self._ctx.Config.BATCH_SIZE + user_from = self._ctx.User.get_user(nick_from) + user_to = self._ctx.User.get_user(nick_to) if nick_to is not None else None if user_from is None: - self._Logs.error(f"The sender nickname [{nick_from}] do not exist") + self._ctx.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}") + await 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}") + await self.send2socket(f":{nick_from} PRIVMSG {user_to.uid} :{batch}") except Exception as err: - self._Logs.error(f"General Error: {err}") + self._ctx.Logs.error(f"General Error: {err}") - def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: + async def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: """Sending NOTICE by batches Args: @@ -129,71 +130,71 @@ class Inspircd(IProtocol): 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) + batch_size = self._ctx.Config.BATCH_SIZE + user_from = self._ctx.User.get_user(nick_from) + user_to = self._ctx.User.get_user(nick_to) if user_from is None or user_to is None: - self._Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist") + self._ctx.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}") + await self.send2socket(f":{user_from.uid} NOTICE {user_to.uid} :{batch}") except Exception as err: - self._Logs.error(f"General Error: {err}") + self._ctx.Logs.error(f"General Error: {err}") - def send_link(self): + async def send_link(self): """Créer le link et envoyer les informations nécessaires pour la connexion au serveur. """ - service_id = self._Config.SERVICE_ID - service_nickname = self._Config.SERVICE_NICKNAME - service_username = self._Config.SERVICE_USERNAME - service_realname = self._Config.SERVICE_REALNAME - service_info = self._Config.SERVICE_INFO - service_smodes = self._Config.SERVICE_SMODES - service_hostname = self._Config.SERVICE_HOST - service_name = self._Config.SERVICE_NAME + service_id = self._ctx.Config.SERVICE_ID + service_nickname = self._ctx.Config.SERVICE_NICKNAME + service_username = self._ctx.Config.SERVICE_USERNAME + service_realname = self._ctx.Config.SERVICE_REALNAME + service_info = self._ctx.Config.SERVICE_INFO + service_smodes = self._ctx.Config.SERVICE_SMODES + service_hostname = self._ctx.Config.SERVICE_HOST + service_name = self._ctx.Config.SERVICE_NAME - server_password = self._Config.SERVEUR_PASSWORD - server_link = self._Config.SERVEUR_LINK - server_id = self._Config.SERVEUR_ID - server_hostname = self._Settings.MAIN_SERVER_HOSTNAME = self._Config.SERVEUR_HOSTNAME + server_password = self._ctx.Config.SERVEUR_PASSWORD + server_link = self._ctx.Config.SERVEUR_LINK + server_id = self._ctx.Config.SERVEUR_ID + server_hostname = self._ctx.Settings.MAIN_SERVER_HOSTNAME = self._ctx.Config.SERVEUR_HOSTNAME - version = self._Config.CURRENT_VERSION - unixtime = self._Utils.get_unixtime() + version = self._ctx.Config.CURRENT_VERSION + unixtime = self._ctx.Utils.get_unixtime() - self.send2socket(f"CAPAB START {self.protocol_version}") - self.send2socket(f"CAPAB MODULES :services") - self.send2socket(f"CAPAB MODSUPPORT :") - self.send2socket(f"CAPAB CAPABILITIES :NICKMAX=30 CHANMAX=64 MAXMODES=20 IDENTMAX=10 MAXQUIT=255 MAXTOPIC=307 MAXKICK=255 MAXREAL=128 MAXAWAY=200 MAXHOST=64 MAXLINE=512 CASEMAPPING=ascii GLOBOPS=0") - self.send2socket(f"CAPAB END") - self.send2socket(f"SERVER {server_link} {server_password} {server_id} :{service_info}") - self.send2socket(f"BURST {unixtime}") - self.send2socket(f":{server_id} SINFO version :{service_name}-{version.split('.')[0]}. {server_hostname} :") - self.send2socket(f":{server_id} SINFO fullversion :{service_name}-{version}. {service_hostname} :") - self.send2socket(f":{server_id} SINFO rawversion :{service_name}-{version}") - self.send_uid(service_nickname, service_username, service_hostname, service_id, service_smodes, service_hostname, "127.0.0.1", service_realname) - self.send2socket(f":{server_id} ENDBURST") + await self.send2socket(f"CAPAB START {self.protocol_version}") + await self.send2socket(f"CAPAB MODULES :services") + await self.send2socket(f"CAPAB MODSUPPORT :") + await self.send2socket(f"CAPAB CAPABILITIES :NICKMAX=30 CHANMAX=64 MAXMODES=20 IDENTMAX=10 MAXQUIT=255 MAXTOPIC=307 MAXKICK=255 MAXREAL=128 MAXAWAY=200 MAXHOST=64 MAXLINE=512 CASEMAPPING=ascii GLOBOPS=0") + await self.send2socket(f"CAPAB END") + await self.send2socket(f"SERVER {server_link} {server_password} {server_id} :{service_info}") + await self.send2socket(f"BURST {unixtime}") + await self.send2socket(f":{server_id} SINFO version :{service_name}-{version.split('.')[0]}. {server_hostname} :") + await self.send2socket(f":{server_id} SINFO fullversion :{service_name}-{version}. {service_hostname} :") + await self.send2socket(f":{server_id} SINFO rawversion :{service_name}-{version}") + await self.send_uid(service_nickname, service_username, service_hostname, service_id, service_smodes, service_hostname, "127.0.0.1", service_realname) + await self.send2socket(f":{server_id} ENDBURST") # self.send_sjoin(chan) - self._Logs.debug(f'>> {__name__} Link information sent to the server') + self._ctx.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: + async 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}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None - def send_set_nick(self, newnickname: str) -> None: + async def send_set_nick(self, newnickname: str) -> None: - self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") + await self.send2socket(f":{self._ctx.Config.SERVICE_NICKNAME} NICK {newnickname}") return None - def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: + async def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: """Set a mode to channel or to a nickname or for a user in a channel Args: @@ -202,94 +203,94 @@ class Inspircd(IProtocol): channel_name (Optional[str]): The channel name params (Optional[str]): Params to pass to the mode """ - service_id = self._Config.SERVICE_ID + service_id = self._ctx.Config.SERVICE_ID params = '' if params is None else params if modes[0] not in ['+', '-']: - self._Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") + self._ctx.Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") return None if nickname and channel_name: - # :98KAAAAAB MODE #services +o defenderdev - if not self._Irc.Channel.is_valid_channel(channel_name): - self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + # :98KAAAAAB MODE #services +o async defenderdev + if not self._ctx.Channel.is_valid_channel(channel_name): + self._ctx.Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None - if not all(mode in self._Settings.PROTOCTL_PREFIX_MODES_SIGNES for mode in list(modes.replace('+','').replace('-',''))): - self._Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') + if not all(mode in self._ctx.Settings.PROTOCTL_PREFIX_MODES_SIGNES for mode in list(modes.replace('+','').replace('-',''))): + self._ctx.Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') return None - self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") + await self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") return None if nickname and channel_name is None: # :98KAAAAAB MODE nickname +o - if not all(mode in self._Settings.PROTOCTL_USER_MODES for mode in list(modes.replace('+','').replace('-',''))): - self._Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') + if not all(mode in self._ctx.Settings.PROTOCTL_USER_MODES for mode in list(modes.replace('+','').replace('-',''))): + self._ctx.Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') return None - self.send2socket(f":{service_id} MODE {nickname} {modes}") + await self.send2socket(f":{service_id} MODE {nickname} {modes}") return None if nickname is None and channel_name: # :98KAAAAAB MODE #channel +o - if not all(mode in self._Settings.PROTOCTL_CHANNEL_MODES for mode in list(modes.replace('+','').replace('-',''))): - self._Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') + if not all(mode in self._ctx.Settings.PROTOCTL_CHANNEL_MODES for mode in list(modes.replace('+','').replace('-',''))): + self._ctx.Logs.debug(f'[USERMODE UNVAILABLE] This mode {modes} is not available!') return None - if not self._Irc.Channel.is_valid_channel(channel_name): - self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._ctx.Channel.is_valid_channel(channel_name): + self._ctx.Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None - self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") + await self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") return None return None - def send_squit(self, server_id: str, server_link: str, reason: str) -> None: + async def send_squit(self, server_id: str, server_link: str, reason: str) -> None: if not reason: reason = 'Service Shutdown' - self.send2socket(f":{server_id} SQUIT {server_link} :{reason}") + await self.send2socket(f":{server_id} SQUIT {server_link} :{reason}") return None - def send_ungline(self, nickname: str, hostname: str) -> None: + async def send_ungline(self, nickname: str, hostname: str) -> None: - self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._ctx.Config.SERVICE_NICKNAME}") return None - def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + async def send_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}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None - def send_sjoin(self, channel: str) -> None: + async def send_sjoin(self, channel: str) -> None: """Service join a channel Args: channel (str): The channel name. """ - server_id = self._Config.SERVEUR_ID - service_nickname = self._Config.SERVICE_NICKNAME - service_modes = self._Config.SERVICE_UMODES - service_id = self._Config.SERVICE_ID + server_id = self._ctx.Config.SERVEUR_ID + service_nickname = self._ctx.Config.SERVICE_NICKNAME + service_modes = self._ctx.Config.SERVICE_UMODES + service_id = self._ctx.Config.SERVICE_ID - if not self._Irc.Channel.is_valid_channel(channel): - self._Logs.error(f"The channel [{channel}] is not valid") + if not self._ctx.Channel.is_valid_channel(channel): + self._ctx.Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{server_id} FJOIN {channel} {self._Utils.get_unixtime()} :o, {service_id}") + await self.send2socket(f":{server_id} FJOIN {channel} {self._ctx.Utils.get_unixtime()} :o, {service_id}") self.send_set_mode(service_modes, nickname=service_nickname, channel_name=channel) - # Add defender to the channel uids list - self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[service_id])) + # Add async defender to the channel uids list + self._ctx.Channel.insert(self._ctx.Definition.MChannel(name=channel, uids=[service_id])) return None - def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: + async def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: """Send quit message Args: @@ -297,22 +298,22 @@ class Inspircd(IProtocol): reason (str): The reason for the quit print_log (bool): If True then print logs """ - user_obj = self._Irc.User.get_user(uidornickname=uid) - reputation_obj = self._Irc.Reputation.get_reputation(uidornickname=uid) + user_obj = self._ctx.User.get_user(uidornickname=uid) + reputation_obj = self._ctx.Reputation.get_reputation(uidornickname=uid) if not user_obj is None: - self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) - self._Irc.User.delete(user_obj.uid) + await self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) + self._ctx.User.delete(user_obj.uid) if not reputation_obj is None: - self._Irc.Reputation.delete(reputation_obj.uid) + self._ctx.Reputation.delete(reputation_obj.uid) - if not self._Irc.Channel.delete_user_from_all_channel(uid): - self._Logs.error(f"The UID [{uid}] has not been deleted from all channels") + if not self._ctx.Channel.delete_user_from_all_channel(uid): + self._ctx.Logs.error(f"The UID [{uid}] has not been deleted from all channels") return None - def send_uid(self, nickname: str, username: str, hostname: str, + async def send_uid(self, nickname: str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None: """Send UID to the server @@ -329,20 +330,20 @@ class Inspircd(IProtocol): print_log (bool, optional): print logs if true. Defaults to True. """ # {self.Config.SERVEUR_ID} UID - # {clone.nickname} 1 {self._Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} + # {clone.nickname} 1 {self._ctx.Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} try: - unixtime = self._Utils.get_unixtime() - # encoded_ip = self._Base.encode_ip(remote_ip) + unixtime = self._ctx.Utils.get_unixtime() + # encoded_ip = self._ctx.Base.encode_ip(remote_ip) new_umodes = [] for mode in list(umodes.replace('+', '').replace('-', '')): - if mode in self._Settings.PROTOCTL_USER_MODES: + if mode in self._ctx.Settings.PROTOCTL_USER_MODES: new_umodes.append(mode) final_umodes = '+' + ''.join(new_umodes) # Create the user - self._Irc.User.insert( - self._Irc.Loader.Definition.MUser( + self._ctx.User.insert( + self._ctx.Definition.MUser( uid=uid, nickname=nickname, username=username, realname=realname,hostname=hostname, umodes=final_umodes, vhost=vhost, remote_ip=remote_ip @@ -350,17 +351,17 @@ class Inspircd(IProtocol): ) # [:] UID []+ : - # :98K UID 98KAAAAAB 1756932359 defenderdev defenderdev.deb.biz.st defenderdev.deb.biz.st Dev-PyDefender 127.0.0.1 1756932359 + :Dev Python Security + # :98K UID 98KAAAAAB 1756932359 async defenderdev async defenderdev.deb.biz.st async defenderdev.deb.biz.st Dev-PyDefender 127.0.0.1 1756932359 + :Dev Python Security # [':97K', 'UID', '97KAAAAAA', '1756926679', 'adator', '172.18.128.1', 'attila.example.org', '...', '...', '172.18.128.1', '1756926678', '+o', ':...'] - uid_msg = f":{self._Config.SERVEUR_ID} UID {uid} {unixtime} {nickname} {hostname} {vhost} {username} {username} {remote_ip} {unixtime} {final_umodes} :{realname}" - self.send2socket(uid_msg, print_log=print_log) + uid_msg = f":{self._ctx.Config.SERVEUR_ID} UID {uid} {unixtime} {nickname} {hostname} {vhost} {username} {username} {remote_ip} {unixtime} {final_umodes} :{realname}" + await self.send2socket(uid_msg, print_log=print_log) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: + async def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: """Joining a channel Args: @@ -370,23 +371,23 @@ class Inspircd(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - user_obj = self._Irc.User.get_user(uidornickname) + user_obj = self._ctx.User.get_user(uidornickname) password_channel = password if not password is None else '' if user_obj is None: return None - if not self._Irc.Channel.is_valid_channel(channel): - self._Logs.error(f"The channel [{channel}] is not valid") + if not self._ctx.Channel.is_valid_channel(channel): + self._ctx.Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{user_obj.uid} FJOIN {channel} {self._Utils.get_unixtime()} :,{user_obj.uid} {password_channel}", print_log=print_log) + await self.send2socket(f":{user_obj.uid} FJOIN {channel} {self._ctx.Utils.get_unixtime()} :,{user_obj.uid} {password_channel}", print_log=print_log) - # Add defender to the channel uids list - self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) + # Add async defender to the channel uids list + self._ctx.Channel.insert(self._ctx.Definition.MChannel(name=channel, uids=[user_obj.uid])) return None - def send_part_chan(self, uidornickname: str, channel: str, print_log: bool = True) -> None: + async def send_part_chan(self, uidornickname: str, channel: str, print_log: bool = True) -> None: """Part from a channel Args: @@ -395,38 +396,38 @@ class Inspircd(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - user_obj = self._Irc.User.get_user(uidornickname) + user_obj = self._ctx.User.get_user(uidornickname) if user_obj is None: - self._Logs.error(f"The user [{uidornickname}] is not valid") + self._ctx.Logs.error(f"The user [{uidornickname}] is not valid") return None - if not self._Irc.Channel.is_valid_channel(channel): - self._Logs.error(f"The channel [{channel}] is not valid") + if not self._ctx.Channel.is_valid_channel(channel): + self._ctx.Logs.error(f"The channel [{channel}] is not valid") return None - self.send2socket(f":{user_obj.uid} PART {channel}", print_log=print_log) + await self.send2socket(f":{user_obj.uid} PART {channel}", print_log=print_log) - # Add defender to the channel uids list - self._Irc.Channel.delete_user_from_channel(channel, user_obj.uid) + # Add async defender to the channel uids list + self._ctx.Channel.delete_user_from_channel(channel, user_obj.uid) return None - def send_unkline(self, nickname: str, hostname: str) -> None: + async def send_unkline(self, nickname: str, hostname: str) -> None: - self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._ctx.Config.SERVICE_NICKNAME}") return None - def send_raw(self, raw_command: str) -> None: + async def send_raw(self, raw_command: str) -> None: - self.send2socket(f":{self._Config.SERVEUR_ID} {raw_command}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} {raw_command}") return None # ------------------------------------------------------------------------ # RECIEVED IRC MESSAGES # ------------------------------------------------------------------------ - def on_umode2(self, server_msg: list[str]) -> None: + async def on_umode2(self, server_msg: list[str]) -> None: """Handle umode2 coming from a server Args: @@ -435,25 +436,25 @@ class Inspircd(IProtocol): try: # [':adator_', 'UMODE2', '-iwx'] - user_obj = self._Irc.User.get_user(str(server_msg[0]).lstrip(':')) + user_obj = self._ctx.User.get_user(str(server_msg[0]).lstrip(':')) user_mode = server_msg[2] if user_obj is None: # If user is not created return None # TODO : User object should be able to update user modes - if self._Irc.User.update_mode(user_obj.uid, user_mode): + if self._ctx.User.update_mode(user_obj.uid, user_mode): return None - # self._Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") + # self._ctx.Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]") return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_quit(self, server_msg: list[str]) -> None: + async def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server >> [':97KAAAAAZ', 'QUIT', ':Quit:', '....'] Args: @@ -463,40 +464,40 @@ class Inspircd(IProtocol): uid_who_quit = str(server_msg[0]).lstrip(':') - self._Irc.Channel.delete_user_from_all_channel(uid_who_quit) - self._Irc.User.delete(uid_who_quit) - self._Irc.Reputation.delete(uid_who_quit) + self._ctx.Channel.delete_user_from_all_channel(uid_who_quit) + self._ctx.User.delete(uid_who_quit) + self._ctx.Reputation.delete(uid_who_quit) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_squit(self, server_msg: list[str]) -> None: + async def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server Args: server_msg (list[str]): Original server message """ - # ['@msgid=QOEolbRxdhpVW5c8qLkbAU;time=2024-09-21T17:33:16.547Z', 'SQUIT', 'defender.deb.biz.st', ':Connection', 'closed'] + # ['@msgid=QOEolbRxdhpVW5c8qLkbAU;time=2024-09-21T17:33:16.547Z', 'SQUIT', 'async defender.deb.biz.st', ':Connection', 'closed'] server_hostname = server_msg[2] uid_to_delete = None - for s_user in self._Irc.User.UID_DB: + for s_user in self._ctx.User.UID_DB: if s_user.hostname == server_hostname and 'S' in s_user.umodes: uid_to_delete = s_user.uid if uid_to_delete is None: return None - self._Irc.User.delete(uid_to_delete) - self._Irc.Channel.delete_user_from_all_channel(uid_to_delete) + self._ctx.User.delete(uid_to_delete) + self._ctx.Channel.delete_user_from_all_channel(uid_to_delete) return None - def on_protoctl(self, server_msg: list[str]) -> None: + async def on_protoctl(self, server_msg: list[str]) -> None: """Handle CAPAB coming from a server Args: @@ -525,9 +526,9 @@ class Inspircd(IProtocol): channel_modes.append(cmode) - self._Settings.PROTOCTL_PREFIX_SIGNES_MODES = sign_mode - self._Settings.PROTOCTL_PREFIX_MODES_SIGNES = mode_sign - self._Settings.PROTOCTL_CHANNEL_MODES = list(set(channel_modes)) + self._ctx.Settings.PROTOCTL_PREFIX_SIGNES_MODES = sign_mode + self._ctx.Settings.PROTOCTL_PREFIX_MODES_SIGNES = mode_sign + self._ctx.Settings.PROTOCTL_CHANNEL_MODES = list(set(channel_modes)) # ['CAPAB', 'USERMODES', ':param-set:snomask=s', 'simple:bot=B', 'simple:invisible=i', 'simple:oper=o', 'simple:servprotect=k', # 'simple:sslqueries=z', 'simple:u_registered=r', 'simple:wallops=w'] @@ -539,11 +540,11 @@ class Inspircd(IProtocol): umode = prefix.split('=')[1] if len(prefix.split('=')) > 1 else None user_modes.append(umode) - self._Settings.PROTOCTL_USER_MODES = list(set(user_modes)) + self._ctx.Settings.PROTOCTL_USER_MODES = list(set(user_modes)) return None - def on_nick(self, server_msg: list[str]) -> None: + async def on_nick(self, server_msg: list[str]) -> None: """Handle nick coming from a server new nickname @@ -560,18 +561,18 @@ class Inspircd(IProtocol): uid = str(scopy[0]).replace(':','') newnickname = scopy[2] - self._Irc.User.update_nickname(uid, newnickname) - self._Irc.Client.update_nickname(uid, newnickname) - self._Irc.Admin.update_nickname(uid, newnickname) + self._ctx.User.update_nickname(uid, newnickname) + self._ctx.Client.update_nickname(uid, newnickname) + self._ctx.Admin.update_nickname(uid, newnickname) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_sjoin(self, server_msg: list[str]) -> None: + async def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server Args: @@ -591,8 +592,8 @@ class Inspircd(IProtocol): list_users = list(set(list_users)) if list_users: - self._Irc.Channel.insert( - self._Irc.Loader.Definition.MChannel( + self._ctx.Channel.insert( + self._ctx.Definition.MChannel( name=channel, uids=list_users ) @@ -600,11 +601,11 @@ class Inspircd(IProtocol): return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_endburst(self, server_msg: list[str]) -> None: + async def on_endburst(self, server_msg: list[str]) -> None: """Handle EOS coming from a server Args: @@ -614,71 +615,71 @@ class Inspircd(IProtocol): # [':97K', 'ENDBURST'] scopy = server_msg.copy() hsid = str(scopy[0]).replace(':','') - 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): + if hsid == self._ctx.Config.HSID: + if self._ctx.Config.DEFENDER_INIT == 1: + current_version = self._ctx.Config.CURRENT_VERSION + latest_version = self._ctx.Config.LATEST_VERSION + if self._ctx.Base.check_for_new_version(False): version = f'{current_version} >>> {latest_version}' else: version = f'{current_version}' print(f"################### DEFENDER ###################") print(f"# SERVICE CONNECTE ") - 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._Config.SSL_VERSION} ") - print(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") - print(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") + print(f"# SERVEUR : {self._ctx.Config.SERVEUR_IP} ") + print(f"# PORT : {self._ctx.Config.SERVEUR_PORT} ") + print(f"# SSL : {self._ctx.Config.SERVEUR_SSL} ") + print(f"# SSL VER : {self._ctx.Config.SSL_VERSION} ") + print(f"# NICKNAME : {self._ctx.Config.SERVICE_NICKNAME} ") + print(f"# CHANNEL : {self._ctx.Config.SERVICE_CHANLOG} ") print(f"# VERSION : {version} ") print(f"################################################") - self._Logs.info(f"################### DEFENDER ###################") - self._Logs.info(f"# SERVICE CONNECTE ") - self._Logs.info(f"# SERVEUR : {self._Config.SERVEUR_IP} ") - self._Logs.info(f"# PORT : {self._Config.SERVEUR_PORT} ") - self._Logs.info(f"# SSL : {self._Config.SERVEUR_SSL} ") - self._Logs.info(f"# SSL VER : {self._Config.SSL_VERSION} ") - self._Logs.info(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") - self._Logs.info(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") - self._Logs.info(f"# VERSION : {version} ") - self._Logs.info(f"################################################") + self._ctx.Logs.info(f"################### DEFENDER ###################") + self._ctx.Logs.info(f"# SERVICE CONNECTE ") + self._ctx.Logs.info(f"# SERVEUR : {self._ctx.Config.SERVEUR_IP} ") + self._ctx.Logs.info(f"# PORT : {self._ctx.Config.SERVEUR_PORT} ") + self._ctx.Logs.info(f"# SSL : {self._ctx.Config.SERVEUR_SSL} ") + self._ctx.Logs.info(f"# SSL VER : {self._ctx.Config.SSL_VERSION} ") + self._ctx.Logs.info(f"# NICKNAME : {self._ctx.Config.SERVICE_NICKNAME} ") + self._ctx.Logs.info(f"# CHANNEL : {self._ctx.Config.SERVICE_CHANLOG} ") + self._ctx.Logs.info(f"# VERSION : {version} ") + self._ctx.Logs.info(f"################################################") - self.send_sjoin(self._Config.SERVICE_CHANLOG) + self.send_sjoin(self._ctx.Config.SERVICE_CHANLOG) - if self._Base.check_for_new_version(False): + if self._ctx.Base.check_for_new_version(False): self.send_priv_msg( - nick_from=self._Config.SERVICE_NICKNAME, + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=f" New Version available {version}", - channel=self._Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) # Initialisation terminé aprés le premier PING self.send_priv_msg( - nick_from=self._Config.SERVICE_NICKNAME, - msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._Config.COLORS.green, self._Config.COLORS.nogc, self._Config.SERVICE_NICKNAME), - channel=self._Config.SERVICE_CHANLOG + nick_from=self._ctx.Config.SERVICE_NICKNAME, + msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._ctx.Config.COLORS.green, self._ctx.Config.COLORS.nogc, self._ctx.Config.SERVICE_NICKNAME), + channel=self._ctx.Config.SERVICE_CHANLOG ) - self._Config.DEFENDER_INIT = 0 + self._ctx.Config.DEFENDER_INIT = 0 # Send EOF to other modules - for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._ctx.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(scopy) # Join saved channels & load existing modules - self._Irc.join_saved_channels() - self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) + self._ctx.Irc.join_saved_channels() + self._ctx.ModuleUtils.db_load_all_existing_modules(self._ctx.Irc) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Key Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Key Error: {ie}") except KeyError as ke: - self._Logs.error(f"{__name__} - Key Error: {ke}") + self._ctx.Logs.error(f"{__name__} - Key Error: {ke}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_part(self, server_msg: list[str]) -> None: + async def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server Args: @@ -690,16 +691,16 @@ class Inspircd(IProtocol): uid = str(server_msg[0]).lstrip(':') channel = str(server_msg[2]).lower() # reason = str(' '.join(server_msg[3:])) - self._Irc.Channel.delete_user_from_channel(channel, uid) + self._ctx.Channel.delete_user_from_channel(channel, uid) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_uid(self, server_msg: list[str]) -> None: + async def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server [:] UID []+ : [':97K', 'UID', '97KAAAAAB', '1756928055', 'adator_', '172.18.128.1', '172.18.128.1', '...', '...', '172.18.128.1', '1756928055', '+', ':...'] @@ -707,9 +708,9 @@ class Inspircd(IProtocol): server_msg (list[str]): Original server message """ try: - red = self._Config.COLORS.red - green = self._Config.COLORS.green - nogc = self._Config.COLORS.nogc + red = self._ctx.Config.COLORS.red + green = self._ctx.Config.COLORS.green + nogc = self._ctx.Config.COLORS.nogc is_webirc = True if 'webirc' in server_msg[0] else False is_websocket = True if 'websocket' in server_msg[0] else False @@ -721,7 +722,7 @@ class Inspircd(IProtocol): vhost = str(server_msg[6]) if not 'S' in umodes: - # remote_ip = self._Base.decode_ip(str(serverMsg[9])) + # remote_ip = self._ctx.Base.decode_ip(str(serverMsg[9])) remote_ip = str(server_msg[9]) else: remote_ip = '127.0.0.1' @@ -740,8 +741,8 @@ class Inspircd(IProtocol): score_connexion = 0 - self._Irc.User.insert( - self._Irc.Loader.Definition.MUser( + self._ctx.User.insert( + self._ctx.Definition.MUser( uid=uid, nickname=nickname, username=username, @@ -758,39 +759,39 @@ class Inspircd(IProtocol): ) ) - for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._ctx.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(server_msg) # SASL authentication - dnickname = self._Config.SERVICE_NICKNAME - dchanlog = self._Config.SERVICE_CHANLOG + dnickname = self._ctx.Config.SERVICE_NICKNAME + dchanlog = self._ctx.Config.SERVICE_CHANLOG # uid = serverMsg[8] # nickname = serverMsg[3] - sasl_obj = self._Irc.Sasl.get_sasl_obj(uid) + sasl_obj = self._ctx.Sasl.get_sasl_obj(uid) if sasl_obj: if sasl_obj.auth_success: - self._Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) - self.send_priv_msg(nick_from=dnickname, + self._ctx.Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) + await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, sasl_obj.username, dnickname), channel=dchanlog) - self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) + await self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) else: - self.send_priv_msg(nick_from=dnickname, + await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s provided a wrong password for this username %s", red, nogc, nickname, sasl_obj.username), channel=dchanlog) - self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) + await self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) # Delete sasl object! - self._Irc.Sasl.delete_sasl_client(uid) + self._ctx.Sasl.delete_sasl_client(uid) return None return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}", exc_info=True) + self._ctx.Logs.error(f"{__name__} - General Error: {err}", exc_info=True) - def on_privmsg(self, server_msg: list[str]) -> None: + async def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server Args: @@ -804,36 +805,36 @@ class Inspircd(IProtocol): cmd.pop(0) get_uid_or_nickname = str(cmd[0].replace(':','')) - user_trigger = self._Irc.User.get_nickname(get_uid_or_nickname) - # dnickname = self._Config.SERVICE_NICKNAME - pattern = fr'(:\{self._Config.SERVICE_PREFIX})(.*)$' + user_trigger = self._ctx.User.get_nickname(get_uid_or_nickname) + # dnickname = self._ctx.Config.SERVICE_NICKNAME + pattern = fr'(:\{self._ctx.Config.SERVICE_PREFIX})(.*)$' hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . if hcmds: # Commande qui commencent par le point liste_des_commandes = list(hcmds.groups()) convert_to_string = ' '.join(liste_des_commandes) arg = convert_to_string.split() - arg.remove(f":{self._Config.SERVICE_PREFIX}") - if not self._Irc.Commands.is_command_exist(arg[0]): - self._Logs.debug(f"This command {arg[0]} is not available") + arg.remove(f":{self._ctx.Config.SERVICE_PREFIX}") + if not self._ctx.Commands.is_command_exist(arg[0]): + self._ctx.Logs.debug(f"This command {arg[0]} is not available") self.send_notice( - nick_from=self._Config.SERVICE_NICKNAME, + nick_from=self._ctx.Config.SERVICE_NICKNAME, nick_to=user_trigger, - msg=f"This command [{self._Config.COLORS.bold}{arg[0]}{self._Config.COLORS.bold}] is not available" + msg=f"This command [{self._ctx.Config.COLORS.bold}{arg[0]}{self._ctx.Config.COLORS.bold}] is not available" ) return None cmd_to_send = convert_to_string.replace(':','') - self._Base.log_cmd(user_trigger, cmd_to_send) + await self._ctx.Base.log_cmd(user_trigger, cmd_to_send) - fromchannel = str(cmd[2]).lower() if self._Irc.Channel.is_valid_channel(cmd[2]) else None - self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) + fromchannel = str(cmd[2]).lower() if self._ctx.Channel.is_valid_channel(cmd[2]) else None + self._ctx.Irc.hcmds(user_trigger, fromchannel, arg, cmd) - if cmd[2] == self._Config.SERVICE_ID: + if cmd[2] == self._ctx.Config.SERVICE_ID: pattern = fr'^:.*?:(.*)$' hcmds = search(pattern, ' '.join(cmd)) - if hcmds: # par /msg defender [commande] + if hcmds: # par /msg async defender [commande] liste_des_commandes = list(hcmds.groups()) convert_to_string = ' '.join(liste_des_commandes) arg = convert_to_string.split() @@ -853,32 +854,32 @@ class Inspircd(IProtocol): self.on_ping(srv_msg) return None - if not self._Irc.Commands.is_command_exist(arg[0]): - self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + if not self._ctx.Commands.is_command_exist(arg[0]): + self._ctx.Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") return None - # if not arg[0].lower() in self._Irc.module_commands_list: - # self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + # if not arg[0].lower() in self._ctx.Irc.module_commands_list: + # self._ctx.Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") # return False cmd_to_send = convert_to_string.replace(':','') - self._Base.log_cmd(user_trigger, cmd_to_send) + await self._ctx.Base.log_cmd(user_trigger, cmd_to_send) fromchannel = None if len(arg) >= 2: - fromchannel = str(arg[1]).lower() if self._Irc.Channel.is_valid_channel(arg[1]) else None + fromchannel = str(arg[1]).lower() if self._ctx.Channel.is_valid_channel(arg[1]) else None - self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) + self._ctx.Irc.hcmds(user_trigger, fromchannel, arg, cmd) return None except KeyError as ke: - self._Logs.error(f"Key Error: {ke}") + self._ctx.Logs.error(f"Key Error: {ke}") except AttributeError as ae: - self._Logs.error(f"Attribute Error: {ae}") + self._ctx.Logs.error(f"Attribute Error: {ae}") except Exception as err: - self._Logs.error(f"General Error: {err}", exc_info=True) + self._ctx.Logs.error(f"General Error: {err}", exc_info=True) - def on_server_ping(self, server_msg: list[str]) -> None: + async def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server Args: @@ -890,13 +891,13 @@ class Inspircd(IProtocol): # -> :808 PONG 3IN hsid = str(server_msg[0]).replace(':','') - self.send2socket(f":{self._Config.SERVEUR_ID} PONG {hsid}", print_log=False) + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} PONG {hsid}", print_log=False) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_server(self, server_msg: list[str]) -> None: + async def on_server(self, server_msg: list[str]) -> None: """_summary_ >>> [':97K', 'SINFO', 'customversion', ':'] >>> [':97K', 'SINFO', 'rawbranch', ':InspIRCd-4'] @@ -906,16 +907,16 @@ class Inspircd(IProtocol): """ try: param = str(server_msg[2]) - self._Config.HSID = self._Settings.MAIN_SERVER_ID = str(server_msg[0]).replace(':', '') + self._ctx.Config.HSID = self._ctx.Settings.MAIN_SERVER_ID = str(server_msg[0]).replace(':', '') if param == 'rawversion': - self._Logs.debug(f">> Server Version: {server_msg[3].replace(':', '')}") + self._ctx.Logs.debug(f">> Server Version: {server_msg[3].replace(':', '')}") elif param == 'rawbranch': - self._Logs.debug(f">> Branch Version: {server_msg[3].replace(':', '')}") + self._ctx.Logs.debug(f">> Branch Version: {server_msg[3].replace(':', '')}") except Exception as err: - self._Logs.error(f'General Error: {err}') + self._ctx.Logs.error(f'General Error: {err}') - def on_version(self, server_msg: list[str]) -> None: + async def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server Args: @@ -925,21 +926,21 @@ class Inspircd(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(server_msg[1])) - dnickname = self._Config.SERVICE_NICKNAME + nickname = self._ctx.User.get_nickname(self._ctx.Utils.clean_uid(server_msg[1])) + dnickname = self._ctx.Config.SERVICE_NICKNAME arg = server_msg[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') + await self.send2socket(f':{dnickname} NOTICE {nickname} :\x01VERSION Service {self._ctx.Config.SERVICE_NICKNAME} V{self._ctx.Config.CURRENT_VERSION}\x01') return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_time(self, server_msg: list[str]) -> None: + async def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor Args: @@ -949,22 +950,22 @@ class Inspircd(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(server_msg[1])) - dnickname = self._Config.SERVICE_NICKNAME + nickname = self._ctx.User.get_nickname(self._ctx.Utils.clean_uid(server_msg[1])) + dnickname = self._ctx.Config.SERVICE_NICKNAME arg = server_msg[4].replace(':', '') - current_datetime = self._Utils.get_sdatetime() + current_datetime = self._ctx.Utils.get_sdatetime() if nickname is None: return None if arg == '\x01TIME\x01': - self.send2socket(f':{dnickname} NOTICE {nickname} :\x01TIME {current_datetime}\x01') + await self.send2socket(f':{dnickname} NOTICE {nickname} :\x01TIME {current_datetime}\x01') return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_ping(self, server_msg: list[str]) -> None: + async def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor Args: @@ -974,8 +975,8 @@ class Inspircd(IProtocol): # Réponse a un CTCP VERSION try: - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(server_msg[1])) - dnickname = self._Config.SERVICE_NICKNAME + nickname = self._ctx.User.get_nickname(self._ctx.Utils.clean_uid(server_msg[1])) + dnickname = self._ctx.Config.SERVICE_NICKNAME arg = server_msg[4].replace(':', '') if nickname is None: @@ -983,10 +984,10 @@ class Inspircd(IProtocol): if arg == '\x01PING': recieved_unixtime = int(server_msg[5].replace('\x01','')) - current_unixtime = self._Utils.get_unixtime() + current_unixtime = self._ctx.Utils.get_unixtime() ping_response = current_unixtime - recieved_unixtime - # self._Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') + # self._ctx.Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') self.send_notice( nick_from=dnickname, nick_to=nickname, @@ -995,9 +996,9 @@ class Inspircd(IProtocol): return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_version_msg(self, server_msg: list[str]) -> None: + async def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server Args: @@ -1005,24 +1006,24 @@ class Inspircd(IProtocol): """ try: # ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender'] - user_obj = self._Irc.User.get_user(self._Utils.clean_uid(server_msg[1])) + user_obj = self._ctx.User.get_user(self._ctx.Utils.clean_uid(server_msg[1])) if user_obj is None: return None - response_351 = f"{self._Config.SERVICE_NAME.capitalize()}-{self._Config.CURRENT_VERSION} {self._Config.SERVICE_HOST} {self.name}" - self.send2socket(f':{self._Config.SERVICE_HOST} 351 {user_obj.nickname} {response_351}') + response_351 = f"{self._ctx.Config.SERVICE_NAME.capitalize()}-{self._ctx.Config.CURRENT_VERSION} {self._ctx.Config.SERVICE_HOST} {self.name}" + await self.send2socket(f':{self._ctx.Config.SERVICE_HOST} 351 {user_obj.nickname} {response_351}') - modules = self._Irc.ModuleUtils.get_all_available_modules() + modules = self._ctx.ModuleUtils.get_all_available_modules() response_005 = ' | '.join(modules) - self.send2socket(f':{self._Config.SERVICE_HOST} 005 {user_obj.nickname} {response_005} are supported by this server') + await self.send2socket(f':{self._ctx.Config.SERVICE_HOST} 005 {user_obj.nickname} {response_005} are supported by this server') return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") - def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: + async def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server Args: @@ -1034,12 +1035,12 @@ class Inspircd(IProtocol): # [':97K', 'ENCAP', '98K', 'SASL', '97KAAAAAF', '*', 'H', '172.18.128.1', '172.18.128.1', 'P'] # [':97K', 'ENCAP', '98K', 'SASL', '97KAAAAAF', '*', 'S', 'PLAIN'] # [':97K', 'ENCAP', '98K', 'SASL', '97KAAAAAP', 'irc.inspircd.local', 'C', 'YWRzefezfzefzefzefzefzefzefzezak='] - # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey'] - # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey=='] - # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A'] - psasl = self._Irc.Sasl + # [':irc.local.org', 'SASL', 'async defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey'] + # [':irc.local.org', 'SASL', 'async defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey=='] + # [':irc.local.org', 'SASL', 'async defender-dev.deb.biz.st', '00157Z26U', 'D', 'A'] + psasl = self._ctx.Sasl sasl_enabled = True # Should be False - for smod in self._Settings.SMOD_MODULES: + for smod in self._ctx.Settings.SMOD_MODULES: if smod.name == 'sasl': sasl_enabled = True break @@ -1051,7 +1052,7 @@ class Inspircd(IProtocol): client_uid = scopy[4] if len(scopy) >= 6 else None # sasl_obj = None sasl_message_type = scopy[6] if len(scopy) >= 6 else None - psasl.insert_sasl_client(self._Irc.Loader.Definition.MSasl(client_uid=client_uid)) + psasl.insert_sasl_client(self._ctx.Definition.MSasl(client_uid=client_uid)) sasl_obj = psasl.get_sasl_obj(client_uid) if sasl_obj is None: @@ -1069,15 +1070,15 @@ class Inspircd(IProtocol): sasl_obj.mechanisme = str(scopy[7]) if sasl_obj.mechanisme == "PLAIN": - self.send2socket(f":{self._Config.SERVEUR_ID} SASL {self._Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} SASL {self._ctx.Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") elif sasl_obj.mechanisme == "EXTERNAL": if str(scopy[7]) == "+": return None sasl_obj.fingerprint = str(scopy[8]) - self.send2socket(f":{self._Config.SERVEUR_ID} SASL {self._Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} SASL {self._ctx.Config.SERVEUR_HOSTNAME} {sasl_obj.client_uid} C +") - self.on_sasl_authentication_process(sasl_obj) + await self.on_sasl_authentication_process(sasl_obj) return sasl_obj case 'C': @@ -1090,31 +1091,31 @@ class Inspircd(IProtocol): sasl_obj.username = username sasl_obj.password = password - self.on_sasl_authentication_process(sasl_obj) + await self.on_sasl_authentication_process(sasl_obj) return sasl_obj elif sasl_obj.mechanisme == "EXTERNAL": sasl_obj.message_type = sasl_message_type - self.on_sasl_authentication_process(sasl_obj) + await self.on_sasl_authentication_process(sasl_obj) return sasl_obj except Exception as err: - self._Logs.error(f'General Error: {err}', exc_info=True) + self._ctx.Logs.error(f'General Error: {err}', exc_info=True) - def on_sasl_authentication_process(self, sasl_model: 'MSasl'): + async def on_sasl_authentication_process(self, sasl_model: 'MSasl'): s = sasl_model - server_id = self._Config.SERVEUR_ID - main_server_hostname = self._Settings.MAIN_SERVER_HOSTNAME - db_admin_table = self._Config.TABLE_ADMIN + server_id = self._ctx.Config.SERVEUR_ID + main_server_hostname = self._ctx.Settings.MAIN_SERVER_HOSTNAME + db_admin_table = self._ctx.Config.TABLE_ADMIN if sasl_model: - def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: + async def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: if fingerprint: mes_donnees = {'fingerprint': fingerprint} query = f"SELECT user, level, language FROM {db_admin_table} WHERE fingerprint = :fingerprint" else: - mes_donnees = {'user': username, 'password': self._Utils.hash_password(password)} + mes_donnees = {'user': username, 'password': self._ctx.Utils.hash_password(password)} query = f"SELECT user, level, language FROM {db_admin_table} WHERE user = :user AND password = :password" - result = self._Base.db_execute_query(query, mes_donnees) + result = await self._ctx.Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if user_from_db: return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]} @@ -1123,37 +1124,37 @@ class Inspircd(IProtocol): if s.message_type == 'C' and s.mechanisme == 'PLAIN': # Connection via PLAIN - admin_info = db_get_admin_info(username=s.username, password=s.password) + admin_info = await db_get_admin_info(username=s.username, password=s.password) if admin_info is not None: s.auth_success = True s.level = admin_info.get('level', 0) s.language = admin_info.get('language', 'EN') - self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D S") - self.send2socket(f":{server_id} SASL {s.username} :SASL authentication successful") + await self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D S") + await self.send2socket(f":{server_id} SASL {s.username} :SASL authentication successful") else: - self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D F") - self.send2socket(f":{server_id} SASL {s.username} :SASL authentication failed") + await self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D F") + await self.send2socket(f":{server_id} SASL {s.username} :SASL authentication failed") elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL': # Connection using fingerprints - admin_info = db_get_admin_info(fingerprint=s.fingerprint) + admin_info = await db_get_admin_info(fingerprint=s.fingerprint) if admin_info is not None: s.auth_success = True s.level = admin_info.get('level', 0) s.username = admin_info.get('user', None) s.language = admin_info.get('language', 'EN') - self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D S") - self.send2socket(f":{server_id} SASL {s.username} :SASL authentication successful") + await self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D S") + await self.send2socket(f":{server_id} SASL {s.username} :SASL authentication successful") else: # "904 :SASL authentication failed" - self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D F") - self.send2socket(f":{server_id} SASL {s.username} :SASL authentication failed") + await self.send2socket(f":{server_id} SASL {main_server_hostname} {s.client_uid} D F") + await self.send2socket(f":{server_id} SASL {s.username} :SASL authentication failed") - def on_error(self, server_msg: list[str]) -> None: - self._Logs.debug(f"{server_msg}") + async def on_error(self, server_msg: list[str]) -> None: + self._ctx.Logs.debug(f"{server_msg}") - def on_metedata(self, server_msg: list[str]) -> None: + async def on_metedata(self, server_msg: list[str]) -> None: """_summary_ Args: @@ -1162,33 +1163,33 @@ class Inspircd(IProtocol): # [':97K', 'METADATA', '97KAAAAAA', 'ssl_cert', ':vTrSe', 'fingerprint90753683519522875', # '/C=FR/OU=Testing/O=Test', 'Sasl/CN=localhost', '/C=FR/OU=Testing/O=Test', 'Sasl/CN=localhost'] scopy = server_msg.copy() - dnickname = self._Config.SERVICE_NICKNAME - dchanlog = self._Config.SERVICE_CHANLOG - green = self._Config.COLORS.green - nogc = self._Config.COLORS.nogc + dnickname = self._ctx.Config.SERVICE_NICKNAME + dchanlog = self._ctx.Config.SERVICE_CHANLOG + green = self._ctx.Config.COLORS.green + nogc = self._ctx.Config.COLORS.nogc if 'ssl_cert' in scopy: fingerprint = scopy[5] uid = scopy[2] - user_obj = self._Irc.User.get_user(uid) + user_obj = self._ctx.User.get_user(uid) if user_obj: user_obj.fingerprint = fingerprint - if self._Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): - admin = self._Irc.Admin.get_admin(uid) + if await self._ctx.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): + admin = self._ctx.Admin.get_admin(uid) account = admin.account if admin else '' - self.send_priv_msg(nick_from=dnickname, + await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTO AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, user_obj.nickname, account, dnickname), channel=dchanlog) - self.send_notice(nick_from=dnickname, nick_to=user_obj.nickname, msg=tr("Successfuly connected to %s", dnickname)) + await self.send_notice(nick_from=dnickname, nick_to=user_obj.nickname, msg=tr("Successfuly connected to %s", dnickname)) - def on_kick(self, server_msg: list[str]) -> None: + async def on_kick(self, server_msg: list[str]) -> None: ... # ------------------------------------------------------------------------ # COMMON IRC PARSER # ------------------------------------------------------------------------ - def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: + async def parse_uid(self, server_msg: list[str]) -> Optional['MUser']: """Parse UID and return dictionary. >>> [':97K', 'UID', '97KAAAAAC', '1762113659', 'adator_', '172.18.128.1', '172.18.128.1', '...', '...', '172.18.128.1', '1762113659', '+', ':...'] Args: @@ -1196,9 +1197,9 @@ class Inspircd(IProtocol): """ scopy = server_msg.copy() uid = scopy[2] - return self._User.get_user(uid) + return self._ctx.User.get_user(uid) - def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: + async def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. >>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit'] Args: @@ -1212,14 +1213,14 @@ class Inspircd(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - user_obj = self._User.get_user(self._Utils.clean_uid(scopy[0])) + user_obj = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[0])) tmp_reason = scopy[3:] tmp_reason[0] = tmp_reason[0].replace(':', '') reason = ' '.join(tmp_reason) return user_obj, reason - def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: + async def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]: """Parse nick changes. >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] @@ -1233,12 +1234,12 @@ class Inspircd(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - user_obj = self._User.get_user(self._User.clean_uid(scopy[0])) + user_obj = self._ctx.User.get_user(self._ctx.User.clean_uid(scopy[0])) newnickname = scopy[2] timestamp = scopy[3] return user_obj, newnickname, timestamp - def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: + async def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]: """Parse PRIVMSG message. >>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message'] >>> [':97KAAAAAF', 'PRIVMSG', '98KAAAAAB', ':My','Message','...'] @@ -1253,9 +1254,9 @@ class Inspircd(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - sender = self._User.get_user(self._Utils.clean_uid(scopy[0])) - reciever = self._User.get_user(self._Utils.clean_uid(scopy[2])) - channel = self._Channel.get_channel(scopy[2]) if self._Channel.is_valid_channel(scopy[2]) else None + sender = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[0])) + reciever = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[2])) + channel = self._ctx.Channel.get_channel(scopy[2]) if self._ctx.Channel.is_valid_channel(scopy[2]) else None tmp_message = scopy[3:] tmp_message = tmp_message[0].replace(':', '') @@ -1267,7 +1268,7 @@ class Inspircd(IProtocol): # IRC SENDER METHODS # ------------------------------------------------------------------------ - def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: + async def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: """_summary_ Args: @@ -1276,7 +1277,7 @@ class Inspircd(IProtocol): """ ... - def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: + async def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: """Send a gline command to the server Args: @@ -1289,7 +1290,7 @@ class Inspircd(IProtocol): """ ... - def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: + async def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: """_summary_ Args: @@ -1298,7 +1299,7 @@ class Inspircd(IProtocol): """ ... - def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: + async def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: """_summary_ Args: @@ -1307,7 +1308,7 @@ class Inspircd(IProtocol): """ ... - def send_svs2mode(self, nickname: str, user_mode: str) -> None: + async def send_svs2mode(self, nickname: str, user_mode: str) -> None: """_summary_ Args: @@ -1316,7 +1317,7 @@ class Inspircd(IProtocol): """ ... - def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: + async def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: """_summary_ Args: @@ -1326,7 +1327,7 @@ class Inspircd(IProtocol): """ ... - def send_svslogin(self, client_uid: str, user_account: str) -> None: + async def send_svslogin(self, client_uid: str, user_account: str) -> None: """Log a client into his account. Args: @@ -1335,7 +1336,7 @@ class Inspircd(IProtocol): """ ... - def send_svslogout(self, client_obj: 'MClient') -> None: + async def send_svslogout(self, client_obj: 'MClient') -> None: """Logout a client from his account Args: @@ -1343,7 +1344,7 @@ class Inspircd(IProtocol): """ ... - def send_svsmode(self, nickname: str, user_mode: str) -> None: + async def send_svsmode(self, nickname: str, user_mode: str) -> None: """_summary_ Args: @@ -1352,7 +1353,7 @@ class Inspircd(IProtocol): """ ... - def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: + async def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: """_summary_ Args: @@ -1362,7 +1363,7 @@ class Inspircd(IProtocol): """ ... - def on_md(self, server_msg: list[str]) -> None: + async def on_md(self, server_msg: list[str]) -> None: """Handle MD responses [':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...'] Args: @@ -1370,7 +1371,7 @@ class Inspircd(IProtocol): """ ... - def on_mode(self, server_msg: list[str]) -> None: + async def on_mode(self, server_msg: list[str]) -> None: """Handle mode coming from a server Args: @@ -1378,7 +1379,7 @@ class Inspircd(IProtocol): """ ... - def on_reputation(self, server_msg: list[str]) -> None: + async def on_reputation(self, server_msg: list[str]) -> None: """Handle REPUTATION coming from a server Args: @@ -1386,7 +1387,7 @@ class Inspircd(IProtocol): """ ... - def on_smod(self, server_msg: list[str]) -> None: + async def on_smod(self, server_msg: list[str]) -> None: """Handle SMOD message coming from the server Args: @@ -1394,7 +1395,7 @@ class Inspircd(IProtocol): """ ... - def on_svs2mode(self, server_msg: list[str]) -> None: + async def on_svs2mode(self, server_msg: list[str]) -> None: """Handle svs2mode coming from a server >>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] @@ -1403,7 +1404,7 @@ class Inspircd(IProtocol): """ ... - def on_eos(self, server_msg: list[str]) -> None: + async def on_eos(self, server_msg: list[str]) -> None: """Handle EOS coming from a server Args: @@ -1411,7 +1412,7 @@ class Inspircd(IProtocol): """ ... - def on_sethost(self, server_msg: list[str]) -> None: + async def on_sethost(self, server_msg: list[str]) -> None: """On SETHOST command Args: diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 154d286..b6dc9ef 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -36,12 +36,12 @@ class Unrealircd6(IProtocol): return index, token.upper() if log: - self._Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") + self._ctx.Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}") return -1, None def register_command(self) -> None: - m = self._Irc.Loader.Definition.MIrcdCommand + m = self._ctx.Definition.MIrcdCommand self.Handler.register(m(command_name="PING", func=self.on_server_ping)) self.Handler.register(m(command_name="UID", func=self.on_uid)) self.Handler.register(m(command_name="QUIT", func=self.on_quit)) @@ -107,30 +107,30 @@ class Unrealircd6(IProtocol): print_log (bool): True print log message in the console """ try: - with self._Base.lock: - self._Irc.writer.write(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[0])) - await self._Irc.writer.drain() + async with self._ctx.Settings.AILOCK: + self._ctx.Irc.writer.write(f"{message}\r\n".encode(self._ctx.Config.SERVEUR_CHARSET[0])) + await self._ctx.Irc.writer.drain() if print_log: - self._Logs.debug(f'<< {message}') + self._ctx.Logs.debug(f'<< {message}') except UnicodeDecodeError as ude: - self._Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') - self._Irc.writer.write(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) - await self._Irc.writer.drain() + self._ctx.Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}') + self._ctx.Irc.writer.write(f"{message}\r\n".encode(self._ctx.Config.SERVEUR_CHARSET[1],'replace')) + await self._ctx.Irc.writer.drain() except UnicodeEncodeError as uee: - self._Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') - self._Irc.writer.write(f"{message}\r\n".encode(self._Config.SERVEUR_CHARSET[1],'replace')) - await self._Irc.writer.drain() + self._ctx.Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}') + self._ctx.Irc.writer.write(f"{message}\r\n".encode(self._ctx.Config.SERVEUR_CHARSET[1],'replace')) + await self._ctx.Irc.writer.drain() except AssertionError as ae: - self._Logs.warning(f'Assertion Error {ae} - message: {message}') + self._ctx.Logs.warning(f'Assertion Error {ae} - message: {message}') except SSLEOFError as soe: - self._Logs.error(f"SSLEOFError: {soe} - {message}") + self._ctx.Logs.error(f"SSLEOFError: {soe} - {message}") except SSLError as se: - self._Logs.error(f"SSLError: {se} - {message}") + self._ctx.Logs.error(f"SSLError: {se} - {message}") except OSError as oe: - self._Logs.error(f"OSError: {oe} - {message}") + self._ctx.Logs.error(f"OSError: {oe} - {message}") except AttributeError as ae: - self._Logs.critical(f"Attribute Error: {ae}") + self._ctx.Logs.critical(f"Attribute Error: {ae}") async def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None): """Sending PRIVMSG to a channel or to a nickname by batches @@ -142,12 +142,12 @@ class Unrealircd6(IProtocol): 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 not nick_to is None else None + batch_size = self._ctx.Config.BATCH_SIZE + user_from = self._ctx.User.get_user(nick_from) + user_to = self._ctx.User.get_user(nick_to) if not nick_to is None else None if user_from is None: - self._Logs.error(f"The sender nickname [{nick_from}] do not exist") + self._ctx.Logs.error(f"The sender nickname [{nick_from}] do not exist") return None if not channel is None: @@ -161,8 +161,8 @@ class Unrealircd6(IProtocol): await self.send2socket(f":{nick_from} PRIVMSG {user_to.uid} :{batch}") except Exception as err: - self._Logs.error(f"General Error: {err}") - self._Logs.error(f"General Error: {nick_from} - {channel} - {nick_to}") + self._ctx.Logs.error(f"General Error: {err}") + self._ctx.Logs.error(f"General Error: {nick_from} - {channel} - {nick_to}") async def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None: """Sending NOTICE by batches @@ -173,12 +173,12 @@ class Unrealircd6(IProtocol): 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) + batch_size = self._ctx.Config.BATCH_SIZE + user_from = self._ctx.User.get_user(nick_from) + user_to = self._ctx.User.get_user(nick_to) if user_from is None or user_to is None: - self._Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist") + self._ctx.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): @@ -186,31 +186,31 @@ class Unrealircd6(IProtocol): await self.send2socket(f":{user_from.uid} NOTICE {user_to.uid} :{batch}") except Exception as err: - self._Logs.error(f"General Error: {err}") + self._ctx.Logs.error(f"General Error: {err}") async def send_link(self): """Créer le link et envoyer les informations nécessaires pour la connexion au serveur. """ - service_id = self._Config.SERVICE_ID - service_nickname = self._Config.SERVICE_NICKNAME - service_username = self._Config.SERVICE_USERNAME - service_realname = self._Config.SERVICE_REALNAME - service_channel_log = self._Config.SERVICE_CHANLOG - service_info = self._Config.SERVICE_INFO - service_smodes = self._Config.SERVICE_SMODES - service_cmodes = self._Config.SERVICE_CMODES - # service_umodes = self._Config.SERVICE_UMODES - service_hostname = self._Config.SERVICE_HOST - service_name = self._Config.SERVICE_NAME + service_id = self._ctx.Config.SERVICE_ID + service_nickname = self._ctx.Config.SERVICE_NICKNAME + service_username = self._ctx.Config.SERVICE_USERNAME + service_realname = self._ctx.Config.SERVICE_REALNAME + service_channel_log = self._ctx.Config.SERVICE_CHANLOG + service_info = self._ctx.Config.SERVICE_INFO + service_smodes = self._ctx.Config.SERVICE_SMODES + service_cmodes = self._ctx.Config.SERVICE_CMODES + # service_umodes = self._ctx.Config.SERVICE_UMODES + service_hostname = self._ctx.Config.SERVICE_HOST + service_name = self._ctx.Config.SERVICE_NAME protocolversion = self.protocol_version - server_password = self._Config.SERVEUR_PASSWORD - server_link = self._Config.SERVEUR_LINK - server_id = self._Config.SERVEUR_ID + server_password = self._ctx.Config.SERVEUR_PASSWORD + server_link = self._ctx.Config.SERVEUR_LINK + server_id = self._ctx.Config.SERVEUR_ID - version = self._Config.CURRENT_VERSION - unixtime = self._Utils.get_unixtime() + version = self._ctx.Config.CURRENT_VERSION + unixtime = self._ctx.Utils.get_unixtime() await self.send2socket(f":{server_id} PASS :{server_password}", print_log=False) await self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS") @@ -225,7 +225,7 @@ class Unrealircd6(IProtocol): await self.send2socket(f":{server_id} TKL + Q * {service_nickname} {service_hostname} 0 {unixtime} :Reserved for services") await self.send2socket(f":{service_id} MODE {service_channel_log} {service_cmodes}") - self._Logs.debug(f'>> {__name__} Link information sent to the server') + self._ctx.Logs.debug(f'>> {__name__} Link information sent to the server') async def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None: """Send a gline command to the server @@ -240,7 +240,7 @@ class Unrealircd6(IProtocol): """ # TKL + G user host set_by expire_timestamp set_at_timestamp :reason - await self.send2socket(f":{self._Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None @@ -250,10 +250,10 @@ class Unrealircd6(IProtocol): Args: newnickname (str): New nickname of the server """ - await self.send2socket(f":{self._Config.SERVICE_NICKNAME} NICK {newnickname}") + await self.send2socket(f":{self._ctx.Config.SERVICE_NICKNAME} NICK {newnickname}") - user_obj = self._Irc.User.get_user(self._Config.SERVICE_NICKNAME) - self._Irc.User.update_nickname(user_obj.uid, newnickname) + user_obj = self._ctx.User.get_user(self._ctx.Config.SERVICE_NICKNAME) + self._ctx.User.update_nickname(user_obj.uid, newnickname) return None async def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None: @@ -265,31 +265,31 @@ class Unrealircd6(IProtocol): channel_name (Optional[str]): The channel name params (Optional[str]): Parameters like password. """ - service_id = self._Config.SERVICE_ID + service_id = self._ctx.Config.SERVICE_ID if modes[0] not in ['+', '-']: - self._Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") + self._ctx.Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}") return None if nickname and channel_name: # :98KAAAAAB MODE #services +o defenderdev - if not self._Irc.Channel.is_valid_channel(channel_name): - self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._ctx.Channel.is_valid_channel(channel_name): + self._ctx.Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None await self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}") return None - + if nickname and channel_name is None: await self.send2socket(f":{service_id} MODE {nickname} {modes}") return None - + if nickname is None and channel_name: - if not self._Irc.Channel.is_valid_channel(channel_name): - self._Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") + if not self._ctx.Channel.is_valid_channel(channel_name): + self._ctx.Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}") return None - await self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") + await self.send2socket(f":{service_id} MODE {channel_name} {modes}") if params is None else await self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}") return None - + return None async def send_squit(self, server_id: str, server_link: str, reason: str) -> None: @@ -302,20 +302,20 @@ class Unrealircd6(IProtocol): async def send_ungline(self, nickname:str, hostname: str) -> None: - await self.send2socket(f":{self._Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self._ctx.Config.SERVICE_NICKNAME}") return None async def send_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 - await self.send2socket(f":{self._Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}") return None async def send_unkline(self, nickname:str, hostname: str) -> None: - await self.send2socket(f":{self._Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._Config.SERVICE_NICKNAME}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self._ctx.Config.SERVICE_NICKNAME}") return None @@ -325,15 +325,15 @@ class Unrealircd6(IProtocol): Args: channel (str): Channel to join """ - if not self._Irc.Channel.is_valid_channel(channel): - self._Logs.error(f"The channel [{channel}] is not valid") + if not self._ctx.Channel.is_valid_channel(channel): + self._ctx.Logs.error(f"The channel [{channel}] is not valid") return None - await self.send2socket(f":{self._Config.SERVEUR_ID} SJOIN {self._Utils.get_unixtime()} {channel} {self._Config.SERVICE_UMODES} :{self._Config.SERVICE_ID}") - await self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} SJOIN {self._ctx.Utils.get_unixtime()} {channel} {self._ctx.Config.SERVICE_UMODES} :{self._ctx.Config.SERVICE_ID}") + await self.send2socket(f":{self._ctx.Config.SERVICE_ID} MODE {channel} {self._ctx.Config.SERVICE_UMODES} {self._ctx.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])) + self._ctx.Channel.insert(self._ctx.Definition.MChannel(name=channel, uids=[self._ctx.Config.SERVICE_ID])) return None async def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None: @@ -345,20 +345,20 @@ class Unrealircd6(IProtocol): """ try: - user_obj = self._Irc.User.get_user(uidornickname=nick_to_sapart) - chan_obj = self._Irc.Channel.get_channel(channel_name) - service_uid = self._Config.SERVICE_ID + user_obj = self._ctx.User.get_user(uidornickname=nick_to_sapart) + chan_obj = self._ctx.Channel.get_channel(channel_name) + service_uid = self._ctx.Config.SERVICE_ID if user_obj is None or chan_obj is None: return None await self.send2socket(f":{service_uid} SAPART {user_obj.nickname} {chan_obj.name}") - self._Irc.Channel.delete_user_from_channel(chan_obj.name, user_obj.uid) + self._ctx.Channel.delete_user_from_channel(chan_obj.name, user_obj.uid) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None: """_summary_ @@ -369,9 +369,9 @@ class Unrealircd6(IProtocol): """ try: - user_obj = self._Irc.User.get_user(uidornickname=nick_to_sajoin) - chan_obj = self._Irc.Channel.get_channel(channel_name) - service_uid = self._Config.SERVICE_ID + user_obj = self._ctx.User.get_user(uidornickname=nick_to_sajoin) + chan_obj = self._ctx.Channel.get_channel(channel_name) + service_uid = self._ctx.Config.SERVICE_ID if user_obj is None: # User not exist: leave @@ -379,53 +379,53 @@ class Unrealircd6(IProtocol): if chan_obj is None: # Channel not exist - if not self._Irc.Channel.is_valid_channel(channel_name): + if not self._ctx.Channel.is_valid_channel(channel_name): # Incorrect channel: leave return None # Create the new channel with the uid - new_chan_obj = self._Irc.Loader.Definition.MChannel(name=channel_name, uids=[user_obj.uid]) - self._Irc.Channel.insert(new_chan_obj) + new_chan_obj = self._ctx.Definition.MChannel(name=channel_name, uids=[user_obj.uid]) + self._ctx.Channel.insert(new_chan_obj) await self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {new_chan_obj.name}") else: - self._Irc.Channel.add_user_to_a_channel(channel_name=channel_name, uid=user_obj.uid) + self._ctx.Channel.add_user_to_a_channel(channel_name=channel_name, uid=user_obj.uid) await self.send2socket(f":{service_uid} SAJOIN {user_obj.nickname} {chan_obj.name}") return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None: - user_obj = self._Irc.User.get_user(nick_to_part) + user_obj = self._ctx.User.get_user(nick_to_part) if user_obj is None: - self._Logs.debug(f"[SVSPART] The nickname {nick_to_part} do not exist!") + self._ctx.Logs.debug(f"[SVSPART] The nickname {nick_to_part} do not exist!") return None - channels_list = ','.join([channel for channel in channels if self._Irc.Channel.is_valid_channel(channel)]) - service_id = self._Config.SERVICE_ID + channels_list = ','.join([channel for channel in channels if self._ctx.Channel.is_valid_channel(channel)]) + service_id = self._ctx.Config.SERVICE_ID await self.send2socket(f':{service_id} SVSPART {user_obj.nickname} {channels_list} {reason}') return None async def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None: - user_obj = self._Irc.User.get_user(nick_to_part) + user_obj = self._ctx.User.get_user(nick_to_part) if user_obj is None: - self._Logs.debug(f"[SVSJOIN] The nickname {nick_to_part} do not exist!") + self._ctx.Logs.debug(f"[SVSJOIN] The nickname {nick_to_part} do not exist!") return None - channels_list = ','.join([channel for channel in channels if self._Irc.Channel.is_valid_channel(channel)]) + channels_list = ','.join([channel for channel in channels if self._ctx.Channel.is_valid_channel(channel)]) keys_list = ','.join([key for key in keys]) - service_id = self._Config.SERVICE_ID + service_id = self._ctx.Config.SERVICE_ID await self.send2socket(f':{service_id} SVSJOIN {user_obj.nickname} {channels_list} {keys_list}') return None async def send_svsmode(self, nickname: str, user_mode: str) -> None: try: - user_obj = self._Irc.User.get_user(uidornickname=nickname) - service_uid = self._Config.SERVICE_ID + user_obj = self._ctx.User.get_user(uidornickname=nickname) + service_uid = self._ctx.Config.SERVICE_ID if user_obj is None: return None @@ -433,16 +433,16 @@ class Unrealircd6(IProtocol): await self.send2socket(f':{service_uid} SVSMODE {nickname} {user_mode}') # Update new mode - self._Irc.User.update_mode(user_obj.uid, user_mode) + self._ctx.User.update_mode(user_obj.uid, user_mode) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def send_svs2mode(self, nickname: str, user_mode: str) -> None: try: - user_obj = self._Irc.User.get_user(uidornickname=nickname) - service_uid = self._Config.SERVICE_ID + user_obj = self._ctx.User.get_user(uidornickname=nickname) + service_uid = self._ctx.Config.SERVICE_ID if user_obj is None: return None @@ -450,11 +450,11 @@ class Unrealircd6(IProtocol): await self.send2socket(f':{service_uid} SVS2MODE {nickname} {user_mode}') # Update new mode - self._Irc.User.update_mode(user_obj.uid, user_mode) + self._ctx.User.update_mode(user_obj.uid, user_mode) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def send_svslogin(self, client_uid: str, user_account: str) -> None: """Log a client into his account. @@ -464,9 +464,9 @@ class Unrealircd6(IProtocol): user_account (str): The account of the user """ try: - await self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {client_uid} {user_account}") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SVSLOGIN {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {client_uid} {user_account}") except Exception as err: - self._Logs.error(f'General Error: {err}') + self._ctx.Logs.error(f'General Error: {err}') async def send_svslogout(self, client_obj: 'MClient') -> None: """Logout a client from his account @@ -477,11 +477,11 @@ class Unrealircd6(IProtocol): try: c_uid = client_obj.uid c_nickname = client_obj.nickname - await self.send2socket(f":{self._Irc.Config.SERVEUR_LINK} SVSLOGIN {self._Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SVSLOGIN {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0") self.send_svs2mode(c_nickname, '-r') except Exception as err: - self._Logs.error(f'General Error: {err}') + self._ctx.Logs.error(f'General Error: {err}') async def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None: """Send quit message @@ -493,18 +493,18 @@ class Unrealircd6(IProtocol): reason (str): The reason for the quit print_log (bool): Print the log """ - user_obj = self._Irc.User.get_user(uidornickname=uid) - reputation_obj = self._Irc.Reputation.get_reputation(uidornickname=uid) + user_obj = self._ctx.User.get_user(uidornickname=uid) + reputation_obj = self._ctx.Reputation.get_reputation(uidornickname=uid) if not user_obj is None: await self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) - self._Irc.User.delete(user_obj.uid) + self._ctx.User.delete(user_obj.uid) if not reputation_obj is None: - self._Irc.Reputation.delete(reputation_obj.uid) + self._ctx.Reputation.delete(reputation_obj.uid) - if not self._Irc.Channel.delete_user_from_all_channel(uid): - self._Logs.error(f"The UID [{uid}] has not been deleted from all channels") + if not self._ctx.Channel.delete_user_from_all_channel(uid): + self._ctx.Logs.error(f"The UID [{uid}] has not been deleted from all channels") return None @@ -524,28 +524,28 @@ class Unrealircd6(IProtocol): print_log (bool, optional): print logs if true. Defaults to True. """ # {self.Config.SERVEUR_ID} UID - # {clone.nickname} 1 {self._Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} + # {clone.nickname} 1 {self._ctx.Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname} try: - unixtime = self._Utils.get_unixtime() - encoded_ip = self._Base.encode_ip(remote_ip) + unixtime = self._ctx.Utils.get_unixtime() + encoded_ip = self._ctx.Base.encode_ip(remote_ip) # Create the user - self._Irc.User.insert( - self._Irc.Loader.Definition.MUser( + self._ctx.User.insert( + self._ctx.Definition.MUser( uid=uid, nickname=nickname, username=username, realname=realname,hostname=hostname, umodes=umodes, vhost=vhost, remote_ip=remote_ip ) ) - uid_msg = f":{self._Config.SERVEUR_ID} UID {nickname} 1 {unixtime} {username} {hostname} {uid} * {umodes} {vhost} * {encoded_ip} :{realname}" + uid_msg = f":{self._ctx.Config.SERVEUR_ID} UID {nickname} 1 {unixtime} {username} {hostname} {uid} * {umodes} {vhost} * {encoded_ip} :{realname}" await self.send2socket(uid_msg, print_log=print_log) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None: """Joining a channel @@ -557,34 +557,34 @@ class Unrealircd6(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - user_obj = self._Irc.User.get_user(uidornickname) + user_obj = self._ctx.User.get_user(uidornickname) pwd_channel = password if not password is None else '' if user_obj is None: return None - if not self._Irc.Channel.is_valid_channel(channel): - self._Logs.error(f"The channel [{channel}] is not valid") + if not self._ctx.Channel.is_valid_channel(channel): + self._ctx.Logs.error(f"The channel [{channel}] is not valid") return None await self.send2socket(f":{user_obj.uid} JOIN {channel} {pwd_channel}", print_log=print_log) - if uidornickname == self._Config.SERVICE_NICKNAME or uidornickname == self._Config.SERVICE_ID: - await self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {self._Config.SERVICE_UMODES} {self._Config.SERVICE_ID}") + if uidornickname == self._ctx.Config.SERVICE_NICKNAME or uidornickname == self._ctx.Config.SERVICE_ID: + await self.send2socket(f":{self._ctx.Config.SERVICE_ID} MODE {channel} {self._ctx.Config.SERVICE_UMODES} {self._ctx.Config.SERVICE_ID}") # Add defender to the channel uids list - self._Irc.Channel.insert(self._Irc.Loader.Definition.MChannel(name=channel, uids=[user_obj.uid])) + self._ctx.Channel.insert(self._ctx.Definition.MChannel(name=channel, uids=[user_obj.uid])) # Set the automode to the user if 'r' not in user_obj.umodes and 'o' not in user_obj.umodes: return None db_data: dict[str, str] = {"nickname": user_obj.nickname, "channel": channel} - db_query = self._Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data) + db_query = await self._ctx.Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data) db_result = db_query.fetchone() if db_result is not None: id_cmd_automode, mode = db_result - await self.send2socket(f":{self._Config.SERVICE_ID} MODE {channel} {mode} {user_obj.nickname}") + await self.send2socket(f":{self._ctx.Config.SERVICE_ID} MODE {channel} {mode} {user_obj.nickname}") return None @@ -597,35 +597,35 @@ class Unrealircd6(IProtocol): print_log (bool, optional): Write logs. Defaults to True. """ - u = self._Irc.User.get_user(uidornickname) + u = self._ctx.User.get_user(uidornickname) if u is None: - self._Logs.error(f"The user [{uidornickname}] is not valid") + self._ctx.Logs.error(f"The user [{uidornickname}] is not valid") return None - if not self._Irc.Channel.is_valid_channel(channel): - self._Logs.error(f"The channel [{channel}] is not valid") + if not self._ctx.Channel.is_valid_channel(channel): + self._ctx.Logs.error(f"The channel [{channel}] is not valid") return None await self.send2socket(f":{u.uid} PART {channel}", print_log=print_log) # Add defender to the channel uids list - self._Irc.Channel.delete_user_from_channel(channel, u.uid) + self._ctx.Channel.delete_user_from_channel(channel, u.uid) return None async def send_mode_chan(self, channel_name: str, channel_mode: str) -> None: - channel = self._Irc.Channel.is_valid_channel(channel_name) + channel = self._ctx.Channel.is_valid_channel(channel_name) if not channel: - self._Logs.error(f'The channel [{channel_name}] is not correct') + self._ctx.Logs.error(f'The channel [{channel_name}] is not correct') return None - await self.send2socket(f":{self._Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}") + await self.send2socket(f":{self._ctx.Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}") return None async def send_raw(self, raw_command: str) -> None: - await self.send2socket(f":{self._Config.SERVICE_NICKNAME} {raw_command}") + await self.send2socket(f":{self._ctx.Config.SERVICE_NICKNAME} {raw_command}") return None @@ -644,7 +644,7 @@ class Unrealircd6(IProtocol): scopy.pop(0) uid = scopy[7] - return self._User.get_user(uid) + return self._ctx.User.get_user(uid) def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]: """Parse quit and return dictionary. @@ -659,7 +659,7 @@ class Unrealircd6(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - user_obj = self._User.get_user(self._Utils.clean_uid(scopy[0])) + user_obj = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[0])) tmp_reason = scopy[3:] tmp_reason[0] = tmp_reason[0].replace(':', '') reason = ' '.join(tmp_reason) @@ -682,7 +682,7 @@ class Unrealircd6(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - user_obj = self._User.get_user(self._User.clean_uid(scopy[0])) + user_obj = self._ctx.User.get_user(self._ctx.User.clean_uid(scopy[0])) newnickname = scopy[2] timestamp = scopy[3] return user_obj, newnickname, timestamp @@ -702,9 +702,9 @@ class Unrealircd6(IProtocol): if scopy[0].startswith('@'): scopy.pop(0) - sender = self._User.get_user(self._Utils.clean_uid(scopy[0])) - reciever = self._User.get_user(self._Utils.clean_uid(scopy[2])) - channel = self._Channel.get_channel(scopy[2]) if self._Channel.is_valid_channel(scopy[2]) else None + sender = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[0])) + reciever = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[2])) + channel = self._ctx.Channel.get_channel(scopy[2]) if self._ctx.Channel.is_valid_channel(scopy[2]) else None tmp_message = scopy[3:] tmp_message[0] = tmp_message[0].replace(':', '') @@ -729,19 +729,19 @@ class Unrealircd6(IProtocol): uid_user_to_edit = scopy[2] umode = scopy[3] - u = self._Irc.User.get_user(uid_user_to_edit) + u = self._ctx.User.get_user(uid_user_to_edit) if u is None: return None - if self._Irc.User.update_mode(u.uid, umode): + if self._ctx.User.update_mode(u.uid, umode): return None return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_mode(self, server_msg: list[str]) -> None: """Handle mode coming from a server @@ -764,22 +764,22 @@ class Unrealircd6(IProtocol): try: # [':adator_', 'UMODE2', '-iwx'] scopy = server_msg.copy() - u = self._Irc.User.get_user(str(scopy[0]).lstrip(':')) + u = self._ctx.User.get_user(str(scopy[0]).lstrip(':')) user_mode = scopy[2] if u is None: # If user is not created return None # TODO : User object should be able to update user modes - if self._Irc.User.update_mode(u.uid, user_mode): + if self._ctx.User.update_mode(u.uid, user_mode): return None return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_quit(self, server_msg: list[str]) -> None: """Handle quit coming from a server @@ -792,18 +792,18 @@ class Unrealircd6(IProtocol): scopy = server_msg.copy() uid_who_quit = str(scopy[1]).lstrip(':') - self._Irc.Channel.delete_user_from_all_channel(uid_who_quit) - self._Irc.User.delete(uid_who_quit) - self._Irc.Client.delete(uid_who_quit) - self._Irc.Reputation.delete(uid_who_quit) - self._Irc.Admin.delete(uid_who_quit) + self._ctx.Channel.delete_user_from_all_channel(uid_who_quit) + self._ctx.User.delete(uid_who_quit) + self._ctx.Client.delete(uid_who_quit) + self._ctx.Reputation.delete(uid_who_quit) + self._ctx.Admin.delete(uid_who_quit) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_squit(self, server_msg: list[str]) -> None: """Handle squit coming from a server @@ -815,15 +815,15 @@ class Unrealircd6(IProtocol): scopy = server_msg.copy() server_hostname = scopy[2] uid_to_delete = None - for s_user in self._Irc.User.UID_DB: + for s_user in self._ctx.User.UID_DB: if s_user.hostname == server_hostname and 'S' in s_user.umodes: uid_to_delete = s_user.uid if uid_to_delete is None: return None - self._Irc.User.delete(uid_to_delete) - self._Irc.Channel.delete_user_from_all_channel(uid_to_delete) + self._ctx.User.delete(uid_to_delete) + self._ctx.Channel.delete_user_from_all_channel(uid_to_delete) return None @@ -858,9 +858,9 @@ class Unrealircd6(IProtocol): if user_modes is None or prefix is None or host_server_id is None: return None - self._Config.HSID = host_server_id - self._Settings.PROTOCTL_USER_MODES = list(user_modes) - self._Settings.PROTOCTL_PREFIX = list(prefix) + self._ctx.Config.HSID = host_server_id + self._ctx.Settings.PROTOCTL_USER_MODES = list(user_modes) + self._ctx.Settings.PROTOCTL_PREFIX = list(prefix) return None @@ -877,17 +877,17 @@ class Unrealircd6(IProtocol): uid = str(server_msg[1]).lstrip(':') newnickname = server_msg[3] - self._Irc.User.update_nickname(uid, newnickname) - self._Irc.Client.update_nickname(uid, newnickname) - self._Irc.Admin.update_nickname(uid, newnickname) - self._Irc.Reputation.update(uid, newnickname) + self._ctx.User.update_nickname(uid, newnickname) + self._ctx.Client.update_nickname(uid, newnickname) + self._ctx.Admin.update_nickname(uid, newnickname) + self._ctx.Reputation.update(uid, newnickname) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_sjoin(self, server_msg: list[str]) -> None: """Handle sjoin coming from a server @@ -924,13 +924,13 @@ class Unrealircd6(IProtocol): # Boucle qui va ajouter l'ensemble des users (UID) for i in range(start_boucle, len(scopy)): parsed_uid = str(scopy[i]) - clean_uid = self._Utils.clean_uid(parsed_uid) + clean_uid = self._ctx.Utils.clean_uid(parsed_uid) if not clean_uid is None and len(clean_uid) == 9: list_users.append(clean_uid) if list_users: - self._Irc.Channel.insert( - self._Irc.Loader.Definition.MChannel( + self._ctx.Channel.insert( + self._ctx.Definition.MChannel( name=channel, uids=list_users ) @@ -938,9 +938,9 @@ class Unrealircd6(IProtocol): return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_part(self, server_msg: list[str]) -> None: """Handle part coming from a server @@ -952,13 +952,13 @@ class Unrealircd6(IProtocol): # ['@unrealircd.org', ':001EPFBRD', 'PART', '#welcome', ':WEB', 'IRC', 'Paris'] uid = str(server_msg[1]).lstrip(':') channel = str(server_msg[3]).lower() - self._Irc.Channel.delete_user_from_channel(channel, uid) + self._ctx.Channel.delete_user_from_channel(channel, uid) return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_eos(self, server_msg: list[str]) -> None: """Handle EOS coming from a server @@ -970,71 +970,71 @@ class Unrealircd6(IProtocol): # [':001', 'EOS'] server_msg_copy = server_msg.copy() hsid = str(server_msg_copy[0]).replace(':','') - 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): + if hsid == self._ctx.Config.HSID: + if self._ctx.Config.DEFENDER_INIT == 1: + current_version = self._ctx.Config.CURRENT_VERSION + latest_version = self._ctx.Config.LATEST_VERSION + if self._ctx.Base.check_for_new_version(False): version = f'{current_version} >>> {latest_version}' else: version = f'{current_version}' print(f"################### DEFENDER ###################") print(f"# SERVICE CONNECTE ") - 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._Config.SSL_VERSION} ") - print(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") - print(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") + print(f"# SERVEUR : {self._ctx.Config.SERVEUR_IP} ") + print(f"# PORT : {self._ctx.Config.SERVEUR_PORT} ") + print(f"# SSL : {self._ctx.Config.SERVEUR_SSL} ") + print(f"# SSL VER : {self._ctx.Config.SSL_VERSION} ") + print(f"# NICKNAME : {self._ctx.Config.SERVICE_NICKNAME} ") + print(f"# CHANNEL : {self._ctx.Config.SERVICE_CHANLOG} ") print(f"# VERSION : {version} ") print(f"################################################") - self._Logs.info(f"################### DEFENDER ###################") - self._Logs.info(f"# SERVICE CONNECTE ") - self._Logs.info(f"# SERVEUR : {self._Config.SERVEUR_IP} ") - self._Logs.info(f"# PORT : {self._Config.SERVEUR_PORT} ") - self._Logs.info(f"# SSL : {self._Config.SERVEUR_SSL} ") - self._Logs.info(f"# SSL VER : {self._Config.SSL_VERSION} ") - self._Logs.info(f"# NICKNAME : {self._Config.SERVICE_NICKNAME} ") - self._Logs.info(f"# CHANNEL : {self._Config.SERVICE_CHANLOG} ") - self._Logs.info(f"# VERSION : {version} ") - self._Logs.info(f"################################################") + self._ctx.Logs.info(f"################### DEFENDER ###################") + self._ctx.Logs.info(f"# SERVICE CONNECTE ") + self._ctx.Logs.info(f"# SERVEUR : {self._ctx.Config.SERVEUR_IP} ") + self._ctx.Logs.info(f"# PORT : {self._ctx.Config.SERVEUR_PORT} ") + self._ctx.Logs.info(f"# SSL : {self._ctx.Config.SERVEUR_SSL} ") + self._ctx.Logs.info(f"# SSL VER : {self._ctx.Config.SSL_VERSION} ") + self._ctx.Logs.info(f"# NICKNAME : {self._ctx.Config.SERVICE_NICKNAME} ") + self._ctx.Logs.info(f"# CHANNEL : {self._ctx.Config.SERVICE_CHANLOG} ") + self._ctx.Logs.info(f"# VERSION : {version} ") + self._ctx.Logs.info(f"################################################") - await self.send_sjoin(self._Config.SERVICE_CHANLOG) + await self.send_sjoin(self._ctx.Config.SERVICE_CHANLOG) - if self._Base.check_for_new_version(False): + if self._ctx.Base.check_for_new_version(False): await self.send_priv_msg( - nick_from=self._Config.SERVICE_NICKNAME, + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=f" New Version available {version}", - channel=self._Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) # Initialisation terminé aprés le premier PING await self.send_priv_msg( - nick_from=self._Config.SERVICE_NICKNAME, - msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._Config.COLORS.green, self._Config.COLORS.nogc, self._Config.SERVICE_NICKNAME), - channel=self._Config.SERVICE_CHANLOG + nick_from=self._ctx.Config.SERVICE_NICKNAME, + msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self._ctx.Config.COLORS.green, self._ctx.Config.COLORS.nogc, self._ctx.Config.SERVICE_NICKNAME), + channel=self._ctx.Config.SERVICE_CHANLOG ) - self._Config.DEFENDER_INIT = 0 + self._ctx.Config.DEFENDER_INIT = 0 # Send EOF to other modules - for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): + for module in self._ctx.ModuleUtils.model_get_loaded_modules().copy(): module.class_instance.cmd(server_msg_copy) # Join saved channels & load existing modules - await self._Irc.join_saved_channels() - await self._Irc.ModuleUtils.db_load_all_existing_modules(self._Irc) + await self._ctx.Channel.db_join_saved_channels() + await self._ctx.ModuleUtils.db_load_all_existing_modules() - await self.send2socket(f":{self._Config.SERVEUR_ID} SMOD :L:Defender:1.0.0 :L:Command:1.0.0") + await self.send2socket(f":{self._ctx.Config.SERVEUR_ID} SMOD :L:Defender:1.0.0 :L:Command:1.0.0") return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except KeyError as ke: - self._Logs.error(f"{__name__} - Key Error: {ke}") + self._ctx.Logs.error(f"{__name__} - Key Error: {ke}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}", exc_info=True) async def on_reputation(self, server_msg: list[str]) -> None: """Handle REPUTATION coming from a server @@ -1045,27 +1045,27 @@ class Unrealircd6(IProtocol): try: # :001 REPUTATION 127.0.0.1 118 server_msg_copy = server_msg.copy() - self._Irc.first_connexion_ip = server_msg_copy[2] - self._Irc.first_score = 0 + self._ctx.Irc.first_connexion_ip = server_msg_copy[2] + self._ctx.Irc.first_score = 0 if str(server_msg_copy[3]).find('*') != -1: # If * available, it means that an ircop changed the repurtation score # means also that the user exist will try to update all users with same IP - self._Irc.first_score = int(str(server_msg_copy[3]).replace('*','')) - for user in self._Irc.User.UID_DB: - if user.remote_ip == self._Irc.first_connexion_ip: - user.score_connexion = self._Irc.first_score + self._ctx.Irc.first_score = int(str(server_msg_copy[3]).replace('*','')) + for user in self._ctx.User.UID_DB: + if user.remote_ip == self._ctx.Irc.first_connexion_ip: + user.score_connexion = self._ctx.Irc.first_score else: - self._Irc.first_score = int(server_msg_copy[3]) + self._ctx.Irc.first_score = int(server_msg_copy[3]) # Possibilité de déclancher les bans a ce niveau. except IndexError as ie: - self._Logs.error(f'Index Error {__name__}: {ie}') + self._ctx.Logs.error(f'Index Error {__name__}: {ie}') except ValueError as ve: - self._Irc.first_score = 0 - self._Logs.error(f'Value Error {__name__}: {ve}', exc_info=True) + self._ctx.Irc.first_score = 0 + self._ctx.Logs.error(f'Value Error {__name__}: {ve}', exc_info=True) except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_uid(self, server_msg: list[str]) -> None: """Handle uid message coming from the server @@ -1087,7 +1087,7 @@ class Unrealircd6(IProtocol): hostname = str(scopy[7]) umodes = str(scopy[10]) vhost = str(scopy[11]) - remote_ip = '127.0.0.1' if 'S' in umodes else self._Base.decode_ip(str(scopy[13])) + remote_ip = '127.0.0.1' if 'S' in umodes else self._ctx.Base.decode_ip(str(scopy[13])) # extract realname realname = ' '.join(scopy[14:]).lstrip(':') @@ -1106,10 +1106,10 @@ class Unrealircd6(IProtocol): pattern = r'^.*tls_cipher=([^;]+).*$' tlsc_match = match(pattern, scopy[0]) tls_cipher = tlsc_match.group(1) if tlsc_match else None - score_connexion = self._Irc.first_score + score_connexion = self._ctx.Irc.first_score - self._Irc.User.insert( - self._Irc.Loader.Definition.MUser( + self._ctx.User.insert( + self._ctx.Definition.MUser( uid=uid, nickname=nickname, username=username, @@ -1129,22 +1129,22 @@ class Unrealircd6(IProtocol): ) # Auto Auth admin via fingerprint - dnickname = self._Config.SERVICE_NICKNAME - dchanlog = self._Config.SERVICE_CHANLOG - green = self._Config.COLORS.green - red = self._Config.COLORS.red - nogc = self._Config.COLORS.nogc + dnickname = self._ctx.Config.SERVICE_NICKNAME + dchanlog = self._ctx.Config.SERVICE_CHANLOG + green = self._ctx.Config.COLORS.green + red = self._ctx.Config.COLORS.red + nogc = self._ctx.Config.COLORS.nogc - # for module in self._Irc.ModuleUtils.model_get_loaded_modules().copy(): + # for module in self._ctx.ModuleUtils.model_get_loaded_modules().copy(): # module.class_instance.cmd(serverMsg) # SASL authentication # ['@s2s-md/..', ':001', 'UID', 'adator__', '0', '1755987444', '...', 'desktop-h1qck20.mshome.net', '001XLTT0U', '0', '+iwxz', '*', 'Clk-EC2256B2.mshome.net', 'rBKAAQ==', ':...'] - sasl_obj = self._Irc.Sasl.get_sasl_obj(uid) + sasl_obj = self._ctx.Sasl.get_sasl_obj(uid) if sasl_obj: if sasl_obj.auth_success: - self._Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) + self._ctx.Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language) await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, sasl_obj.username, dnickname), channel=dchanlog) @@ -1156,12 +1156,12 @@ class Unrealircd6(IProtocol): await self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!")) # Delete sasl object! - self._Irc.Sasl.delete_sasl_client(uid) + self._ctx.Sasl.delete_sasl_client(uid) return None # If no sasl authentication then auto connect via fingerprint - if self._Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): - admin = self._Irc.Admin.get_admin(uid) + if await self._ctx.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): + admin = self._ctx.Admin.get_admin(uid) account = admin.account if admin else '' await self.send_priv_msg(nick_from=dnickname, msg=tr("[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s", green, nogc, nickname, account, dnickname), @@ -1170,9 +1170,9 @@ class Unrealircd6(IProtocol): return None except IndexError as ie: - self._Logs.error(f"{__name__} - Index Error: {ie}") + self._ctx.Logs.error(f"{__name__} - Index Error: {ie}") except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_privmsg(self, server_msg: list[str]) -> None: """Handle PRIVMSG message coming from the server @@ -1189,31 +1189,31 @@ class Unrealircd6(IProtocol): cmd.pop(0) get_uid_or_nickname = str(cmd[0].replace(':','')) - user_trigger = self._Irc.User.get_nickname(get_uid_or_nickname) - pattern = fr'(:\{self._Config.SERVICE_PREFIX})(.*)$' + user_trigger = self._ctx.User.get_nickname(get_uid_or_nickname) + pattern = fr'(:\{self._ctx.Config.SERVICE_PREFIX})(.*)$' hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . if hcmds: # Commande qui commencent par le point liste_des_commandes = list(hcmds.groups()) convert_to_string = ' '.join(liste_des_commandes) arg = convert_to_string.split() - arg.remove(f':{self._Config.SERVICE_PREFIX}') - if not self._Irc.Commands.is_command_exist(arg[0]): - self._Logs.debug(f"This command {arg[0]} is not available") + arg.remove(f':{self._ctx.Config.SERVICE_PREFIX}') + if not self._ctx.Commands.is_command_exist(arg[0]): + self._ctx.Logs.debug(f"This command {arg[0]} is not available") await self.send_notice( - nick_from=self._Config.SERVICE_NICKNAME, + nick_from=self._ctx.Config.SERVICE_NICKNAME, nick_to=user_trigger, - msg=f"This command [{self._Config.COLORS.bold}{arg[0]}{self._Config.COLORS.bold}] is not available" + msg=f"This command [{self._ctx.Config.COLORS.bold}{arg[0]}{self._ctx.Config.COLORS.bold}] is not available" ) return None cmd_to_send = convert_to_string.replace(':','') - self._Base.log_cmd(user_trigger, cmd_to_send) + await self._ctx.Base.log_cmd(user_trigger, cmd_to_send) - fromchannel = str(cmd[2]).lower() if self._Irc.Channel.is_valid_channel(cmd[2]) else None - await self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) + fromchannel = str(cmd[2]).lower() if self._ctx.Channel.is_valid_channel(cmd[2]) else None + await self._ctx.Irc.hcmds(user_trigger, fromchannel, arg, cmd) - if cmd[2] == self._Config.SERVICE_ID: + if cmd[2] == self._ctx.Config.SERVICE_ID: pattern = fr'^:.*?:(.*)$' hcmds = search(pattern, ' '.join(cmd)) @@ -1237,26 +1237,26 @@ class Unrealircd6(IProtocol): await self.on_ping(srv_msg) return None - if not self._Irc.Commands.is_command_exist(arg[0]): - self._Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") + if not self._ctx.Commands.is_command_exist(arg[0]): + self._ctx.Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available") return None cmd_to_send = convert_to_string.replace(':','') - self._Base.log_cmd(user_trigger, cmd_to_send) + await self._ctx.Base.log_cmd(user_trigger, cmd_to_send) fromchannel = None if len(arg) >= 2: - fromchannel = str(arg[1]).lower() if self._Irc.Channel.is_valid_channel(arg[1]) else None + fromchannel = str(arg[1]).lower() if self._ctx.Channel.is_valid_channel(arg[1]) else None - await self._Irc.hcmds(user_trigger, fromchannel, arg, cmd) + await self._ctx.Irc.hcmds(user_trigger, fromchannel, arg, cmd) return None except KeyError as ke: - self._Logs.error(f"Key Error: {ke}") + self._ctx.Logs.error(f"Key Error: {ke}") except AttributeError as ae: - self._Logs.error(f"Attribute Error: {ae}") + self._ctx.Logs.error(f"Attribute Error: {ae}", exc_info=True) except Exception as err: - self._Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True) + self._ctx.Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True) async def on_server_ping(self, server_msg: list[str]) -> None: """Send a PONG message to the server @@ -1266,11 +1266,11 @@ class Unrealircd6(IProtocol): """ try: scopy = server_msg.copy() - await self.send2socket(' '.join(scopy).replace('PING', 'PONG'), print_log=True) + await self.send2socket(' '.join(scopy).replace('PING', 'PONG'), print_log=False) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_server(self, server_msg: list[str]) -> None: """_summary_ @@ -1281,9 +1281,9 @@ class Unrealircd6(IProtocol): try: # ['SERVER', 'irc.local.org', '1', ':U6100-Fhn6OoE-001', 'Local', 'Server'] scopy = server_msg.copy() - self._Irc.Settings.MAIN_SERVER_HOSTNAME = scopy[1] + self._ctx.Settings.MAIN_SERVER_HOSTNAME = scopy[1] except Exception as err: - self._Logs.error(f'General Error: {err}') + self._ctx.Logs.error(f'General Error: {err}') async def on_version(self, server_msg: list[str]) -> None: """Sending Server Version to the server @@ -1295,19 +1295,19 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION try: scopy = server_msg.copy() - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(scopy[1])) - dnickname = self._Config.SERVICE_NICKNAME + nickname = self._ctx.User.get_nickname(self._ctx.Utils.clean_uid(scopy[1])) + dnickname = self._ctx.Config.SERVICE_NICKNAME arg = scopy[4].replace(':', '') if nickname is None: return None if arg == '\x01VERSION\x01': - await self.send2socket(f':{dnickname} NOTICE {nickname} :\x01VERSION Service {self._Config.SERVICE_NICKNAME} V{self._Config.CURRENT_VERSION}\x01') + await self.send2socket(f':{dnickname} NOTICE {nickname} :\x01VERSION Service {self._ctx.Config.SERVICE_NICKNAME} V{self._ctx.Config.CURRENT_VERSION}\x01') return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_time(self, server_msg: list[str]) -> None: """Sending TIME answer to a requestor @@ -1319,10 +1319,10 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION try: scopy = server_msg.copy() - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(scopy[1])) - dnickname = self._Config.SERVICE_NICKNAME + nickname = self._ctx.User.get_nickname(self._ctx.Utils.clean_uid(scopy[1])) + dnickname = self._ctx.Config.SERVICE_NICKNAME arg = scopy[4].replace(':', '') - current_datetime = self._Utils.get_sdatetime() + current_datetime = self._ctx.Utils.get_sdatetime() if nickname is None: return None @@ -1332,7 +1332,7 @@ class Unrealircd6(IProtocol): return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_ping(self, server_msg: list[str]) -> None: """Sending a PING answer to requestor @@ -1344,30 +1344,30 @@ class Unrealircd6(IProtocol): # Réponse a un CTCP VERSION try: scopy = server_msg.copy() - nickname = self._Irc.User.get_nickname(self._Utils.clean_uid(scopy[1])) - dnickname = self._Config.SERVICE_NICKNAME + nickname = self._ctx.User.get_nickname(self._ctx.Utils.clean_uid(scopy[1])) + dnickname = self._ctx.Config.SERVICE_NICKNAME arg = scopy[4].replace(':', '') if nickname is None: - self._Logs.debug(scopy) + self._ctx.Logs.debug(scopy) return None if arg == '\x01PING': recieved_unixtime = int(scopy[5].replace('\x01','')) - current_unixtime = self._Utils.get_unixtime() + current_unixtime = self._ctx.Utils.get_unixtime() ping_response = current_unixtime - recieved_unixtime - # self._Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') + # self._ctx.Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01') await self.send_notice( nick_from=dnickname, nick_to=nickname, msg=f"\x01PING {ping_response} secs\x01" ) - self._Logs.debug(scopy) + self._ctx.Logs.debug(scopy) return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_version_msg(self, server_msg: list[str]) -> None: """Handle version coming from the server @@ -1381,25 +1381,25 @@ class Unrealircd6(IProtocol): if '@' in list(scopy[0])[0]: scopy.pop(0) - u = self._Irc.User.get_user(self._Utils.clean_uid(scopy[0])) + u = self._ctx.User.get_user(self._ctx.Utils.clean_uid(scopy[0])) if u is None: return None - response_351 = f"{self._Config.SERVICE_NAME.capitalize()}-{self._Config.CURRENT_VERSION} {self._Config.SERVICE_HOST} {self.name}" - await self.send2socket(f':{self._Config.SERVICE_HOST} 351 {u.nickname} {response_351}') + response_351 = f"{self._ctx.Config.SERVICE_NAME.capitalize()}-{self._ctx.Config.CURRENT_VERSION} {self._ctx.Config.SERVICE_HOST} {self.name}" + await self.send2socket(f':{self._ctx.Config.SERVICE_HOST} 351 {u.nickname} {response_351}') - modules = self._Irc.ModuleUtils.get_all_available_modules() + modules = self._ctx.ModuleUtils.get_all_available_modules() response_005 = ' | '.join(modules) - await self.send2socket(f':{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server') + await self.send2socket(f':{self._ctx.Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server') - response_005 = ''.join(self._Settings.PROTOCTL_USER_MODES) - await self.send2socket(f":{self._Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server") + response_005 = ''.join(self._ctx.Settings.PROTOCTL_USER_MODES) + await self.send2socket(f":{self._ctx.Config.SERVICE_HOST} 005 {u.nickname} {response_005} are supported by this server") return None except Exception as err: - self._Logs.error(f"{__name__} - General Error: {err}") + self._ctx.Logs.error(f"{__name__} - General Error: {err}") async def on_smod(self, server_msg: list[str]) -> None: """Handle SMOD message coming from the server @@ -1414,11 +1414,11 @@ class Unrealircd6(IProtocol): for smod in modules: smod_split = smod.split(':') - smodobj = self._Irc.Loader.Definition.MSModule(type=smod_split[0], name=smod_split[1], version=smod_split[2]) - self._Settings.SMOD_MODULES.append(smodobj) + smodobj = self._ctx.Definition.MSModule(type=smod_split[0], name=smod_split[1], version=smod_split[2]) + self._ctx.Settings.SMOD_MODULES.append(smodobj) except Exception as err: - self._Logs.error(f'General Error: {err}') + self._ctx.Logs.error(f'General Error: {err}') async def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']: """Handle SASL coming from a server @@ -1433,9 +1433,9 @@ class Unrealircd6(IProtocol): # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey=='] # [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A'] scopy = server_msg.copy() - psasl = self._Irc.Sasl + psasl = self._ctx.Sasl sasl_enabled = False - for smod in self._Settings.SMOD_MODULES: + for smod in self._ctx.Settings.SMOD_MODULES: if smod.name == 'sasl': sasl_enabled = True break @@ -1445,7 +1445,7 @@ class Unrealircd6(IProtocol): client_uid = scopy[3] if len(scopy) >= 6 else None sasl_message_type = scopy[4] if len(scopy) >= 6 else None - psasl.insert_sasl_client(self._Irc.Loader.Definition.MSasl(client_uid=client_uid)) + psasl.insert_sasl_client(self._ctx.Definition.MSasl(client_uid=client_uid)) sasl_obj = psasl.get_sasl_obj(client_uid) if sasl_obj is None: @@ -1463,13 +1463,13 @@ class Unrealircd6(IProtocol): sasl_obj.mechanisme = str(scopy[5]) if sasl_obj.mechanisme == "PLAIN": - await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") elif sasl_obj.mechanisme == "EXTERNAL": if str(scopy[5]) == "+": return None sasl_obj.fingerprint = str(scopy[6]) - await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +") self.on_sasl_authentication_process(sasl_obj) return sasl_obj @@ -1493,20 +1493,20 @@ class Unrealircd6(IProtocol): return sasl_obj except Exception as err: - self._Logs.error(f'General Error: {err}', exc_info=True) + self._ctx.Logs.error(f'General Error: {err}', exc_info=True) async def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> None: s = sasl_model if sasl_model: - def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: + async def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: if fingerprint: mes_donnees = {'fingerprint': fingerprint} - query = f"SELECT user, level, language FROM {self._Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint" + query = f"SELECT user, level, language FROM {self._ctx.Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint" else: - mes_donnees = {'user': username, 'password': self._Utils.hash_password(password)} - query = f"SELECT user, level, language FROM {self._Config.TABLE_ADMIN} WHERE user = :user AND password = :password" + mes_donnees = {'user': username, 'password': self._ctx.Utils.hash_password(password)} + query = f"SELECT user, level, language FROM {self._ctx.Config.TABLE_ADMIN} WHERE user = :user AND password = :password" - result = self._Base.db_execute_query(query, mes_donnees) + result = await self._ctx.Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if user_from_db: return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]} @@ -1515,32 +1515,32 @@ class Unrealircd6(IProtocol): if s.message_type == 'C' and s.mechanisme == 'PLAIN': # Connection via PLAIN - admin_info = db_get_admin_info(username=s.username, password=s.password) + admin_info = await db_get_admin_info(username=s.username, password=s.password) if admin_info is not None: s.auth_success = True s.level = admin_info.get('level', 0) s.language = admin_info.get('language', 'EN') - await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - await self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: - await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - await self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL': # Connection using fingerprints - admin_info = db_get_admin_info(fingerprint=s.fingerprint) + admin_info = await db_get_admin_info(fingerprint=s.fingerprint) if admin_info is not None: s.auth_success = True s.level = admin_info.get('level', 0) s.username = admin_info.get('user', None) s.language = admin_info.get('language', 'EN') - await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - await self.send2socket(f":{self._Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: # "904 :SASL authentication failed" - await self.send2socket(f":{self._Config.SERVEUR_LINK} SASL {self._Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - await self.send2socket(f":{self._Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") async def on_md(self, server_msg: list[str]) -> None: """Handle MD responses @@ -1556,7 +1556,7 @@ class Unrealircd6(IProtocol): var = str(scopy[4]).lower() value = str(scopy[5]).replace(':', '') - user_obj = self._Irc.User.get_user(uid) + user_obj = self._ctx.User.get_user(uid) if user_obj is None: return None @@ -1569,7 +1569,7 @@ class Unrealircd6(IProtocol): return None except Exception as e: - self._Logs.error(f"General Error: {e}") + self._ctx.Logs.error(f"General Error: {e}") async def on_kick(self, server_msg: list[str]) -> None: """When a user is kicked out from a channel @@ -1583,7 +1583,7 @@ class Unrealircd6(IProtocol): channel = scopy[3] # Delete the user from the channel. - self._Irc.Channel.delete_user_from_channel(channel, uid) + self._ctx.Channel.delete_user_from_channel(channel, uid) return None async def on_sethost(self, server_msg: list[str]) -> None: @@ -1594,7 +1594,7 @@ class Unrealircd6(IProtocol): server_msg (list[str]): _description_ """ scopy = server_msg.copy() - uid = self._User.clean_uid(scopy[0]) + uid = self._ctx.User.clean_uid(scopy[0]) vhost = scopy[2].lstrip(':') - user = self._User.get_user(uid) + user = self._ctx.User.get_user(uid) user.vhost = vhost diff --git a/core/definition.py b/core/definition.py index 72f9062..6d9ef95 100644 --- a/core/definition.py +++ b/core/definition.py @@ -3,6 +3,7 @@ from json import dumps from dataclasses import dataclass, field, asdict, fields, replace from typing import Literal, Any, Optional from os import sep +from core.classes.interfaces.imodule import IModule @dataclass class MainModel: @@ -354,7 +355,7 @@ class MCommand(MainModel): class MModule(MainModel): module_name: str = None class_name: str = None - class_instance: Optional[Any] = None + class_instance: Optional[IModule] = None @dataclass class DefenderModuleHeader(MainModel): diff --git a/core/irc.py b/core/irc.py index 5469a2b..ff19528 100644 --- a/core/irc.py +++ b/core/irc.py @@ -1,7 +1,5 @@ import asyncio -import sys import socket -import ssl import re import time from ssl import SSLSocket @@ -29,61 +27,25 @@ class Irc: self.signal: bool = True - # Loader class - self.Loader = loader - - # Load the configuration - self.Config = self.Loader.Config - - # Load Main utils functions - self.Utils = self.Loader.Utils + # Load Context class (Loader) + self.ctx = loader # Date et heure de la premiere connexion de Defender - self.defender_connexion_datetime = self.Config.DEFENDER_CONNEXION_DATETIME + self.defender_connexion_datetime = self.ctx.Config.DEFENDER_CONNEXION_DATETIME # Lancer toutes les 30 secondes des actions de nettoyages - self.beat = self.Config.DEFENDER_HEARTBEAT_FREQUENCY + self.beat = self.ctx.Config.DEFENDER_HEARTBEAT_FREQUENCY # Heartbeat active - self.hb_active = self.Config.DEFENDER_HEARTBEAT + self.hb_active = self.ctx.Config.DEFENDER_HEARTBEAT # ID du serveur qui accueil le service ( Host Serveur Id ) - self.HSID = self.Config.HSID + self.HSID = self.ctx.Config.HSID # Charset utiliser pour décoder/encoder les messages - self.CHARSET = self.Config.SERVEUR_CHARSET + self.CHARSET = self.ctx.Config.SERVEUR_CHARSET """0: utf-8 | 1: iso-8859-1""" - # Use Base Instance - self.Base = self.Loader.Base - - # Logger - self.Logs = self.Loader.Logs - - # Get Settings. - self.Settings = self.Base.Settings - - # Use User Instance - self.User = self.Loader.User - - # Use Admin Instance - self.Admin = self.Loader.Admin - - # Use Client Instance - self.Client = self.Loader.Client - - # Use Channel Instance - self.Channel = self.Loader.Channel - - # Use Reputation Instance - self.Reputation = self.Loader.Reputation - - # Use Module Utils - self.ModuleUtils = self.Loader.ModuleUtils - - # Use Main Sasl module - self.Sasl = self.Loader.Sasl - self.autolimit_started: bool = False """This variable is to make sure the thread is not running""" @@ -94,7 +56,7 @@ class Irc: self.first_connexion_ip: str = None # Load Commands Utils - self.Commands = self.Loader.Commands + # self.Commands = self.Loader.Commands """Command utils""" self.build_command(0, 'core', 'help', 'This provide the help') @@ -102,8 +64,8 @@ class Irc: self.build_command(0, 'core', 'copyright', 'Give some information about the IRC Service') self.build_command(0, 'core', 'uptime', 'Give you since when the service is connected') self.build_command(0, 'core', 'firstauth', 'First authentication of the Service') - self.build_command(0, 'core', 'register', f'Register your nickname /msg {self.Config.SERVICE_NICKNAME} REGISTER ') - self.build_command(0, 'core', 'identify', f'Identify yourself with your password /msg {self.Config.SERVICE_NICKNAME} IDENTIFY ') + self.build_command(0, 'core', 'register', f'Register your nickname /msg {self.ctx.Config.SERVICE_NICKNAME} REGISTER ') + self.build_command(0, 'core', 'identify', f'Identify yourself with your password /msg {self.ctx.Config.SERVICE_NICKNAME} IDENTIFY ') self.build_command(0, 'core', 'logout', 'Reverse the effect of the identify command') self.build_command(1, 'core', 'load', 'Load an existing module') self.build_command(1, 'core', 'unload', 'Unload a module') @@ -113,6 +75,7 @@ class Irc: self.build_command(2, 'core', 'show_modules', 'Display a list of loaded modules') self.build_command(2, 'core', 'show_timers', 'Display active timers') self.build_command(2, 'core', 'show_threads', 'Display active threads in the system') + self.build_command(2, 'core', 'show_asyncio', 'Display active asyncio') self.build_command(2, 'core', 'show_channels', 'Display a list of active channels') self.build_command(2, 'core', 'show_users', 'Display a list of connected users') self.build_command(2, 'core', 'show_clients', 'Display a list of connected clients') @@ -138,23 +101,21 @@ class Irc: self.reader: Optional[asyncio.StreamReader] = None self.writer: Optional[asyncio.StreamWriter] = None - self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, )) + self.ctx.Base.create_asynctask(self.heartbeat(self.beat)) async def connect(self): - if self.Config.SERVEUR_SSL: - self.reader, self.writer = await asyncio.open_connection(self.Config.SERVEUR_IP, self.Config.SERVEUR_PORT, ssl=self.Utils.get_ssl_context()) + if self.ctx.Config.SERVEUR_SSL: + self.reader, self.writer = await asyncio.open_connection(self.ctx.Config.SERVEUR_IP, self.ctx.Config.SERVEUR_PORT, ssl=self.ctx.Utils.get_ssl_context()) else: - self.reader, self.writer = await asyncio.open_connection(self.Config.SERVEUR_IP, self.Config.SERVEUR_PORT) + self.reader, self.writer = await asyncio.open_connection(self.ctx.Config.SERVEUR_IP, self.ctx.Config.SERVEUR_PORT) self.init_service_user() - self.Protocol: 'IProtocol' = self.Loader.PFactory.get() + self.Protocol: 'IProtocol' = self.ctx.PFactory.get() self.Protocol.register_command() await self.Protocol.send_link() - async def listen(self): - while self.signal: data = await self.reader.readuntil(b'\r\n') await self.send_response(data.splitlines()) @@ -166,104 +127,22 @@ class Irc: ############################################## # CONNEXION IRC # ############################################## - def init_irc(self) -> None: - """Create a socket and connect to irc server - - Args: - ircInstance (Irc): Instance of Irc object. - """ - try: - self.init_service_user() - self.Utils.create_socket(self) - self.__connect_to_irc() - - except AssertionError as ae: - self.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 + self.ctx.User.insert(self.ctx.Definition.MUser( + uid=self.ctx.Config.SERVICE_ID, + nickname=self.ctx.Config.SERVICE_NICKNAME, + username=self.ctx.Config.SERVICE_USERNAME, + realname=self.ctx.Config.SERVICE_REALNAME, + hostname=self.ctx.Config.SERVICE_HOST, + umodes=self.ctx.Config.SERVICE_SMODES )) return None - def __connect_to_irc(self) -> None: - try: - self.init_service_user() - self.Protocol: 'IProtocol' = self.Loader.PFactory.get() - self.Protocol.register_command() - self.Protocol.send_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.ModuleUtils.db_load_all_existing_modules(self) - - while self.signal: - try: - if self.Config.DEFENDER_RESTART == 1: - rehash.restart_service(self) - - # 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) - eol = True - if data_in_bytes[-2:] != b"\r\n": - eol = False - - while not eol: - new_data = self.IrcSocket.recv(buffer_size) - data_in_bytes += new_data - if data_in_bytes[-2:] == eol: - eol = False - - # 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: - break - - self.send_response(data) - - except ssl.SSLEOFError as soe: - self.Logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}") - except ssl.SSLError as se: - self.Logs.error(f"SSLError __connect_to_irc: {se} - {data}") - sys.exit(-1) - except OSError as oe: - self.Logs.error(f"SSLError __connect_to_irc: {oe} {oe.errno}") - if oe.errno == 10053: - sys.exit(-1) - except (socket.error, ConnectionResetError): - self.Logs.debug("Connexion reset") - - self.IrcSocket.shutdown(socket.SHUT_RDWR) - self.IrcSocket.close() - self.Logs.info("-- Fermeture de Defender ...") - sys.exit(0) - - except AssertionError as ae: - self.Logs.error(f'AssertionError: {ae}') - except ValueError as ve: - self.Logs.error(f'ValueError: {ve}') - except ssl.SSLEOFError as soe: - self.Logs.error(f"SSLEOFError: {soe}") - except AttributeError as atte: - self.Logs.critical(f"AttributeError: {atte}", exc_info=True) - except Exception as e: - self.Logs.critical(f"General Error: {e}", exc_info=True) - async def join_saved_channels(self) -> None: """## Joining saved channels""" - exec_query = self.Base.db_execute_query(f'SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}') + exec_query = await self.ctx.Base.db_execute_query(f'SELECT distinct channel_name FROM {self.ctx.Config.TABLE_CHANNEL}') result_query = exec_query.fetchall() if result_query: @@ -281,18 +160,18 @@ class Irc: for data in responses: response = data.decode(self.CHARSET[1],'replace').split() await self.cmd(response) - self.Logs.error(f'UnicodeEncodeError: {ue}') - self.Logs.error(response) + self.ctx.Logs.error(f'UnicodeEncodeError: {ue}') + self.ctx.Logs.error(response) except UnicodeDecodeError as ud: for data in responses: response = data.decode(self.CHARSET[1],'replace').split() await self.cmd(response) - self.Logs.error(f'UnicodeDecodeError: {ud}') - self.Logs.error(response) + self.ctx.Logs.error(f'UnicodeDecodeError: {ud}') + self.ctx.Logs.error(response) except AssertionError as ae: - self.Logs.error(f"Assertion error : {ae}") + self.ctx.Logs.error(f"Assertion error : {ae}") def unload(self) -> None: # This is only to reference the method @@ -312,7 +191,7 @@ class Irc: command_description (str): The description of the command """ # Build Model. - self.Commands.build(self.Loader.Definition.MCommand(module_name, command_name, command_description, level)) + self.ctx.Commands.build(self.ctx.Definition.MCommand(module_name, command_name, command_description, level)) return None @@ -320,10 +199,10 @@ class Irc: # Check if the nickname is an admin p = self.Protocol - admin_obj = self.Admin.get_admin(nickname) - dnickname = self.Config.SERVICE_NICKNAME - color_nogc = self.Config.COLORS.nogc - color_black = self.Config.COLORS.black + admin_obj = self.ctx.Admin.get_admin(nickname) + dnickname = self.ctx.Config.SERVICE_NICKNAME + color_nogc = self.ctx.Config.COLORS.nogc + color_black = self.ctx.Config.COLORS.black current_level = 0 if admin_obj is not None: @@ -334,7 +213,7 @@ class Irc: line = "-"*75 await p.send_notice(nick_from=dnickname,nick_to=nickname, msg=header) await p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" {line}") - for cmd in self.Commands.get_commands_by_level(current_level): + for cmd in self.ctx.Commands.get_commands_by_level(current_level): if module is None or cmd.module_name.lower() == module.lower(): await p.send_notice( nick_from=dnickname, @@ -344,18 +223,18 @@ class Irc: return None - def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool: + async def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool: s = sasl_model if sasl_model: - def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: + async def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]: if fingerprint: mes_donnees = {'fingerprint': fingerprint} - query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint" + query = f"SELECT user, level, language FROM {self.ctx.Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint" else: - mes_donnees = {'user': username, 'password': self.Utils.hash_password(password)} - query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password" + mes_donnees = {'user': username, 'password': self.ctx.Utils.hash_password(password)} + query = f"SELECT user, level, language FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user AND password = :password" - result = self.Base.db_execute_query(query, mes_donnees) + result = await self.ctx.Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if user_from_db: return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]} @@ -364,32 +243,32 @@ class Irc: if s.message_type == 'C' and s.mechanisme == 'PLAIN': # Connection via PLAIN - admin_info = db_get_admin_info(username=s.username, password=s.password) + admin_info = await db_get_admin_info(username=s.username, password=s.password) if admin_info is not None: s.auth_success = True s.level = admin_info.get('level', 0) s.language = admin_info.get('language', 'EN') - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL': # Connection using fingerprints - admin_info = db_get_admin_info(fingerprint=s.fingerprint) + admin_info = await db_get_admin_info(fingerprint=s.fingerprint) if admin_info is not None: s.auth_success = True s.level = admin_info.get('level', 0) s.username = admin_info.get('user', None) s.language = admin_info.get('language', 'EN') - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful") else: # "904 :SASL authentication failed" - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") - self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F") + await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed") def get_defender_uptime(self) -> str: """Savoir depuis quand Defender est connecté @@ -403,7 +282,7 @@ class Irc: return uptime - def heartbeat(self, beat: float) -> None: + async def heartbeat(self, beat: float) -> None: """Execute certaines commandes de nettoyage toutes les x secondes x étant définit a l'initialisation de cette class (self.beat) @@ -411,17 +290,17 @@ class Irc: beat (float): Nombre de secondes entre chaque exécution """ while self.hb_active: - time.sleep(beat) - self.Base.execute_periodic_action() + await asyncio.sleep(beat) + self.ctx.Base.execute_periodic_action() def insert_db_admin(self, uid: str, account: str, level: int, language: str) -> None: - user_obj = self.User.get_user(uid) + user_obj = self.ctx.User.get_user(uid) if user_obj is None: return None - self.Admin.insert( - self.Loader.Definition.MAdmin( + self.ctx.Admin.insert( + self.ctx.Definition.MAdmin( **user_obj.to_dict(), language=language, account=account, @@ -433,15 +312,15 @@ class Irc: def delete_db_admin(self, uid:str) -> None: - if self.Admin.get_admin(uid) is None: + if self.ctx.Admin.get_admin(uid) is None: return None - if not self.Admin.delete(uid): - self.Logs.critical(f'UID: {uid} was not deleted') + if not self.ctx.Admin.delete(uid): + self.ctx.Logs.critical(f'UID: {uid} was not deleted') return None - def create_defender_user(self, sender: str, new_admin: str, new_level: int, new_password: str) -> bool: + async def create_defender_user(self, sender: str, new_admin: str, new_level: int, new_password: str) -> bool: """Create a new admin user for defender Args: @@ -455,50 +334,50 @@ class Irc: """ # > addaccess [nickname] [level] [password] - dnick = self.Config.SERVICE_NICKNAME + dnick = self.ctx.Config.SERVICE_NICKNAME p = self.Protocol - get_user = self.User.get_user(new_admin) - level = self.Base.convert_to_int(new_level) + get_user = self.ctx.User.get_user(new_admin) + level = self.ctx.Base.convert_to_int(new_level) password = new_password if get_user is None: response = tr("The nickname (%s) is not currently connected! please create a new admin when the nickname is connected to the network!", new_admin) - p.send_notice(dnick, sender, response) - self.Logs.debug(f"New admin {new_admin} sent by {sender} is not connected") + await p.send_notice(dnick, sender, response) + self.ctx.Logs.debug(f"New admin {new_admin} sent by {sender} is not connected") return False if level is None or level > 4 or level == 0: - p.send_notice(dnick, sender, tr("The level (%s) must be a number from 1 to 4", level)) - self.Logs.debug(f"Level must a number between 1 to 4 (sent by {sender})") + await p.send_notice(dnick, sender, tr("The level (%s) must be a number from 1 to 4", level)) + self.ctx.Logs.debug(f"Level must a number between 1 to 4 (sent by {sender})") return False nickname = get_user.nickname hostname = get_user.hostname vhost = get_user.vhost - spassword = self.Loader.Utils.hash_password(password) + spassword = self.ctx.Utils.hash_password(password) # Check if the user already exist - if not self.Admin.db_is_admin_exist(nickname): - mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level, 'language': self.Config.LANG} - self.Base.db_execute_query(f'''INSERT INTO {self.Config.TABLE_ADMIN} + if not self.ctx.Admin.db_is_admin_exist(nickname): + mes_donnees = {'datetime': self.ctx.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level, 'language': self.ctx.Config.LANG} + await self.ctx.Base.db_execute_query(f'''INSERT INTO {self.ctx.Config.TABLE_ADMIN} (createdOn, user, password, hostname, vhost, level, language) VALUES (:datetime, :user, :password, :hostname, :vhost, :level, :language) ''', mes_donnees) - p.send_notice(dnick, sender, tr("New admin (%s) has been added with level %s", nickname, level)) - self.Logs.info(f"A new admin ({nickname}) has been created by {sender}!") + await p.send_notice(dnick, sender, tr("New admin (%s) has been added with level %s", nickname, level)) + self.ctx.Logs.info(f"A new admin ({nickname}) has been created by {sender}!") return True else: - p.send_notice(dnick, sender, tr("The nickname (%s) Already exist!", nickname)) - self.Logs.info(f"The nickname {nickname} already exist! (sent by {sender})") + await p.send_notice(dnick, sender, tr("The nickname (%s) Already exist!", nickname)) + self.ctx.Logs.info(f"The nickname {nickname} already exist! (sent by {sender})") return False async def thread_check_for_new_version(self, fromuser: str) -> None: - dnickname = self.Config.SERVICE_NICKNAME + dnickname = self.ctx.Config.SERVICE_NICKNAME - if self.Base.check_for_new_version(True): - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" New Version available : {self.Config.CURRENT_VERSION} >>> {self.Config.LATEST_VERSION}") + if self.ctx.Base.check_for_new_version(True): + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" New Version available : {self.ctx.Config.CURRENT_VERSION} >>> {self.ctx.Config.LATEST_VERSION}") await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" Please run (git pull origin main) in the current folder") else: await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" You have the latest version of defender") @@ -514,29 +393,29 @@ class Irc: try: original_response: list[str] = data.copy() if len(original_response) < 2: - self.Logs.warning(f'Size ({str(len(original_response))}) - {original_response}') + self.ctx.Logs.warning(f'Size ({str(len(original_response))}) - {original_response}') return None - self.Logs.debug(f">> {self.Utils.hide_sensitive_data(original_response)}") + self.ctx.Logs.debug(f">> {self.ctx.Utils.hide_sensitive_data(original_response)}") pos, parsed_protocol = self.Protocol.get_ircd_protocol_poisition(cmd=original_response, log=True) - modules = self.ModuleUtils.model_get_loaded_modules().copy() + modules = self.ctx.ModuleUtils.model_get_loaded_modules().copy() for parsed in self.Protocol.Handler.get_ircd_commands(): if parsed.command_name.upper() == parsed_protocol: await parsed.func(original_response) for module in modules: - module.class_instance.cmd(original_response) + await module.class_instance.cmd(original_response) if self.ctx.Utils.is_coroutinefunction(module.class_instance.cmd) else module.class_instance.cmd(original_response) # if len(original_response) > 2: # if original_response[2] != 'UID': # # Envoyer la commande aux classes dynamiquement chargées - # for module in self.ModuleUtils.model_get_loaded_modules().copy(): + # for module in self.ctx.ModuleUtils.model_get_loaded_modules().copy(): # module.class_instance.cmd(original_response) except IndexError as ie: - self.Logs.error(f"IndexError: {ie}") + self.ctx.Logs.error(f"IndexError: {ie}") except Exception as err: - self.Logs.error(f"General Error: {err}", exc_info=True) + self.ctx.Logs.error(f"General Error: {err}", exc_info=True) async def hcmds(self, user: str, channel: Union[str, None], cmd: list, fullcmd: list = []) -> None: """Create @@ -550,38 +429,38 @@ class Irc: Returns: None: Nothing to return """ - u = self.User.get_user(user) + u = self.ctx.User.get_user(user) """The User Object""" if u is None: return None - c = self.Client.get_Client(u.uid) + c = self.ctx.Client.get_Client(u.uid) """The Client Object""" fromuser = u.nickname uid = u.uid - self.Settings.current_admin = self.Admin.get_admin(user) # set Current admin if any. + self.ctx.Settings.current_admin = self.ctx.Admin.get_admin(user) # set Current admin if any. - RED = self.Config.COLORS.red - GREEN = self.Config.COLORS.green - BLACK = self.Config.COLORS.black - NOGC = self.Config.COLORS.nogc + RED = self.ctx.Config.COLORS.red + GREEN = self.ctx.Config.COLORS.green + BLACK = self.ctx.Config.COLORS.black + NOGC = self.ctx.Config.COLORS.nogc # Defender information - dnickname = self.Config.SERVICE_NICKNAME # Defender nickname - dchanlog = self.Config.SERVICE_CHANLOG # Defender chan log + dnickname = self.ctx.Config.SERVICE_NICKNAME # Defender nickname + dchanlog = self.ctx.Config.SERVICE_CHANLOG # Defender chan log if len(cmd) > 0: command = str(cmd[0]).lower() else: return False - if not self.Commands.is_client_allowed_to_run_command(fromuser, command): + if not self.ctx.Commands.is_client_allowed_to_run_command(fromuser, command): command = 'notallowed' # Envoyer la commande aux classes dynamiquement chargées if command != 'notallowed': - for module in self.ModuleUtils.DB_MODULES: + for module in self.ctx.ModuleUtils.DB_MODULES: await module.class_instance.hcmds(user, channel, cmd, fullcmd) match command: @@ -602,7 +481,7 @@ class Irc: ) except IndexError as ie: - self.Logs.error(f'{ie}') + self.ctx.Logs.error(f'{ie}') case 'deauth': @@ -610,13 +489,13 @@ class Irc: uid_to_deauth = uid self.delete_db_admin(uid_to_deauth) - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( msg=tr("[ %s%s%s ] - %s has been disconnected from %s", RED, current_command, NOGC, fromuser, dnickname), nick_from=dnickname, channel=dchanlog ) - self.Protocol.send_notice(dnickname, fromuser, tr("You have been successfully disconnected from %s", dnickname)) + await self.Protocol.send_notice(dnickname, fromuser, tr("You have been successfully disconnected from %s", dnickname)) return None case 'firstauth': @@ -627,22 +506,22 @@ class Irc: current_command = str(cmd[0]) if current_nickname is None: - self.Logs.critical(f"This nickname [{fromuser}] don't exist") + self.ctx.Logs.critical(f"This nickname [{fromuser}] don't exist") return None if len(cmd) < 3: - self.Protocol.send_notice(dnickname,fromuser, tr("Syntax. /msg %s %s [OWNER_NICKNAME] [OWNER_PASSWORD]", self.Config.SERVICE_NICKNAME, current_command)) + await self.Protocol.send_notice(dnickname,fromuser, tr("Syntax. /msg %s %s [OWNER_NICKNAME] [OWNER_PASSWORD]", self.ctx.Config.SERVICE_NICKNAME, current_command)) return None - query = f"SELECT count(id) as c FROM {self.Config.TABLE_ADMIN}" - result = self.Base.db_execute_query(query) + query = f"SELECT count(id) as c FROM {self.ctx.Config.TABLE_ADMIN}" + result = await self.ctx.Base.db_execute_query(query) result_db = result.fetchone() if result_db[0] > 0: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=tr("You can't use this command anymore ! Please use [%sauth] instead", self.Config.SERVICE_PREFIX) + msg=tr("You can't use this command anymore ! Please use [%sauth] instead", self.ctx.Config.SERVICE_PREFIX) ) return None @@ -651,12 +530,12 @@ class Irc: cmd_password = str(cmd[2]) # Credentials coming from the Configuration - config_owner = self.Config.OWNER - config_password = self.Config.PASSWORD + config_owner = self.ctx.Config.OWNER + config_password = self.ctx.Config.PASSWORD if cmd_owner != config_owner: - self.Logs.critical(f"The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !") - self.Protocol.send_notice( + self.ctx.Logs.critical(f"The nickname sent [{cmd_owner}] is different than the configuration owner [{config_owner}] !") + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=tr("The nickname sent [%s] is different than the one set in the configuration file !", cmd_owner) @@ -664,52 +543,52 @@ class Irc: return None if cmd_owner == config_owner and cmd_password == config_password: - self.Base.db_create_first_admin() - self.insert_db_admin(current_uid, cmd_owner, 5, self.Config.LANG) - self.Protocol.send_priv_msg( + await self.ctx.Base.db_create_first_admin() + self.insert_db_admin(current_uid, cmd_owner, 5, self.ctx.Config.LANG) + await self.Protocol.send_priv_msg( msg=tr("[%s %s %s] - %s is now connected to %s", GREEN, current_command.upper(), NOGC, fromuser, dnickname), nick_from=dnickname, channel=dchanlog ) - self.Protocol.send_notice(dnickname, fromuser, tr("Successfuly connected to %s", dnickname)) + await self.Protocol.send_notice(dnickname, fromuser, tr("Successfuly connected to %s", dnickname)) else: - self.Protocol.send_priv_msg( + await self.Protocol.send_priv_msg( msg=tr("[ %s %s %s ] - %s provided a wrong password!", RED, current_command.upper(), NOGC, current_nickname), nick_from=dnickname, channel=dchanlog ) - self.Protocol.send_notice(dnickname, fromuser, tr("Wrong password!")) + await self.Protocol.send_notice(dnickname, fromuser, tr("Wrong password!")) case 'auth': # Syntax. !auth nickname password if len(cmd) < 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [password]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [password]") return None user_to_log = cmd[1] password = cmd[2] current_client = u - admin_obj = self.Admin.get_admin(fromuser) + admin_obj = self.ctx.Admin.get_admin(fromuser) if current_client is None: # This case should never happen - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {RED}{str(command).upper()} FAIL{NOGC} ] - Nickname {fromuser} is trying to connect to defender wrongly", channel=dchanlog) return None if admin_obj: - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {GREEN}{str(command).upper()}{NOGC} ] - {fromuser} is already connected to {dnickname}", channel=dchanlog) - self.Protocol.send_notice(dnickname, fromuser, tr("You are already connected to %s", dnickname)) + await self.Protocol.send_notice(dnickname, fromuser, tr("You are already connected to %s", dnickname)) return None - mes_donnees = {'user': user_to_log, 'password': self.Loader.Utils.hash_password(password)} - query = f"SELECT id, user, level, language FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password" - result = self.Base.db_execute_query(query, mes_donnees) + mes_donnees = {'user': user_to_log, 'password': self.ctx.Utils.hash_password(password)} + query = f"SELECT id, user, level, language FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user AND password = :password" + result = await self.ctx.Base.db_execute_query(query, mes_donnees) user_from_db = result.fetchone() if user_from_db: @@ -717,54 +596,54 @@ class Irc: level = int(user_from_db[2]) language = str(user_from_db[3]) self.insert_db_admin(current_client.uid, account, level, language) - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {GREEN}{str(command).upper()} SUCCESS{NOGC} ] - {current_client.nickname} ({account}) est désormais connecté a {dnickname}", channel=dchanlog) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=tr("Successfuly connected to %s", dnickname)) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=tr("Successfuly connected to %s", dnickname)) return None else: - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {RED}{str(command).upper()} FAIL{NOGC} ] - {current_client.nickname} a tapé un mauvais mot de pass", channel=dchanlog) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=tr("Wrong password!")) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=tr("Wrong password!")) return None case 'addaccess': try: # .addaccess adator 5 password if len(cmd) < 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} addaccess [nickname] [level] [password]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} addaccess [nickname] [level] [password]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4") return None new_admin = str(cmd[1]) - level = self.Base.int_if_possible(cmd[2]) + level = self.ctx.Base.int_if_possible(cmd[2]) password = str(cmd[3]) self.create_defender_user(fromuser, new_admin, level, password) return None except IndexError as ie: - self.Logs.error(f'_hcmd addaccess: {ie}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") + self.ctx.Logs.error(f'_hcmd addaccess: {ie}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") except TypeError as te: - self.Logs.error(f'_hcmd addaccess: out of index : {te}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") + self.ctx.Logs.error(f'_hcmd addaccess: out of index : {te}') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} addaccess [nickname] [level] [password]") case 'editaccess': # .editaccess [USER] [NEW_PASSWORD] [LEVEL] try: if len(cmd) < 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} editaccess [nickname] [NEWPASSWORD] [NEWLEVEL]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} editaccess [nickname] [NEWPASSWORD] [NEWLEVEL]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4") return None user_to_edit = cmd[1] - user_password = self.Loader.Utils.hash_password(cmd[2]) + user_password = self.ctx.Utils.hash_password(cmd[2]) - get_admin = self.Admin.get_admin(fromuser) + get_admin = self.ctx.Admin.get_admin(fromuser) if get_admin is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no Admin access") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no Admin access") return None current_user = fromuser @@ -777,40 +656,40 @@ class Irc: user_new_level = get_admin.level if user_new_level > 5: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Maximum authorized level is 5") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="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" - result = self.Base.db_execute_query(query, mes_donnees) + query = f"SELECT user, level FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user" + result = await self.ctx.Base.db_execute_query(query, mes_donnees) isUserExist = result.fetchone() if not isUserExist is None: if current_user_level < int(isUserExist[1]): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You are not allowed to edit this access") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You are not allowed to edit this access") return None if current_user_level == int(isUserExist[1]) and current_user != user_to_edit: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You can't edit access of a user with same level") + await self.Protocol.send_notice(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" - exec_query = self.Base.db_execute_query(sql_update, data_to_update) + sql_update = f"UPDATE {self.ctx.Config.TABLE_ADMIN} SET level = :level, password = :password WHERE user = :user" + exec_query = await self.ctx.Base.db_execute_query(sql_update, data_to_update) if exec_query.rowcount > 0: - self.Protocol.send_notice(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) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" User {user_to_edit} has been modified with level {str(user_new_level)}") + self.ctx.Admin.update_level(user_to_edit, user_new_level) else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Impossible de modifier l'utilisateur {str(user_new_level)}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Impossible de modifier l'utilisateur {str(user_new_level)}") except TypeError as te: - self.Logs.error(f"Type error : {te}") + self.ctx.Logs.error(f"Type error : {te}") except ValueError as ve: - self.Logs.error(f"Value Error : {ve}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {self.Config.SERVICE_PREFIX}editaccess [USER] [NEWPASSWORD] [NEWLEVEL]") + self.ctx.Logs.error(f"Value Error : {ve}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {self.ctx.Config.SERVICE_PREFIX}editaccess [USER] [NEWPASSWORD] [NEWLEVEL]") case 'delaccess': # .delaccess [USER] [CONFIRMUSER] @@ -818,18 +697,18 @@ class Irc: user_confirmation = cmd[2] if user_to_del != user_confirmation: - self.Protocol.send_notice(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.Logs.warning(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer') + await self.Protocol.send_notice(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.ctx.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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}delaccess [USER] [CONFIRMUSER]") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.ctx.Config.SERVICE_PREFIX}delaccess [USER] [CONFIRMUSER]") return None - get_admin = self.Admin.get_admin(fromuser) + get_admin = self.ctx.Admin.get_admin(fromuser) if get_admin is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no admin access") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no admin access") return None current_user = fromuser @@ -838,82 +717,82 @@ 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" - result = self.Base.db_execute_query(query, mes_donnees) + query = f"SELECT user, level FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user" + result = await self.ctx.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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are not allowed to delete this access") - self.Logs.warning(f':{dnickname} NOTICE {fromuser} : You are not allowed to delete this access') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are not allowed to delete this access") + self.ctx.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" - exec_query = self.Base.db_execute_query(sql_delete, data_to_delete) + sql_delete = f"DELETE FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user" + exec_query = await self.ctx.Base.db_execute_query(sql_delete, data_to_delete) if exec_query.rowcount > 0: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"User {user_to_del} has been deleted !") - self.Admin.delete(user_to_del) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"User {user_to_del} has been deleted !") + self.ctx.Admin.delete(user_to_del) else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Impossible de supprimer l'utilisateur.") - self.Logs.warning(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Impossible de supprimer l'utilisateur.") + self.ctx.Logs.warning(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.") case 'cert': # Syntax !cert try: if len(cmd) < 2: - self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert add") - self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert del") + await self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert add") + await self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert del") return None - admin_obj = self.Admin.get_admin(fromuser) + admin_obj = self.ctx.Admin.get_admin(fromuser) param = cmd[1] # add or del match param: case 'add': if admin_obj: if admin_obj.fingerprint is not None: - query = f'UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user = :user' - r = self.Base.db_execute_query(query, {'fingerprint': admin_obj.fingerprint, 'user': admin_obj.account}) + query = f'UPDATE {self.ctx.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user = :user' + r = await self.ctx.Base.db_execute_query(query, {'fingerprint': admin_obj.fingerprint, 'user': admin_obj.account}) if r.rowcount > 0: - self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your new fingerprint has been attached to your account. {admin_obj.fingerprint}') + await self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your new fingerprint has been attached to your account. {admin_obj.fingerprint}') else: - self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to add your fingerprint.{admin_obj.fingerprint}') + await self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to add your fingerprint.{admin_obj.fingerprint}') else: - self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] There is no fingerprint to add.') + await self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] There is no fingerprint to add.') case 'del': if admin_obj: - query = f"UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user =:user" - r = self.Base.db_execute_query(query, {'fingerprint': None, 'user': admin_obj.account}) + query = f"UPDATE {self.ctx.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user =:user" + r = await self.ctx.Base.db_execute_query(query, {'fingerprint': None, 'user': admin_obj.account}) if r.rowcount > 0: - self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your fingerprint has been removed from your account. {admin_obj.fingerprint}') + await self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your fingerprint has been removed from your account. {admin_obj.fingerprint}') else: - self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to remove your fingerprint.{admin_obj.fingerprint}') + await self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to remove your fingerprint.{admin_obj.fingerprint}') case _: - self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert add") - self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert del") + await self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert add") + await self.Protocol.send_notice(dnickname, fromuser, f"Right command : /msg {dnickname} cert del") return None except Exception as e: - self.Logs.error(e) + self.ctx.Logs.error(e) case 'register': # Syntax. Register PASSWORD EMAIL try: if len(cmd) < 3: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f'/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ' + msg=f'/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} ' ) return None password = cmd[1] email = cmd[2] - if not self.Base.is_valid_email(email_to_control=email): - self.Protocol.send_notice( + if not self.ctx.Base.is_valid_email(email_to_control=email): + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg='The email is not valid. You must provide a valid email address (first.name@email.extension)' @@ -923,34 +802,34 @@ class Irc: user_obj = u if user_obj is None: - self.Logs.error(f"Nickname ({fromuser}) doesn't exist, it is impossible to register this nickname") + self.ctx.Logs.error(f"Nickname ({fromuser}) doesn't exist, it is impossible to register this nickname") return None # If the account already exist. - if self.Client.db_is_account_exist(fromuser): - self.Protocol.send_notice( + if self.ctx.Client.db_is_account_exist(fromuser): + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f"Your account already exist, please try to login instead /msg {self.Config.SERVICE_NICKNAME} IDENTIFY " + msg=f"Your account already exist, please try to login instead /msg {self.ctx.Config.SERVICE_NICKNAME} IDENTIFY " ) return None # If the account doesn't exist then insert into database data_to_record = { - 'createdOn': self.Utils.get_sdatetime(), 'account': fromuser, + 'createdOn': self.ctx.Utils.get_sdatetime(), 'account': fromuser, 'nickname': user_obj.nickname, 'hostname': user_obj.hostname, 'vhost': user_obj.vhost, 'realname': user_obj.realname, 'email': email, - 'password': self.Loader.Utils.hash_password(password=password), 'level': 0 + 'password': self.ctx.Utils.hash_password(password=password), 'level': 0 } - insert_to_db = self.Base.db_execute_query(f""" - INSERT INTO {self.Config.TABLE_CLIENT} + insert_to_db = await self.ctx.Base.db_execute_query(f""" + INSERT INTO {self.ctx.Config.TABLE_CLIENT} (createdOn, account, nickname, hostname, vhost, realname, email, password, level) VALUES (:createdOn, :account, :nickname, :hostname, :vhost, :realname, :email, :password, :level) """, data_to_record) if insert_to_db.rowcount > 0: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"You have register your nickname successfully" @@ -959,84 +838,84 @@ class Irc: return None except ValueError as ve: - self.Logs.error(f"Value Error : {ve}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {self.Config.SERVICE_PREFIX}{command.upper()} ") + self.ctx.Logs.error(f"Value Error : {ve}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {self.ctx.Config.SERVICE_PREFIX}{command.upper()} ") case 'identify': # Identify ACCOUNT PASSWORD try: if len(cmd) < 3: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f'/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ' + msg=f'/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} ' ) return None account = str(cmd[1]) # account - encrypted_password = self.Loader.Utils.hash_password(cmd[2]) + encrypted_password = self.ctx.Utils.hash_password(cmd[2]) user_obj = u client_obj = c if client_obj is not None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are already logged in") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are already logged in") return None - db_query = f"SELECT account FROM {self.Config.TABLE_CLIENT} WHERE account = :account AND password = :password" + db_query = f"SELECT account FROM {self.ctx.Config.TABLE_CLIENT} WHERE account = :account AND password = :password" db_param = {'account': account, 'password': encrypted_password} - exec_query = self.Base.db_execute_query(db_query, db_param) + exec_query = await self.ctx.Base.db_execute_query(db_query, db_param) result_query = exec_query.fetchone() if result_query: account = result_query[0] - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are now logged in") - client = self.Loader.Definition.MClient(**user_obj.to_dict(), account=account) - self.Client.insert(client) - self.Protocol.send_svslogin(user_obj.uid, account) - self.Protocol.send_svs2mode(nickname=fromuser, user_mode='+r') + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are now logged in") + client = self.ctx.Definition.MClient(**user_obj.to_dict(), account=account) + self.ctx.Client.insert(client) + await self.Protocol.send_svslogin(user_obj.uid, account) + await self.Protocol.send_svs2mode(nickname=fromuser, user_mode='+r') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Wrong password or account") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Wrong password or account") return None except ValueError as ve: - self.Logs.error(f"Value Error: {ve}") - self.Protocol.send_notice( + self.ctx.Logs.error(f"Value Error: {ve}") + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f'/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ' + msg=f'/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} ' ) except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}") case 'logout': try: # LOGOUT if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") return None user_obj = u if user_obj is None: - self.Logs.error(f"The User [{fromuser}] is not available in the database") + self.ctx.Logs.error(f"The User [{fromuser}] is not available in the database") return None client_obj = c if client_obj is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nothing to logout. please login first") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nothing to logout. please login first") return None - self.Protocol.send_svslogout(client_obj) - self.Client.delete(user_obj.uid) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You have been logged out successfully") + await self.Protocol.send_svslogout(client_obj) + self.ctx.Client.delete(user_obj.uid) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You have been logged out successfully") except ValueError as ve: - self.Logs.error(f"Value Error: {ve}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") + self.ctx.Logs.error(f"Value Error: {ve}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") except Exception as err: - self.Logs.error(f"General Error: {err}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") + self.ctx.Logs.error(f"General Error: {err}") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} ") case 'help': # Syntax. !help [module_name] @@ -1052,12 +931,12 @@ class Irc: return None mod_name = str(cmd[1]) - await self.ModuleUtils.load_one_module(self, mod_name, fromuser) + await self.ctx.ModuleUtils.load_one_module(mod_name, fromuser) return None except KeyError as ke: - self.Logs.error(f"Key Error: {ke} - list recieved: {cmd}") + self.ctx.Logs.error(f"Key Error: {ke} - list recieved: {cmd}") except Exception as err: - self.Logs.error(f"General Error: {err} - list recieved: {cmd}", exc_info=True) + self.ctx.Logs.error(f"General Error: {err} - list recieved: {cmd}", exc_info=True) case 'unload': # unload mod_defender @@ -1067,10 +946,10 @@ class Irc: self.Protocol.send_notice(dnickname, fromuser, tr("Syntax. /msg %s %s MODULE_NAME", dnickname, command.upper())) return None module_name = str(cmd[1]).lower() - self.ModuleUtils.unload_one_module(self, module_name, False) + await self.ctx.ModuleUtils.unload_one_module(module_name, False) return None except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}") case 'reload': # reload mod_defender @@ -1081,63 +960,72 @@ class Irc: return None module_name = str(cmd[1]).lower() - await self.ModuleUtils.reload_one_module(self, module_name, fromuser) + await self.ctx.ModuleUtils.reload_one_module(module_name, fromuser) return None except Exception as e: - self.Logs.error(f"Something went wrong with a module you want to reload: {e}") + self.ctx.Logs.error(f"Something went wrong with a module you want to reload: {e}") await self.Protocol.send_priv_msg( nick_from=dnickname, msg=f"Something went wrong with the module: {e}", channel=dchanlog ) - self.ModuleUtils.db_delete_module(module_name) + await self.ctx.ModuleUtils.db_delete_module(module_name) case 'quit': try: final_reason = ' '.join(cmd[1:]) self.hb_active = False - self.Base.shutdown() - self.Base.execute_periodic_action() + await self.ctx.Base.shutdown() + self.ctx.Base.execute_periodic_action() - for chan_name in self.Channel.UID_CHANNEL_DB: + for chan_name in self.ctx.Channel.UID_CHANNEL_DB: # self.Protocol.send_mode_chan(chan_name.name, '-l') - self.Protocol.send_set_mode('-l', channel_name=chan_name.name) + await self.Protocol.send_set_mode('-l', channel_name=chan_name.name) - for client in self.Client.CLIENT_DB: - self.Protocol.send_svslogout(client) + for client in self.ctx.Client.CLIENT_DB: + await self.Protocol.send_svslogout(client) - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"Arrêt du service {dnickname}" ) - self.Protocol.send_squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason) - self.Logs.info(f'Arrêt du server {dnickname}') - self.Config.DEFENDER_RESTART = 0 self.signal = False + await self.Protocol.send_squit(server_id=self.ctx.Config.SERVEUR_ID, server_link=self.ctx.Config.SERVEUR_LINK, reason=final_reason) + self.ctx.Logs.info(f'Arrêt du server {dnickname}') + self.ctx.Config.DEFENDER_RESTART = 0 + + await self.writer.drain() + self.writer.close() + await self.writer.wait_closed() except IndexError as ie: - self.Logs.error(f'{ie}') + self.ctx.Logs.error(f'{ie}') + except ConnectionResetError as cerr: + if self.writer.is_closing(): + self.ctx.Logs.debug(f"Defender stopped properly! {cerr}") case 'restart': final_reason = ' '.join(cmd[1:]) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{dnickname.capitalize()} is going to restart!") + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{dnickname.capitalize()} is going to restart!") # Set restart status to 1 saying that the service will restart - self.Config.DEFENDER_RESTART = 1 + self.ctx.Config.DEFENDER_RESTART = 1 # set init to 1 saying that the service will be re initiated - self.Config.DEFENDER_INIT = 1 + self.ctx.Config.DEFENDER_INIT = 1 + + await rehash.restart_service(self.ctx) case 'rehash': - rehash.rehash_service(self, fromuser) + await rehash.rehash_service(self.ctx, fromuser) return None case 'show_modules': - self.Logs.debug('List of modules: ' + ', '.join([module.module_name for module in self.ModuleUtils.model_get_loaded_modules()])) - all_modules = self.ModuleUtils.get_all_available_modules() + self.ctx.Logs.debug('List of modules: ' + ', '.join([module.module_name for module in self.ctx.ModuleUtils.model_get_loaded_modules()])) + all_modules = self.ctx.ModuleUtils.get_all_available_modules() loaded = False - results = self.Base.db_execute_query(f'SELECT datetime, user, module_name FROM {self.Config.TABLE_MODULE}') + results = await self.ctx.Base.db_execute_query(f'SELECT datetime, user, module_name FROM {self.ctx.Config.TABLE_MODULE}') results = results.fetchall() for module in all_modules: @@ -1162,15 +1050,15 @@ class Irc: ) case 'show_timers': - if self.Base.running_timers: - for the_timer in self.Base.running_timers: - self.Protocol.send_notice( + if self.ctx.Base.running_timers: + for the_timer in self.ctx.Base.running_timers: + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f">> {the_timer.name} - {the_timer.is_alive()}" ) else: - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg="There is no timers that are running!" @@ -1178,29 +1066,33 @@ class Irc: return None case 'show_threads': - for thread in self.Base.running_threads: + for thread in self.ctx.Base.running_threads: await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f">> {thread.name} ({thread.is_alive()})" ) - - asyncio.create_task(self.new_coro(), name='my_new_coro') - for task in asyncio.all_tasks(): - print(task.get_name()) - print(task) return None + case 'show_asyncio': + for task in asyncio.all_tasks(): + await self.Protocol.send_notice( + nick_from=dnickname, + nick_to=fromuser, + msg=f">> {task.get_name()} (active)" + ) + return None + case 'show_channels': - for chan in self.Channel.UID_CHANNEL_DB: + for chan in self.ctx.Channel.UID_CHANNEL_DB: list_nicknames: list = [] for uid in chan.uids: pattern = fr'[:|@|%|\+|~|\*]*' parsed_UID = re.sub(pattern, '', uid) - list_nicknames.append(self.User.get_nickname(parsed_UID)) + list_nicknames.append(self.ctx.User.get_nickname(parsed_UID)) - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"Channel: {chan.name} - Users: {list_nicknames}" @@ -1208,10 +1100,10 @@ class Irc: return None case 'show_users': - count_users = len(self.User.UID_DB) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Total Connected Users: {count_users}") - for db_user in self.User.UID_DB: - self.Protocol.send_notice( + count_users = len(self.ctx.User.UID_DB) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Total Connected Users: {count_users}") + for db_user in self.ctx.User.UID_DB: + await self.Protocol.send_notice( 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}" @@ -1219,10 +1111,10 @@ class Irc: return None case 'show_clients': - count_users = len(self.Client.CLIENT_DB) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Total Connected Clients: {count_users}") - for db_client in self.Client.CLIENT_DB: - self.Protocol.send_notice( + count_users = len(self.ctx.Client.CLIENT_DB) + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Total Connected Clients: {count_users}") + for db_client in self.ctx.Client.CLIENT_DB: + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"UID : {db_client.uid} - isWebirc: {db_client.isWebirc} - isWebSocket: {db_client.isWebsocket} - Nickname: {db_client.nickname} - Account: {db_client.account} - Connection: {db_client.connexion_datetime}" @@ -1230,8 +1122,8 @@ class Irc: return None case 'show_admins': - for db_admin in self.Admin.UID_ADMIN_DB: - self.Protocol.send_notice( + for db_admin in self.ctx.Admin.UID_ADMIN_DB: + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"UID : {db_admin.uid} - Nickname: {db_admin.nickname} - Account: {db_admin.account} - Level: {db_admin.level} - Language: {db_admin.language} - Connection: {db_admin.connexion_datetime}" @@ -1239,8 +1131,8 @@ class Irc: return None case 'show_configuration': - for key, value in self.Config.to_dict().items(): - self.Protocol.send_notice( + for key, value in self.ctx.Config.to_dict().items(): + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f'{key} = {value}' @@ -1248,9 +1140,9 @@ class Irc: return None case 'show_cache': - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The cache is currently contains {self.Settings.get_cache_size()} value(s).") - for key, value in self.Settings.show_cache().items(): - self.Protocol.send_notice( + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The cache is currently contains {self.ctx.Settings.get_cache_size()} value(s).") + for key, value in self.ctx.Settings.show_cache().items(): + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"Key : {key} - Value: {value}" @@ -1258,15 +1150,15 @@ class Irc: return None case 'clear_cache': - cache_size = self.Settings.get_cache_size() + cache_size = self.ctx.Settings.get_cache_size() if cache_size > 0: - self.Settings.clear_cache() - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{cache_size} value(s) has been cleared from the cache.") + self.ctx.Settings.clear_cache() + await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{cache_size} value(s) has been cleared from the cache.") return None case 'uptime': uptime = self.get_defender_uptime() - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=uptime @@ -1274,51 +1166,47 @@ class Irc: return None case 'copyright': - self.Protocol.send_notice( + await self.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, - msg=f">> Defender V{self.Config.CURRENT_VERSION} Developped by adator®." + msg=f">> Defender V{self.ctx.Config.CURRENT_VERSION} Developped by adator®." ) return None case 'checkversion': - self.Base.create_thread(self.thread_check_for_new_version, (fromuser, )) + self.ctx.Base.create_asynctask(self.thread_check_for_new_version(fromuser)) return None case 'raw': raw_command = ' '.join(cmd[1:]) - self.Protocol.send_raw(raw_command) + await self.Protocol.send_raw(raw_command) return None case 'print_vars': with open('users.txt', 'w') as fw: i = 1 - for u in self.User.UID_DB: + for u in self.ctx.User.UID_DB: w = fw.write(u.to_dict().__str__() + "\n") - self.Logs.debug(f" {i} - chars written {w}") + self.ctx.Logs.debug(f" {i} - chars written {w}") i += 1 - self.Protocol.send_priv_msg(dnickname, "Data written in users.txt file", dchanlog) + await self.Protocol.send_priv_msg(dnickname, "Data written in users.txt file", dchanlog) with open('modules.txt', 'w') as fw: i = 1 - for u in self.ModuleUtils.DB_MODULE_HEADERS: + for u in self.ctx.ModuleUtils.DB_MODULE_HEADERS: w = fw.write(u.to_dict().__str__() + "\n") - self.Logs.debug(f" {i} - chars written {w}") + self.ctx.Logs.debug(f" {i} - chars written {w}") i += 1 - self.Protocol.send_priv_msg(dnickname, "Data written in modules.txt file", dchanlog) + await self.Protocol.send_priv_msg(dnickname, "Data written in modules.txt file", dchanlog) return None case 'start_rpc': - self.Loader.RpcServer.start_server() + self.ctx.Base.create_asynctask(self.ctx.RpcServer.start_server()) case 'stop_rpc': - self.Loader.RpcServer.stop_server() + self.ctx.Base.create_asynctask(self.ctx.RpcServer.stop_server()) case _: pass - async def new_coro(self): - self.Logs.debug("Creating new coro") - await asyncio.sleep(5) - self.Logs.debug("End of the coro") \ No newline at end of file diff --git a/core/loader.py b/core/loader.py index c254552..611fc9f 100644 --- a/core/loader.py +++ b/core/loader.py @@ -14,6 +14,15 @@ import core.classes.protocols.factory as factory class Loader: + _instance = None + + def __new__(cls, *agrs): + + if cls._instance is None: + cls._instance = super().__new__(cls) + + return cls._instance + def __init__(self): # Load Main Modules @@ -70,10 +79,11 @@ class Loader: self.Irc: irc.Irc = irc.Irc(self) - self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc) + self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self) - self.RpcServer: rpc_mod.JSONRPCServer = rpc_mod.JSONRPCServer(self) - - self.Base.init() + self.RpcServer: rpc_mod.JSonRpcServer = rpc_mod.JSonRpcServer(self) self.Logs.debug(self.Utils.tr("Loader %s success", __name__)) + + async def start(self): + await self.Base.init() diff --git a/core/logs.py b/core/logs.py index 1ed5152..fbf02a7 100644 --- a/core/logs.py +++ b/core/logs.py @@ -15,7 +15,7 @@ class ServiceLogging: self.SERVER_PREFIX = None self.LOGGING_CONSOLE = True - self.LOG_FILTERS: list[str] = [f":{self.SERVER_PREFIX}auth", "['PASS'"] + self.LOG_FILTERS: list[str] = ["PING", f":{self.SERVER_PREFIX}auth", "['PASS'"] self.file_handler = None self.stdout_handler = None diff --git a/core/module.py b/core/module.py index df684dd..4d3b0ee 100644 --- a/core/module.py +++ b/core/module.py @@ -1,9 +1,9 @@ ''' This is the main operational file to handle modules ''' -from pathlib import Path import sys import importlib +from pathlib import Path from types import ModuleType from typing import TYPE_CHECKING, Optional from core.definition import DefenderModuleHeader, MModule @@ -12,6 +12,7 @@ from core.utils import tr if TYPE_CHECKING: from core.loader import Loader from core.irc import Irc + from core.classes.interfaces.imodule import IModule class Module: @@ -19,11 +20,7 @@ class Module: DB_MODULE_HEADERS: list[DefenderModuleHeader] = [] def __init__(self, loader: 'Loader') -> None: - self.__Loader = loader - self.__Base = loader.Base - self.__Logs = loader.Logs - self.__Utils = loader.Utils - self.__Config = loader.Config + self._ctx = loader def get_all_available_modules(self) -> list[str]: """Get list of all main modules @@ -34,7 +31,7 @@ class Module: """ base_path = Path('mods') modules_available = [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')] - self.__Logs.debug(f"Modules available: {modules_available}") + self._ctx.Logs.debug(f"Modules available: {modules_available}") return modules_available def get_module_information(self, module_name: str) -> tuple[Optional[str], Optional[str], Optional[str]]: @@ -45,14 +42,14 @@ class Module: module_name = module_name.lower() # --> mod_defender module_folder = module_name.split('_')[1].lower() # --> defender class_name = module_name.split('_')[1].capitalize() # --> Defender - self.__Logs.debug(f"Module information Folder: {module_folder}, Name: {module_name}, Class: {class_name}") + self._ctx.Logs.debug(f"Module information Folder: {module_folder}, Name: {module_name}, Class: {class_name}") return module_folder, module_name, class_name def get_module_header(self, module_name: str) -> Optional[DefenderModuleHeader]: for mod_h in self.DB_MODULE_HEADERS: if module_name.lower() == mod_h.name.lower(): - self.__Logs.debug(f"Module Header found: {mod_h}") + self._ctx.Logs.debug(f"Module Header found: {mod_h}") return mod_h return None @@ -68,7 +65,7 @@ class Module: """ mod_header = DefenderModuleHeader(**module_header) if self.get_module_header(mod_header.name) is None: - self.__Logs.debug(f"[MOD_HEADER] The module header has been created! ({mod_header.name} v{mod_header.version})") + self._ctx.Logs.debug(f"[MOD_HEADER] The module header has been created! ({mod_header.name} v{mod_header.version})") self.DB_MODULE_HEADERS.append(mod_header) return True @@ -77,73 +74,74 @@ class Module: def delete_module_header(self, module_name: str) -> bool: mod_header = self.get_module_header(module_name) if mod_header is not None: - self.__Logs.debug(f"[MOD_HEADER] The module header has been deleted ({mod_header.name} v{mod_header.version})") + self._ctx.Logs.debug(f"[MOD_HEADER] The module header has been deleted ({mod_header.name} v{mod_header.version})") self.DB_MODULE_HEADERS.remove(mod_header) return True - self.__Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})") + self._ctx.Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})") return False - async def load_one_module(self, uplink: 'Irc', module_name: str, nickname: str, is_default: bool = False) -> bool: + async def load_one_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool: module_folder, module_name, class_name = self.get_module_information(module_name) if module_folder is None or module_name is None or class_name is None: - self.__Logs.error(f"There is an error with the module name! {module_folder}, {module_name}, {class_name}") + self._ctx.Logs.error(f"There is an error with the module name! {module_folder}, {module_name}, {class_name}") return False if self.is_module_exist_in_sys_module(module_name): - self.__Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!") + self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!") if self.model_is_module_exist(module_name): # Si le module existe dans la variable globale retourne False - self.__Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!") - await uplink.Protocol.send_priv_msg( - 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 + self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!") + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, + msg=f"Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self._ctx.Config.SERVICE_PREFIX}reload {module_name}", + channel=self._ctx.Config.SERVICE_CHANLOG ) return False - return self.reload_one_module(uplink, module_name, nickname) + return self.reload_one_module(module_name, nickname) # Charger le module try: loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}') my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe - create_instance_of_the_class = my_class(uplink.Loader) # Créer une nouvelle instance de la classe + create_instance_of_the_class: 'IModule' = my_class(self._ctx) # Créer une nouvelle instance de la classe + await create_instance_of_the_class.load() if self._ctx.Utils.is_coroutinefunction(create_instance_of_the_class.load) else create_instance_of_the_class.load() self.create_module_header(create_instance_of_the_class.MOD_HEADER) except AttributeError as attr: - red = uplink.Config.COLORS.red - nogc = uplink.Config.COLORS.nogc - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + red = self._ctx.Config.COLORS.red + nogc = self._ctx.Config.COLORS.red + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr), - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.__Logs.error(msg=attr, exc_info=True) + self._ctx.Logs.error(msg=attr, exc_info=True) return False if not hasattr(create_instance_of_the_class, 'cmd'): - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=tr("cmd method is not available in the module (%s)", module_name), - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.__Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available") - self.db_delete_module(module_name) + self._ctx.Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available") + await self.db_delete_module(module_name) return False # Charger la nouvelle class dans la variable globale if self.model_insert_module(MModule(module_name, class_name, create_instance_of_the_class)): # Enregistrer le module dans la base de données - self.db_register_module(module_name, nickname, is_default) - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + await self.db_register_module(module_name, nickname, is_default) + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=tr("Module %s loaded!", module_name), - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.__Logs.debug(f"Module {class_name} has been loaded") + self._ctx.Logs.debug(f"Module {class_name} has been loaded") return True return False @@ -151,7 +149,7 @@ class Module: def load_all_modules(self) -> bool: ... - async def reload_one_module(self, uplink: 'Irc', module_name: str, nickname: str) -> bool: + async def reload_one_module(self, module_name: str, nickname: str) -> bool: """Reloading one module and insert it into the model as well as the database Args: @@ -163,21 +161,21 @@ class Module: bool: True if the module has been reloaded """ module_folder, module_name, class_name = self.get_module_information(module_name) - red = self.__Config.COLORS.red - nogc = self.__Config.COLORS.nogc + red = self._ctx.Config.COLORS.red + nogc = self._ctx.Config.COLORS.nogc try: if self.is_module_exist_in_sys_module(module_name): module_model = self.model_get_module(module_name) if module_model: self.delete_module_header(module_model.class_instance.MOD_HEADER['name']) - module_model.class_instance.unload() + await module_model.class_instance.unload() if self._ctx.Utils.is_coroutinefunction(module_model.class_instance.unload) else module_model.class_instance.unload() else: - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, - msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}", - channel=self.__Config.SERVICE_CHANLOG + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, + msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}", + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.__Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self.__Config.SERVICE_PREFIX}load {module_name}") + self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self._ctx.Config.SERVICE_PREFIX}load {module_name}") return False # reload module dependencies @@ -186,37 +184,38 @@ class Module: the_module = sys.modules[f'mods.{module_folder}.{module_name}'] importlib.reload(the_module) my_class = getattr(the_module, class_name, None) - new_instance = my_class(uplink.Loader) + new_instance: 'IModule' = my_class(self._ctx) + await new_instance.load() if self._ctx.Utils.is_coroutinefunction(new_instance.load) else new_instance.load() self.create_module_header(new_instance.MOD_HEADER) module_model.class_instance = new_instance # Créer le module dans la base de données - self.db_register_module(module_name, nickname) - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + await self.db_register_module(module_name, nickname) + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=f"Module [{module_folder}.{module_name}] has been reloaded!", - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.__Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!") + self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!") return True else: # Module is not loaded! Nothing to reload - self.__Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}") - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, - msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}", - channel=self.__Config.SERVICE_CHANLOG + self._ctx.Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}") + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, + msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}", + channel=self._ctx.Config.SERVICE_CHANLOG ) return False except (TypeError, AttributeError, KeyError, Exception) as err: - self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True) - await uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + self._ctx.Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True) + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=f"[RELOAD MODULE ERROR]: {err}", - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.db_delete_module(module_name) + await self.db_delete_module(module_name) def reload_all_modules(self) -> bool: ... @@ -242,12 +241,12 @@ class Module: try: if 'mod_' not in name and 'schemas' not in name: importlib.reload(module) - self.__Logs.debug(f'[LOAD_MODULE] Module {module} success') + self._ctx.Logs.debug(f'[LOAD_MODULE] Module {module} success') except Exception as err: - self.__Logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}') + self._ctx.Logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}') - def unload_one_module(self, uplink: 'Irc', module_name: str, keep_in_db: bool = True) -> bool: + async def unload_one_module(self, module_name: str, keep_in_db: bool = True) -> bool: """Unload a module Args: @@ -260,23 +259,23 @@ class Module: """ try: # Le nom du module. exemple: mod_defender - red = self.__Config.COLORS.red - nogc = self.__Config.COLORS.nogc + red = self._ctx.Config.COLORS.red + nogc = self._ctx.Config.COLORS.nogc module_folder, module_name, class_name = self.get_module_information(module_name) module = self.model_get_module(module_name) if module is None: - self.__Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!") - self.db_delete_module(module_name) - uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + self._ctx.Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!") + await self.db_delete_module(module_name) + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=f"[ {red}UNLOAD MODULE ERROR{nogc} ] This module {module_name} is not loaded!", - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) return False if module: self.delete_module_header(module.class_instance.MOD_HEADER['name']) - module.class_instance.unload() + await module.class_instance.unload() if self._ctx.Utils.is_coroutinefunction(module.class_instance.unload) else module.class_instance.unload() self.DB_MODULES.remove(module) # Delete from the sys.modules. @@ -284,25 +283,25 @@ class Module: del sys.modules[f"mods.{module_folder}.{module_name}"] if sys.modules.get(f'mods.{module_folder}.{module_name}'): - self.__Logs.debug(f"Module mods.{module_folder}.{module_name} still in the sys.modules") + self._ctx.Logs.debug(f"Module mods.{module_folder}.{module_name} still in the sys.modules") # Supprimer le module de la base de données if not keep_in_db: - self.db_delete_module(module_name) + await self.db_delete_module(module_name) - uplink.Protocol.send_priv_msg( - nick_from=self.__Config.SERVICE_NICKNAME, + await self._ctx.Irc.Protocol.send_priv_msg( + nick_from=self._ctx.Config.SERVICE_NICKNAME, msg=f"[ UNLOAD MODULE INFO ] Module {module_name} has been unloaded!", - channel=self.__Config.SERVICE_CHANLOG + channel=self._ctx.Config.SERVICE_CHANLOG ) - self.__Logs.debug(f"[ UNLOAD MODULE ] {module_name} has been unloaded!") + self._ctx.Logs.debug(f"[ UNLOAD MODULE ] {module_name} has been unloaded!") return True - self.__Logs.debug(f"[UNLOAD MODULE]: Module {module_name} not found in DB_MODULES variable!") + self._ctx.Logs.debug(f"[UNLOAD MODULE]: Module {module_name} not found in DB_MODULES variable!") return False except Exception as err: - self.__Logs.error(f"General Error: {err}", exc_info=True) + self._ctx.Logs.error(f"General Error: {err}", exc_info=True) return False def unload_all_modules(self) -> bool: @@ -319,9 +318,9 @@ class Module: """ module_folder, module_name, class_name = self.get_module_information(module_name) if "mods." + module_folder + "." + module_name in sys.modules: - self.__Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) found in sys.modules") + self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) found in sys.modules") return True - self.__Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules") + self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules") return False ''' @@ -338,10 +337,10 @@ class Module: """ for module in self.DB_MODULES: if module.module_name.lower() == module_name.lower(): - self.__Logs.debug(f"[MODEL MODULE GET] The module {module_name} has been found in the model DB_MODULES") + self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} has been found in the model DB_MODULES") return module - self.__Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES") + self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES") return None def model_get_loaded_modules(self) -> list[MModule]: @@ -351,7 +350,7 @@ class Module: Returns: list[MModule]: A list of module model object """ - # self.__Logs.debug(f"[MODEL MODULE LOADED MODULES] {len(self.DB_MODULES)} modules found!") + # self._ctx.Logs.debug(f"[MODEL MODULE LOADED MODULES] {len(self.DB_MODULES)} modules found!") return self.DB_MODULES def model_insert_module(self, module_model: MModule) -> bool: @@ -366,17 +365,17 @@ class Module: module = self.model_get_module(module_model.module_name) if module is None: self.DB_MODULES.append(module_model) - self.__Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} has been inserted in the local variable model DB_MODULES") + self._ctx.Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} has been inserted in the local variable model DB_MODULES") return True - self.__Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} already exist in the local variable model DB_MODULES") + self._ctx.Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} already exist in the local variable model DB_MODULES") return False def model_clear(self) -> None: """Clear DB_MODULES list! """ self.DB_MODULES.clear() - self.__Logs.debug("[MODEL MODULE CLEAR] The local variable model DB_MODULES has been cleared") + self._ctx.Logs.debug("[MODEL MODULE CLEAR] The local variable model DB_MODULES has been cleared") return None def model_is_module_exist(self, module_name: str) -> bool: @@ -389,30 +388,30 @@ class Module: bool: True if the module_name exist """ if self.model_get_module(module_name): - self.__Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} exist in the local model DB_MODULES!") + self._ctx.Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} exist in the local model DB_MODULES!") return True - self.__Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} is not available in the local model DB_MODULES!") + self._ctx.Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} is not available in the local model DB_MODULES!") return False ''' OPERATION DEDICATED TO DATABASE MANAGEMENT ''' - async def db_load_all_existing_modules(self, uplink: 'Irc') -> bool: + async def db_load_all_existing_modules(self) -> bool: """Charge les modules qui existe déja dans la base de données Returns: None: Aucun retour requis, elle charge puis c'est tout """ - self.__Logs.debug("[DB LOAD MODULE] Loading modules from the database!") - result = self.__Base.db_execute_query(f"SELECT module_name FROM {self.__Config.TABLE_MODULE}") + self._ctx.Logs.debug("[DB LOAD MODULE] Loading modules from the database!") + result = await self._ctx.Base.db_execute_query(f"SELECT module_name FROM {self._ctx.Config.TABLE_MODULE}") for r in result.fetchall(): - await self.load_one_module(uplink, r[0], 'sys', True) + await self.load_one_module(r[0], 'sys', True) return True - def db_is_module_exist(self, module_name: str) -> bool: + async def db_is_module_exist(self, module_name: str) -> bool: """Check if the module exist in the database Args: @@ -421,18 +420,18 @@ class Module: Returns: bool: True if the module exist in the database """ - query = f"SELECT id FROM {self.__Config.TABLE_MODULE} WHERE module_name = :module_name" + query = f"SELECT id FROM {self._ctx.Config.TABLE_MODULE} WHERE module_name = :module_name" mes_donnes = {'module_name': module_name.lower()} - results = self.__Base.db_execute_query(query, mes_donnes) + results = await self._ctx.Base.db_execute_query(query, mes_donnes) if results.fetchall(): - self.__Logs.debug(f"[DB MODULE EXIST] The module {module_name} exist in the database!") + self._ctx.Logs.debug(f"[DB MODULE EXIST] The module {module_name} exist in the database!") return True else: - self.__Logs.debug(f"[DB MODULE EXIST] The module {module_name} is not available in the database!") + self._ctx.Logs.debug(f"[DB MODULE EXIST] The module {module_name} is not available in the database!") return False - def db_register_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool: + async def db_register_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool: """Insert a new module in the database Args: @@ -440,49 +439,49 @@ class Module: nickname (str): The user who loaded the module isdefault (int): Is this a default module. Default 0 """ - if not self.db_is_module_exist(module_name): - insert_cmd_query = f"INSERT INTO {self.__Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)" - mes_donnees = {'datetime': self.__Utils.get_sdatetime(), 'user': nickname, 'module_name': module_name.lower(), 'isdefault': is_default} - insert = self.__Base.db_execute_query(insert_cmd_query, mes_donnees) + if not await self.db_is_module_exist(module_name): + insert_cmd_query = f"INSERT INTO {self._ctx.Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)" + mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'user': nickname, 'module_name': module_name.lower(), 'isdefault': is_default} + insert = await self._ctx.Base.db_execute_query(insert_cmd_query, mes_donnees) if insert.rowcount > 0: - self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} has been inserted to the database!") + self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} has been inserted to the database!") return True else: - self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} not inserted to the database!") + self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} not inserted to the database!") return False - self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} already exist in the database! Nothing to insert!") + self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} already exist in the database! Nothing to insert!") return False - def db_update_module(self, module_name: str, nickname: str) -> None: + async def db_update_module(self, module_name: str, nickname: str) -> None: """Update the datetime and the user that updated the module Args: module_name (str): The module name to update nickname (str): The nickname who updated the module """ - update_cmd_query = f"UPDATE {self.__Config.TABLE_MODULE} SET datetime = :datetime, LOWER(user) = :user WHERE LOWER(module_name) = :module_name" - mes_donnees = {'datetime': self.__Utils.get_sdatetime(), 'user': nickname.lower(), 'module_name': module_name.lower()} - result = self.__Base.db_execute_query(update_cmd_query, mes_donnees) + update_cmd_query = f"UPDATE {self._ctx.Config.TABLE_MODULE} SET datetime = :datetime, LOWER(user) = :user WHERE LOWER(module_name) = :module_name" + mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'user': nickname.lower(), 'module_name': module_name.lower()} + result = await self._ctx.Base.db_execute_query(update_cmd_query, mes_donnees) if result.rowcount > 0: - self.__Logs.debug(f"[DB UPDATE MODULE] Module {module_name} has been updated!") + self._ctx.Logs.debug(f"[DB UPDATE MODULE] Module {module_name} has been updated!") return True else: - self.__Logs.debug(f"[DB UPDATE MODULE] Module {module_name} not found! Nothing to update!") + self._ctx.Logs.debug(f"[DB UPDATE MODULE] Module {module_name} not found! Nothing to update!") return False - def db_delete_module(self, module_name:str) -> None: + async def db_delete_module(self, module_name:str) -> None: """Delete a module from the database Args: module_name (str): The module name you want to delete """ - insert_cmd_query = f"DELETE FROM {self.__Config.TABLE_MODULE} WHERE LOWER(module_name) = :module_name" + insert_cmd_query = f"DELETE FROM {self._ctx.Config.TABLE_MODULE} WHERE LOWER(module_name) = :module_name" mes_donnees = {'module_name': module_name.lower()} - delete = self.__Base.db_execute_query(insert_cmd_query, mes_donnees) + delete = await self._ctx.Base.db_execute_query(insert_cmd_query, mes_donnees) if delete.rowcount > 0: - self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} has been deleted from the dabatase!") + self._ctx.Logs.debug(f"[DB MODULE DELETE] The module {module_name} has been deleted from the dabatase!") return True - self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!") + self._ctx.Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!") return False diff --git a/core/utils.py b/core/utils.py index 0abd02d..a887214 100644 --- a/core/utils.py +++ b/core/utils.py @@ -13,6 +13,7 @@ from time import time from random import choice from hashlib import md5, sha3_512 from core.classes.modules.settings import global_settings +from asyncio import iscoroutinefunction if TYPE_CHECKING: from core.irc import Irc @@ -243,3 +244,14 @@ def hide_sensitive_data(srvmsg: list[str]) -> list[str]: except ValueError: return srvmsg + +def is_coroutinefunction(func: Any) -> bool: + """Check if the function is a coroutine or not + + Args: + func (Any): an callable object + + Returns: + bool: True if the function is a coroutine + """ + return iscoroutinefunction(func) \ No newline at end of file diff --git a/defender.py b/defender.py index 9b03d89..c5787bd 100644 --- a/defender.py +++ b/defender.py @@ -13,6 +13,7 @@ from core import install async def main(): from core.loader import Loader loader = Loader() + await loader.start() await loader.Irc.run() if __name__ == "__main__": diff --git a/mods/clone/clone_manager.py b/mods/clone/clone_manager.py index 486795b..7491830 100644 --- a/mods/clone/clone_manager.py +++ b/mods/clone/clone_manager.py @@ -10,7 +10,7 @@ class CloneManager: def __init__(self, uplink: 'Clone'): - self.Logs = uplink.Logs + self.Logs = uplink.ctx.Logs def insert(self, new_clone_object: MClone) -> bool: """Create new Clone object diff --git a/mods/clone/mod_clone.py b/mods/clone/mod_clone.py index 999dd3b..6ae6084 100644 --- a/mods/clone/mod_clone.py +++ b/mods/clone/mod_clone.py @@ -8,6 +8,7 @@ from mods.clone.clone_manager import CloneManager if TYPE_CHECKING: from faker import Faker + from core.loader import Loader class Clone(IModule): @@ -23,7 +24,15 @@ class Clone(IModule): 'core_version':'Defender-6' } - def create_tables(self) -> None: + def __init__(self, context: 'Loader') -> None: + super().__init__(context) + self._mod_config: Optional[schemas.ModConfModel] = None + + @property + def mod_config(self) -> ModConfModel: + return self._mod_config + + async def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -39,63 +48,69 @@ class Clone(IModule): ) ''' - # self.Base.db_execute_query(table_channel) + # await self.ctx.Base.db_execute_query(table_channel) return None - def load(self) -> None: - self.ModConfig = self.ModConfModel() + async def load(self) -> None: + + # Variable qui va contenir les options de configuration du module Defender + self._mod_config: schemas.ModConfModel = self.ModConfModel() + + # sync the database with local variable (Mandatory) + await self.sync_db() + self.stop = False self.Schemas = schemas self.Utils = utils self.Threads = thds self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB') self.Clone = CloneManager(self) - metadata = self.Settings.get_cache('UID_CLONE_DB') + metadata = self.ctx.Settings.get_cache('UID_CLONE_DB') if metadata is not None: self.Clone.UID_CLONE_DB = metadata - self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}") + self.ctx.Logs.debug(f"Cache Size = {self.ctx.Settings.get_cache_size()}") # Créer les nouvelles commandes du module - self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones') + self.ctx.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones') - self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_sjoin(self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('+o', nickname=self.Config.SERVICE_NICKNAME, channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('+nts', channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('+k', channel_name=self.Config.CLONE_CHANNEL, params=self.Config.CLONE_CHANNEL_PASSWORD) + await self.ctx.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_sjoin(self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_set_mode('+o', nickname=self.ctx.Config.SERVICE_NICKNAME, channel_name=self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_set_mode('+nts', channel_name=self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_set_mode('+k', channel_name=self.ctx.Config.CLONE_CHANNEL, params=self.ctx.Config.CLONE_CHANNEL_PASSWORD) - def unload(self) -> None: + async def unload(self) -> None: """Cette methode sera executée a chaque désactivation ou rechargement de module """ # Store Clones DB into the global Settings to retrieve it after the reload. - self.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB) + self.ctx.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB) - self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('-nts', channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_set_mode('-k', channel_name=self.Config.CLONE_CHANNEL) - self.Protocol.send_part_chan(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL) + await self.ctx.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_set_mode('-nts', channel_name=self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_set_mode('-k', channel_name=self.ctx.Config.CLONE_CHANNEL) + await self.ctx.Irc.Protocol.send_part_chan(self.ctx.Config.SERVICE_NICKNAME, self.ctx.Config.CLONE_CHANNEL) - self.Irc.Commands.drop_command_by_module(self.module_name) + self.ctx.Commands.drop_command_by_module(self.module_name) return None - def cmd(self, data:list) -> None: + async def cmd(self, data:list) -> None: try: if not data or len(data) < 2: return None cmd = data.copy() if isinstance(data, list) else list(data).copy() - index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd) + index, command = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd) if index == -1: return None match command: case 'PRIVMSG': - self.Utils.handle_on_privmsg(self, cmd) + await self.Utils.handle_on_privmsg(self, cmd) return None case 'QUIT': @@ -105,10 +120,10 @@ class Clone(IModule): return None except Exception as err: - self.Logs.error(f'General Error: {err}', exc_info=True) + self.ctx.Logs.error(f'General Error: {err}', exc_info=True) return None - def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: + async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: try: @@ -117,18 +132,18 @@ class Clone(IModule): command = str(cmd[0]).lower() fromuser = user - dnickname = self.Config.SERVICE_NICKNAME + dnickname = self.ctx.Config.SERVICE_NICKNAME match command: case 'clone': - if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") + if len(cmd) < 2: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") return None option = str(cmd[1]).lower() @@ -143,15 +158,13 @@ class Clone(IModule): group = str(cmd[3]).lower() connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2 - self.Base.create_thread( - func=self.Threads.thread_connect_clones, - func_args=(self, number_of_clones, group, False, connection_interval) + self.ctx.Base.create_asynctask( + func=self.Threads.coro_connect_clones(self, number_of_clones, group, False, connection_interval) ) - except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group] [freq]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance") + except IndexError: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group] [freq]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance") case 'kill': try: @@ -160,27 +173,26 @@ class Clone(IModule): option = str(cmd[2]) if option.lower() == 'all': - self.Base.create_thread(func=self.Threads.thread_kill_clones, func_args=(self, )) + self.ctx.Base.create_asynctask(func=self.Threads.thread_kill_clones(self)) elif self.Clone.group_exists(option): list_of_clones_in_group = self.Clone.get_clones_from_groupname(option) if len(list_of_clones_in_group) > 0: - self.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}") + self.ctx.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}") for clone in list_of_clones_in_group: - self.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False) + await self.ctx.Irc.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False) self.Clone.delete(clone.uid) else: clone_obj = self.Clone.get_clone(option) if not clone_obj is None: - self.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False) + await self.ctx.Irc.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False) self.Clone.delete(clone_obj.uid) - except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]") + except IndexError: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]") case 'join': try: @@ -191,25 +203,24 @@ class Clone(IModule): if option.lower() == 'all': for clone in self.Clone.UID_CLONE_DB: - self.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False) + await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False) elif self.Clone.group_exists(option): list_of_clones_in_group = self.Clone.get_clones_from_groupname(option) if len(list_of_clones_in_group) > 0: - self.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}") + self.ctx.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}") for clone in list_of_clones_in_group: - self.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False) + await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False) else: if self.Clone.nickname_exists(option): clone_uid = self.Clone.get_clone(option).uid - self.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False) + await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False) - except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel") + except IndexError: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel") case 'part': try: @@ -220,67 +231,66 @@ class Clone(IModule): if option.lower() == 'all': for clone in self.Clone.UID_CLONE_DB: - self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) + await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) elif self.Clone.group_exists(option): list_of_clones_in_group = self.Clone.get_clones_from_groupname(option) if len(list_of_clones_in_group) > 0: - self.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}") + self.ctx.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}") for clone in list_of_clones_in_group: - self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) + await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False) else: if self.Clone.nickname_exists(option): clone_uid = self.Clone.get_uid(option) if not clone_uid is None: - self.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False) + await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False) - except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel") + except IndexError: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel") case 'list': try: # Syntax. /msg defender clone list header = f" {'Nickname':<12}| {'Real name':<25}| {'Group name':<15}| {'Connected':<35}" line = "-"*67 - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header) + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") group_name = cmd[2] if len(cmd) > 2 else None if group_name is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") for clone_name in self.Clone.UID_CLONE_DB: - self.Protocol.send_notice( + await self.ctx.Irc.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f" {clone_name.nickname:<12}| {clone_name.realname:<25}| {clone_name.group:<15}| {clone_name.connected:<35}") else: if not self.Clone.group_exists(group_name): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!") return None clones = self.Clone.get_clones_from_groupname(group_name) - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}") for clone in clones: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {clone.nickname:<12}| {clone.realname:<25}| {clone.group:<15}| {clone.connected:<35}") - except Exception as err: - self.Logs.error(f'{err}') + except IndexError: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") case 'say': try: # clone say clone_nickname #channel message clone_name = str(cmd[2]) - clone_channel = str(cmd[3]) if self.Channel.is_valid_channel(str(cmd[3])) else None + clone_channel = str(cmd[3]) if self.ctx.Channel.is_valid_channel(str(cmd[3])) else None final_message = ' '.join(cmd[4:]) if clone_channel is None or not self.Clone.nickname_exists(clone_name): - self.Protocol.send_notice( + await self.ctx.Irc.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone say [clone_nickname] #channel message" @@ -288,24 +298,21 @@ class Clone(IModule): return None if self.Clone.nickname_exists(clone_name): - self.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel) - except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice( + except IndexError: + await self.ctx.Irc.Protocol.send_notice( nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone say [clone_nickname] #channel message" ) case _: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]") - except IndexError as ie: - self.Logs.error(f'Index Error: {ie}') except Exception as err: - self.Logs.error(f'General Error: {err}') + self.ctx.Logs.error(f'General Error: {err}', exc_info=True) diff --git a/mods/clone/threads.py b/mods/clone/threads.py index c8c216a..e078a05 100644 --- a/mods/clone/threads.py +++ b/mods/clone/threads.py @@ -1,10 +1,11 @@ +import asyncio from typing import TYPE_CHECKING from time import sleep if TYPE_CHECKING: from mods.clone.mod_clone import Clone -def thread_connect_clones(uplink: 'Clone', +async def coro_connect_clones(uplink: 'Clone', number_of_clones:int , group: str = 'Default', auto_remote_ip: bool = False, @@ -27,18 +28,18 @@ def thread_connect_clones(uplink: 'Clone', break if not clone.connected: - uplink.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False) - uplink.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.Config.CLONE_CHANNEL, password=uplink.Config.CLONE_CHANNEL_PASSWORD, print_log=False) + await uplink.ctx.Irc.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False) + await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.ctx.Config.CLONE_CHANNEL, password=uplink.ctx.Config.CLONE_CHANNEL_PASSWORD, print_log=False) - sleep(interval) + await asyncio.sleep(interval) clone.connected = True -def thread_kill_clones(uplink: 'Clone'): +async def thread_kill_clones(uplink: 'Clone'): clone_to_kill = uplink.Clone.UID_CLONE_DB.copy() for clone in clone_to_kill: - uplink.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False) + await uplink.ctx.Irc.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False) uplink.Clone.delete(clone.uid) del clone_to_kill diff --git a/mods/clone/utils.py b/mods/clone/utils.py index b371ea1..4b03bb3 100644 --- a/mods/clone/utils.py +++ b/mods/clone/utils.py @@ -125,8 +125,8 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def """ faker = faker_instance - uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID) - umodes = uplink.Config.CLONE_UMODES + uid = generate_uid_for_clone(faker, uplink.ctx.Config.SERVEUR_ID) + umodes = uplink.ctx.Config.CLONE_UMODES # Generate Username username = generate_username_for_clone(faker) @@ -153,7 +153,7 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def checkNickname = uplink.Clone.nickname_exists(nickname) while checkUid: - uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID) + uid = generate_uid_for_clone(faker, uplink.ctx.Config.SERVEUR_ID) checkUid = uplink.Clone.uid_exists(uid=uid) clone = uplink.Schemas.MClone( @@ -174,12 +174,12 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def return True -def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None: +async def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None: - senderObj, recieverObj, channel, message = uplink.Protocol.parse_privmsg(srvmsg) + senderObj, recieverObj, channel, message = uplink.ctx.Irc.Protocol.parse_privmsg(srvmsg) if senderObj is not None: - if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT: + if senderObj.hostname in uplink.ctx.Config.CLONE_LOG_HOST_EXEMPT: return senderMsg = message clone_obj = recieverObj @@ -187,12 +187,12 @@ def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None: if clone_obj is None: return - if clone_obj.uid != uplink.Config.SERVICE_ID: + if clone_obj.uid != uplink.ctx.Config.SERVICE_ID: final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}" - uplink.Protocol.send_priv_msg( + await uplink.ctx.Irc.Protocol.send_priv_msg( nick_from=clone_obj.uid, msg=final_message, - channel=uplink.Config.CLONE_CHANNEL + channel=uplink.ctx.Config.CLONE_CHANNEL ) return None diff --git a/mods/command/mod_command.py b/mods/command/mod_command.py index 083b199..f7a7aaa 100644 --- a/mods/command/mod_command.py +++ b/mods/command/mod_command.py @@ -5,6 +5,7 @@ import mods.command.utils as utils if TYPE_CHECKING: from core.definition import MUser + from core.loader import Loader class Command(IModule): @@ -22,6 +23,14 @@ class Command(IModule): 'core_version':'Defender-6' } + def __init__(self, uplink: 'Loader'): + super().__init__(uplink) + self._mod_config: Optional[Command.ModConfModel] = self.ModConfModel() + + @property + def mod_config(self) -> ModConfModel: + return self._mod_config + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -42,91 +51,87 @@ class Command(IModule): ) ''' - self.Base.db_execute_query(table_automode) + self.ctx.Base.db_execute_query(table_automode) return None def load(self) -> None: # Module Utils self.mod_utils = utils - - # Build the default configuration model (Mandatory) - self.ModConfig = self.ModConfModel() - self.user_to_notice: str = '' self.show_219: bool = True # Register new commands into the protocol new_cmds = {'403', '401', '006', '018', '219', '223'} for c in new_cmds: - self.Irc.Protocol.known_protocol.add(c) + self.ctx.Irc.Protocol.known_protocol.add(c) - self.Irc.build_command(2, self.module_name, 'join', 'Join a channel') - self.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task') - self.Irc.build_command(2, self.module_name, 'part', 'Leave a channel') - self.Irc.build_command(2, self.module_name, 'unassign', 'Remove a user from a role or task') - self.Irc.build_command(2, self.module_name, 'owner', 'Give channel ownership to a user') - self.Irc.build_command(2, self.module_name, 'deowner', 'Remove channel ownership from a user') - self.Irc.build_command(2, self.module_name, 'protect', 'Protect a user from being kicked') - self.Irc.build_command(2, self.module_name, 'deprotect', 'Remove protection from a user') - self.Irc.build_command(2, self.module_name, 'op', 'Grant operator privileges to a user') - self.Irc.build_command(2, self.module_name, 'deop', 'Remove operator privileges from a user') - self.Irc.build_command(1, self.module_name, 'halfop', 'Grant half-operator privileges to a user') - self.Irc.build_command(1, self.module_name, 'dehalfop', 'Remove half-operator privileges from a user') - self.Irc.build_command(1, self.module_name, 'voice', 'Grant voice privileges to a user') - self.Irc.build_command(1, self.module_name, 'devoice', 'Remove voice privileges from a user') - self.Irc.build_command(1, self.module_name, 'topic', 'Change the topic of a channel') - self.Irc.build_command(2, self.module_name, 'opall', 'Grant operator privileges to all users') - self.Irc.build_command(2, self.module_name, 'deopall', 'Remove operator privileges from all users') - self.Irc.build_command(2, self.module_name, 'devoiceall', 'Remove voice privileges from all users') - self.Irc.build_command(2, self.module_name, 'voiceall', 'Grant voice privileges to all users') - self.Irc.build_command(2, self.module_name, 'ban', 'Ban a user from a channel') - self.Irc.build_command(2, self.module_name, 'automode', 'Automatically set user modes upon join') - self.Irc.build_command(2, self.module_name, 'unban', 'Remove a ban from a user') - self.Irc.build_command(2, self.module_name, 'kick', 'Kick a user from a channel') - self.Irc.build_command(2, self.module_name, 'kickban', 'Kick and ban a user from a channel') - self.Irc.build_command(2, self.module_name, 'umode', 'Set user mode') - self.Irc.build_command(2, self.module_name, 'mode', 'Set channel mode') - self.Irc.build_command(2, self.module_name, 'get_mode', 'Retrieve current channel mode') - self.Irc.build_command(2, self.module_name, 'svsjoin', 'Force a user to join a channel') - self.Irc.build_command(2, self.module_name, 'svspart', 'Force a user to leave a channel') - self.Irc.build_command(2, self.module_name, 'svsnick', 'Force a user to change their nickname') - self.Irc.build_command(2, self.module_name, 'wallops', 'Send a message to all operators') - self.Irc.build_command(2, self.module_name, 'globops', 'Send a global operator message') - self.Irc.build_command(2, self.module_name, 'gnotice', 'Send a global notice') - self.Irc.build_command(2, self.module_name, 'whois', 'Get information about a user') - self.Irc.build_command(2, self.module_name, 'names', 'List users in a channel') - self.Irc.build_command(2, self.module_name, 'invite', 'Invite a user to a channel') - self.Irc.build_command(2, self.module_name, 'inviteme', 'Invite yourself to a channel') - self.Irc.build_command(2, self.module_name, 'sajoin', 'Force yourself into a channel') - self.Irc.build_command(2, self.module_name, 'sapart', 'Force yourself to leave a channel') - self.Irc.build_command(2, self.module_name, 'kill', 'Disconnect a user from the server') - self.Irc.build_command(2, self.module_name, 'gline', 'Ban a user from the entire server') - self.Irc.build_command(2, self.module_name, 'ungline', 'Remove a global server ban') - self.Irc.build_command(2, self.module_name, 'kline', 'Ban a user based on their hostname') - self.Irc.build_command(2, self.module_name, 'unkline', 'Remove a K-line ban') - self.Irc.build_command(2, self.module_name, 'shun', 'Prevent a user from sending messages') - self.Irc.build_command(2, self.module_name, 'unshun', 'Remove a shun from a user') - self.Irc.build_command(2, self.module_name, 'glinelist', 'List all global bans') - self.Irc.build_command(2, self.module_name, 'shunlist', 'List all shunned users') - self.Irc.build_command(2, self.module_name, 'klinelist', 'List all K-line bans') - self.Irc.build_command(3, self.module_name, 'map', 'Show the server network map') + self.ctx.Irc.build_command(2, self.module_name, 'join', 'Join a channel') + self.ctx.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task') + self.ctx.Irc.build_command(2, self.module_name, 'part', 'Leave a channel') + self.ctx.Irc.build_command(2, self.module_name, 'unassign', 'Remove a user from a role or task') + self.ctx.Irc.build_command(2, self.module_name, 'owner', 'Give channel ownership to a user') + self.ctx.Irc.build_command(2, self.module_name, 'deowner', 'Remove channel ownership from a user') + self.ctx.Irc.build_command(2, self.module_name, 'protect', 'Protect a user from being kicked') + self.ctx.Irc.build_command(2, self.module_name, 'deprotect', 'Remove protection from a user') + self.ctx.Irc.build_command(2, self.module_name, 'op', 'Grant operator privileges to a user') + self.ctx.Irc.build_command(2, self.module_name, 'deop', 'Remove operator privileges from a user') + self.ctx.Irc.build_command(1, self.module_name, 'halfop', 'Grant half-operator privileges to a user') + self.ctx.Irc.build_command(1, self.module_name, 'dehalfop', 'Remove half-operator privileges from a user') + self.ctx.Irc.build_command(1, self.module_name, 'voice', 'Grant voice privileges to a user') + self.ctx.Irc.build_command(1, self.module_name, 'devoice', 'Remove voice privileges from a user') + self.ctx.Irc.build_command(1, self.module_name, 'topic', 'Change the topic of a channel') + self.ctx.Irc.build_command(2, self.module_name, 'opall', 'Grant operator privileges to all users') + self.ctx.Irc.build_command(2, self.module_name, 'deopall', 'Remove operator privileges from all users') + self.ctx.Irc.build_command(2, self.module_name, 'devoiceall', 'Remove voice privileges from all users') + self.ctx.Irc.build_command(2, self.module_name, 'voiceall', 'Grant voice privileges to all users') + self.ctx.Irc.build_command(2, self.module_name, 'ban', 'Ban a user from a channel') + self.ctx.Irc.build_command(2, self.module_name, 'automode', 'Automatically set user modes upon join') + self.ctx.Irc.build_command(2, self.module_name, 'unban', 'Remove a ban from a user') + self.ctx.Irc.build_command(2, self.module_name, 'kick', 'Kick a user from a channel') + self.ctx.Irc.build_command(2, self.module_name, 'kickban', 'Kick and ban a user from a channel') + self.ctx.Irc.build_command(2, self.module_name, 'umode', 'Set user mode') + self.ctx.Irc.build_command(2, self.module_name, 'mode', 'Set channel mode') + self.ctx.Irc.build_command(2, self.module_name, 'get_mode', 'Retrieve current channel mode') + self.ctx.Irc.build_command(2, self.module_name, 'svsjoin', 'Force a user to join a channel') + self.ctx.Irc.build_command(2, self.module_name, 'svspart', 'Force a user to leave a channel') + self.ctx.Irc.build_command(2, self.module_name, 'svsnick', 'Force a user to change their nickname') + self.ctx.Irc.build_command(2, self.module_name, 'wallops', 'Send a message to all operators') + self.ctx.Irc.build_command(2, self.module_name, 'globops', 'Send a global operator message') + self.ctx.Irc.build_command(2, self.module_name, 'gnotice', 'Send a global notice') + self.ctx.Irc.build_command(2, self.module_name, 'whois', 'Get information about a user') + self.ctx.Irc.build_command(2, self.module_name, 'names', 'List users in a channel') + self.ctx.Irc.build_command(2, self.module_name, 'invite', 'Invite a user to a channel') + self.ctx.Irc.build_command(2, self.module_name, 'inviteme', 'Invite yourself to a channel') + self.ctx.Irc.build_command(2, self.module_name, 'sajoin', 'Force yourself into a channel') + self.ctx.Irc.build_command(2, self.module_name, 'sapart', 'Force yourself to leave a channel') + self.ctx.Irc.build_command(2, self.module_name, 'kill', 'Disconnect a user from the server') + self.ctx.Irc.build_command(2, self.module_name, 'gline', 'Ban a user from the entire server') + self.ctx.Irc.build_command(2, self.module_name, 'ungline', 'Remove a global server ban') + self.ctx.Irc.build_command(2, self.module_name, 'kline', 'Ban a user based on their hostname') + self.ctx.Irc.build_command(2, self.module_name, 'unkline', 'Remove a K-line ban') + self.ctx.Irc.build_command(2, self.module_name, 'shun', 'Prevent a user from sending messages') + self.ctx.Irc.build_command(2, self.module_name, 'unshun', 'Remove a shun from a user') + self.ctx.Irc.build_command(2, self.module_name, 'glinelist', 'List all global bans') + self.ctx.Irc.build_command(2, self.module_name, 'shunlist', 'List all shunned users') + self.ctx.Irc.build_command(2, self.module_name, 'klinelist', 'List all K-line bans') + self.ctx.Irc.build_command(3, self.module_name, 'map', 'Show the server network map') def unload(self) -> None: - self.Irc.Commands.drop_command_by_module(self.module_name) + self.ctx.Commands.drop_command_by_module(self.module_name) return None - def cmd(self, data: list[str]) -> None: + async def cmd(self, data: list[str]) -> None: try: - # service_id = self.Config.SERVICE_ID - dnickname = self.Config.SERVICE_NICKNAME - # dchanlog = self.Config.SERVICE_CHANLOG - red = self.Config.COLORS.red - green = self.Config.COLORS.green - bold = self.Config.COLORS.bold - nogc = self.Config.COLORS.nogc + # service_id = self.ctx.Config.SERVICE_ID + dnickname = self.ctx.Config.SERVICE_NICKNAME + # dchanlog = self.ctx.Config.SERVICE_CHANLOG + red = self.ctx.Config.COLORS.red + green = self.ctx.Config.COLORS.green + bold = self.ctx.Config.COLORS.bold + nogc = self.ctx.Config.COLORS.nogc cmd = list(data).copy() - pos, parsed_cmd = self.Irc.Protocol.get_ircd_protocol_poisition(cmd=cmd, log=True) + pos, parsed_cmd = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd=cmd, log=True) if pos == -1: return None @@ -136,31 +141,31 @@ class Command(IModule): case '403' | '401': try: message = ' '.join(cmd[3:]) - self.Protocol.send_notice( + await self.ctx.Irc.Protocol.send_notice( nick_from=dnickname, nick_to=self.user_to_notice, msg=f"[{red}ERROR MSG{nogc}] {message}" ) - self.Logs.error(f"{cmd[1]} - {message}") + self.ctx.Logs.error(f"{cmd[1]} - {message}") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case '006' | '018': try: # [':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.Protocol.send_notice( + await self.ctx.Irc.Protocol.send_notice( nick_from=dnickname, nick_to=self.user_to_notice, msg=f"[{green}SERVER MSG{nogc}] {message}" ) except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case '219': try: @@ -174,16 +179,16 @@ class Command(IModule): match type_of_stats: case 's': - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No shun") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No shun") case 'G': - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No gline") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No gline") case 'k': - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No kline") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No kline") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case '223': try: @@ -193,23 +198,23 @@ class Command(IModule): author = str(cmd[7]) reason = ' '.join(cmd[8:]) - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, + await self.ctx.Irc.Protocol.send_notice(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.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'SJOIN': # ['@msgid=yldTlbwAGbzCGUcCIHi3ku;time=2024-11-11T17:56:24.297Z', ':001', 'SJOIN', '1728815963', '#znc', ':001LQ0L0C'] # Check if the user has an automode try: - user_uid = self.User.clean_uid(cmd[5]) - userObj: MUser = self.User.get_user(user_uid) - channel_name = cmd[4] if self.Channel.is_valid_channel(cmd[4]) else None - client_obj = self.Client.get_Client(user_uid) + user_uid = self.ctx.User.clean_uid(cmd[5]) + userObj: MUser = self.ctx.User.get_user(user_uid) + channel_name = cmd[4] if self.ctx.Channel.is_valid_channel(cmd[4]) else None + client_obj = self.ctx.Client.get_Client(user_uid) nickname = userObj.nickname if userObj is not None else None if client_obj is not None: @@ -218,31 +223,31 @@ class Command(IModule): if userObj is None: return None - if 'r' not in userObj.umodes and 'o' not in userObj.umodes and not self.Client.is_exist(userObj.uid): + if 'r' not in userObj.umodes and 'o' not in userObj.umodes and not self.ctx.Client.is_exist(userObj.uid): return None db_data: dict[str, str] = {"nickname": nickname.lower(), "channel": channel_name.lower()} - db_query = self.Base.db_execute_query("SELECT id, mode FROM command_automode WHERE LOWER(nickname) = :nickname AND LOWER(channel) = :channel", db_data) + db_query = await self.ctx.Base.db_execute_query("SELECT id, mode FROM command_automode WHERE LOWER(nickname) = :nickname AND LOWER(channel) = :channel", db_data) db_result = db_query.fetchone() if db_result: id, mode = db_result - self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {channel_name} {mode} {userObj.nickname}") + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVICE_ID} MODE {channel_name} {mode} {userObj.nickname}") except KeyError as ke: - self.Logs.error(f"Key Error: {err}") + self.ctx.Logs.error(f"Key Error: {err}") case _: pass except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}", exc_info=True) - def hcmds(self, uidornickname: str, channel_name: Optional[str], cmd: list, fullcmd: list = []): + async def hcmds(self, uidornickname: str, channel_name: Optional[str], cmd: list, fullcmd: list = []): command = str(cmd[0]).lower() - dnickname = self.Config.SERVICE_NICKNAME - service_id = self.Config.SERVICE_ID - dchanlog = self.Config.SERVICE_CHANLOG + dnickname = self.ctx.Config.SERVICE_NICKNAME + service_id = self.ctx.Config.SERVICE_ID + dchanlog = self.ctx.Config.SERVICE_CHANLOG self.user_to_notice = uidornickname fromuser = uidornickname fromchannel = channel_name @@ -251,365 +256,365 @@ class Command(IModule): case 'automode': try: - self.mod_utils.set_automode(self, cmd, fromuser) + await self.mod_utils.set_automode(self, cmd, fromuser) except IndexError: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(self.Loader.Settings.PROTOCTL_PREFIX)}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(self.ctx.Settings.PROTOCTL_PREFIX)}") except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}") case 'deopall': try: - self.mod_utils.set_deopall(self, fromchannel) + await self.mod_utils.set_deopall(self, fromchannel) except Exception as err: - self.Logs.error(f'Unknown Error: {str(err)}') + self.ctx.Logs.error(f'Unknown Error: {str(err)}') case 'devoiceall': try: - self.mod_utils.set_devoiceall(self, fromchannel) + await self.mod_utils.set_devoiceall(self, fromchannel) except Exception as err: - self.Logs.error(f'Unknown Error: {str(err)}') + self.ctx.Logs.error(f'Unknown Error: {str(err)}') case 'voiceall': try: - self.mod_utils.set_mode_to_all(self, fromchannel, '+', 'v') + await self.mod_utils.set_mode_to_all(self, fromchannel, '+', 'v') except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'opall': try: - self.mod_utils.set_mode_to_all(self, fromchannel, '+', 'o') + await self.mod_utils.set_mode_to_all(self, fromchannel, '+', 'o') except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'op': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+o') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+o') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} op [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'deop': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-o') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-o') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deop [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'owner': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+q') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+q') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} owner [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'deowner': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-q') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-q') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'protect': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+a') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+a') except IndexError as e: - self.Logs.warning(f'_hcmd DEOWNER: {str(e)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") + self.ctx.Logs.warning(f'_hcmd DEOWNER: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'deprotect': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-a') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-a') except IndexError as e: - self.Logs.warning(f'_hcmd DEOWNER: {str(e)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") + self.ctx.Logs.warning(f'_hcmd DEOWNER: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'halfop': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+h') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+h') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'dehalfop': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-h') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-h') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'voice': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+v') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+v') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} voice [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'devoice': try: - self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-v') + await self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-v') except IndexError as e: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]") + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'ban': try: - self.mod_utils.set_ban(self, cmd, '+', fromuser) + await self.mod_utils.set_ban(self, cmd, '+', fromuser) except IndexError as e: - self.Logs.warning(f'_hcmd BAN: {str(e)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") + self.ctx.Logs.warning(f'_hcmd BAN: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'unban': try: - self.mod_utils.set_ban(self, cmd, '-', fromuser) + await self.mod_utils.set_ban(self, cmd, '-', fromuser) except IndexError as e: - self.Logs.warning(f'_hcmd UNBAN: {str(e)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") + self.ctx.Logs.warning(f'_hcmd UNBAN: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'kick': try: - self.mod_utils.set_kick(self, cmd, fromuser) + await self.mod_utils.set_kick(self, cmd, fromuser) except IndexError as e: - self.Logs.warning(f'_hcmd KICK: {str(e)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME] [REASON]") + self.ctx.Logs.warning(f'_hcmd KICK: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME] [REASON]") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'kickban': try: - self.mod_utils.set_kickban(self, cmd, fromuser) + await self.mod_utils.set_kickban(self, cmd, fromuser) except IndexError as e: - self.Logs.warning(f'_hcmd KICKBAN: {str(e)}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME] [REASON]") + self.ctx.Logs.warning(f'_hcmd KICKBAN: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME] [REASON]") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'join' | 'assign': try: - self.mod_utils.set_assign_channel_to_service(self, cmd, fromuser) + await self.mod_utils.set_assign_channel_to_service(self, cmd, fromuser) except IndexError as ie: - self.Logs.debug(f'{ie}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") + self.ctx.Logs.debug(f'{ie}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'part' | 'unassign': try: # Syntax. !part #channel - self.mod_utils.set_unassign_channel_to_service(self, cmd, fromuser) + await self.mod_utils.set_unassign_channel_to_service(self, cmd, fromuser) except IndexError as ie: - self.Logs.debug(f'{ie}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") + self.ctx.Logs.debug(f'{ie}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'topic': try: if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") return None chan = str(cmd[1]) - if not self.Channel.is_valid_channel(chan): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") + if not self.ctx.Channel.is_valid_channel(chan): + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f':{dnickname} TOPIC {chan} :{topic_msg}') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} TOPIC {chan} :{topic_msg}') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the topic") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the topic") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'wallops': try: if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} WALLOPS THE_WALLOPS_MESSAGE") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f':{dnickname} WALLOPS {wallops_msg} ({dnickname})') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} WALLOPS {wallops_msg} ({dnickname})') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the wallops message") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the wallops message") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'globops': try: if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} GLOBOPS THE_GLOBOPS_MESSAGE") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f':{dnickname} GLOBOPS {globops_msg} ({dnickname})') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} GLOBOPS {globops_msg} ({dnickname})') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the globops message") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the globops message") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'gnotice': try: if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} THE_GLOBAL_NOTICE_MESSAGE") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send_notice(nick_from=dnickname, nick_to='$*.*', msg=f"[{self.Config.COLORS.red}GLOBAL NOTICE{self.Config.COLORS.nogc}] {gnotice_msg}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to='$*.*', msg=f"[{self.ctx.Config.COLORS.red}GLOBAL NOTICE{self.ctx.Config.COLORS.nogc}] {gnotice_msg}") else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the global notice message") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the global notice message") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'whois': try: self.user_to_notice = fromuser if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nickname not found !") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") + if self.ctx.User.get_nickname(nickname) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nickname not found !") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") return None - self.Protocol.send2socket(f':{dnickname} WHOIS {nickname}') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} WHOIS {nickname}') except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'names': try: if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #CHANNEL") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #CHANNEL") return None chan = str(cmd[1]) - if not self.Channel.is_valid_channel(chan): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel") + if not self.ctx.Channel.is_valid_channel(chan): + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel") return None - self.Protocol.send2socket(f':{dnickname} NAMES {chan}') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} NAMES {chan}') except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'invite': try: if len(cmd) < 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") return None nickname = str(cmd[1]) chan = str(cmd[2]) - if not self.Channel.is_valid_channel(chan): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") + if not self.ctx.Channel.is_valid_channel(chan): + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") return None - if self.User.get_nickname(nickname) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nickname not found !") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") + if self.ctx.User.get_nickname(nickname) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nickname not found !") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") return None - self.Protocol.send2socket(f':{dnickname} INVITE {nickname} {chan}') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} INVITE {nickname} {chan}') except KeyError as ke: - self.Logs.error(f"KeyError: {ke}") + self.ctx.Logs.error(f"KeyError: {ke}") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'inviteme': try: if len(cmd) == 0: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()}") return None - self.Protocol.send2socket(f':{dnickname} INVITE {fromuser} {self.Config.SERVICE_CHANLOG}') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} INVITE {fromuser} {self.ctx.Config.SERVICE_CHANLOG}') except KeyError as ke: - self.Logs.error(f"KeyError: {ke}") + self.ctx.Logs.error(f"KeyError: {ke}") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'map': try: self.user_to_notice = fromuser - self.Protocol.send2socket(f':{dnickname} MAP') + await self.ctx.Irc.Protocol.send2socket(f':{dnickname} MAP') except KeyError as ke: - self.Logs.error(f"KeyError: {ke}") + self.ctx.Logs.error(f"KeyError: {ke}") except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'umode': try: # .umode nickname +mode if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [NICKNAME] [+/-]mode") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [NICKNAME] [+/-]mode") return None nickname = str(cmd[1]) umode = str(cmd[2]) - self.Protocol.send_svsmode(nickname=nickname, user_mode=umode) + await self.ctx.Irc.Protocol.send_svsmode(nickname=nickname, user_mode=umode) except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'mode': # .mode #channel +/-mode @@ -617,100 +622,100 @@ class Command(IModule): try: if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") return None if fromchannel is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") + await self.ctx.Irc.Protocol.send_notice(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.Channel.is_valid_channel(fromchannel): - self.Protocol.send2socket(f":{dnickname} MODE {fromchannel} {channel_mode}") + if self.ctx.Channel.is_valid_channel(fromchannel): + await self.ctx.Irc.Protocol.send2socket(f":{dnickname} MODE {fromchannel} {channel_mode}") else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : Channel [{fromchannel}] is not correct should start with #") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f":{service_id} MODE {provided_channel} {channel_mode}") + await self.ctx.Irc.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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#CHANNEL] [+/-]mode") + self.ctx.Logs.warning(f'_hcmd OP: {str(e)}') + await self.ctx.Irc.Protocol.send_notice(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)}') + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'get_mode': try: - self.Protocol.send2socket(f'MODE {fromchannel}') + await self.ctx.Irc.Protocol.send2socket(f'MODE {fromchannel}') except Exception as err: - self.Logs.error(f"General Error {err}") + self.ctx.Logs.error(f"General Error {err}") case 'svsjoin': try: # SVSJOIN [,..] [key1[,key2[..]]] if len(cmd) < 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN [,..] [key1[,key2[..]]]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN [,..] [key1[,key2[..]]]") return None nickname = str(cmd[1]) channels = str(cmd[2]).split(',') keys = str(cmd[3]).split(',') - self.Protocol.send_svsjoin(nickname, channels, keys) + await self.ctx.Irc.Protocol.send_svsjoin(nickname, channels, keys) except IndexError as ke: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN [,..] [key1[,key2[..]]]") - self.Logs.error(ke) + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN [,..] [key1[,key2[..]]]") + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN [,..] [key1[,key2[..]]]") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN [,..] [key1[,key2[..]]]") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'svspart': try: # SVSPART [,..] [] if len(cmd) < 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART [,..] []") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART [,..] []") return None nickname = str(cmd[1]) channels = str(cmd[2]).split(',') reason = ' '.join(cmd[3:]) - self.Protocol.send_svspart(nickname, channels, reason) + await self.ctx.Irc.Protocol.send_svspart(nickname, channels, reason) except IndexError as ke: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART [,..] []") - self.Logs.error(ke) + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART [,..] []") + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART [,..] []") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART [,..] []") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'svsnick': try: # .svsnick nickname newnickname nickname = str(cmd[1]) newnickname = str(cmd[2]) - unixtime = self.MainUtils.get_unixtime() + unixtime = self.ctx.Utils.get_unixtime() - if self.User.get_nickname(nickname) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" This nickname do not exist") + if self.ctx.User.get_nickname(nickname) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" This nickname do not exist") return None if len(cmd) != 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") return None - self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSNICK {nickname} {newnickname} {unixtime}') + await self.ctx.Irc.Protocol.send2socket(f':{self.ctx.Config.SERVEUR_ID} SVSNICK {nickname} {newnickname} {unixtime}') except IndexError as ke: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") - self.Logs.error(ke) + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname newnickname") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'sajoin': try: @@ -718,78 +723,78 @@ class Command(IModule): nickname = str(cmd[1]) channel = str(cmd[2]) if len(cmd) < 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") return None - self.Protocol.send_sajoin(nick_to_sajoin=nickname, channel_name=channel) + await self.ctx.Irc.Protocol.send_sajoin(nick_to_sajoin=nickname, channel_name=channel) except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'sapart': try: # .sapart nickname #channel if len(cmd) < 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") return None nickname = str(cmd[1]) channel = str(cmd[2]) - self.Protocol.send_sapart(nick_to_sapart=nickname, channel_name=channel) + await self.ctx.Irc.Protocol.send_sapart(nick_to_sapart=nickname, channel_name=channel) except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") - self.Logs.error(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") + self.ctx.Logs.error(f'Unknown Error: {str(err)}') case 'kill': try: # 'kill', 'gline', 'ungline', 'shun', 'unshun' # .kill nickname reason if len(cmd) < 3: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname reason") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f":{service_id} KILL {nickname} {kill_reason} ({self.Config.COLORS.red}{dnickname}{self.Config.COLORS.nogc})") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} KILL {nickname} {kill_reason} ({self.ctx.Config.COLORS.red}{dnickname}{self.ctx.Config.COLORS.nogc})") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSNICK nickname newnickname") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSNICK nickname newnickname") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'gline': try: # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .gline [nickname] [host] [reason] if len(cmd) < 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None nickname = str(cmd[1]) hostname = str(cmd[2]) - set_at_timestamp = self.MainUtils.get_unixtime() + set_at_timestamp = self.ctx.Utils.get_unixtime() expire_time = (60 * 60 * 24) + set_at_timestamp gline_reason = ' '.join(cmd[3:]) if nickname == '*' and hostname == '*': - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None - self.Protocol.send_gline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason) + await self.ctx.Irc.Protocol.send_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.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'ungline': try: @@ -797,47 +802,47 @@ class Command(IModule): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .ungline nickname host if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {dnickname}") - self.Protocol.send_ungline(nickname=nickname, hostname=hostname) + # await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {dnickname}") + await self.ctx.Irc.Protocol.send_ungline(nickname=nickname, hostname=hostname) except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'kline': try: # TKL + k user host set_by expire_timestamp set_at_timestamp :reason # .gline [nickname] [host] [reason] if len(cmd) < 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None nickname = str(cmd[1]) hostname = str(cmd[2]) - set_at_timestamp = self.MainUtils.get_unixtime() + set_at_timestamp = self.ctx.Utils.get_unixtime() expire_time = (60 * 60 * 24) + set_at_timestamp gline_reason = ' '.join(cmd[3:]) if nickname == '*' and hostname == '*': - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None - self.Protocol.send_kline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason) + await self.ctx.Irc.Protocol.send_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.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'unkline': try: @@ -845,19 +850,19 @@ class Command(IModule): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .ungline nickname host if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send_unkline(nickname=nickname, hostname=hostname) + await self.ctx.Irc.Protocol.send_unkline(nickname=nickname, hostname=hostname) except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'shun': try: @@ -865,26 +870,26 @@ class Command(IModule): # .shun [nickname] [host] [reason] if len(cmd) < 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None nickname = str(cmd[1]) hostname = str(cmd[2]) - set_at_timestamp = self.MainUtils.get_unixtime() + set_at_timestamp = self.ctx.Utils.get_unixtime() expire_time = (60 * 60 * 24) + set_at_timestamp shun_reason = ' '.join(cmd[3:]) if nickname == '*' and hostname == '*': - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You want to close the server ? i would recommand ./unrealircd stop :)") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") return None - self.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL + s {nickname} {hostname} {dnickname} {expire_time} {set_at_timestamp} :{shun_reason}") + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_ID} TKL + s {nickname} {hostname} {dnickname} {expire_time} {set_at_timestamp} :{shun_reason}") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'unshun': try: @@ -892,52 +897,52 @@ class Command(IModule): # TKL + G user host set_by expire_timestamp set_at_timestamp :reason # .unshun nickname host if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") + await self.ctx.Irc.Protocol.send_notice(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.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL - s {nickname} {hostname} {dnickname}") + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_ID} TKL - s {nickname} {hostname} {dnickname}") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname hostname") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'glinelist': try: self.user_to_notice = fromuser - self.Protocol.send2socket(f":{self.Config.SERVICE_ID} STATS G") + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVICE_ID} STATS G") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'shunlist': try: self.user_to_notice = fromuser - self.Protocol.send2socket(f":{self.Config.SERVICE_ID} STATS s") + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVICE_ID} STATS s") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case 'klinelist': try: self.user_to_notice = fromuser - self.Protocol.send2socket(f":{self.Config.SERVICE_ID} STATS k") + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVICE_ID} STATS k") except KeyError as ke: - self.Logs.error(ke) + self.ctx.Logs.error(ke) except Exception as err: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") - self.Logs.warning(f'Unknown Error: {str(err)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()}") + self.ctx.Logs.warning(f'Unknown Error: {str(err)}') case _: pass diff --git a/mods/command/utils.py b/mods/command/utils.py index d7ef806..3a5f521 100644 --- a/mods/command/utils.py +++ b/mods/command/utils.py @@ -4,243 +4,243 @@ if TYPE_CHECKING: from mods.command.mod_command import Command -def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None: +async def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None: command: str = str(cmd[0]).lower() option: str = str(cmd[1]).lower() - allowed_modes: list[str] = uplink.Loader.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v'] - dnickname = uplink.Config.SERVICE_NICKNAME - service_id = uplink.Config.SERVICE_ID + allowed_modes: list[str] = uplink.ctx.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v'] + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + service_id = uplink.ctx.Config.SERVICE_ID fromuser = client match option: case 'set': if len(cmd) < 5: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]") - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}") return None nickname = str(cmd[2]) mode = str(cmd[3]) - chan: str = str(cmd[4]).lower() if uplink.Channel.is_valid_channel(cmd[4]) else None + chan: str = str(cmd[4]).lower() if uplink.ctx.Channel.is_valid_channel(cmd[4]) else None sign = mode[0] if mode.startswith( ('+', '-')) else None clean_mode = mode[1:] if len(mode) > 0 else None if sign is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -") return None if clean_mode not in allowed_modes: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") return None if chan is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") return None db_data: dict[str, str] = {"nickname": nickname, "channel": chan} - db_query = uplink.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data) + db_query = await uplink.ctx.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data) db_result = db_query.fetchone() if db_result is not None: if sign == '+': - db_data = {"updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode} - db_result = uplink.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel", + db_data = {"updated_on": uplink.ctx.Utils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode} + db_result = await uplink.ctx.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel", params=db_data) if db_result.rowcount > 0: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}") elif sign == '-': db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"} - db_result = uplink.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode", + db_result = await uplink.ctx.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode", params=db_data) if db_result.rowcount > 0: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}") else: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}") return None # Instert a new automode if sign == '+': - db_data = {"created_on": uplink.MainUtils.get_sdatetime(), "updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode} - db_query = uplink.Base.db_execute_query( + db_data = {"created_on": uplink.ctx.Utils.get_sdatetime(), "updated_on": uplink.ctx.Utils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode} + db_query = await uplink.ctx.Base.db_execute_query( query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)", params=db_data ) if db_query.rowcount > 0: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}") - if uplink.Channel.is_user_present_in_channel(chan, uplink.User.get_uid(nickname)): - uplink.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}") + if uplink.ctx.Channel.is_user_present_in_channel(chan, uplink.ctx.User.get_uid(nickname)): + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}") else: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist") case 'list': - db_query = uplink.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode") + db_query = await uplink.ctx.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode") db_results = db_query.fetchall() if not db_results: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="There is no automode to display.") for db_result in db_results: db_nickname, db_channel, db_mode = db_result - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}") case _: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]") - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST") - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}") -def set_deopall(uplink: 'Command', channel_name: str) -> None: +async def set_deopall(uplink: 'Command', channel_name: str) -> None: - service_id = uplink.Config.SERVICE_ID - uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o") + service_id = uplink.ctx.Config.SERVICE_ID + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o") return None -def set_devoiceall(uplink: 'Command', channel_name: str) -> None: +async def set_devoiceall(uplink: 'Command', channel_name: str) -> None: - service_id = uplink.Config.SERVICE_ID - uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v") + service_id = uplink.ctx.Config.SERVICE_ID + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v") return None -def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None: +async def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None: - chan_info = uplink.Channel.get_channel(channel_name) - service_id = uplink.Config.SERVICE_ID - dnickname = uplink.Config.SERVICE_NICKNAME + chan_info = uplink.ctx.Channel.get_channel(channel_name) + service_id = uplink.ctx.Config.SERVICE_ID + dnickname = uplink.ctx.Config.SERVICE_NICKNAME set_mode = pmode mode:str = '' users:str = '' uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)] - uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}") + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}") for uid in uids_split: for i in range(0, len(uid)): mode += set_mode - users += f'{uplink.User.get_nickname(uplink.MainUtils.clean_uid(uid[i]))} ' + users += f'{uplink.ctx.User.get_nickname(uplink.ctx.Utils.clean_uid(uid[i]))} ' if i == len(uid) - 1: - uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}") + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}") mode = '' users = '' -def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None: +async def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None: - dnickname = uplink.Config.SERVICE_NICKNAME - service_id = uplink.Config.SERVICE_ID + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + service_id = uplink.ctx.Config.SERVICE_ID if channel_name is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]") return False if len(cmd) == 1: - # uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}") - uplink.Protocol.send_set_mode(mode, nickname=client, channel_name=channel_name) + # await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}") + await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=client, channel_name=channel_name) return None # deop nickname if len(cmd) == 2: nickname = cmd[1] - # uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}") - uplink.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name) + # await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}") + await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name) return None nickname = cmd[2] - # uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}") - uplink.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name) + # await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}") + await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name) return None -def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None: +async def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None: command = str(cmd[0]) - dnickname = uplink.Config.SERVICE_NICKNAME - service_id = uplink.Config.SERVICE_ID - sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + service_id = uplink.ctx.Config.SERVICE_ID + sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None if sentchannel is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]") return None nickname = cmd[2] - uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*") - uplink.Logs.debug(f'{client} has banned {nickname} from {sentchannel}') + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*") + uplink.ctx.Logs.debug(f'{client} has banned {nickname} from {sentchannel}') return None -def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None: +async def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None: command = str(cmd[0]) - dnickname = uplink.Config.SERVICE_NICKNAME - service_id = uplink.Config.SERVICE_ID + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + service_id = uplink.ctx.Config.SERVICE_ID - sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None + sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None if sentchannel is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") return False nickname = cmd[2] final_reason = ' '.join(cmd[3:]) - uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") - uplink.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}') + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") + uplink.ctx.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}') return None -def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None: +async def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None: command = str(cmd[0]) - dnickname = uplink.Config.SERVICE_NICKNAME - service_id = uplink.Config.SERVICE_ID + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + service_id = uplink.ctx.Config.SERVICE_ID - sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None + sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None if sentchannel is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]") return False nickname = cmd[2] final_reason = ' '.join(cmd[3:]) - uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") - uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") - uplink.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}') + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}") + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*") + uplink.ctx.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}') -def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: +async def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: if len(cmd) < 2: raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter") command = str(cmd[0]) - dnickname = uplink.Config.SERVICE_NICKNAME - sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + sent_channel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None if sent_channel is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") return None # self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}') - uplink.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel) - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}") - uplink.Channel.db_query_channel('add', uplink.module_name, sent_channel) + await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel) + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}") + await uplink.ctx.Channel.db_query_channel('add', uplink.module_name, sent_channel) return None -def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: +async def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: if len(cmd) < 2: raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter") command = str(cmd[0]) - dnickname = uplink.Config.SERVICE_NICKNAME - dchanlog = uplink.Config.SERVICE_CHANLOG + dnickname = uplink.ctx.Config.SERVICE_NICKNAME + dchanlog = uplink.ctx.Config.SERVICE_CHANLOG - sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None + sent_channel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None if sent_channel is None: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]") return None if sent_channel == dchanlog: - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]") + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]") return None - uplink.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel) - uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}") + await uplink.ctx.Irc.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel) + await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}") - uplink.Channel.db_query_channel('del', uplink.module_name, sent_channel) + await uplink.ctx.Channel.db_query_channel('del', uplink.module_name, sent_channel) return None \ No newline at end of file diff --git a/mods/defender/mod_defender.py b/mods/defender/mod_defender.py index 2a5476c..1127a3e 100644 --- a/mods/defender/mod_defender.py +++ b/mods/defender/mod_defender.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, TYPE_CHECKING +from typing import Any, TYPE_CHECKING, Optional from core.classes.interfaces.imodule import IModule import mods.defender.schemas as schemas import mods.defender.utils as utils @@ -24,7 +24,12 @@ class Defender(IModule): } def __init__(self, context: 'Loader') -> None: - self.ctx = context + super().__init__(context) + self._mod_config: Optional[schemas.ModConfModel] = None + + @property + def mod_config(self) -> ModConfModel: + return self._mod_config def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. @@ -44,34 +49,37 @@ class Defender(IModule): # ) # ''' - # self.Base.db_execute_query(table_autoop) - # self.Base.db_execute_query(table_config) - # self.Base.db_execute_query(table_trusted) + # self.ctx.Base.db_execute_query(table_autoop) + # self.ctx.Base.db_execute_query(table_config) + # self.ctx.Base.db_execute_query(table_trusted) return None async def load(self): - + + # Variable qui va contenir les options de configuration du module Defender + self._mod_config: schemas.ModConfModel = self.ModConfModel() + + # sync the database with local variable (Mandatory) + await self.sync_db() + # Add module schemas self.Schemas = schemas - # Add utils functions - self.Utils = utils + # Add module utils functions + self.mod_utils = utils - # Variable qui va contenir les options de configuration du module Defender - self.ModConfig: schemas.ModConfModel = self.ModConfModel() - # Create module commands (Mandatory) - self.Irc.build_command(0, self.module_name, 'code', 'Display the code or key for access') - self.Irc.build_command(1, self.module_name, 'info', 'Provide information about the channel or server') - self.Irc.build_command(1, self.module_name, 'autolimit', 'Automatically set channel user limits') - self.Irc.build_command(3, self.module_name, 'reputation', 'Check or manage user reputation') - self.Irc.build_command(3, self.module_name, 'proxy_scan', 'Scan users for proxy connections') - self.Irc.build_command(3, self.module_name, 'flood', 'Handle flood detection and mitigation') - self.Irc.build_command(3, self.module_name, 'status', 'Check the status of the server or bot') - self.Irc.build_command(3, self.module_name, 'show_reputation', 'Display reputation information') - self.Irc.build_command(3, self.module_name, 'sentinel', 'Monitor and guard the channel or server') + self.ctx.Irc.build_command(0, self.module_name, 'code', 'Display the code or key for access') + self.ctx.Irc.build_command(1, self.module_name, 'info', 'Provide information about the channel or server') + self.ctx.Irc.build_command(1, self.module_name, 'autolimit', 'Automatically set channel user limits') + self.ctx.Irc.build_command(3, self.module_name, 'reputation', 'Check or manage user reputation') + self.ctx.Irc.build_command(3, self.module_name, 'proxy_scan', 'Scan users for proxy connections') + self.ctx.Irc.build_command(3, self.module_name, 'flood', 'Handle flood detection and mitigation') + self.ctx.Irc.build_command(3, self.module_name, 'status', 'Check the status of the server or bot') + self.ctx.Irc.build_command(3, self.module_name, 'show_reputation', 'Display reputation information') + self.ctx.Irc.build_command(3, self.module_name, 'sentinel', 'Monitor and guard the channel or server') - self.timeout = self.Config.API_TIMEOUT + self.timeout = self.ctx.Config.API_TIMEOUT # Listes qui vont contenir les ip a scanner avec les différentes API self.Schemas.DB_ABUSEIPDB_USERS = self.Schemas.DB_FREEIPAPI_USERS = self.Schemas.DB_CLOUDFILT_USERS = [] @@ -93,27 +101,27 @@ class Defender(IModule): self.cloudfilt_key = 'r1gEtjtfgRQjtNBDMxsg' # Démarrer les threads pour démarrer les api - self.Base.create_thread(func=thds.thread_freeipapi_scan, func_args=(self, )) - self.Base.create_thread(func=thds.thread_cloudfilt_scan, func_args=(self, )) - self.Base.create_thread(func=thds.thread_abuseipdb_scan, func_args=(self, )) - self.Base.create_thread(func=thds.thread_local_scan, func_args=(self, )) - self.Base.create_thread(func=thds.thread_psutil_scan, func_args=(self, )) - self.Base.create_thread(func=thds.thread_apply_reputation_sanctions, func_args=(self, )) + self.ctx.Base.create_asynctask(thds.coro_freeipapi_scan(self)) + self.ctx.Base.create_asynctask(thds.coro_cloudfilt_scan(self)) + self.ctx.Base.create_asynctask(thds.coro_abuseipdb_scan(self)) + self.ctx.Base.create_asynctask(thds.coro_local_scan(self)) + self.ctx.Base.create_asynctask(thds.coro_psutil_scan(self)) + self.ctx.Base.create_asynctask(thds.coro_apply_reputation_sanctions(self)) - if self.ModConfig.autolimit == 1: - self.Base.create_thread(func=thds.thread_autolimit, func_args=(self, )) + if self.mod_config.autolimit == 1: + self.ctx.Base.create_asynctask(thds.coro_autolimit(self)) - if self.ModConfig.reputation == 1: - await self.Protocol.send_sjoin(self.Config.SALON_JAIL) - await self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.SALON_JAIL} +o {self.Config.SERVICE_NICKNAME}") + if self.mod_config.reputation == 1: + await self.ctx.Irc.Protocol.send_sjoin(self.ctx.Config.SALON_JAIL) + await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVICE_NICKNAME} SAMODE {self.ctx.Config.SALON_JAIL} +o {self.ctx.Config.SERVICE_NICKNAME}") def __onload(self): - abuseipdb = self.Settings.get_cache('ABUSEIPDB') - freeipapi = self.Settings.get_cache('FREEIPAPI') - cloudfilt = self.Settings.get_cache('CLOUDFILT') - psutils = self.Settings.get_cache('PSUTIL') - localscan = self.Settings.get_cache('LOCALSCAN') + abuseipdb = self.ctx.Settings.get_cache('ABUSEIPDB') + freeipapi = self.ctx.Settings.get_cache('FREEIPAPI') + cloudfilt = self.ctx.Settings.get_cache('CLOUDFILT') + psutils = self.ctx.Settings.get_cache('PSUTIL') + localscan = self.ctx.Settings.get_cache('LOCALSCAN') if abuseipdb: self.Schemas.DB_ABUSEIPDB_USERS = abuseipdb @@ -148,12 +156,12 @@ class Defender(IModule): self.reputationTimer_isRunning:bool = False self.autolimit_isRunning: bool = False - self.Irc.Commands.drop_command_by_module(self.module_name) + self.ctx.Commands.drop_command_by_module(self.module_name) return None - def insert_db_trusted(self, uid: str, nickname:str) -> None: - u = self.User.get_user(uid) + async def insert_db_trusted(self, uid: str, nickname:str) -> None: + u = self.ctx.User.get_user(uid) if u is None: return None @@ -161,119 +169,119 @@ class Defender(IModule): nickname = u.nickname query = "SELECT id FROM def_trusted WHERE user = ?" - exec_query = self.Base.db_execute_query(query, {"user": nickname}) + exec_query = await self.ctx.Base.db_execute_query(query, {"user": nickname}) response = exec_query.fetchone() if response is not None: q_insert = "INSERT INTO def_trusted (datetime, user, host, vhost) VALUES (?, ?, ?, ?)" - mes_donnees = {'datetime': self.Loader.Utils.get_datetime(), 'user': nickname, 'host': '*', 'vhost': '*'} - exec_query = self.Base.db_execute_query(q_insert, mes_donnees) + mes_donnees = {'datetime': self.ctx.mod_utils.get_datetime(), 'user': nickname, 'host': '*', 'vhost': '*'} + exec_query = self.ctx.Base.db_execute_query(q_insert, mes_donnees) pass async def join_saved_channels(self) -> None: """_summary_ """ try: - result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}") + result = await self.ctx.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.ctx.Config.TABLE_CHANNEL}") channels = result.fetchall() - jail_chan = self.Config.SALON_JAIL - jail_chan_mode = self.Config.SALON_JAIL_MODES - service_id = self.Config.SERVICE_ID - dumodes = self.Config.SERVICE_UMODES - dnickname = self.Config.SERVICE_NICKNAME + jail_chan = self.ctx.Config.SALON_JAIL + jail_chan_mode = self.ctx.Config.SALON_JAIL_MODES + service_id = self.ctx.Config.SERVICE_ID + dumodes = self.ctx.Config.SERVICE_UMODES + dnickname = self.ctx.Config.SERVICE_NICKNAME for channel in channels: chan = channel[0] - await self.Protocol.send_sjoin(chan) + await self.ctx.Irc.Protocol.send_sjoin(chan) if chan == jail_chan: - await self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") - await self.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") return None except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}") - def cmd(self, data: list[str]) -> None: + async def cmd(self, data: list[str]) -> None: if not data or len(data) < 2: return None cmd = data.copy() if isinstance(data, list) else list(data).copy() try: - index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd) + index, command = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd) if index == -1: return None match command: case 'REPUTATION': - self.Utils.handle_on_reputation(self, cmd) + self.mod_utils.handle_on_reputation(self, cmd) return None case 'MODE': - self.Utils.handle_on_mode(self, cmd) + await self.mod_utils.handle_on_mode(self, cmd) return None case 'PRIVMSG': - self.Utils.handle_on_privmsg(self, cmd) + await self.mod_utils.handle_on_privmsg(self, cmd) return None case 'UID': - self.Utils.handle_on_uid(self, cmd) + await self.mod_utils.handle_on_uid(self, cmd) return None case 'SJOIN': - self.Utils.handle_on_sjoin(self, cmd) + await self.mod_utils.handle_on_sjoin(self, cmd) return None case 'SLOG': - self.Utils.handle_on_slog(self, cmd) + self.mod_utils.handle_on_slog(self, cmd) return None case 'NICK': - self.Utils.handle_on_nick(self, cmd) + await self.mod_utils.handle_on_nick(self, cmd) return None case 'QUIT': - self.Utils.handle_on_quit(self, cmd) + await self.mod_utils.handle_on_quit(self, cmd) return None case _: return None except KeyError as ke: - self.Logs.error(f"{ke} / {cmd} / length {str(len(cmd))}") + self.ctx.Logs.error(f"{ke} / {cmd} / length {str(len(cmd))}") except IndexError as ie: - self.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}") + self.ctx.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}") except Exception as err: - self.Logs.error(f"General Error: {err}", exc_info=True) + self.ctx.Logs.error(f"General Error: {err}", exc_info=True) async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None: - u = self.User.get_user(user) + u = self.ctx.User.get_user(user) if u is None: return None command = str(cmd[0]).lower() fromuser = u.nickname - channel = fromchannel = channel if self.Channel.is_valid_channel(channel) else None + channel = fromchannel = channel if self.ctx.Channel.is_valid_channel(channel) else None - dnickname = self.Config.SERVICE_NICKNAME # Defender nickname - dchanlog = self.Config.SERVICE_CHANLOG # Defender chan log - dumodes = self.Config.SERVICE_UMODES # Les modes de Defender - service_id = self.Config.SERVICE_ID # Defender serveur id - jail_chan = self.Config.SALON_JAIL # Salon pot de miel - jail_chan_mode = self.Config.SALON_JAIL_MODES # Mode du salon "pot de miel" + dnickname = self.ctx.Config.SERVICE_NICKNAME # Defender nickname + dchanlog = self.ctx.Config.SERVICE_CHANLOG # Defender chan log + dumodes = self.ctx.Config.SERVICE_UMODES # Les modes de Defender + service_id = self.ctx.Config.SERVICE_ID # Defender serveur id + jail_chan = self.ctx.Config.SALON_JAIL # Salon pot de miel + jail_chan_mode = self.ctx.Config.SALON_JAIL_MODES # Mode du salon "pot de miel" match command: case 'show_reputation': - if not self.Reputation.UID_REPUTATION_DB: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="No one is suspected") + if not self.ctx.Reputation.UID_REPUTATION_DB: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="No one is suspected") - for suspect in self.Reputation.UID_REPUTATION_DB: - await self.Protocol.send_notice(nick_from=dnickname, + for suspect in self.ctx.Reputation.UID_REPUTATION_DB: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Uid: {suspect.uid} | Nickname: {suspect.nickname} | Reputation: {suspect.score_connexion} | Secret code: {suspect.secret_code} | Connected on: {suspect.connexion_datetime}") @@ -282,106 +290,106 @@ class Defender(IModule): release_code = cmd[1] jailed_nickname = u.nickname jailed_UID = u.uid - get_reputation = self.Reputation.get_reputation(jailed_UID) + get_reputation = self.ctx.Reputation.get_reputation(jailed_UID) if get_reputation is None: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...") return False jailed_IP = get_reputation.remote_ip - jailed_salon = self.Config.SALON_JAIL - reputation_seuil = self.ModConfig.reputation_seuil - welcome_salon = self.Config.SALON_LIBERER + jailed_salon = self.ctx.Config.SALON_JAIL + reputation_seuil = self.mod_config.reputation_seuil + welcome_salon = self.ctx.Config.SALON_LIBERER - self.Logs.debug(f"IP de {jailed_nickname} : {jailed_IP}") - link = self.Config.SERVEUR_LINK - color_green = self.Config.COLORS.green - color_black = self.Config.COLORS.black + self.ctx.Logs.debug(f"IP de {jailed_nickname} : {jailed_IP}") + link = self.ctx.Config.SERVEUR_LINK + color_green = self.ctx.Config.COLORS.green + color_black = self.ctx.Config.COLORS.black if release_code == get_reputation.secret_code: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg="Bon mot de passe. Allez du vent !", channel=jailed_salon) + await self.ctx.Irc.Protocol.send_priv_msg(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 self.mod_config.reputation_ban_all_chan == 1: + for chan in self.ctx.Channel.UID_CHANNEL_DB: if chan.name != jailed_salon: - await self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {jailed_nickname}!*@*") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} -b {jailed_nickname}!*@*") - self.Reputation.delete(jailed_UID) - self.Logs.debug(f'{jailed_UID} - {jailed_nickname} removed from REPUTATION_DB') - await self.Protocol.send_sapart(nick_to_sapart=jailed_nickname, channel_name=jailed_salon) - await self.Protocol.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=welcome_salon) - await self.Protocol.send2socket(f":{link} REPUTATION {jailed_IP} {self.ModConfig.reputation_score_after_release}") + self.ctx.Reputation.delete(jailed_UID) + self.ctx.Logs.debug(f'{jailed_UID} - {jailed_nickname} removed from REPUTATION_DB') + await self.ctx.Irc.Protocol.send_sapart(nick_to_sapart=jailed_nickname, channel_name=jailed_salon) + await self.ctx.Irc.Protocol.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=welcome_salon) + await self.ctx.Irc.Protocol.send2socket(f":{link} REPUTATION {jailed_IP} {self.mod_config.reputation_score_after_release}") u.score_connexion = reputation_seuil + 1 - await self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, msg="Mauvais password", channel=jailed_salon ) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[{color_green} MAUVAIS PASSWORD {color_black}] You have typed a wrong code. for recall your password is: {self.Config.SERVICE_PREFIX}code {get_reputation.secret_code}", + msg=f"[{color_green} MAUVAIS PASSWORD {color_black}] You have typed a wrong code. for recall your password is: {self.ctx.Config.SERVICE_PREFIX}code {get_reputation.secret_code}", nick_to=jailed_nickname ) except IndexError as ie: - self.Logs.error(f'Index Error: {ie}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} code [code]") + self.ctx.Logs.error(f'Index Error: {ie}') + await self.ctx.Irc.Protocol.send_notice(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.ctx.Logs.error(f'_hcmd code: KeyError {ke}') case 'autolimit': try: # autolimit on # autolimit set [amount] [interval] if len(cmd) < 2: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} ON") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") return None arg = str(cmd[1]).lower() match arg: case 'on': - if self.ModConfig.autolimit == 0: - self.update_configuration('autolimit', 1) + if self.mod_config.autolimit == 0: + await self.update_configuration('autolimit', 1) self.autolimit_isRunning = True - self.Base.create_thread(func=thds.thread_autolimit, func_args=(self, )) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Activated", channel=self.Config.SERVICE_CHANLOG) + self.ctx.Base.create_asynctask(thds.coro_autolimit(self), async_name='coro_autolimit') + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.ctx.Config.COLORS.green}AUTOLIMIT{self.ctx.Config.COLORS.nogc}] Activated", channel=self.ctx.Config.SERVICE_CHANLOG) else: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already activated", channel=self.Config.SERVICE_CHANLOG) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.ctx.Config.COLORS.red}AUTOLIMIT{self.ctx.Config.COLORS.nogc}] Already activated", channel=self.ctx.Config.SERVICE_CHANLOG) case 'off': - if self.ModConfig.autolimit == 1: - self.update_configuration('autolimit', 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.green}AUTOLIMIT{self.Config.COLORS.nogc}] Deactivated", channel=self.Config.SERVICE_CHANLOG) + if self.mod_config.autolimit == 1: + await self.update_configuration('autolimit', 0) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.ctx.Config.COLORS.green}AUTOLIMIT{self.ctx.Config.COLORS.nogc}] Deactivated", channel=self.ctx.Config.SERVICE_CHANLOG) else: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.Config.COLORS.red}AUTOLIMIT{self.Config.COLORS.nogc}] Already Deactivated", channel=self.Config.SERVICE_CHANLOG) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{self.ctx.Config.COLORS.red}AUTOLIMIT{self.ctx.Config.COLORS.nogc}] Already Deactivated", channel=self.ctx.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) - await self.Protocol.send_priv_msg( + await self.update_configuration('autolimit_amount', amount) + await self.update_configuration('autolimit_interval', interval) + await self.ctx.Irc.Protocol.send_priv_msg( 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 + msg=f"[{self.ctx.Config.COLORS.green}AUTOLIMIT{self.ctx.Config.COLORS.nogc}] Amount set to ({amount}) | Interval set to ({interval})", + channel=self.ctx.Config.SERVICE_CHANLOG ) case _: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} ON") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") except Exception as err: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} ON") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") - self.Logs.error(f"Value Error -> {err}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} ON") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} SET [AMOUNT] [INTERVAL]") + self.ctx.Logs.error(f"Value Error -> {err}") case 'reputation': # .reputation [on/off] --> activate or deactivate reputation system @@ -401,54 +409,54 @@ class Defender(IModule): key = 'reputation' if activation == 'on': - if self.ModConfig.reputation == 1: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already activated", channel=dchanlog) + if self.mod_config.reputation == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION{self.ctx.Config.COLORS.black} ] : Already activated", channel=dchanlog) return False # self.update_db_configuration('reputation', 1) - self.update_configuration(key, 1) + await self.update_configuration(key, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION{self.ctx.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) - await self.Protocol.send_join_chan(uidornickname=dnickname, channel=jail_chan) - await self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") - await self.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}") + await self.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname, channel=jail_chan) + await self.ctx.Irc.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}") + await self.ctx.Irc.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 self.mod_config.reputation_sg == 1: + for chan in self.ctx.Channel.UID_CHANNEL_DB: if chan.name != jail_chan: - await self.Protocol.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users") - await self.Protocol.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") - self.Channel.db_query_channel('add', self.module_name, jail_chan) + await self.ctx.Channel.db_query_channel('add', self.module_name, jail_chan) if activation == 'off': - if self.ModConfig.reputation == 0: - await self.Protocol.send_priv_msg( + if self.mod_config.reputation == 0: + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}REPUTATION{self.Config.COLORS.black} ] : Already deactivated", + msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION{self.ctx.Config.COLORS.black} ] : Already deactivated", channel=dchanlog ) return False - self.update_configuration(key, 0) + await self.update_configuration(key, 0) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.red}REPUTATION{self.Config.COLORS.black} ] : Deactivated by {fromuser}", + msg=f"[ {self.ctx.Config.COLORS.red}REPUTATION{self.ctx.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog ) - await self.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} -{dumodes} {dnickname}") - await self.Protocol.send2socket(f":{service_id} MODE {jail_chan} -sS") - await self.Protocol.send2socket(f":{service_id} PART {jail_chan}") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} -{dumodes} {dnickname}") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {jail_chan} -sS") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} PART {jail_chan}") - for chan in self.Channel.UID_CHANNEL_DB: + for chan in self.ctx.Channel.UID_CHANNEL_DB: if chan.name != jail_chan: - await self.Protocol.send2socket(f":{service_id} MODE {chan.name} -b ~security-group:unknown-users") - await self.Protocol.send2socket(f":{service_id} MODE {chan.name} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} -b ~security-group:unknown-users") + await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") - self.Channel.db_query_channel('del', self.module_name, jail_chan) + await self.ctx.Channel.db_query_channel('del', self.module_name, jail_chan) if len_cmd == 3: get_options = str(cmd[1]).lower() @@ -456,44 +464,44 @@ class Defender(IModule): match get_options: case 'release': # .reputation release [nick] - p = await self.Protocol - link = self.Config.SERVEUR_LINK - jailed_salon = self.Config.SALON_JAIL - welcome_salon = self.Config.SALON_LIBERER - client_obj = self.User.get_user(str(cmd[2])) + p = await self.ctx.Irc.Protocol + link = self.ctx.Config.SERVEUR_LINK + jailed_salon = self.ctx.Config.SALON_JAIL + welcome_salon = self.ctx.Config.SALON_LIBERER + client_obj = self.ctx.User.get_user(str(cmd[2])) if client_obj is None: - p.send_notice(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This nickname ({str(cmd[2])}) is not connected to the network!") return None - client_to_release = self.Reputation.get_reputation(client_obj.uid) + client_to_release = self.ctx.Reputation.get_reputation(client_obj.uid) if client_to_release is None: - p.send_notice(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This nickname ({str(cmd[2])}) doesn't exist in the reputation databalse!") return None - if self.Reputation.delete(client_to_release.uid): - p.send_priv_msg( + if self.ctx.Reputation.delete(client_to_release.uid): + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}REPUTATION RELEASE{self.Config.COLORS.black} ] : {client_to_release.nickname} has been released", + msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION RELEASE{self.ctx.Config.COLORS.black} ] : {client_to_release.nickname} has been released", channel=dchanlog) - p.send_notice(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This nickname has been released from reputation system") - p.send_notice(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client_to_release.nickname, msg=f"You have been released from the reputation system by ({fromuser})") - p.send_sapart(nick_to_sapart=client_to_release.nickname, channel_name=jailed_salon) - p.send_sajoin(nick_to_sajoin=client_to_release.nickname, channel_name=welcome_salon) - p.send2socket(f":{link} REPUTATION {client_to_release.remote_ip} {self.ModConfig.reputation_score_after_release}") + await self.ctx.Irc.Protocol.send_sapart(nick_to_sapart=client_to_release.nickname, channel_name=jailed_salon) + await self.ctx.Irc.Protocol.send_sajoin(nick_to_sajoin=client_to_release.nickname, channel_name=welcome_salon) + await self.ctx.Irc.Protocol.send2socket(f":{link} REPUTATION {client_to_release.remote_ip} {self.mod_config.reputation_score_after_release}") return None else: - p.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.red}REPUTATION RELEASE ERROR{self.Config.COLORS.black} ] : " + msg=f"[ {self.ctx.Config.COLORS.red}REPUTATION RELEASE ERROR{self.ctx.Config.COLORS.black} ] : " f"{client_to_release.nickname} has not been released! as he is not in the reputation database", channel=dchanlog ) @@ -512,38 +520,38 @@ class Defender(IModule): get_value = str(cmd[3]).lower() if get_value == 'on': - if self.ModConfig.reputation_ban_all_chan == 1: - await self.Protocol.send_priv_msg( + if self.mod_config.reputation_ban_all_chan == 1: + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already activated", + msg=f"[ {self.ctx.Config.COLORS.red}BAN ON ALL CHANS{self.ctx.Config.COLORS.black} ] : Already activated", channel=dchanlog ) return False # self.update_db_configuration(key, 1) - self.update_configuration(key, 1) + await self.update_configuration(key, 1) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Activated by {fromuser}", + msg=f"[ {self.ctx.Config.COLORS.green}BAN ON ALL CHANS{self.ctx.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog ) elif get_value == 'off': - if self.ModConfig.reputation_ban_all_chan == 0: - await self.Protocol.send_priv_msg( + if self.mod_config.reputation_ban_all_chan == 0: + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.red}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Already deactivated", + msg=f"[ {self.ctx.Config.COLORS.red}BAN ON ALL CHANS{self.ctx.Config.COLORS.black} ] : Already deactivated", channel=dchanlog ) return False # self.update_db_configuration(key, 0) - self.update_configuration(key, 0) + await self.update_configuration(key, 0) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}BAN ON ALL CHANS{self.Config.COLORS.black} ] : Deactivated by {fromuser}", + msg=f"[ {self.ctx.Config.COLORS.green}BAN ON ALL CHANS{self.ctx.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog ) @@ -552,73 +560,73 @@ class Defender(IModule): key = 'reputation_seuil' # self.update_db_configuration(key, reputation_seuil) - self.update_configuration(key, reputation_seuil) + await self.update_configuration(key, reputation_seuil) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}REPUTATION SEUIL{self.Config.COLORS.black} ] : Limit set to {str(reputation_seuil)} by {fromuser}", + msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION SEUIL{self.ctx.Config.COLORS.black} ] : Limit set to {str(reputation_seuil)} by {fromuser}", channel=dchanlog ) - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation set to {reputation_seuil}") + await self.ctx.Irc.Protocol.send_notice(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) + await self.update_configuration(key, reputation_timer) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( 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}", + msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION TIMER{self.ctx.Config.COLORS.black} ] : Timer set to {str(reputation_timer)} minute(s) by {fromuser}", channel=dchanlog ) - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation set to {reputation_timer}") + await self.ctx.Irc.Protocol.send_notice(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) + await self.update_configuration(key, reputation_score_after_release) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( 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}", + msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION SCORE AFTER RELEASE{self.ctx.Config.COLORS.black} ] : Reputation score after release set to {str(reputation_score_after_release)} by {fromuser}", channel=dchanlog ) - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_score_after_release}") + await self.ctx.Irc.Protocol.send_notice(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) + await self.update_configuration(key, reputation_sg) - await self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( 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}", + msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION SECURITY-GROUP{self.ctx.Config.COLORS.black} ] : Reputation Security-group set to {str(reputation_sg)} by {fromuser}", channel=dchanlog ) - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_sg}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Reputation score after release set to {reputation_sg}") case _: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set action [kill|None]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") + await self.ctx.Irc.Protocol.send_notice(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}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set action [kill|None]") + self.ctx.Logs.warning(f'{ie}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation [ON/OFF]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation release [nickname]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set banallchan [ON/OFF]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set limit [1234]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set score_after_release [1234]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} reputation set timer [1234]") + await self.ctx.Irc.Protocol.send_notice(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}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" La valeur devrait etre un entier >= 0") + self.ctx.Logs.warning(f'{ve}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" La valeur devrait etre un entier >= 0") case 'proxy_scan': @@ -626,19 +634,19 @@ class Defender(IModule): # .proxy_scan set psutil_scan on/off --> Active les informations de connexion a la machine locale # .proxy_scan set abuseipdb_scan on/off --> Active le scan via l'api abuseipdb len_cmd = len(cmd) - color_green = self.Config.COLORS.green - color_red = self.Config.COLORS.red - color_black = self.Config.COLORS.black + color_green = self.ctx.Config.COLORS.green + color_red = self.ctx.Config.COLORS.red + color_black = self.ctx.Config.COLORS.black if len_cmd == 4: set_key = str(cmd[1]).lower() if set_key != 'set': - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(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 @@ -646,106 +654,106 @@ class Defender(IModule): match option: case 'local_scan': if action == 'on': - if self.ModConfig.local_scan == 1: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + if self.mod_config.local_scan == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None - self.update_configuration(option, 1) + await self.update_configuration(option, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + if self.mod_config.local_scan == 0: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None - self.update_configuration(option, 0) + await self.update_configuration(option, 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + if self.mod_config.psutil_scan == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None - self.update_configuration(option, 1) + await self.update_configuration(option, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + if self.mod_config.psutil_scan == 0: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None - self.update_configuration(option, 0) + await self.update_configuration(option, 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + if self.mod_config.abuseipdb_scan == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None - self.update_configuration(option, 1) + await self.update_configuration(option, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + if self.mod_config.abuseipdb_scan == 0: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None - self.update_configuration(option, 0) + await self.update_configuration(option, 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + if self.mod_config.freeipapi_scan == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None - self.update_configuration(option, 1) + await self.update_configuration(option, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + if self.mod_config.freeipapi_scan == 0: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None - self.update_configuration(option, 0) + await self.update_configuration(option, 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) + if self.mod_config.cloudfilt_scan == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog) return None - self.update_configuration(option, 1) + await self.update_configuration(option, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(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: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) + if self.mod_config.cloudfilt_scan == 0: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated", channel=dchanlog) return None - self.update_configuration(option, 0) + await self.update_configuration(option, 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog) case _: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') else: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]') case 'flood': # .flood on/off @@ -759,22 +767,22 @@ class Defender(IModule): activation = str(cmd[1]).lower() key = 'flood' if activation == 'on': - if self.ModConfig.flood == 1: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Already activated", channel=dchanlog) + if self.mod_config.flood == 1: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}FLOOD{self.ctx.Config.COLORS.black} ] : Already activated", channel=dchanlog) return False - self.update_configuration(key, 1) + await self.update_configuration(key, 1) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}FLOOD{self.ctx.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog) if activation == 'off': - if self.ModConfig.flood == 0: - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.red}FLOOD{self.Config.COLORS.black} ] : Already Deactivated", channel=dchanlog) + if self.mod_config.flood == 0: + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.red}FLOOD{self.ctx.Config.COLORS.black} ] : Already Deactivated", channel=dchanlog) return False - self.update_configuration(key, 0) + await self.update_configuration(key, 0) - await self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}FLOOD{self.ctx.Config.COLORS.black} ] : Deactivated by {fromuser}", channel=dchanlog) if len_cmd == 4: set_key = str(cmd[2]).lower() @@ -784,124 +792,126 @@ class Defender(IModule): case 'flood_message': key = 'flood_message' set_value = int(cmd[3]) - self.update_configuration(key, set_value) + await self.update_configuration(key, set_value) - await self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood message set to {set_value} by {fromuser}", + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, + msg=f"[ {self.ctx.Config.COLORS.green}FLOOD{self.ctx.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) + await self.update_configuration(key, set_value) - await self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood time set to {set_value} by {fromuser}", + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, + msg=f"[ {self.ctx.Config.COLORS.green}FLOOD{self.ctx.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) + await self.update_configuration(key, set_value) - await self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"[ {self.Config.COLORS.green}FLOOD{self.Config.COLORS.black} ] : Flood timer set to {set_value} by {fromuser}", + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, + msg=f"[ {self.ctx.Config.COLORS.green}FLOOD{self.ctx.Config.COLORS.black} ] : Flood timer set to {set_value} by {fromuser}", channel=dchanlog) case _: pass except ValueError as ve: - self.Logs.error(f"{self.__class__.__name__} Value Error : {ve}") + self.ctx.Logs.error(f"{self.__class__.__name__} Value Error : {ve}") case 'status': - color_green = self.Config.COLORS.green - color_red = self.Config.COLORS.red - color_black = self.Config.COLORS.black - nogc = self.Config.COLORS.nogc + color_green = self.ctx.Config.COLORS.green + color_red = self.ctx.Config.COLORS.red + color_black = self.ctx.Config.COLORS.black + nogc = self.ctx.Config.COLORS.nogc try: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.reputation == 1 else color_red}Reputation{nogc}] ==> {self.ModConfig.reputation}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_seuil ==> {self.ModConfig.reputation_seuil}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_after_release ==> {self.ModConfig.reputation_score_after_release}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_ban_all_chan ==> {self.ModConfig.reputation_ban_all_chan}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_timer ==> {self.ModConfig.reputation_timer}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' [Proxy_scan]') - await self.Protocol.send_notice(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}') - await self.Protocol.send_notice(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}') - await self.Protocol.send_notice(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}') - await self.Protocol.send_notice(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}') - await self.Protocol.send_notice(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}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit{nogc}] ==> {self.ModConfig.autolimit}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit Amount{nogc} ==> {self.ModConfig.autolimit_amount}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.autolimit == 1 else color_red}Autolimit Interval{nogc} ==> {self.ModConfig.autolimit_interval}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Flood{nogc}] ==> {self.ModConfig.flood}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' flood_action ==> Coming soon') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.ModConfig.flood_message}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.ModConfig.flood_time}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.ModConfig.flood_timer}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Sentinel{nogc}] ==> {self.ModConfig.sentinel}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.mod_config.reputation == 1 else color_red}Reputation{nogc}] ==> {self.mod_config.reputation}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_seuil ==> {self.mod_config.reputation_seuil}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_after_release ==> {self.mod_config.reputation_score_after_release}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_ban_all_chan ==> {self.mod_config.reputation_ban_all_chan}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_timer ==> {self.mod_config.reputation_timer}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' [Proxy_scan]') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.local_scan == 1 else color_red}local_scan{nogc} ==> {self.mod_config.local_scan}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.psutil_scan == 1 else color_red}psutil_scan{nogc} ==> {self.mod_config.psutil_scan}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.abuseipdb_scan == 1 else color_red}abuseipdb_scan{nogc} ==> {self.mod_config.abuseipdb_scan}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.freeipapi_scan == 1 else color_red}freeipapi_scan{nogc} ==> {self.mod_config.freeipapi_scan}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.cloudfilt_scan == 1 else color_red}cloudfilt_scan{nogc} ==> {self.mod_config.cloudfilt_scan}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.mod_config.autolimit == 1 else color_red}Autolimit{nogc}] ==> {self.mod_config.autolimit}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.autolimit == 1 else color_red}Autolimit Amount{nogc} ==> {self.mod_config.autolimit_amount}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.mod_config.autolimit == 1 else color_red}Autolimit Interval{nogc} ==> {self.mod_config.autolimit_interval}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.mod_config.flood == 1 else color_red}Flood{nogc}] ==> {self.mod_config.flood}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' flood_action ==> Coming soon') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.mod_config.flood_message}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.mod_config.flood_time}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.mod_config.flood_timer}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.mod_config.flood == 1 else color_red}Sentinel{nogc}] ==> {self.mod_config.sentinel}') except KeyError as ke: - self.Logs.error(f"Key Error : {ke}") + self.ctx.Logs.error(f"Key Error : {ke}") case 'info': try: if len(cmd) < 2: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Syntax. /msg {dnickname} INFO [nickname]") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Syntax. /msg {dnickname} INFO [nickname]") return None nickoruid = cmd[1] - UserObject = self.User.get_user(nickoruid) + UserObject = self.ctx.User.get_user(nickoruid) if UserObject is not None: - channels: list = [chan.name for chan in self.Channel.UID_CHANNEL_DB for uid_in_chan in chan.uids if self.Loader.Utils.clean_uid(uid_in_chan) == UserObject.uid] + channels: list = [chan.name for chan in self.ctx.Channel.UID_CHANNEL_DB for uid_in_chan in chan.uids if self.ctx.mod_utils.clean_uid(uid_in_chan) == UserObject.uid] - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' UID : {UserObject.uid}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' NICKNAME : {UserObject.nickname}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' USERNAME : {UserObject.username}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REALNAME : {UserObject.realname}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' HOSTNAME : {UserObject.hostname}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' VHOST : {UserObject.vhost}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' IP : {UserObject.remote_ip}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Country : {UserObject.geoip}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebIrc : {UserObject.isWebirc}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {", ".join(channels)}') - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' UID : {UserObject.uid}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' NICKNAME : {UserObject.nickname}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' USERNAME : {UserObject.username}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REALNAME : {UserObject.realname}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' HOSTNAME : {UserObject.hostname}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' VHOST : {UserObject.vhost}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' IP : {UserObject.remote_ip}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' Country : {UserObject.geoip}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebIrc : {UserObject.isWebirc}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {", ".join(channels)}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}') else: - await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {nickoruid} doesn't exist") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {nickoruid} doesn't exist") except KeyError as ke: - self.Logs.warning(f"Key error info user : {ke}") + self.ctx.Logs.warning(f"Key error info user : {ke}") case 'sentinel': # .sentinel on activation = str(cmd[1]).lower() - channel_to_dont_quit = [self.Config.SALON_JAIL, self.Config.SERVICE_CHANLOG] + channel_to_dont_quit = [self.ctx.Config.SALON_JAIL, self.ctx.Config.SERVICE_CHANLOG] if activation == 'on': - result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}") + result = await self.ctx.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.ctx.Config.TABLE_CHANNEL}") channels = result.fetchall() channel_in_db = [channel[0] for channel in channels] channel_to_dont_quit.extend(channel_in_db) - self.update_configuration('sentinel', 1) - for chan in self.Channel.UID_CHANNEL_DB: + await self.update_configuration('sentinel', 1) + for chan in self.ctx.Channel.UID_CHANNEL_DB: if chan.name not in channel_to_dont_quit: - await self.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name) - await self.Protocol.send_priv_msg(dnickname, f"Sentinel mode activated on {channel}", channel=chan.name) + await self.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name) + await self.ctx.Irc.Protocol.send_priv_msg(dnickname, f"Sentinel mode activated on {channel}", channel=chan.name) return None if activation == 'off': - result = self.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.Config.TABLE_CHANNEL}") + result = await self.ctx.Base.db_execute_query(f"SELECT distinct channel_name FROM {self.ctx.Config.TABLE_CHANNEL}") channels = result.fetchall() channel_in_db = [channel[0] for channel in channels] channel_to_dont_quit.extend(channel_in_db) - self.update_configuration('sentinel', 0) - for chan in self.Channel.UID_CHANNEL_DB: + await self.update_configuration('sentinel', 0) + for chan in self.ctx.Channel.UID_CHANNEL_DB: if chan.name not in channel_to_dont_quit: - await self.Protocol.send_part_chan(uidornickname=dnickname, channel=chan.name) - await self.Protocol.send_priv_msg(dnickname, f"Sentinel mode deactivated on {channel}", channel=chan.name) - self.join_saved_channels() + await self.ctx.Irc.Protocol.send_part_chan(uidornickname=dnickname, channel=chan.name) + await self.ctx.Irc.Protocol.send_priv_msg(dnickname, f"Sentinel mode deactivated on {channel}", channel=chan.name) + + await self.join_saved_channels() + return None diff --git a/mods/defender/threads.py b/mods/defender/threads.py index 9f00077..e785238 100644 --- a/mods/defender/threads.py +++ b/mods/defender/threads.py @@ -1,115 +1,116 @@ +import asyncio from typing import TYPE_CHECKING from time import sleep if TYPE_CHECKING: from mods.defender.mod_defender import Defender -def thread_apply_reputation_sanctions(uplink: 'Defender'): +async def coro_apply_reputation_sanctions(uplink: 'Defender'): while uplink.reputationTimer_isRunning: - uplink.Utils.action_apply_reputation_santions(uplink) - sleep(5) + await uplink.mod_utils.action_apply_reputation_santions(uplink) + await asyncio.sleep(5) -def thread_cloudfilt_scan(uplink: 'Defender'): +async def coro_cloudfilt_scan(uplink: 'Defender'): while uplink.cloudfilt_isRunning: list_to_remove:list = [] for user in uplink.Schemas.DB_CLOUDFILT_USERS: - uplink.Utils.action_scan_client_with_cloudfilt(uplink, user) + uplink.mod_utils.action_scan_client_with_cloudfilt(uplink, user) list_to_remove.append(user) - sleep(1) + await asyncio.sleep(1) for user_model in list_to_remove: uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model) - sleep(1) + await asyncio.sleep(1) -def thread_freeipapi_scan(uplink: 'Defender'): +async def coro_freeipapi_scan(uplink: 'Defender'): while uplink.freeipapi_isRunning: list_to_remove: list = [] for user in uplink.Schemas.DB_FREEIPAPI_USERS: - uplink.Utils.action_scan_client_with_freeipapi(uplink, user) + uplink.mod_utils.action_scan_client_with_freeipapi(uplink, user) list_to_remove.append(user) - sleep(1) + await asyncio.sleep(1) for user_model in list_to_remove: uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model) - sleep(1) + await asyncio.sleep(1) -def thread_abuseipdb_scan(uplink: 'Defender'): +async def coro_abuseipdb_scan(uplink: 'Defender'): while uplink.abuseipdb_isRunning: list_to_remove: list = [] for user in uplink.Schemas.DB_ABUSEIPDB_USERS: - uplink.Utils.action_scan_client_with_abuseipdb(uplink, user) + uplink.mod_utils.action_scan_client_with_abuseipdb(uplink, user) list_to_remove.append(user) - sleep(1) + await asyncio.sleep(1) for user_model in list_to_remove: uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model) - sleep(1) + await asyncio.sleep(1) -def thread_local_scan(uplink: 'Defender'): +async def coro_local_scan(uplink: 'Defender'): while uplink.localscan_isRunning: list_to_remove:list = [] for user in uplink.Schemas.DB_LOCALSCAN_USERS: - uplink.Utils.action_scan_client_with_local_socket(uplink, user) + uplink.mod_utils.action_scan_client_with_local_socket(uplink, user) list_to_remove.append(user) - sleep(1) + await asyncio.sleep(1) for user_model in list_to_remove: uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model) - sleep(1) + await asyncio.sleep(1) -def thread_psutil_scan(uplink: 'Defender'): +async def coro_psutil_scan(uplink: 'Defender'): while uplink.psutil_isRunning: list_to_remove:list = [] for user in uplink.Schemas.DB_PSUTIL_USERS: - uplink.Utils.action_scan_client_with_psutil(uplink, user) + uplink.mod_utils.action_scan_client_with_psutil(uplink, user) list_to_remove.append(user) - sleep(1) + await asyncio.sleep(1) for user_model in list_to_remove: uplink.Schemas.DB_PSUTIL_USERS.remove(user_model) - sleep(1) + await asyncio.sleep(1) -def thread_autolimit(uplink: 'Defender'): +async def coro_autolimit(uplink: 'Defender'): - if uplink.ModConfig.autolimit == 0: - uplink.Logs.debug("autolimit deactivated ... canceling the thread") + if uplink.mod_config.autolimit == 0: + uplink.ctx.Logs.debug("autolimit deactivated ... canceling the thread") return None - while uplink.Irc.autolimit_started: - sleep(0.2) + while uplink.ctx.Irc.autolimit_started: + await asyncio.sleep(0.2) - uplink.Irc.autolimit_started = True - init_amount = uplink.ModConfig.autolimit_amount - p = uplink.Protocol + uplink.ctx.Irc.autolimit_started = True + init_amount = uplink.mod_config.autolimit_amount + p = uplink.ctx.Irc.Protocol 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 uplink.Channel.UID_CHANNEL_DB] - chan_list: list[str] = [c.name for c in uplink.Channel.UID_CHANNEL_DB] + chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in uplink.ctx.Channel.UID_CHANNEL_DB] + chan_list: list[str] = [c.name for c in uplink.ctx.Channel.UID_CHANNEL_DB] while uplink.autolimit_isRunning: - if uplink.ModConfig.autolimit == 0: - uplink.Logs.debug("autolimit deactivated ... stopping the current thread") + if uplink.mod_config.autolimit == 0: + uplink.ctx.Logs.debug("autolimit deactivated ... stopping the current thread") break - for chan in uplink.Channel.UID_CHANNEL_DB: + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: for chan_copy in chanObj_copy: if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]: - p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}") + await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}") chan_copy["uids_count"] = len(chan.uids) if chan.name not in chan_list: @@ -117,51 +118,55 @@ def thread_autolimit(uplink: 'Defender'): chanObj_copy.append({"name": chan.name, "uids_count": 0}) # Verifier si un salon a été vidé - current_chan_in_list = [d.name for d in uplink.Channel.UID_CHANNEL_DB] + current_chan_in_list = [d.name for d in uplink.ctx.Channel.UID_CHANNEL_DB] for c in chan_list: if c not in current_chan_in_list: chan_list.remove(c) # Si c'est la premiere execution if INIT == 1: - for chan in uplink.Channel.UID_CHANNEL_DB: - p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}") + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: + await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}") # Si le nouveau amount est différent de l'initial - if init_amount != uplink.ModConfig.autolimit_amount: - init_amount = uplink.ModConfig.autolimit_amount - for chan in uplink.Channel.UID_CHANNEL_DB: - p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}") + if init_amount != uplink.mod_config.autolimit_amount: + init_amount = uplink.mod_config.autolimit_amount + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: + await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}") INIT = 0 if uplink.autolimit_isRunning: - sleep(uplink.ModConfig.autolimit_interval) + await asyncio.sleep(uplink.mod_config.autolimit_interval) - for chan in uplink.Channel.UID_CHANNEL_DB: - p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} -l") + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: + # await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} -l") + await p.send_set_mode('-l', channel_name=chan.name) - uplink.Irc.autolimit_started = False + uplink.ctx.Irc.autolimit_started = False return None -def timer_release_mode_mute(uplink: 'Defender', action: str, channel: str): - """DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING +async def coro_release_mode_mute(uplink: 'Defender', action: str, channel: str): + """DO NOT EXECUTE THIS FUNCTION DIRECTLY + IT WILL BLOCK THE PROCESS Args: - action (str): _description_ + action (str): mode-m channel (str): The related channel """ - service_id = uplink.Config.SERVICE_ID + service_id = uplink.ctx.Config.SERVICE_ID + timeout = uplink.mod_config.flood_timer + await asyncio.sleep(timeout) - if not uplink.Channel.is_valid_channel(channel): - uplink.Logs.debug(f"Channel is not valid {channel}") + if not uplink.ctx.Channel.is_valid_channel(channel): + uplink.ctx.Logs.debug(f"Channel is not valid {channel}") return match action: case 'mode-m': # Action -m sur le salon - uplink.Protocol.send2socket(f":{service_id} MODE {channel} -m") + await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel} -m") case _: pass diff --git a/mods/defender/utils.py b/mods/defender/utils.py index a930600..a880a42 100644 --- a/mods/defender/utils.py +++ b/mods/defender/utils.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Optional from mods.defender.schemas import FloodUser if TYPE_CHECKING: + from core.loader import Loader from core.definition import MUser from mods.defender.mod_defender import Defender @@ -28,10 +29,10 @@ def handle_on_reputation(uplink: 'Defender', srvmsg: list[str]): return # Possibilité de déclancher les bans a ce niveau. - if not uplink.Base.is_valid_ip(ip): + if not uplink.ctx.Base.is_valid_ip(ip): return -def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): +async def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): """_summary_ >>> srvmsg = ['@unrealircd.org/...', ':001C0MF01', 'MODE', '#services', '+l', '1'] >>> srvmsg = ['...', ':001XSCU0Q', 'MODE', '#jail', '+b', '~security-group:unknown-users'] @@ -40,10 +41,10 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): srvmsg (list[str]): The Server MSG confmodel (ModConfModel): The Module Configuration """ - irc = uplink.Irc - gconfig = uplink.Config - p = uplink.Protocol - confmodel = uplink.ModConfig + irc = uplink.ctx.Irc + gconfig = uplink.ctx.Config + p = irc.Protocol + confmodel = uplink.mod_config channel = str(srvmsg[3]) mode = str(srvmsg[4]) @@ -52,25 +53,25 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]): if confmodel.autolimit == 1: if mode == '+l' or mode == '-l': - chan = irc.Channel.get_channel(channel) - p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}") + chan = uplink.ctx.Channel.get_channel(channel) + await p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}") if gconfig.SALON_JAIL == channel: if mode == '+b' and group_to_unban in group_to_check: - p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users") - p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + await p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users") + await p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") -def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]): +async def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]): # ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg'] - sender, reciever, channel, message = uplink.Protocol.parse_privmsg(srvmsg) - if uplink.ModConfig.sentinel == 1 and channel.name != uplink.Config.SERVICE_CHANLOG: - uplink.Protocol.send_priv_msg(uplink.Config.SERVICE_NICKNAME, f"{sender.nickname} say on {channel.name}: {' '.join(message)}", uplink.Config.SERVICE_CHANLOG) + sender, reciever, channel, message = uplink.ctx.Irc.Protocol.parse_privmsg(srvmsg) + if uplink.mod_config.sentinel == 1 and channel.name != uplink.ctx.Config.SERVICE_CHANLOG: + await uplink.ctx.Irc.Protocol.send_priv_msg(uplink.ctx.Config.SERVICE_NICKNAME, f"{sender.nickname} say on {channel.name}: {' '.join(message)}", uplink.ctx.Config.SERVICE_CHANLOG) - action_on_flood(uplink, srvmsg) + await action_on_flood(uplink, srvmsg) return None -def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]): +async def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]): """If Joining a new channel, it applies group bans. >>> srvmsg = ['@msgid..', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL'] @@ -80,37 +81,37 @@ def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]): srvmsg (list[str]): The Server MSG confmodel (ModConfModel): The Module Configuration """ - irc = uplink.Irc + irc = uplink.ctx.Irc p = irc.Protocol - gconfig = uplink.Config - confmodel = uplink.ModConfig + gconfig = uplink.ctx.Config + confmodel = uplink.mod_config - parsed_chan = srvmsg[4] if irc.Channel.is_valid_channel(srvmsg[4]) else None - parsed_UID = uplink.Loader.Utils.clean_uid(srvmsg[5]) + parsed_chan = srvmsg[4] if uplink.ctx.Channel.is_valid_channel(srvmsg[4]) else None + parsed_UID = uplink.ctx.Utils.clean_uid(srvmsg[5]) if parsed_chan is None or parsed_UID is None: return if confmodel.reputation == 1: - get_reputation = irc.Reputation.get_reputation(parsed_UID) + get_reputation = uplink.ctx.Reputation.get_reputation(parsed_UID) if parsed_chan != gconfig.SALON_JAIL: - p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users") - p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") + await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users") + await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") if get_reputation is not None: isWebirc = get_reputation.isWebirc if not isWebirc: if parsed_chan != gconfig.SALON_JAIL: - p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan) + await p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan) if confmodel.reputation_ban_all_chan == 1 and not isWebirc: if parsed_chan != gconfig.SALON_JAIL: - p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*") - p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}") + await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*") + await p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}") - irc.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}') + uplink.ctx.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}') def handle_on_slog(uplink: 'Defender', srvmsg: list[str]): """Handling SLOG messages @@ -122,27 +123,27 @@ def handle_on_slog(uplink: 'Defender', srvmsg: list[str]): """ ['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)'] - if not uplink.Base.is_valid_ip(srvmsg[8]): + if not uplink.ctx.Base.is_valid_ip(srvmsg[8]): return None - # if self.ModConfig.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: + # if self.mod_config.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # self.localscan_remote_ip.append(cmd[7]) - # if self.ModConfig.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: + # if self.mod_config.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # self.psutil_remote_ip.append(cmd[7]) - # if self.ModConfig.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: + # if self.mod_config.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # self.abuseipdb_remote_ip.append(cmd[7]) - # if self.ModConfig.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: + # if self.mod_config.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # self.freeipapi_remote_ip.append(cmd[7]) - # if self.ModConfig.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: + # if self.mod_config.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP: # self.cloudfilt_remote_ip.append(cmd[7]) return None -def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): +async def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): """Handle nickname changes. >>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712'] >>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740'] @@ -151,22 +152,22 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): srvmsg (list[str]): The Server MSG confmodel (ModConfModel): The Module Configuration """ - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol u, new_nickname, timestamp = p.parse_nick(srvmsg) if u is None: - uplink.Logs.error(f"[USER OBJ ERROR {timestamp}] - {srvmsg}") + uplink.ctx.Logs.error(f"[USER OBJ ERROR {timestamp}] - {srvmsg}") return None uid = u.uid - confmodel = uplink.ModConfig + confmodel = uplink.mod_config - get_reputation = uplink.Reputation.get_reputation(uid) - jail_salon = uplink.Config.SALON_JAIL - service_id = uplink.Config.SERVICE_ID + get_reputation = uplink.ctx.Reputation.get_reputation(uid) + jail_salon = uplink.ctx.Config.SALON_JAIL + service_id = uplink.ctx.Config.SERVICE_ID if get_reputation is None: - uplink.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass') + uplink.ctx.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass') return None # Update the new nickname @@ -176,42 +177,42 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]): # If ban in all channel is ON then unban old nickname an ban the new nickname if confmodel.reputation_ban_all_chan == 1: - for chan in uplink.Channel.UID_CHANNEL_DB: + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: if chan.name != jail_salon: - p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*") - p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*") + await p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*") + await p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*") -def handle_on_quit(uplink: 'Defender', srvmsg: list[str]): +async def handle_on_quit(uplink: 'Defender', srvmsg: list[str]): """Handle on quit message >>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'QUIT', ':Quit:', 'quit message'] Args: uplink (Irc): The Defender Module instance srvmsg (list[str]): The Server MSG """ - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol userobj, reason = p.parse_quit(srvmsg) - confmodel = uplink.ModConfig + confmodel = uplink.mod_config if userobj is None: - uplink.Logs.debug(f"This UID do not exist anymore: {srvmsg}") + uplink.ctx.Logs.debug(f"This UID do not exist anymore: {srvmsg}") return None - ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan) - jail_salon = uplink.Config.SALON_JAIL - service_id = uplink.Config.SERVICE_ID - get_user_reputation = uplink.Reputation.get_reputation(userobj.uid) + ban_all_chan = uplink.ctx.Base.int_if_possible(confmodel.reputation_ban_all_chan) + jail_salon = uplink.ctx.Config.SALON_JAIL + service_id = uplink.ctx.Config.SERVICE_ID + get_user_reputation = uplink.ctx.Reputation.get_reputation(userobj.uid) if get_user_reputation is not None: final_nickname = get_user_reputation.nickname - for chan in uplink.Channel.UID_CHANNEL_DB: + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: if chan.name != jail_salon and ban_all_chan == 1: - p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*") - uplink.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}") + await p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*") + uplink.ctx.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}") - uplink.Reputation.delete(userobj.uid) - uplink.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB") + uplink.ctx.Reputation.delete(userobj.uid) + uplink.ctx.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB") -def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): +async def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): """_summary_ >>> ['@s2s-md...', ':001', 'UID', 'nickname', '0', '1754675249', '...', '125-168-141-239.hostname.net', '001BAPN8M', '0', '+iwx', '*', '32001BBE.25ACEFE7.429FE90D.IP', 'ZA2ic7w==', ':realname'] @@ -220,10 +221,10 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): uplink (Defender): The Defender instance srvmsg (list[str]): The Server MSG """ - _User = uplink.Protocol.parse_uid(srvmsg) - gconfig = uplink.Config - irc = uplink.Irc - confmodel = uplink.ModConfig + irc = uplink.ctx.Irc + _User = irc.Protocol.parse_uid(srvmsg) + gconfig = uplink.ctx.Config + confmodel = uplink.mod_config # If Init then do nothing if gconfig.DEFENDER_INIT == 1: @@ -231,7 +232,7 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): # Get User information if _User is None: - irc.Logs.warning(f'Error when parsing UID', exc_info=True) + uplink.ctx.Logs.warning(f'Error when parsing UID', exc_info=True) return # If user is not service or IrcOp then scan them @@ -250,38 +251,38 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]): if not match(r'^.*[S|o?].*$', _User.umodes): if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: # currentDateTime = self.Base.get_datetime() - irc.Reputation.insert( - irc.Loader.Definition.MReputation( + uplink.ctx.Reputation.insert( + uplink.ctx.Definition.MReputation( **_User.to_dict(), - secret_code=irc.Utils.generate_random_string(8) + secret_code=uplink.ctx.Utils.generate_random_string(8) ) ) - if irc.Reputation.is_exist(_User.uid): + if uplink.ctx.Reputation.is_exist(_User.uid): if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: - action_add_reputation_sanctions(uplink, _User.uid) - irc.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})') + await action_add_reputation_sanctions(uplink, _User.uid) + uplink.ctx.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})') #################### # ACTION FUNCTIONS # #################### # [:] UID []+ : # [:] UID nickname hopcount timestamp username hostname uid servicestamp umodes virthost cloakedhost ip :gecos -def action_on_flood(uplink: 'Defender', srvmsg: list[str]): +async def action_on_flood(uplink: 'Defender', srvmsg: list[str]): - confmodel = uplink.ModConfig + confmodel = uplink.mod_config if confmodel.flood == 0: return None - irc = uplink.Irc - gconfig = uplink.Config - p = uplink.Protocol + irc = uplink.ctx.Irc + gconfig = uplink.ctx.Config + p = irc.Protocol flood_users = uplink.Schemas.DB_FLOOD_USERS user_trigger = str(srvmsg[1]).replace(':','') channel = srvmsg[3] - User = irc.User.get_user(user_trigger) + User = uplink.ctx.User.get_user(user_trigger) - if User is None or not irc.Channel.is_valid_channel(channel_to_check=channel): + if User is None or not uplink.ctx.Channel.is_valid_channel(channel_to_check=channel): return flood_time = confmodel.flood_time @@ -294,7 +295,7 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]): get_detected_uid = User.uid get_detected_nickname = User.nickname - unixtime = irc.Utils.get_unixtime() + unixtime = uplink.ctx.Utils.get_unixtime() get_diff_secondes = 0 def get_flood_user(uid: str) -> Optional[FloodUser]: @@ -315,29 +316,29 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]): fu.nbr_msg = 0 get_diff_secondes = unixtime - fu.first_msg_time elif fu.nbr_msg > flood_message: - irc.Logs.info('system de flood detecté') - p.send_priv_msg( + uplink.ctx.Logs.info('system de flood detecté') + await p.send_priv_msg( nick_from=dnickname, msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)", channel=channel ) - p.send2socket(f":{service_id} MODE {channel} +m") - irc.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}') + await p.send2socket(f":{service_id} MODE {channel} +m") + uplink.ctx.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}') fu.nbr_msg = 0 fu.first_msg_time = unixtime - irc.Base.create_timer(flood_timer, dthreads.timer_release_mode_mute, (uplink, 'mode-m', channel)) + uplink.ctx.Base.create_asynctask(dthreads.coro_release_mode_mute(uplink, 'mode-m', channel)) -def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ): +async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ): - irc = uplink.Irc - gconfig = uplink.Config - p = uplink.Protocol - confmodel = uplink.ModConfig + irc = uplink.ctx.Irc + gconfig = uplink.ctx.Config + p = irc.Protocol + confmodel = uplink.mod_config - get_reputation = irc.Reputation.get_reputation(jailed_uid) + get_reputation = uplink.ctx.Reputation.get_reputation(jailed_uid) if get_reputation is None: - irc.Logs.warning(f'UID {jailed_uid} has not been found') + uplink.ctx.Logs.warning(f'UID {jailed_uid} has not been found') return salon_logs = gconfig.SERVICE_CHANLOG @@ -357,33 +358,33 @@ def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ): if not get_reputation.isWebirc: # Si le user ne vient pas de webIrc - p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail) - p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME, + await p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail) + await p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME, msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}", channel=salon_logs ) - p.send_notice( + await p.send_notice( nick_from=gconfig.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 irc.Channel.UID_CHANNEL_DB: + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: if chan.name != salon_jail: - p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*") - p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}") + await p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*") + await p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}") - irc.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})") + uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})") else: - irc.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)") - irc.Reputation.delete(jailed_uid) + uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)") + uplink.ctx.Reputation.delete(jailed_uid) -def action_apply_reputation_santions(uplink: 'Defender') -> None: +async def action_apply_reputation_santions(uplink: 'Defender') -> None: - irc = uplink.Irc - gconfig = uplink.Config - p = uplink.Protocol - confmodel = uplink.ModConfig + irc = uplink.ctx.Irc + gconfig = uplink.ctx.Config + p = irc.Protocol + confmodel = uplink.mod_config reputation_flag = confmodel.reputation reputation_timer = confmodel.reputation_timer @@ -396,36 +397,36 @@ def action_apply_reputation_santions(uplink: 'Defender') -> None: salon_jail = gconfig.SALON_JAIL uid_to_clean = [] - if reputation_flag == 0 or reputation_timer == 0 or not irc.Reputation.UID_REPUTATION_DB: + if reputation_flag == 0 or reputation_timer == 0 or not uplink.ctx.Reputation.UID_REPUTATION_DB: return None - for user in irc.Reputation.UID_REPUTATION_DB: + for user in uplink.ctx.Reputation.UID_REPUTATION_DB: if not user.isWebirc: # Si il ne vient pas de WebIRC - if irc.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil): - p.send_priv_msg( + if uplink.ctx.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil): + await p.send_priv_msg( nick_from=service_id, msg=f"[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité", channel=dchanlog ) - p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code") - p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0") + await p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code") + await p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0") - irc.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity") + uplink.ctx.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity") uid_to_clean.append(user.uid) for uid in uid_to_clean: # Suppression des éléments dans {UID_DB} et {REPUTATION_DB} - for chan in irc.Channel.UID_CHANNEL_DB: + for chan in uplink.ctx.Channel.UID_CHANNEL_DB: if chan.name != salon_jail and ban_all_chan == 1: - get_user_reputation = irc.Reputation.get_reputation(uid) - p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*") + get_user_reputation = uplink.ctx.Reputation.get_reputation(uid) + await p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*") # Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}. - irc.Channel.delete_user_from_all_channel(uid) - irc.Reputation.delete(uid) - irc.User.delete(uid) + uplink.ctx.Channel.delete_user_from_all_channel(uid) + uplink.ctx.Reputation.delete(uid) + uplink.ctx.User.delete(uid) -def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: +async def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: """Analyse l'ip avec cloudfilt Cette methode devra etre lancer toujours via un thread ou un timer. Args: @@ -440,19 +441,19 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') - username = user_model.username hostname = user_model.hostname nickname = user_model.nickname - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol - if remote_ip in uplink.Config.WHITELISTED_IP: + if remote_ip in uplink.ctx.Config.WHITELISTED_IP: return None - if uplink.ModConfig.cloudfilt_scan == 0: + if uplink.mod_config.cloudfilt_scan == 0: return None if uplink.cloudfilt_key == '': return None - service_id = uplink.Config.SERVICE_ID - service_chanlog = uplink.Config.SERVICE_CHANLOG - color_red = uplink.Config.COLORS.red - nogc = uplink.Config.COLORS.nogc + service_id = uplink.ctx.Config.SERVICE_ID + service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG + color_red = uplink.ctx.Config.COLORS.red + nogc = uplink.ctx.Config.COLORS.nogc url = "https://developers18334.cloudfilt.com/" @@ -466,7 +467,7 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') - decoded_response: dict = loads(response.text) status_code = response.status_code if status_code != 200: - uplink.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}') + uplink.ctx.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}') return result = { @@ -479,22 +480,22 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') - # pseudo!ident@host fullname = f'{nickname}!{username}@{hostname}' - p.send_priv_msg( + await p.send_priv_msg( 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) - uplink.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}") + uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}") if result['listed']: - p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt") - uplink.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}") + await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt") + uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}") response.close() return result -def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: +async def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: """Analyse l'ip avec Freeipapi Cette methode devra etre lancer toujours via un thread ou un timer. Args: @@ -504,21 +505,21 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') - dict[str, any] | None: les informations du provider keys : 'countryCode', 'isProxy' """ - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol remote_ip = user_model.remote_ip username = user_model.username hostname = user_model.hostname nickname = user_model.nickname - if remote_ip in uplink.Config.WHITELISTED_IP: + if remote_ip in uplink.ctx.Config.WHITELISTED_IP: return None - if uplink.ModConfig.freeipapi_scan == 0: + if uplink.mod_config.freeipapi_scan == 0: return None - service_id = uplink.Config.SERVICE_ID - service_chanlog = uplink.Config.SERVICE_CHANLOG - color_red = uplink.Config.COLORS.red - nogc = uplink.Config.COLORS.nogc + service_id = uplink.ctx.Config.SERVICE_ID + service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG + color_red = uplink.ctx.Config.COLORS.red + nogc = uplink.ctx.Config.COLORS.nogc url = f'https://freeipapi.com/api/json/{remote_ip}' @@ -533,10 +534,10 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') - status_code = response.status_code if status_code == 429: - uplink.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.') + uplink.ctx.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.') return None elif status_code != 200: - uplink.Logs.warning(f'status code = {str(status_code)}') + uplink.ctx.Logs.warning(f'status code = {str(status_code)}') return None result = { @@ -547,21 +548,21 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') - # pseudo!ident@host fullname = f'{nickname}!{username}@{hostname}' - p.send_priv_msg( + await p.send_priv_msg( 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) - uplink.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}") + uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}") if result['isProxy']: - p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi") - uplink.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}") + await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi") + uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}") response.close() return result -def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: +async def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]: """Analyse l'ip avec AbuseIpDB Cette methode devra etre lancer toujours via un thread ou un timer. Args: @@ -571,15 +572,15 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') - Returns: dict[str, str] | None: les informations du provider """ - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol remote_ip = user_model.remote_ip username = user_model.username hostname = user_model.hostname nickname = user_model.nickname - if remote_ip in uplink.Config.WHITELISTED_IP: + if remote_ip in uplink.ctx.Config.WHITELISTED_IP: return None - if uplink.ModConfig.abuseipdb_scan == 0: + if uplink.mod_config.abuseipdb_scan == 0: return None if uplink.abuseipdb_key == '': @@ -611,81 +612,81 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') - 'totalReports': decoded_response.get('data', {}).get('totalReports', 0) } - service_id = uplink.Config.SERVICE_ID - service_chanlog = uplink.Config.SERVICE_CHANLOG - color_red = uplink.Config.COLORS.red - nogc = uplink.Config.COLORS.nogc + service_id = uplink.ctx.Config.SERVICE_ID + service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG + color_red = uplink.ctx.Config.COLORS.red + nogc = uplink.ctx.Config.COLORS.nogc # pseudo!ident@host fullname = f'{nickname}!{username}@{hostname}' - p.send_priv_msg( + await p.send_priv_msg( 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 ) - uplink.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}") + uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}") if result['isTor']: - p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb") - uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}") + await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb") + uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}") elif result['score'] >= 95: - p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb") - uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}") + await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb") + uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}") response.close() return result -def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'): +async def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'): """local_scan Args: uplink (Defender): Defender instance object user_model (MUser): l'objet User qui contient l'ip """ - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol remote_ip = user_model.remote_ip username = user_model.username hostname = user_model.hostname nickname = user_model.nickname fullname = f'{nickname}!{username}@{hostname}' - if remote_ip in uplink.Config.WHITELISTED_IP: + if remote_ip in uplink.ctx.Config.WHITELISTED_IP: return None - for port in uplink.Config.PORTS_TO_SCAN: + for port in uplink.ctx.Config.PORTS_TO_SCAN: try: newSocket = '' newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK) newSocket.settimeout(0.5) - connection = (remote_ip, uplink.Base.int_if_possible(port)) + connection = (remote_ip, uplink.ctx.Base.int_if_possible(port)) newSocket.connect(connection) - p.send_priv_msg( - nick_from=uplink.Config.SERVICE_NICKNAME, - msg=f"[ {uplink.Config.COLORS.red}PROXY_SCAN{uplink.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]", - channel=uplink.Config.SERVICE_CHANLOG + await p.send_priv_msg( + nick_from=uplink.ctx.Config.SERVICE_NICKNAME, + msg=f"[ {uplink.ctx.Config.COLORS.red}PROXY_SCAN{uplink.ctx.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]", + channel=uplink.ctx.Config.SERVICE_CHANLOG ) # print(f"=======> Le port {str(port)} est ouvert !!") - uplink.Base.running_sockets.append(newSocket) + uplink.ctx.Base.running_sockets.append(newSocket) # print(newSocket) newSocket.shutdown(socket.SHUT_RDWR) newSocket.close() except (socket.timeout, ConnectionRefusedError): - uplink.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé") + uplink.ctx.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé") except AttributeError as ae: - uplink.Logs.warning(f"AttributeError ({remote_ip}): {ae}") + uplink.ctx.Logs.warning(f"AttributeError ({remote_ip}): {ae}") except socket.gaierror as err: - uplink.Logs.warning(f"Address Info Error ({remote_ip}): {err}") + uplink.ctx.Logs.warning(f"Address Info Error ({remote_ip}): {err}") finally: # newSocket.shutdown(socket.SHUT_RDWR) newSocket.close() - uplink.Logs.info('=======> Fermeture de la socket') + uplink.ctx.Logs.info('=======> Fermeture de la socket') -def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]: +async def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]: """psutil_scan for Linux (should be run on the same location as the unrealircd server) Args: @@ -694,13 +695,13 @@ def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> l Returns: list[int]: list of ports """ - p = uplink.Protocol + p = uplink.ctx.Irc.Protocol remote_ip = user_model.remote_ip username = user_model.username hostname = user_model.hostname nickname = user_model.nickname - if remote_ip in uplink.Config.WHITELISTED_IP: + if remote_ip in uplink.ctx.Config.WHITELISTED_IP: return None try: @@ -708,16 +709,16 @@ def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> l fullname = f'{nickname}!{username}@{hostname}' matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip] - uplink.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}") + uplink.ctx.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}") if matching_ports: - p.send_priv_msg( - nick_from=uplink.Config.SERVICE_NICKNAME, - msg=f"[ {uplink.Config.COLORS.red}PSUTIL_SCAN{uplink.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}", - channel=uplink.Config.SERVICE_CHANLOG + await p.send_priv_msg( + nick_from=uplink.ctx.Config.SERVICE_NICKNAME, + msg=f"[ {uplink.ctx.Config.COLORS.red}PSUTIL_SCAN{uplink.ctx.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}", + channel=uplink.ctx.Config.SERVICE_CHANLOG ) return matching_ports except psutil.AccessDenied as ad: - uplink.Logs.critical(f'psutil_scan: Permission error: {ad}') \ No newline at end of file + uplink.ctx.Logs.critical(f'psutil_scan: Permission error: {ad}') \ No newline at end of file diff --git a/mods/test/mod_test.py b/mods/test/mod_test.py index 4b8aac7..f4dd35f 100644 --- a/mods/test/mod_test.py +++ b/mods/test/mod_test.py @@ -48,7 +48,7 @@ class Test(IModule): # self.ctx.Base.db_execute_query(table_logs) return None - def load(self) -> None: + async def load(self) -> None: """### Load Module Configuration (Mandatory) """ @@ -62,8 +62,11 @@ class Test(IModule): # Build the default configuration model (Mandatory) self._mod_config = self.ModConfModel(param_exemple1='str', param_exemple2=1) - # Init the module (Mandatory) - self.init() + # sync the database with local variable (Mandatory) + await self.sync_db() + + if self.mod_config.param_exemple2 == 1: + await self.ctx.Irc.Protocol.send_priv_msg(self.ctx.Config.SERVICE_NICKNAME, "Param activated", self.ctx.Config.SERVICE_CHANLOG) @property def mod_config(self) -> ModConfModel: @@ -71,7 +74,7 @@ class Test(IModule): def unload(self) -> None: """### This method is called when you unload, or you reload the module (Mandatory)""" - self.ctx.Irc.Commands.drop_command_by_module(self.module_name) + self.ctx.Commands.drop_command_by_module(self.module_name) return None def cmd(self, data: list[str]) -> None: diff --git a/requirements.txt b/requirements.txt index 005b826..c0408c3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,6 @@ psutil==7.1.2 PyYAML==6.0.3 requests==2.32.5 SQLAlchemy==2.0.44 -unrealircd_rpc_py==3.0.2 \ No newline at end of file +unrealircd_rpc_py==3.0.2 +starlette==0.50.0 +uvicorn==0.38.0 \ No newline at end of file diff --git a/version.json b/version.json index f8598c8..18a4577 100644 --- a/version.json +++ b/version.json @@ -1,10 +1,12 @@ { - "version": "6.3.3", + "version": "6.4.0", "requests": "2.32.5", "psutil": "7.1.2", "unrealircd_rpc_py": "3.0.1", "sqlalchemy": "2.0.44", "faker": "37.12.0", - "pyyaml": "6.0.3" + "pyyaml": "6.0.3", + "starlette":"0.50.0", + "uvicorn":"0.38.0" } From 51f709e4a1cd191e9c1b25bc963205fa586d9f7c Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:02:45 +0100 Subject: [PATCH 50/56] Final main file --- core/classes/interfaces/irpc_endpoint.py | 34 +++++++++++++ core/classes/modules/rpc/rpc.py | 64 +++++------------------- core/classes/modules/rpc/rpc_channel.py | 15 ++++-- core/classes/modules/rpc/rpc_command.py | 47 +++++++++++------ core/classes/modules/rpc/rpc_errors.py | 43 ++++++++++++++++ core/classes/modules/rpc/rpc_user.py | 35 +++++++++---- defender.py | 6 ++- 7 files changed, 159 insertions(+), 85 deletions(-) create mode 100644 core/classes/interfaces/irpc_endpoint.py create mode 100644 core/classes/modules/rpc/rpc_errors.py diff --git a/core/classes/interfaces/irpc_endpoint.py b/core/classes/interfaces/irpc_endpoint.py new file mode 100644 index 0000000..0f5d0b4 --- /dev/null +++ b/core/classes/interfaces/irpc_endpoint.py @@ -0,0 +1,34 @@ +import starlette.status as http_status_code +from typing import TYPE_CHECKING +from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode + +if TYPE_CHECKING: + from core.loader import Loader + +class IRPC: + + def __init__(self, loader: 'Loader'): + self.ctx = loader + self.http_status_code = http_status_code + self.response_model = { + "jsonrpc": "2.0", + "id": 123 + } + + def reset(self): + self.response_model = { + "jsonrpc": "2.0", + "id": 123 + } + + def create_error_response(self, error_code: JSONRPCErrorCode, details: dict = None) -> dict[str, str]: + """Create a JSON-RPC error!""" + response = { + "code": error_code.value, + "message": error_code.description(), + } + + if details: + response["data"] = details + + return response \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc.py b/core/classes/modules/rpc/rpc.py index b26e34e..1b6646d 100644 --- a/core/classes/modules/rpc/rpc.py +++ b/core/classes/modules/rpc/rpc.py @@ -1,11 +1,12 @@ import base64 import json +import uvicorn +import core.classes.modules.rpc.rpc_errors as rpcerr +import starlette.status as http_status_code from starlette.applications import Starlette from starlette.responses import JSONResponse from starlette.requests import Request from starlette.routing import Route -import uvicorn -from enum import Enum from typing import TYPE_CHECKING, Any, Optional from core.classes.modules.rpc.rpc_user import RPCUser from core.classes.modules.rpc.rpc_channel import RPCChannel @@ -82,15 +83,17 @@ class JSonRpcServer: response_data['method'] = method rip = request.client.host rport = request.client.port - http_code = 200 + http_code = http_status_code.HTTP_200_OK if method in self.methods: - response_data['result'] = self.methods[method](**params) - return JSONResponse(response_data, http_code) + r: JSONResponse = self.methods[method](**params) + resp = json.loads(r.body) + resp['id'] = request_data.get('id', 123) + return JSONResponse(resp, r.status_code) - response_data['error'] = create_error_response(JSONRPCErrorCode.METHOD_NOT_FOUND) + response_data['error'] = rpcerr.create_error_response(rpcerr.JSONRPCErrorCode.METHOD_NOT_FOUND) self._ctx.Logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}') - http_code = 404 + http_code = http_status_code.HTTP_404_NOT_FOUND return JSONResponse(response_data, http_code) def authenticate(self, headers: dict, body: dict) -> JSONResponse: @@ -131,49 +134,6 @@ class JSonRpcServer: response_data = { 'jsonrpc': '2.0', 'id': request_data.get('id', 123), - 'error': create_error_response(JSONRPCErrorCode.AUTHENTICATION_ERROR) + 'error': rpcerr.create_error_response(rpcerr.JSONRPCErrorCode.AUTHENTICATION_ERROR) } - return JSONResponse(response_data) - - -class JSONRPCErrorCode(Enum): - PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON) - INVALID_REQUEST = -32600 # Invalid Request (incorrect structure or missing fields) - METHOD_NOT_FOUND = -32601 # Method not found (the requested method does not exist) - INVALID_PARAMS = -32602 # Invalid Params (the parameters provided are incorrect) - INTERNAL_ERROR = -32603 # Internal Error (an internal server error occurred) - - # Custom application-specific errors (beyond standard JSON-RPC codes) - CUSTOM_ERROR = 1001 # Custom application-defined error (e.g., user not found) - AUTHENTICATION_ERROR = 1002 # Authentication failure (e.g., invalid credentials) - PERMISSION_ERROR = 1003 # Permission error (e.g., user does not have access to this method) - RESOURCE_NOT_FOUND = 1004 # Resource not found (e.g., the requested resource does not exist) - DUPLICATE_REQUEST = 1005 # Duplicate request (e.g., a similar request has already been processed) - - def description(self): - """Returns a description associated with each error code""" - descriptions = { - JSONRPCErrorCode.PARSE_ERROR: "The JSON request is malformed.", - JSONRPCErrorCode.INVALID_REQUEST: "The request is invalid (missing or incorrect fields).", - JSONRPCErrorCode.METHOD_NOT_FOUND: "The requested method could not be found.", - JSONRPCErrorCode.INVALID_PARAMS: "The parameters provided are invalid.", - JSONRPCErrorCode.INTERNAL_ERROR: "An internal error occurred on the server.", - JSONRPCErrorCode.CUSTOM_ERROR: "A custom error defined by the application.", - JSONRPCErrorCode.AUTHENTICATION_ERROR: "User authentication failed.", - JSONRPCErrorCode.PERMISSION_ERROR: "User does not have permission to access this method.", - JSONRPCErrorCode.RESOURCE_NOT_FOUND: "The requested resource could not be found.", - JSONRPCErrorCode.DUPLICATE_REQUEST: "The request is a duplicate or is already being processed.", - } - return descriptions.get(self, "Unknown error") - -def create_error_response(error_code: JSONRPCErrorCode, details: dict = None) -> dict[str, str]: - """Create a JSON-RPC error!""" - response = { - "code": error_code.value, - "message": error_code.description(), - } - - if details: - response["data"] = details - - return response \ No newline at end of file + return JSONResponse(response_data, http_status_code.HTTP_403_FORBIDDEN) diff --git a/core/classes/modules/rpc/rpc_channel.py b/core/classes/modules/rpc/rpc_channel.py index 4f39338..b1388eb 100644 --- a/core/classes/modules/rpc/rpc_channel.py +++ b/core/classes/modules/rpc/rpc_channel.py @@ -1,12 +1,17 @@ from typing import TYPE_CHECKING +from starlette.responses import JSONResponse +from core.classes.interfaces.irpc_endpoint import IRPC +from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode + if TYPE_CHECKING: from core.loader import Loader -class RPCChannel: +class RPCChannel(IRPC): def __init__(self, loader: 'Loader'): - self._Loader = loader - self._Channel = loader.Channel + super().__init__(loader) - def channel_list(self, **kwargs) -> list[dict]: - return [chan.to_dict() for chan in self._Channel.UID_CHANNEL_DB] \ No newline at end of file + def channel_list(self, **kwargs) -> JSONResponse: + self.reset() + self.response_model['result'] = [chan.to_dict() for chan in self.ctx.Channel.UID_CHANNEL_DB] + return JSONResponse(self.response_model) \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_command.py b/core/classes/modules/rpc/rpc_command.py index 230af53..ebf0691 100644 --- a/core/classes/modules/rpc/rpc_command.py +++ b/core/classes/modules/rpc/rpc_command.py @@ -1,29 +1,44 @@ -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING +from starlette.responses import JSONResponse +from core.classes.interfaces.irpc_endpoint import IRPC +from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode if TYPE_CHECKING: from core.loader import Loader -class RPCCommand: +class RPCCommand(IRPC): def __init__(self, loader: 'Loader'): - self._Loader = loader - self._Command = loader.Commands + super().__init__(loader) - def command_list(self, **kwargs) -> list[dict]: - return [command.to_dict() for command in self._Command.DB_COMMANDS] + def command_list(self, **kwargs) -> JSONResponse: + self.reset() + self.response_model['result'] = [command.to_dict() for command in self.ctx.Commands.DB_COMMANDS] + return JSONResponse(self.response_model) - def command_get_by_module(self, **kwargs) -> list[dict]: - module_name = kwargs.get('module_name', None) - if module_name is None: - return [] + def command_get_by_module(self, **kwargs) -> JSONResponse: + self.reset() + module_name: str = kwargs.get('module_name', '') - return [command.to_dict() for command in self._Command.DB_COMMANDS if command.module_name.lower() == module_name.lower()] + if not module_name: + self.response_model['error'] = self.create_error_response(JSONRPCErrorCode.INVALID_PARAMS, {'module_name': 'The param to use is module_name'}) + return JSONResponse(self.response_model, self.http_status_code.HTTP_405_METHOD_NOT_ALLOWED) + + self.response_model['result'] = [command.to_dict() for command in self.ctx.Commands.DB_COMMANDS if command.module_name.lower() == module_name.lower()] + return JSONResponse(self.response_model) + + def command_get_by_name(self, **kwargs) -> JSONResponse: + self.reset() - def command_get_by_name(self, **kwargs) -> dict: command_name: str = kwargs.get('command_name', '') if not command_name: - return dict() + self.response_model['error'] = self.create_error_response(JSONRPCErrorCode.INVALID_PARAMS, {'command_name': f'The param to use is command_name'}) + return JSONResponse(self.response_model, self.http_status_code.HTTP_405_METHOD_NOT_ALLOWED) - for command in self._Command.DB_COMMANDS: + command_to_return: list[dict] = [] + for command in self.ctx.Commands.DB_COMMANDS: if command.command_name.lower() == command_name.lower(): - return command.to_dict() - return dict() \ No newline at end of file + command_to_return.append(command.to_dict()) + + self.response_model['result'] = command_to_return + + return JSONResponse(self.response_model) \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_errors.py b/core/classes/modules/rpc/rpc_errors.py new file mode 100644 index 0000000..dc9fb90 --- /dev/null +++ b/core/classes/modules/rpc/rpc_errors.py @@ -0,0 +1,43 @@ +from enum import Enum + +class JSONRPCErrorCode(Enum): + PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON) + INVALID_REQUEST = -32600 # Invalid Request (incorrect structure or missing fields) + METHOD_NOT_FOUND = -32601 # Method not found (the requested method does not exist) + INVALID_PARAMS = -32602 # Invalid Params (the parameters provided are incorrect) + INTERNAL_ERROR = -32603 # Internal Error (an internal server error occurred) + + # Custom application-specific errors (beyond standard JSON-RPC codes) + CUSTOM_ERROR = 1001 # Custom application-defined error (e.g., user not found) + AUTHENTICATION_ERROR = 1002 # Authentication failure (e.g., invalid credentials) + PERMISSION_ERROR = 1003 # Permission error (e.g., user does not have access to this method) + RESOURCE_NOT_FOUND = 1004 # Resource not found (e.g., the requested resource does not exist) + DUPLICATE_REQUEST = 1005 # Duplicate request (e.g., a similar request has already been processed) + + def description(self): + """Returns a description associated with each error code""" + descriptions = { + JSONRPCErrorCode.PARSE_ERROR: "The JSON request is malformed.", + JSONRPCErrorCode.INVALID_REQUEST: "The request is invalid (missing or incorrect fields).", + JSONRPCErrorCode.METHOD_NOT_FOUND: "The requested method could not be found.", + JSONRPCErrorCode.INVALID_PARAMS: "The parameters provided are invalid.", + JSONRPCErrorCode.INTERNAL_ERROR: "An internal error occurred on the server.", + JSONRPCErrorCode.CUSTOM_ERROR: "A custom error defined by the application.", + JSONRPCErrorCode.AUTHENTICATION_ERROR: "User authentication failed.", + JSONRPCErrorCode.PERMISSION_ERROR: "User does not have permission to access this method.", + JSONRPCErrorCode.RESOURCE_NOT_FOUND: "The requested resource could not be found.", + JSONRPCErrorCode.DUPLICATE_REQUEST: "The request is a duplicate or is already being processed.", + } + return descriptions.get(self, "Unknown error") + +def create_error_response(error_code: JSONRPCErrorCode, details: dict = None) -> dict[str, str]: + """Create a JSON-RPC error!""" + response = { + "code": error_code.value, + "message": error_code.description(), + } + + if details: + response["data"] = details + + return response \ No newline at end of file diff --git a/core/classes/modules/rpc/rpc_user.py b/core/classes/modules/rpc/rpc_user.py index bf8a323..667005a 100644 --- a/core/classes/modules/rpc/rpc_user.py +++ b/core/classes/modules/rpc/rpc_user.py @@ -1,15 +1,20 @@ from typing import TYPE_CHECKING, Optional +from starlette.responses import JSONResponse +from core.classes.interfaces.irpc_endpoint import IRPC +from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode + if TYPE_CHECKING: from core.loader import Loader from core.definition import MUser -class RPCUser: +class RPCUser(IRPC): def __init__(self, loader: 'Loader'): - self._ctx = loader + super().__init__(loader) - def user_list(self, **kwargs) -> list[dict]: - users = self._ctx.User.UID_DB.copy() + def user_list(self, **kwargs) -> JSONResponse: + self.reset() + users = self.ctx.User.UID_DB.copy() copy_users: list['MUser'] = [] for user in users: @@ -17,14 +22,24 @@ class RPCUser: copy_user.connexion_datetime = copy_user.connexion_datetime.strftime('%d-%m-%Y') copy_users.append(copy_user) - return [user.to_dict() for user in copy_users] + self.response_model['result'] = [user.to_dict() for user in copy_users] - def user_get(self, **kwargs) -> Optional[dict]: - uidornickname = kwargs.get('uid_or_nickname', None) - user = self._ctx.User.get_user(uidornickname) + return JSONResponse(self.response_model) + + def user_get(self, **kwargs) -> JSONResponse: + self.reset() + uidornickname = kwargs.get('uid_or_nickname', '') + + if not uidornickname: + self.response_model['error'] = self.create_error_response(JSONRPCErrorCode.INVALID_PARAMS, {'uid_or_nickname': 'The param to use is uid_or_nickname'}) + return JSONResponse(self.response_model, self.http_status_code.HTTP_405_METHOD_NOT_ALLOWED) + + user = self.ctx.User.get_user(uidornickname) if user: user_copy = user.copy() user_copy.connexion_datetime = user_copy.connexion_datetime.strftime('%d-%m-%Y') - return user_copy.to_dict() + self.response_model['result'] = user_copy.to_dict() + return JSONResponse(self.response_model) - return None \ No newline at end of file + self.response_model['result'] = 'User not found!' + return JSONResponse(self.response_model, self.http_status_code.HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/defender.py b/defender.py index c5787bd..e6aeb98 100644 --- a/defender.py +++ b/defender.py @@ -2,19 +2,21 @@ import asyncio from core import install ############################################# -# @Version : 6.3 # +# @Version : 6.4 # # Requierements : # # Python3.10 or higher # # SQLAlchemy, requests, psutil # # unrealircd-rpc-py, pyyaml # +# uvicorn, starlette, faker # # UnrealIRCD 6.2.2 or higher # ############################################# async def main(): + install.update_packages() from core.loader import Loader loader = Loader() await loader.start() await loader.Irc.run() if __name__ == "__main__": - asyncio.run(main(), debug=True) + asyncio.run(main()) From 5b7c2e83d19e511d11ccca595a05546886b5eb88 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:04:19 +0100 Subject: [PATCH 51/56] Adapt mod_jsonrpc to the new asyncio approach. --- mods/jsonrpc/mod_jsonrpc.py | 211 ++++++++++++++++++------------------ mods/jsonrpc/schemas.py | 5 + mods/jsonrpc/threads.py | 53 +++++---- 3 files changed, 143 insertions(+), 126 deletions(-) create mode 100644 mods/jsonrpc/schemas.py diff --git a/mods/jsonrpc/mod_jsonrpc.py b/mods/jsonrpc/mod_jsonrpc.py index bc8fd33..61787d3 100644 --- a/mods/jsonrpc/mod_jsonrpc.py +++ b/mods/jsonrpc/mod_jsonrpc.py @@ -1,19 +1,24 @@ import logging +from typing import TYPE_CHECKING, Any, Optional from unrealircd_rpc_py.objects.Definition import LiveRPCResult from core.classes.interfaces.imodule import IModule +import mods.jsonrpc.schemas as schemas import mods.jsonrpc.utils as utils import mods.jsonrpc.threads as thds from dataclasses import dataclass from unrealircd_rpc_py.ConnectionFactory import ConnectionFactory from unrealircd_rpc_py.LiveConnectionFactory import LiveConnectionFactory +if TYPE_CHECKING: + from core.loader import Loader + class Jsonrpc(IModule): @dataclass - class ModConfModel: + class ModConfModel(schemas.ModConfModel): """The Model containing the module parameters """ - jsonrpc: int = 0 + ... MOD_HEADER: dict[str, str] = { 'name':'JsonRPC', @@ -23,26 +28,34 @@ class Jsonrpc(IModule): 'core_version':'Defender-6' } - def callback_sent_to_irc(self, response: LiveRPCResult) -> None: + def __init__(self, context: 'Loader') -> None: + super().__init__(context) + self._mod_config: Optional[schemas.ModConfModel] = None - dnickname = self.Config.SERVICE_NICKNAME - dchanlog = self.Config.SERVICE_CHANLOG - green = self.Config.COLORS.green - nogc = self.Config.COLORS.nogc - bold = self.Config.COLORS.bold - red = self.Config.COLORS.red + @property + def mod_config(self) -> ModConfModel: + return self._mod_config + + async def callback_sent_to_irc(self, response: LiveRPCResult) -> None: + + dnickname = self.ctx.Config.SERVICE_NICKNAME + dchanlog = self.ctx.Config.SERVICE_CHANLOG + green = self.ctx.Config.COLORS.green + nogc = self.ctx.Config.COLORS.nogc + bold = self.ctx.Config.COLORS.bold + red = self.ctx.Config.COLORS.red if response.error.code != 0: - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[{bold}{red}JSONRPC ERROR{nogc}{bold}] {response.error.message} ({response.error.code})", channel=dchanlog) return None if isinstance(response.result, bool): if response.result: - self.Protocol.send_priv_msg( - nick_from=self.Config.SERVICE_NICKNAME, - msg=f"[{bold}{green}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.Config.JSONRPC_URL}", + await self.ctx.Irc.Protocol.send_priv_msg( + nick_from=self.ctx.Config.SERVICE_NICKNAME, + msg=f"[{bold}{green}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.ctx.Config.JSONRPC_URL}", channel=dchanlog) return None @@ -53,99 +66,92 @@ class Jsonrpc(IModule): msg = response.result.msg if hasattr(response.result, 'msg') else '' build_msg = f"{green}{log_source}{nogc}: [{bold}{level}{bold}] {subsystem}.{event_id} - {msg}" - self.Protocol.send_priv_msg(nick_from=dnickname, msg=build_msg, channel=dchanlog) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=build_msg, channel=dchanlog) return None def create_tables(self) -> None: return None - def load(self) -> None: + async def load(self) -> None: logging.getLogger('websockets').setLevel(logging.WARNING) logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL) logging.getLogger('unrealircd-liverpc-py').setLevel(logging.CRITICAL) - self.ModConfig = self.ModConfModel(jsonrpc=0) + self._mod_config = self.ModConfModel(jsonrpc=0) - if self.Config.SERVEUR_PROTOCOL != 'unreal6': - self.Loader.ModuleUtils.unload_one_module(self.Irc, self.module_name, False) + await self.sync_db() + + if self.ctx.Config.SERVEUR_PROTOCOL.lower() != 'unreal6': + self.ctx.ModuleUtils.unload_one_module(self.module_name, False) return None # Is RPC Active? self.is_streaming = False - - # Module Utils - self.Utils = utils - - # Module threads - self.Threads = thds - - # Run Garbage collector. - self.Base.create_timer(10, self.MainUtils.run_python_garbage_collector) # Create module commands (Mandatory) - self.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]') - self.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC') - self.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances') + self.ctx.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]') + self.ctx.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC') + self.ctx.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances') try: - self.Rpc = ConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) - self.LiveRpc = LiveConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD) + self.Rpc = ConnectionFactory(self.ctx.Config.DEBUG_LEVEL).get(self.ctx.Config.JSONRPC_METHOD) + self.LiveRpc = LiveConnectionFactory(self.ctx.Config.DEBUG_LEVEL).get(self.ctx.Config.JSONRPC_METHOD) - sync_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE} - sync_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD} + sync_unixsocket = {'path_to_socket_file': self.ctx.Config.JSONRPC_PATH_TO_SOCKET_FILE} + sync_http = {'url': self.ctx.Config.JSONRPC_URL, 'username': self.ctx.Config.JSONRPC_USER, 'password': self.ctx.Config.JSONRPC_PASSWORD} - live_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE, + live_unixsocket = {'path_to_socket_file': self.ctx.Config.JSONRPC_PATH_TO_SOCKET_FILE, 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} - live_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD, + live_http = {'url': self.ctx.Config.JSONRPC_URL, 'username': self.ctx.Config.JSONRPC_USER, 'password': self.ctx.Config.JSONRPC_PASSWORD, 'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'} - sync_param = sync_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else sync_http - live_param = live_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else live_http + sync_param = sync_unixsocket if self.ctx.Config.JSONRPC_METHOD == 'unixsocket' else sync_http + live_param = live_unixsocket if self.ctx.Config.JSONRPC_METHOD == 'unixsocket' else live_http self.Rpc.setup(sync_param) self.LiveRpc.setup(live_param) - if self.ModConfig.jsonrpc == 1: - self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True) + if self.mod_config.jsonrpc == 1: + self.ctx.Base.create_asynctask(thds.thread_subscribe(self)) return None except Exception as err: - self.Protocol.send_priv_msg( - nick_from=self.Config.SERVICE_NICKNAME, - msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {err.__str__()}", - channel=self.Config.SERVICE_CHANLOG + await self.ctx.Irc.Protocol.send_priv_msg( + nick_from=self.ctx.Config.SERVICE_NICKNAME, + msg=f"[{self.ctx.Config.COLORS.red}JSONRPC ERROR{self.ctx.Config.COLORS.nogc}] {err.__str__()}", + channel=self.ctx.Config.SERVICE_CHANLOG ) - self.Logs.error(f"JSONRPC ERROR: {err.__str__()}") + self.ctx.Logs.error(f"JSONRPC ERROR: {err.__str__()}") - def unload(self) -> None: + async def unload(self) -> None: - if self.Config.SERVEUR_PROTOCOL != 'unreal6': - self.Loader.ModuleUtils.unload_one_module(self.Irc, self.module_name, False) + if self.ctx.Config.SERVEUR_PROTOCOL != 'unreal6': + await self.ctx.ModuleUtils.unload_one_module(self.ctx.Irc, self.module_name, False) return None if self.is_streaming: - self.Protocol.send_priv_msg( - nick_from=self.Config.SERVICE_NICKNAME, - msg=f"[{self.Config.COLORS.green}JSONRPC INFO{self.Config.COLORS.nogc}] Shutting down RPC system!", - channel=self.Config.SERVICE_CHANLOG + await self.ctx.Irc.Protocol.send_priv_msg( + nick_from=self.ctx.Config.SERVICE_NICKNAME, + msg=f"[{self.ctx.Config.COLORS.green}JSONRPC INFO{self.ctx.Config.COLORS.nogc}] Shutting down RPC system!", + channel=self.ctx.Config.SERVICE_CHANLOG ) - self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True) - self.update_configuration('jsonrpc', 0) - self.Irc.Commands.drop_command_by_module(self.module_name) - self.Logs.debug(f"Unloading {self.module_name}") + self.ctx.Base.create_asynctask(thds.thread_unsubscribe(self)) + # await self.update_configuration('jsonrpc', 0) + self.ctx.Commands.drop_command_by_module(self.module_name) + self.ctx.Logs.debug(f"Unloading {self.module_name}") return None - def cmd(self, data: list) -> None: + def cmd(self, data: list[str]) -> None: return None - def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None: + async def hcmds(self, user: str, channel: Any, cmd: list[str], fullcmd: list[str] = []) -> None: command = str(cmd[0]).lower() - dnickname = self.Config.SERVICE_NICKNAME - dchannel = self.Config.SERVICE_CHANLOG + dnickname = self.ctx.Config.SERVICE_NICKNAME + dchannel = self.ctx.Config.SERVICE_CHANLOG fromuser = user fromchannel = str(channel) if not channel is None else None @@ -154,39 +160,30 @@ class Jsonrpc(IModule): case 'jsonrpc': try: if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc on') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc off') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc on') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc off') return None option = str(cmd[1]).lower() match option: case 'on': - thread_name = 'thread_subscribe' - if self.Base.is_thread_alive(thread_name): - self.Protocol.send_priv_msg(nick_from=dnickname, channel=dchannel, msg=f"The Subscription is running") - return None - elif self.Base.is_thread_exist(thread_name): - self.Protocol.send_priv_msg( - nick_from=dnickname, channel=dchannel, - msg=f"The subscription is not running, wait untill the process will be cleaned up" - ) - return None - - self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True) - self.update_configuration('jsonrpc', 1) + self.ctx.Base.create_asynctask(thds.thread_subscribe(self)) + await self.update_configuration('jsonrpc', 1) case 'off': - self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True) - self.update_configuration('jsonrpc', 0) + self.ctx.Base.create_asynctask(thds.thread_unsubscribe(self)) + await self.update_configuration('jsonrpc', 0) except IndexError as ie: - self.Logs.error(ie) + self.ctx.Logs.error(ie) case 'jruser': try: if len(cmd) < 2: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jruser get nickname') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jruser get nickname') + return None + option = str(cmd[1]).lower() match option: case 'get': @@ -195,42 +192,42 @@ class Jsonrpc(IModule): UserInfo = rpc.User.get(nickname) if UserInfo.error.code != 0: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'{UserInfo.error.message}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'{UserInfo.error.message}') return None - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'UID : {UserInfo.id}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'NICKNAME : {UserInfo.name}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REALNAME : {UserInfo.user.realname}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'MODES : {UserInfo.user.modes}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {[chan.name for chan in UserInfo.user.channels]}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SECURITY GROUP : {UserInfo.user.security_groups}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REPUTATION : {UserInfo.user.reputation}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'UID : {UserInfo.id}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'NICKNAME : {UserInfo.name}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REALNAME : {UserInfo.user.realname}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'MODES : {UserInfo.user.modes}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {[chan.name for chan in UserInfo.user.channels]}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SECURITY GROUP : {UserInfo.user.security_groups}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REPUTATION : {UserInfo.user.reputation}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IP : {UserInfo.ip}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'COUNTRY CODE : {UserInfo.geoip.country_code}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASN : {UserInfo.geoip.asn}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASNAME : {UserInfo.geoip.asname}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLOAKED HOST : {UserInfo.user.cloakedhost}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'HOSTNAME : {UserInfo.hostname}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'VHOST : {UserInfo.user.vhost}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLIENT PORT : {UserInfo.client_port}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SERVER PORT : {UserInfo.server_port}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IP : {UserInfo.ip}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'COUNTRY CODE : {UserInfo.geoip.country_code}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASN : {UserInfo.geoip.asn}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASNAME : {UserInfo.geoip.asname}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLOAKED HOST : {UserInfo.user.cloakedhost}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'HOSTNAME : {UserInfo.hostname}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'VHOST : {UserInfo.user.vhost}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLIENT PORT : {UserInfo.client_port}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SERVER PORT : {UserInfo.server_port}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CERTFP : {UserInfo.tls.certfp}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CIPHER : {UserInfo.tls.cipher}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CERTFP : {UserInfo.tls.certfp}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CIPHER : {UserInfo.tls.cipher}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IDLE SINCE : {UserInfo.idle_since}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CONNECTED SINCE : {UserInfo.connected_since}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IDLE SINCE : {UserInfo.idle_since}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CONNECTED SINCE : {UserInfo.connected_since}') except IndexError as ie: - self.Logs.error(ie) + self.ctx.Logs.error(ie) case 'jrinstances': try: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"GC Collect: {self.MainUtils.run_python_garbage_collector()}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveWebsock: {self.MainUtils.get_number_gc_objects(LiveConnectionFactory)}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance ConnectionFactory: {self.MainUtils.get_number_gc_objects(ConnectionFactory)}") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.MainUtils.get_number_gc_objects()}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"GC Collect: {self.ctx.Utils.run_python_garbage_collector()}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveWebsock: {self.ctx.Utils.get_number_gc_objects(LiveConnectionFactory)}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance ConnectionFactory: {self.ctx.Utils.get_number_gc_objects(ConnectionFactory)}") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.ctx.Utils.get_number_gc_objects()}") except Exception as err: - self.Logs.error(f"Unknown Error: {err}") \ No newline at end of file + self.ctx.Logs.error(f"Unknown Error: {err}") \ No newline at end of file diff --git a/mods/jsonrpc/schemas.py b/mods/jsonrpc/schemas.py new file mode 100644 index 0000000..ce969f3 --- /dev/null +++ b/mods/jsonrpc/schemas.py @@ -0,0 +1,5 @@ +from core.definition import MainModel, dataclass + +@dataclass +class ModConfModel(MainModel): + jsonrpc: int = 0 diff --git a/mods/jsonrpc/threads.py b/mods/jsonrpc/threads.py index 1585acd..c28442e 100644 --- a/mods/jsonrpc/threads.py +++ b/mods/jsonrpc/threads.py @@ -4,16 +4,23 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from mods.jsonrpc.mod_jsonrpc import Jsonrpc -def thread_subscribe(uplink: 'Jsonrpc') -> None: +async def thread_subscribe(uplink: 'Jsonrpc') -> None: + + snickname = uplink.ctx.Config.SERVICE_NICKNAME + schannel = uplink.ctx.Config.SERVICE_CHANLOG + if uplink.is_streaming: + await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=snickname, + msg=f"[{uplink.ctx.Config.COLORS.green}JSONRPC INFO{uplink.ctx.Config.COLORS.nogc}] IRCd Json-rpc already connected!", + channel=schannel + ) + return None - snickname = uplink.Config.SERVICE_NICKNAME - schannel = uplink.Config.SERVICE_CHANLOG uplink.is_streaming = True - response = asyncio.run(uplink.LiveRpc.subscribe(["all"])) + response = await uplink.LiveRpc.subscribe(["all"]) if response.error.code != 0: - uplink.Protocol.send_priv_msg(nick_from=snickname, - msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {response.error.message}", + await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=snickname, + msg=f"[{uplink.ctx.Config.COLORS.red}JSONRPC ERROR{uplink.ctx.Config.COLORS.nogc}] {response.error.message}", channel=schannel ) @@ -21,33 +28,41 @@ def thread_subscribe(uplink: 'Jsonrpc') -> None: message = response.error.message if code == 0: - uplink.Protocol.send_priv_msg( + await uplink.ctx.Irc.Protocol.send_priv_msg( nick_from=snickname, - msg=f"[{uplink.Config.COLORS.green}JSONRPC{uplink.Config.COLORS.nogc}] Stream is OFF", + msg=f"[{uplink.ctx.Config.COLORS.green}JSONRPC{uplink.ctx.Config.COLORS.nogc}] Stream is OFF", channel=schannel ) + uplink.is_streaming = False else: - uplink.Protocol.send_priv_msg( + await uplink.ctx.Irc.Protocol.send_priv_msg( nick_from=snickname, - msg=f"[{uplink.Config.COLORS.red}JSONRPC{uplink.Config.COLORS.nogc}] Stream has crashed! {code} - {message}", + msg=f"[{uplink.ctx.Config.COLORS.red}JSONRPC{uplink.ctx.Config.COLORS.nogc}] Stream has crashed! {code} - {message}", channel=schannel ) + uplink.is_streaming = False -def thread_unsubscribe(uplink: 'Jsonrpc') -> None: +async def thread_unsubscribe(uplink: 'Jsonrpc') -> None: - response = asyncio.run(uplink.LiveRpc.unsubscribe()) - uplink.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!") + snickname = uplink.ctx.Config.SERVICE_NICKNAME + schannel = uplink.ctx.Config.SERVICE_CHANLOG + + if not uplink.is_streaming: + await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=snickname, + msg=f"[{uplink.ctx.Config.COLORS.green}JSONRPC INFO{uplink.ctx.Config.COLORS.nogc}] IRCd Json-rpc is already off!", + channel=schannel + ) + return None + + response = await uplink.LiveRpc.unsubscribe() + uplink.ctx.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!") uplink.is_streaming = False - uplink.update_configuration('jsonrpc', 0) - snickname = uplink.Config.SERVICE_NICKNAME - schannel = uplink.Config.SERVICE_CHANLOG - code = response.error.code message = response.error.message if code != 0: - uplink.Protocol.send_priv_msg( + await uplink.ctx.Irc.Protocol.send_priv_msg( nick_from=snickname, - msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {message} ({code})", + msg=f"[{uplink.ctx.Config.COLORS.red}JSONRPC ERROR{uplink.ctx.Config.COLORS.nogc}] {message} ({code})", channel=schannel ) From 1e72906f7ba3938801c7307c555e7f629c601f83 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:05:42 +0100 Subject: [PATCH 52/56] Handling the exception when IRCd is down! --- core/irc.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/irc.py b/core/irc.py index ff19528..8d183dc 100644 --- a/core/irc.py +++ b/core/irc.py @@ -121,8 +121,13 @@ class Irc: await self.send_response(data.splitlines()) async def run(self): - await self.connect() - await self.listen() + try: + await self.connect() + await self.listen() + except asyncio.exceptions.IncompleteReadError as ie: + # When IRCd server is down + # asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of undefined expected bytes + self.ctx.Logs.critical(f"The IRCd server is no more connected! {ie}") ############################################## # CONNEXION IRC # From 3a8c7f0632c28410f1d16b7f4d117da2308e63d3 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:06:40 +0100 Subject: [PATCH 53/56] Updating unrealircd_rpc_py version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 18a4577..7583b06 100644 --- a/version.json +++ b/version.json @@ -3,7 +3,7 @@ "requests": "2.32.5", "psutil": "7.1.2", - "unrealircd_rpc_py": "3.0.1", + "unrealircd_rpc_py": "3.0.3", "sqlalchemy": "2.0.44", "faker": "37.12.0", "pyyaml": "6.0.3", From e9af3f91551905dac220ac97eb2bc7ed6be270f2 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:07:20 +0100 Subject: [PATCH 54/56] Unloading modules when stopping defender! --- core/base.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/base.py b/core/base.py index 6d9fbb7..648d740 100644 --- a/core/base.py +++ b/core/base.py @@ -495,6 +495,11 @@ class Base: async def shutdown(self) -> None: """Methode qui va préparer l'arrêt complêt du service """ + # unload modules. + self.logs.debug(f"=======> Unloading all modules!") + for module in self.Loader.ModuleUtils.model_get_loaded_modules().copy(): + await self.Loader.ModuleUtils.unload_one_module(module.module_name) + # Nettoyage des timers self.logs.debug(f"=======> Checking for Timers to stop") for timer in self.running_timers: @@ -521,8 +526,9 @@ class Base: self.running_sockets.remove(soc) self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}") - + await self.Loader.RpcServer.stop_server() + self.db_close() return None From fe4b68e1153ddd636f6bee0c0a6795aafd25ab3d Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:13:36 +0100 Subject: [PATCH 55/56] Fix blocking Coroutines when shutdown! --- core/base.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/base.py b/core/base.py index 648d740..763e709 100644 --- a/core/base.py +++ b/core/base.py @@ -495,11 +495,17 @@ class Base: async def shutdown(self) -> None: """Methode qui va préparer l'arrêt complêt du service """ + # Stop RpcServer if running + await self.Loader.RpcServer.stop_server() + # unload modules. self.logs.debug(f"=======> Unloading all modules!") for module in self.Loader.ModuleUtils.model_get_loaded_modules().copy(): await self.Loader.ModuleUtils.unload_one_module(module.module_name) + self.logs.debug(f"=======> Closing all Coroutines!") + await asyncio.gather(*self.running_asynctasks) + # Nettoyage des timers self.logs.debug(f"=======> Checking for Timers to stop") for timer in self.running_timers: @@ -527,8 +533,6 @@ class Base: self.running_sockets.remove(soc) self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}") - await self.Loader.RpcServer.stop_server() - self.db_close() return None From 6af13778231d0b4e14ddf03a6aff926507f683e1 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:17:27 +0100 Subject: [PATCH 56/56] Moving votekick to use asyncio, fix when shutdown defender --- core/base.py | 12 +- core/context.py | 69 --------- core/irc.py | 6 +- mods/votekick/mod_votekick.py | 247 +++++++++++++++--------------- mods/votekick/threads.py | 23 +-- mods/votekick/utils.py | 18 +-- mods/votekick/votekick_manager.py | 4 +- 7 files changed, 165 insertions(+), 214 deletions(-) delete mode 100644 core/context.py diff --git a/core/base.py b/core/base.py index 763e709..801c051 100644 --- a/core/base.py +++ b/core/base.py @@ -504,7 +504,15 @@ class Base: await self.Loader.ModuleUtils.unload_one_module(module.module_name) self.logs.debug(f"=======> Closing all Coroutines!") - await asyncio.gather(*self.running_asynctasks) + try: + await asyncio.wait_for(asyncio.gather(*self.running_asynctasks), timeout=5) + except asyncio.exceptions.TimeoutError as te: + self.logs.debug(f"Asyncio Timeout reached! {te}") + for task in self.running_asynctasks: + task.cancel() + except asyncio.exceptions.CancelledError as cerr: + self.logs.debug(f"Asyncio CancelledError reached! {cerr}") + # Nettoyage des timers self.logs.debug(f"=======> Checking for Timers to stop") @@ -512,7 +520,7 @@ class Base: while timer.is_alive(): self.logs.debug(f"> waiting for {timer.name} to close") timer.cancel() - time.sleep(0.2) + await asyncio.sleep(0.2) self.running_timers.remove(timer) self.logs.debug(f"> Cancelling {timer.name} {timer.native_id}") diff --git a/core/context.py b/core/context.py deleted file mode 100644 index c8f4006..0000000 --- a/core/context.py +++ /dev/null @@ -1,69 +0,0 @@ -from logging import Logger -from core.classes.modules.settings import global_settings -from core.classes.modules import translation, user, admin, client, channel, reputation, settings, sasl -import core.logs as logs -import core.definition as df -import core.utils as utils -import core.base as base_mod -import core.module as module_mod -import core.classes.modules.commands as commands_mod -import core.classes.modules.config as conf_mod -import core.classes.modules.rpc.rpc as rpc_mod -import core.irc as irc -import core.classes.protocols.factory as factory - -class IrcContext: - - def ctx_modules(self) -> None: - self.Definition: df = df - self.ConfModule: conf_mod = conf_mod - self.BaseModule: base_mod = base_mod - self.CommandModule: commands_mod = commands_mod - self.LoggingModule: logs = logs - self.RpcServerModule: rpc_mod = rpc_mod - self.Utils: utils = utils - - def ctx_system(self) -> None: - self.Settings: settings.Settings = global_settings - self.Settings.global_lang = self.Config.LANG if self.Config.LANG else "EN" - - self.ServiceLogging: logs.ServiceLogging = self.LoggingModule.ServiceLogging() - self.Logs: Logger = self.ServiceLogging.get_logger() - - self.Config: df.MConfig = self.ConfModule.Configuration(self.Logs, self.ServiceLogging).configuration_model - - self.Settings.global_logger = self.Logs - - self.Translation: translation.Translation = translation.Translation(self) - - self.Settings.global_translation = self.Translation.get_translation() - - self.Base: base_mod.Base = self.BaseModule.Base(self) - - self.User: user.User = user.User(self) - - self.Settings.global_user = self.User - - self.Client: client.Client = client.Client(self) - - self.Admin: admin.Admin = admin.Admin(self) - - self.Channel: channel.Channel = channel.Channel(self) - - self.Reputation: reputation.Reputation = reputation.Reputation(self) - - self.Commands: commands_mod.Command = commands_mod.Command(self) - - self.ModuleUtils: module_mod.Module = module_mod.Module(self) - - self.Sasl: sasl.Sasl = sasl.Sasl(self) - - self.Irc: irc.Irc = irc.Irc(self) - - self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc) - - self.RpcServer: rpc_mod.JSONRPCServer = rpc_mod.JSONRPCServer(self) - - self.Base.init() - - self.Logs.debug(self.Utils.tr("Loader %s success", __name__)) diff --git a/core/irc.py b/core/irc.py index 8d183dc..c691237 100644 --- a/core/irc.py +++ b/core/irc.py @@ -128,6 +128,8 @@ class Irc: # When IRCd server is down # asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of undefined expected bytes self.ctx.Logs.critical(f"The IRCd server is no more connected! {ie}") + except asyncio.exceptions.CancelledError as cerr: + self.ctx.Logs.debug(f"Asyncio CancelledError reached! {cerr}") ############################################## # CONNEXION IRC # @@ -1006,9 +1008,9 @@ class Irc: except IndexError as ie: self.ctx.Logs.error(f'{ie}') - except ConnectionResetError as cerr: + except ConnectionResetError: if self.writer.is_closing(): - self.ctx.Logs.debug(f"Defender stopped properly! {cerr}") + self.ctx.Logs.debug(f"Defender stopped properly!") case 'restart': final_reason = ' '.join(cmd[1:]) diff --git a/mods/votekick/mod_votekick.py b/mods/votekick/mod_votekick.py index b6307e6..86aa308 100644 --- a/mods/votekick/mod_votekick.py +++ b/mods/votekick/mod_votekick.py @@ -15,7 +15,11 @@ import mods.votekick.schemas as schemas import mods.votekick.utils as utils from mods.votekick.votekick_manager import VotekickManager import mods.votekick.threads as thds -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional + + +if TYPE_CHECKING: + from core.loader import Loader class Votekick(IModule): @@ -31,6 +35,14 @@ class Votekick(IModule): 'core_version':'Defender-6' } + def __init__(self, context: 'Loader') -> None: + super().__init__(context) + self._mod_config: Optional[schemas.VoteChannelModel] = None + + @property + def mod_config(self) -> ModConfModel: + return self._mod_config + def create_tables(self) -> None: """Methode qui va créer la base de donnée si elle n'existe pas. Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module @@ -53,57 +65,52 @@ class Votekick(IModule): ) ''' - self.Base.db_execute_query(table_logs) - self.Base.db_execute_query(table_vote) + self.ctx.Base.db_execute_query(table_logs) + self.ctx.Base.db_execute_query(table_vote) return None - def load(self) -> None: + async def load(self) -> None: - self.ModConfig = self.ModConfModel() + self._mod_config = self.ModConfModel() + await self.sync_db() # Add VoteKick Manager self.VoteKickManager = VotekickManager(self) - # Add Utils module - self.ModUtils = utils - - # Add Schemas module - self.Schemas = schemas - # Add Threads module self.Threads = thds - self.ModUtils.join_saved_channels(self) + await utils.join_saved_channels(self) - metadata = self.Settings.get_cache('VOTEKICK') + metadata = self.ctx.Settings.get_cache('VOTEKICK') if metadata is not None: self.VoteKickManager.VOTE_CHANNEL_DB = metadata # Créer les nouvelles commandes du module - self.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module') + self.ctx.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module') - def unload(self) -> None: + async def unload(self) -> None: try: # Cache the local DB with current votes. if self.VoteKickManager.VOTE_CHANNEL_DB: - self.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB) + self.ctx.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB) for chan in self.VoteKickManager.VOTE_CHANNEL_DB: - self.Protocol.send_part_chan(uidornickname=self.Config.SERVICE_ID, channel=chan.channel_name) + await self.ctx.Irc.Protocol.send_part_chan(uidornickname=self.ctx.Config.SERVICE_ID, channel=chan.channel_name) self.VoteKickManager.VOTE_CHANNEL_DB = [] - self.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VoteKickManager.VOTE_CHANNEL_DB}') + self.ctx.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VoteKickManager.VOTE_CHANNEL_DB}') - self.Irc.Commands.drop_command_by_module(self.module_name) + self.ctx.Commands.drop_command_by_module(self.module_name) return None except UnboundLocalError as ne: - self.Logs.error(f'{ne}') + self.ctx.Logs.error(f'{ne}') except NameError as ue: - self.Logs.error(f'{ue}') + self.ctx.Logs.error(f'{ue}') except Exception as err: - self.Logs.error(f'General Error: {err}') + self.ctx.Logs.error(f'General Error: {err}') def cmd(self, data: list) -> None: @@ -111,7 +118,7 @@ class Votekick(IModule): return None cmd = data.copy() if isinstance(data, list) else list(data).copy() - index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd) + index, command = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd) if index == -1: return None @@ -129,19 +136,19 @@ class Votekick(IModule): return None except KeyError as ke: - self.Logs.error(f"Key Error: {ke}") + self.ctx.Logs.error(f"Key Error: {ke}") except IndexError as ie: - self.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}") + self.ctx.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}") except Exception as err: - self.Logs.error(f"General Error: {err}") + self.ctx.Logs.error(f"General Error: {err}") - def hcmds(self, user:str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None: + async def hcmds(self, user:str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None: # cmd is the command starting from the user command # full cmd is sending the entire server response command = str(cmd[0]).lower() fullcmd = fullcmd - dnickname = self.Config.SERVICE_NICKNAME + dnickname = self.ctx.Config.SERVICE_NICKNAME fromuser = user fromchannel = channel @@ -150,14 +157,14 @@ class Votekick(IModule): case 'vote': if len(cmd) == 1: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict') return None option = str(cmd[1]).lower() @@ -167,19 +174,19 @@ class Votekick(IModule): case 'activate': try: # vote activate #channel - if self.Admin.get_admin(fromuser) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' :Your are not allowed to execute this command') + if self.ctx.Admin.get_admin(fromuser) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' :Your are not allowed to execute this command') return None - sentchannel = str(cmd[2]).lower() if self.Channel.is_valid_channel(str(cmd[2]).lower()) else None + sentchannel = str(cmd[2]).lower() if self.ctx.Channel.is_valid_channel(str(cmd[2]).lower()) else None if sentchannel is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.ctx.Config.SERVICE_PREFIX}{command} {option} #CHANNEL") if self.VoteKickManager.activate_new_channel(sentchannel): - self.Channel.db_query_channel('add', self.module_name, sentchannel) - self.Protocol.send_join_chan(uidornickname=dnickname, channel=sentchannel) - self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}") - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Channel.db_query_channel('add', self.module_name, sentchannel) + await self.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname, channel=sentchannel) + await self.ctx.Irc.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}") + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="You can now use !submit to decide if he will stay or not on this channel ", channel=sentchannel ) @@ -187,117 +194,117 @@ class Votekick(IModule): return None except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} #channel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} #welcome') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} #channel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} #welcome') case 'deactivate': try: # vote deactivate #channel - if self.Admin.get_admin(fromuser) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Your are not allowed to execute this command") + if self.ctx.Admin.get_admin(fromuser) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Your are not allowed to execute this command") return None - sentchannel = str(cmd[2]).lower() if self.Channel.is_valid_channel(str(cmd[2]).lower()) else None + sentchannel = str(cmd[2]).lower() if self.ctx.Channel.is_valid_channel(str(cmd[2]).lower()) else None if sentchannel is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.ctx.Config.SERVICE_PREFIX}{command} {option} #CHANNEL") - self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}") - self.Protocol.send_part_chan(uidornickname=dnickname, channel=sentchannel) + await self.ctx.Irc.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}") + await self.ctx.Irc.Protocol.send_part_chan(uidornickname=dnickname, channel=sentchannel) if self.VoteKickManager.drop_vote_channel_model(sentchannel): - self.Channel.db_query_channel('del', self.module_name, sentchannel) + await self.ctx.Channel.db_query_channel('del', self.module_name, sentchannel) return None except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" /msg {dnickname} {command} {option} #channel") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Exemple /msg {dnickname} {command} {option} #welcome") + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" /msg {dnickname} {command} {option} #channel") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Exemple /msg {dnickname} {command} {option} #welcome") case '+': try: # vote + channel = fromchannel if self.VoteKickManager.action_vote(channel, fromuser, '+'): - self.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel) else: - self.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel) except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') case '-': try: # vote - channel = fromchannel if self.VoteKickManager.action_vote(channel, fromuser, '-'): - self.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel) else: - self.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel) except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') case 'cancel': try: # vote cancel - if self.Admin.get_admin(fromuser) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command') + if self.ctx.Admin.get_admin(fromuser) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command') return None if channel is None: - self.Logs.error(f"The channel is not known, defender can't cancel the vote") - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' You need to specify the channel => /msg {dnickname} vote_cancel #channel') + self.ctx.Logs.error(f"The channel is not known, defender can't cancel the vote") + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' You need to specify the channel => /msg {dnickname} vote_cancel #channel') for vote in self.VoteKickManager.VOTE_CHANNEL_DB: if vote.channel_name == channel: if self.VoteKickManager.init_vote_system(channel): - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote system re-initiated", channel=channel ) except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') case 'status': try: # vote status for chan in self.VoteKickManager.VOTE_CHANNEL_DB: if chan.channel_name == channel: - self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"Channel: {chan.channel_name} | Target: {self.User.get_nickname(chan.target_user)} | For: {chan.vote_for} | Against: {chan.vote_against} | Number of voters: {str(len(chan.voter_users))}", + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, + msg=f"Channel: {chan.channel_name} | Target: {self.ctx.User.get_nickname(chan.target_user)} | For: {chan.vote_for} | Against: {chan.vote_against} | Number of voters: {str(len(chan.voter_users))}", channel=channel ) except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') case 'submit': try: # vote submit nickname - if self.Admin.get_admin(fromuser) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command') + if self.ctx.Admin.get_admin(fromuser) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command') return None nickname_submitted = cmd[2] - uid_submitted = self.User.get_uid(nickname_submitted) - user_submitted = self.User.get_user(nickname_submitted) + uid_submitted = self.ctx.User.get_uid(nickname_submitted) + user_submitted = self.ctx.User.get_user(nickname_submitted) ongoing_user = None # check if there is an ongoing vote if self.VoteKickManager.is_vote_ongoing(channel): votec = self.VoteKickManager.get_vote_channel_model(channel) if votec: - ongoing_user = self.User.get_nickname(votec.target_user) - self.Protocol.send_priv_msg(nick_from=dnickname, + ongoing_user = self.ctx.User.get_nickname(votec.target_user) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"There is an ongoing vote on {ongoing_user}", channel=channel ) @@ -305,24 +312,24 @@ class Votekick(IModule): # check if the user exist if user_submitted is None: - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This nickname <{nickname_submitted}> do not exist", channel=channel ) return None - uid_cleaned = self.Loader.Utils.clean_uid(uid_submitted) - channel_obj = self.Channel.get_channel(channel) + uid_cleaned = self.ctx.Utils.clean_uid(uid_submitted) + channel_obj = self.ctx.Channel.get_channel(channel) if channel_obj is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' This channel [{channel}] do not exist in the Channel Object') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' This channel [{channel}] do not exist in the Channel Object') return None clean_uids_in_channel: list = [] for uid in channel_obj.uids: - clean_uids_in_channel.append(self.Loader.Utils.clean_uid(uid)) + clean_uids_in_channel.append(self.ctx.Utils.clean_uid(uid)) if not uid_cleaned in clean_uids_in_channel: - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This nickname <{nickname_submitted}> is not available in this channel", channel=channel ) @@ -332,7 +339,7 @@ class Votekick(IModule): pattern = fr'[o|B|S]' operator_user = re.findall(pattern, user_submitted.umodes) if operator_user: - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="You cant vote for this user ! he/she is protected", channel=channel ) @@ -340,49 +347,49 @@ class Votekick(IModule): for chan in self.VoteKickManager.VOTE_CHANNEL_DB: if chan.channel_name == channel: - chan.target_user = self.User.get_uid(nickname_submitted) + chan.target_user = self.ctx.User.get_uid(nickname_submitted) - self.Protocol.send_priv_msg(nick_from=dnickname, + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"{nickname_submitted} has been targeted for a vote", channel=channel ) - self.Base.create_timer(60, self.Threads.timer_vote_verdict, (self, channel)) - self.Protocol.send_priv_msg(nick_from=dnickname, + self.ctx.Base.create_asynctask(thds.timer_vote_verdict(self, channel)) + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="This vote will end after 60 secondes", channel=channel ) except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} nickname') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} adator') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} nickname') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} adator') case 'verdict': try: # vote verdict - if self.Admin.get_admin(fromuser) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f'Your are not allowed to execute this command') + if self.ctx.Admin.get_admin(fromuser) is None: + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f'Your are not allowed to execute this command') return None votec = self.VoteKickManager.get_vote_channel_model(channel) if votec: - target_user = self.User.get_nickname(votec.target_user) + target_user = self.ctx.User.get_nickname(votec.target_user) if votec.vote_for >= votec.vote_against: - self.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel", + await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, + msg=f"User {self.ctx.Config.COLORS.bold}{target_user}{self.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel", channel=channel ) - self.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}") + await self.ctx.Irc.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}") else: - self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel", + msg=f"User {self.ctx.Config.COLORS.bold}{target_user}{self.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel", channel=channel ) if self.VoteKickManager.init_vote_system(channel): - self.Protocol.send_priv_msg( + await self.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, msg="System vote re initiated", channel=channel @@ -390,19 +397,19 @@ class Votekick(IModule): return None except Exception as err: - self.Logs.error(f'{err}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') + self.ctx.Logs.error(f'{err}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}') case _: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname') + await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict') return None case _: diff --git a/mods/votekick/threads.py b/mods/votekick/threads.py index 66d4edc..14eb209 100644 --- a/mods/votekick/threads.py +++ b/mods/votekick/threads.py @@ -1,35 +1,38 @@ +import asyncio from typing import TYPE_CHECKING if TYPE_CHECKING: from mods.votekick.mod_votekick import Votekick -def timer_vote_verdict(uplink: 'Votekick', channel: str) -> None: +async def timer_vote_verdict(uplink: 'Votekick', channel: str) -> None: - dnickname = uplink.Config.SERVICE_NICKNAME + dnickname = uplink.ctx.Config.SERVICE_NICKNAME if not uplink.VoteKickManager.is_vote_ongoing(channel): return None - + + asyncio.sleep(60) + votec = uplink.VoteKickManager.get_vote_channel_model(channel) if votec: - target_user = uplink.User.get_nickname(votec.target_user) + target_user = uplink.ctx.User.get_nickname(votec.target_user) if votec.vote_for >= votec.vote_against and votec.vote_for != 0: - uplink.Protocol.send_priv_msg(nick_from=dnickname, - msg=f"User {uplink.Config.COLORS.bold}{target_user}{uplink.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel", + await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, + msg=f"User {uplink.ctx.Config.COLORS.bold}{target_user}{uplink.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel", channel=channel ) - uplink.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}") + await uplink.ctx.Irc.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}") else: - uplink.Protocol.send_priv_msg( + await uplink.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, - msg=f"User {uplink.Config.COLORS.bold}{target_user}{uplink.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel", + msg=f"User {uplink.ctx.Config.COLORS.bold}{target_user}{uplink.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel", channel=channel ) if uplink.VoteKickManager.init_vote_system(channel): - uplink.Protocol.send_priv_msg( + await uplink.ctx.Irc.Protocol.send_priv_msg( nick_from=dnickname, msg="System vote re initiated", channel=channel diff --git a/mods/votekick/utils.py b/mods/votekick/utils.py index 4f81bb5..0361ea2 100644 --- a/mods/votekick/utils.py +++ b/mods/votekick/utils.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from mods.votekick.mod_votekick import Votekick -def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool: +async def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool: """Adds a new channel to the votekick database if it doesn't already exist. This function checks if the specified channel is already registered in the @@ -18,16 +18,16 @@ def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool: bool: True if the channel was successfully inserted into the database. False if the channel already exists or the insertion failed. """ - current_datetime = uplink.Utils.get_sdatetime() + current_datetime = uplink.ctx.Utils.get_sdatetime() mes_donnees = {'channel': channel} - response = uplink.Base.db_execute_query("SELECT id FROM votekick_channel WHERE channel = :channel", mes_donnees) + response = await uplink.ctx.Base.db_execute_query("SELECT id FROM votekick_channel WHERE channel = :channel", mes_donnees) is_channel_exist = response.fetchone() if is_channel_exist is None: mes_donnees = {'datetime': current_datetime, 'channel': channel} - insert = uplink.Base.db_execute_query(f"INSERT INTO votekick_channel (datetime, channel) VALUES (:datetime, :channel)", mes_donnees) + insert = await uplink.ctx.Base.db_execute_query(f"INSERT INTO votekick_channel (datetime, channel) VALUES (:datetime, :channel)", mes_donnees) if insert.rowcount > 0: return True else: @@ -35,7 +35,7 @@ def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool: else: return False -def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool: +async def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool: """Deletes a channel entry from the votekick database. This function removes the specified channel from the `votekick_channel` table @@ -49,7 +49,7 @@ def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool: bool: True if the channel was successfully deleted, False if no rows were affected. """ mes_donnes = {'channel': channel} - response = uplink.Base.db_execute_query("DELETE FROM votekick_channel WHERE channel = :channel", mes_donnes) + response = await uplink.ctx.Base.db_execute_query("DELETE FROM votekick_channel WHERE channel = :channel", mes_donnes) affected_row = response.rowcount @@ -61,14 +61,14 @@ def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool: async def join_saved_channels(uplink: 'Votekick') -> None: param = {'module_name': uplink.module_name} - result = uplink.Base.db_execute_query(f"SELECT id, channel_name FROM {uplink.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param) + result = await uplink.ctx.Base.db_execute_query(f"SELECT id, channel_name FROM {uplink.ctx.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param) channels = result.fetchall() for channel in channels: id_, chan = channel uplink.VoteKickManager.activate_new_channel(chan) - await uplink.Protocol.send_sjoin(channel=chan) - await uplink.Protocol.send2socket(f":{uplink.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.Config.SERVICE_NICKNAME}") + await uplink.ctx.Irc.Protocol.send_sjoin(channel=chan) + await uplink.ctx.Irc.Protocol.send2socket(f":{uplink.ctx.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.ctx.Config.SERVICE_NICKNAME}") return None \ No newline at end of file diff --git a/mods/votekick/votekick_manager.py b/mods/votekick/votekick_manager.py index aaef559..b5dea33 100644 --- a/mods/votekick/votekick_manager.py +++ b/mods/votekick/votekick_manager.py @@ -10,8 +10,8 @@ class VotekickManager: def __init__(self, uplink: 'Votekick'): self.uplink = uplink - self.Logs = uplink.Logs - self.Utils = uplink.MainUtils + self.Logs = uplink.ctx.Logs + self.Utils = uplink.ctx.Utils def activate_new_channel(self, channel_name: str) -> bool: """Activate a new channel in the votekick systeme