V6.2.1 Adding main module utils and rehash utils to manager reload/rehash/restart

This commit is contained in:
adator
2025-08-23 19:26:22 +02:00
parent ae1f0ed424
commit bd95b6b448
23 changed files with 1085 additions and 912 deletions

View File

@@ -4,10 +4,7 @@ import re
import json import json
import sys import sys
import time import time
import random
import socket import socket
import hashlib
import logging
import threading import threading
import ipaddress import ipaddress
import ast import ast
@@ -17,7 +14,6 @@ from types import ModuleType
from dataclasses import fields from dataclasses import fields
from typing import Any, Optional, TYPE_CHECKING from typing import Any, Optional, TYPE_CHECKING
from base64 import b64decode, b64encode from base64 import b64decode, b64encode
from datetime import datetime, timedelta, timezone
from sqlalchemy import create_engine, Engine, Connection, CursorResult from sqlalchemy import create_engine, Engine, Connection, CursorResult
from sqlalchemy.sql import text from sqlalchemy.sql import text
@@ -34,7 +30,6 @@ class Base:
self.Utils = loader.Utils self.Utils = loader.Utils
self.logs = loader.Logs self.logs = loader.Logs
# self.init_log_system() # Demarrer le systeme de log
self.check_for_new_version(True) # Verifier si une nouvelle version est disponible self.check_for_new_version(True) # Verifier si une nouvelle version est disponible
# Liste des timers en cours # Liste des timers en cours
@@ -141,42 +136,6 @@ class Base:
except Exception as err: except Exception as err:
self.logs.error(f'General Error: {err}') self.logs.error(f'General Error: {err}')
def get_all_modules(self) -> list[str]:
"""Get list of all main modules
using this pattern mod_*.py
Returns:
list[str]: List of module names.
"""
base_path = Path('mods')
return [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')]
def reload_modules_with_dependencies(self, prefix: str = 'mods'):
"""
Reload all modules in sys.modules that start with the given prefix.
Useful for reloading a full package during development.
"""
modules_to_reload = []
# Collect target modules
for name, module in sys.modules.items():
if (
isinstance(module, ModuleType)
and module is not None
and name.startswith(prefix)
):
modules_to_reload.append((name, module))
# Sort to reload submodules before parent modules
for name, module in sorted(modules_to_reload, key=lambda x: x[0], reverse=True):
try:
if 'mod_' not in name and 'schemas' not in name:
importlib.reload(module)
self.logs.debug(f'[LOAD_MODULE] Module {module} success')
except Exception as err:
self.logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}')
def create_log(self, log_message: str) -> None: def create_log(self, log_message: str) -> None:
"""Enregiste les logs """Enregiste les logs
@@ -212,68 +171,6 @@ class Base:
return None return None
def db_isModuleExist(self, module_name:str) -> bool:
"""Teste si un module existe déja dans la base de données
Args:
module_name (str): le non du module a chercher dans la base de données
Returns:
bool: True si le module existe déja dans la base de données sinon False
"""
query = f"SELECT id FROM {self.Config.TABLE_MODULE} WHERE module_name = :module_name"
mes_donnes = {'module_name': module_name}
results = self.db_execute_query(query, mes_donnes)
if results.fetchall():
return True
else:
return False
def db_record_module(self, user_cmd: str, module_name: str, isdefault: int = 0) -> None:
"""Enregistre les modules dans la base de données
Args:
user_cmd (str): The user who performed the command
module_name (str): The module name
isdefault (int): Is this a default module. Default 0
"""
if not self.db_isModuleExist(module_name):
self.logs.debug(f"Le module {module_name} n'existe pas alors ont le créer")
insert_cmd_query = f"INSERT INTO {self.Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)"
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'module_name': module_name, 'isdefault': isdefault}
self.db_execute_query(insert_cmd_query, mes_donnees)
else:
self.logs.debug(f"Le module {module_name} existe déja dans la base de données")
return None
def db_update_module(self, user_cmd: str, module_name: str) -> None:
"""Modifie la date et le user qui a rechargé le module
Args:
user_cmd (str): le user qui a rechargé le module
module_name (str): le module a rechargé
"""
update_cmd_query = f"UPDATE {self.Config.TABLE_MODULE} SET datetime = :datetime, user = :user WHERE module_name = :module_name"
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'module_name': module_name}
self.db_execute_query(update_cmd_query, mes_donnees)
return None
def db_delete_module(self, module_name:str) -> None:
"""Supprime les modules de la base de données
Args:
module_name (str): The module name you want to delete
"""
insert_cmd_query = f"DELETE FROM {self.Config.TABLE_MODULE} WHERE module_name = :module_name"
mes_donnees = {'module_name': module_name}
self.db_execute_query(insert_cmd_query, mes_donnees)
return None
def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool: def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool:
"""Sync module local parameters with the database """Sync module local parameters with the database
if new module then local param will be stored in the database if new module then local param will be stored in the database
@@ -667,8 +564,8 @@ class Base:
self.db_execute_query(table_core_config) self.db_execute_query(table_core_config)
if self.install: if self.install:
self.db_record_module('sys', 'mod_command', 1) self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True)
self.db_record_module('sys', 'mod_defender', 1) self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
self.install = False self.install = False
return None return None

View File

@@ -1,5 +1,4 @@
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from core.base import Base
from core.definition import MAdmin from core.definition import MAdmin
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -24,7 +23,6 @@ class Admin:
for record in self.UID_ADMIN_DB: for record in self.UID_ADMIN_DB:
if record.uid == new_admin.uid: if record.uid == new_admin.uid:
# If the admin exist then return False and do not go further
self.Logs.debug(f'{record.uid} already exist') self.Logs.debug(f'{record.uid} already exist')
return False return False

View File

@@ -9,6 +9,7 @@ class Command:
DB_COMMANDS: list['MCommand'] = [] DB_COMMANDS: list['MCommand'] = []
def __init__(self, loader: 'Loader'): def __init__(self, loader: 'Loader'):
self.Loader = loader
self.Base = loader.Base self.Base = loader.Base
def build(self, new_command_obj: MCommand) -> bool: def build(self, new_command_obj: MCommand) -> bool:
@@ -57,3 +58,26 @@ class Command:
new_list.append(cmd) new_list.append(cmd)
return new_list return new_list
def is_client_allowed_to_run_command(self, nickname: str, command_name: str) -> bool:
admin = self.Loader.Admin.get_admin(nickname)
admin_level = admin.level if admin else 0
commands = self.get_commands_by_level(admin_level)
if command_name in [command.command_name for command in commands]:
return True
return False
def is_command_exist(self, command_name: str) -> bool:
"""Check if the command name exist
Args:
command_name (str): The command name you want to check
Returns:
bool: True if the command exist
"""
if command_name.lower() in [command.command_name.lower() for command in self.get_ordered_commands()]:
return True
return False

View File

@@ -1,23 +1,32 @@
from json import load from json import load
from sys import exit from sys import exit
from os import sep from os import sep
from typing import Union from typing import Any, Optional, Union, TYPE_CHECKING
from core.definition import MConfig from core.definition import MConfig
from logging import Logger
if TYPE_CHECKING:
from core.loader import Loader
class Configuration: class Configuration:
def __init__(self, logs: Logger) -> None: def __init__(self, loader: 'Loader') -> None:
self.Logs = logs
self.ConfigObject: MConfig = self.__load_service_configuration() self.Loader = loader
self.Logs = loader.Logs
self._config_model: MConfig = self.__load_service_configuration()
loader.ServiceLogging.set_file_handler_level(self._config_model.DEBUG_LEVEL)
loader.ServiceLogging.set_stdout_handler_level(self._config_model.DEBUG_LEVEL)
loader.ServiceLogging.update_handler_format(self._config_model.DEBUG_HARD)
return None return None
def __load_json_service_configuration(self): def get_config_model(self) -> MConfig:
return self._config_model
def __load_json_service_configuration(self) -> Optional[dict[str, Any]]:
try: try:
conf_filename = f'config{sep}configuration.json' conf_filename = f'config{sep}configuration.json'
with open(conf_filename, 'r') as configuration_data: with open(conf_filename, 'r') as configuration_data:
configuration:dict[str, Union[str, int, list, dict]] = load(configuration_data) configuration: dict[str, Union[str, int, list, dict]] = load(configuration_data)
return configuration return configuration
@@ -48,11 +57,8 @@ class Configuration:
import_config.pop(json_conf, None) import_config.pop(json_conf, None)
self.Logs.warning(f"[!] The key {json_conf} is not expected, it has been removed from the system ! please remove it from configuration.json file [!]") self.Logs.warning(f"[!] The key {json_conf} is not expected, it has been removed from the system ! please remove it from configuration.json file [!]")
ConfigObject: MConfig = MConfig( self.Logs.debug(f"[LOADING CONFIGURATION]: Loading configuration with {len(import_config)} parameters!")
**import_config return MConfig(**import_config)
)
return ConfigObject
except TypeError as te: except TypeError as te:
self.Logs.error(te) self.Logs.error(te)

View File

@@ -59,8 +59,8 @@ class Inspircd:
""" """
try: try:
batch_size = self.__Config.BATCH_SIZE batch_size = self.__Config.BATCH_SIZE
User_from = self.__Irc.User.get_User(nick_from) User_from = self.__Irc.User.get_user(nick_from)
User_to = self.__Irc.User.get_User(nick_to) if nick_to is None else None User_to = self.__Irc.User.get_user(nick_to) if 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") self.__Logs.error(f"The sender nickname [{nick_from}] do not exist")
@@ -88,8 +88,8 @@ class Inspircd:
""" """
try: try:
batch_size = self.__Config.BATCH_SIZE batch_size = self.__Config.BATCH_SIZE
User_from = self.__Irc.User.get_User(nick_from) User_from = self.__Irc.User.get_user(nick_from)
User_to = self.__Irc.User.get_User(nick_to) 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") self.__Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist")
@@ -188,17 +188,13 @@ class Inspircd:
uidornickname (str): The UID or the Nickname uidornickname (str): The UID or the Nickname
reason (str): The reason for the quit reason (str): The reason for the quit
""" """
user_obj = self.__Irc.User.get_User(uidornickname=uid) user_obj = self.__Irc.User.get_user(uidornickname=uid)
clone_obj = self.__Irc.Clone.get_clone(uidornickname=uid)
reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid) reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid)
if not user_obj is None: if not user_obj is None:
self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log) 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 clone_obj is None:
self.__Irc.Clone.delete(clone_obj.uid)
if not reputationObj is None: if not reputationObj is None:
self.__Irc.Reputation.delete(reputationObj.uid) self.__Irc.Reputation.delete(reputationObj.uid)
@@ -255,7 +251,7 @@ class Inspircd:
print_log (bool, optional): Write logs. Defaults to True. 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 '' passwordChannel = password if not password is None else ''
if userObj is None: if userObj is None:
@@ -280,7 +276,7 @@ class Inspircd:
print_log (bool, optional): Write logs. Defaults to True. 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: if userObj is None:
self.__Logs.error(f"The user [{uidornickname}] is not valid") self.__Logs.error(f"The user [{uidornickname}] is not valid")
@@ -311,7 +307,7 @@ class Inspircd:
try: try:
# [':adator_', 'UMODE2', '-iwx'] # [':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] userMode = serverMsg[2]
if userObj is None: # If user is not created if userObj is None: # If user is not created
@@ -346,7 +342,6 @@ class Inspircd:
self.__Irc.Channel.delete_user_from_all_channel(uid_who_quit) self.__Irc.Channel.delete_user_from_all_channel(uid_who_quit)
self.__Irc.User.delete(uid_who_quit) self.__Irc.User.delete(uid_who_quit)
self.__Irc.Reputation.delete(uid_who_quit) self.__Irc.Reputation.delete(uid_who_quit)
self.__Irc.Clone.delete(uid_who_quit)
return None return None
@@ -655,7 +650,7 @@ class Inspircd:
""" """
try: try:
# ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender'] # ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender']
getUser = self.__Irc.User.get_User(self.__Utils.clean_uid(serverMsg[1])) getUser = self.__Irc.User.get_user(self.__Utils.clean_uid(serverMsg[1]))
if getUser is None: if getUser is None:
return None return None
@@ -663,7 +658,7 @@ class Inspircd:
response_351 = f"{self.__Config.SERVICE_NAME.capitalize()}-{self.__Config.CURRENT_VERSION} {self.__Config.SERVICE_HOST} {self.name}" 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 {getUser.nickname} {response_351}')
modules = self.__Base.get_all_modules() modules = self.__Irc.ModuleUtils.get_all_available_modules()
response_005 = ' | '.join(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')

View File

@@ -5,6 +5,7 @@ from ssl import SSLEOFError, SSLError
if TYPE_CHECKING: if TYPE_CHECKING:
from core.irc import Irc from core.irc import Irc
from core.definition import MClient
class Unrealircd6: class Unrealircd6:
@@ -23,7 +24,8 @@ class Unrealircd6:
'EOS', 'PRIVMSG', 'MODE', 'UMODE2', 'EOS', 'PRIVMSG', 'MODE', 'UMODE2',
'VERSION', 'REPUTATION', 'SVS2MODE', 'VERSION', 'REPUTATION', 'SVS2MODE',
'SLOG', 'NICK', 'PART', 'PONG', 'SLOG', 'NICK', 'PART', 'PONG',
'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO'} 'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO',
'006', '007', '018'}
self.__Logs.info(f"** Loading protocol [{__name__}]") self.__Logs.info(f"** Loading protocol [{__name__}]")
@@ -44,6 +46,40 @@ class Unrealircd6:
return (-1, None) return (-1, None)
def parse_server_msg(self, server_msg: list[str]) -> Optional[str]:
"""Parse the server message and return the command
Args:
server_msg (list[str]): The Original server message >>
Returns:
Union[str, None]: Return the command protocol name
"""
protocol_exception = ['PING', 'SERVER', 'PROTOCTL']
increment = 0
server_msg_copy = server_msg.copy()
first_index = 0
second_index = 0
for index, element in enumerate(server_msg_copy):
# Handle the protocol exceptions ex. ping, server ....
if element in protocol_exception and index == 0:
return element
if element.startswith(':'):
increment += 1
first_index = index + 1 if increment == 1 else first_index
second_index = index if increment == 2 else second_index
second_index = len(server_msg_copy) if second_index == 0 else second_index
parsed_msg = server_msg_copy[first_index:second_index]
for cmd in parsed_msg:
if cmd in self.known_protocol:
return cmd
return None
def send2socket(self, message: str, print_log: bool = True) -> None: def send2socket(self, message: str, print_log: bool = True) -> None:
"""Envoit les commandes à envoyer au serveur. """Envoit les commandes à envoyer au serveur.
@@ -84,8 +120,8 @@ class Unrealircd6:
""" """
try: try:
batch_size = self.__Config.BATCH_SIZE batch_size = self.__Config.BATCH_SIZE
User_from = self.__Irc.User.get_User(nick_from) 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_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") self.__Logs.error(f"The sender nickname [{nick_from}] do not exist")
@@ -115,8 +151,8 @@ class Unrealircd6:
""" """
try: try:
batch_size = self.__Config.BATCH_SIZE batch_size = self.__Config.BATCH_SIZE
User_from = self.__Irc.User.get_User(nick_from) User_from = self.__Irc.User.get_user(nick_from)
User_to = self.__Irc.User.get_User(nick_to) 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") self.__Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist")
@@ -129,40 +165,6 @@ class Unrealircd6:
except Exception as err: except Exception as err:
self.__Logs.error(f"General Error: {err}") self.__Logs.error(f"General Error: {err}")
def parse_server_msg(self, server_msg: list[str]) -> Optional[str]:
"""Parse the server message and return the command
Args:
server_msg (list[str]): The Original server message >>
Returns:
Union[str, None]: Return the command protocol name
"""
protocol_exception = ['PING', 'SERVER', 'PROTOCTL']
increment = 0
server_msg_copy = server_msg.copy()
first_index = 0
second_index = 0
for index, element in enumerate(server_msg_copy):
# Handle the protocol exceptions ex. ping, server ....
if element in protocol_exception and index == 0:
return element
if element.startswith(':'):
increment += 1
first_index = index + 1 if increment == 1 else first_index
second_index = index if increment == 2 else second_index
second_index = len(server_msg_copy) if second_index == 0 else second_index
parsed_msg = server_msg_copy[first_index:second_index]
for cmd in parsed_msg:
if cmd in self.known_protocol:
return cmd
return None
def send_link(self): def send_link(self):
"""Créer le link et envoyer les informations nécessaires pour la """Créer le link et envoyer les informations nécessaires pour la
connexion au serveur. connexion au serveur.
@@ -217,7 +219,7 @@ class Unrealircd6:
""" """
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) userObj = self.__Irc.User.get_user(self.__Config.SERVICE_NICKNAME)
self.__Irc.User.update_nickname(userObj.uid, newnickname) self.__Irc.User.update_nickname(userObj.uid, newnickname)
return None return None
@@ -275,7 +277,7 @@ class Unrealircd6:
""" """
try: try:
userObj = self.__Irc.User.get_User(uidornickname=nick_to_sapart) userObj = self.__Irc.User.get_user(uidornickname=nick_to_sapart)
chanObj = self.__Irc.Channel.get_channel(channel_name) chanObj = self.__Irc.Channel.get_channel(channel_name)
service_uid = self.__Config.SERVICE_ID service_uid = self.__Config.SERVICE_ID
@@ -299,7 +301,7 @@ class Unrealircd6:
""" """
try: try:
userObj = self.__Irc.User.get_User(uidornickname=nick_to_sajoin) userObj = self.__Irc.User.get_user(uidornickname=nick_to_sajoin)
chanObj = self.__Irc.Channel.get_channel(channel_name) chanObj = self.__Irc.Channel.get_channel(channel_name)
service_uid = self.__Config.SERVICE_ID service_uid = self.__Config.SERVICE_ID
@@ -327,25 +329,92 @@ class Unrealircd6:
except Exception as err: except Exception as err:
self.__Logs.error(f"{__name__} - General Error: {err}") self.__Logs.error(f"{__name__} - General Error: {err}")
def send_svs_mode(self, nickname: str, user_mode: str) -> None: def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None:
try: user_obj = self.__Irc.User.get_user(nick_to_part)
userObj = self.__Irc.User.get_User(uidornickname=nickname) if user_obj is None:
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
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)
if user_obj is None:
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)])
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}')
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 service_uid = self.__Config.SERVICE_ID
if userObj is None: if user_obj is None:
# User not exist: leave
return None return None
self.send2socket(f':{service_uid} SVSMODE {nickname} {user_mode}') self.send2socket(f':{service_uid} SVSMODE {nickname} {user_mode}')
# Update new mode # Update new mode
self.__Irc.User.update_mode(userObj.uid, user_mode) self.__Irc.User.update_mode(user_obj.uid, user_mode)
return None return None
except Exception as err: 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
if user_obj is None:
return None
self.send2socket(f':{service_uid} SVS2MODE {nickname} {user_mode}')
# Update new 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}")
def send_svslogin(self, client_uid: str, user_account: str) -> None:
"""Log a client into his account.
Args:
client_uid (str): Client UID
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}")
except Exception as err:
self.__Irc.Logs.error(f'General Error: {err}')
def send_svslogout(self, client_obj: 'MClient') -> None:
"""Logout a client from his account
Args:
client_uid (str): The Client UID
"""
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.send_svs2mode(c_nickname, '-r')
except Exception as err:
self.__Irc.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: True) -> None:
"""Send quit message """Send quit message
- Delete uid from User object - Delete uid from User object
@@ -355,7 +424,7 @@ class Unrealircd6:
uidornickname (str): The UID or the Nickname uidornickname (str): The UID or the Nickname
reason (str): The reason for the quit reason (str): The reason for the quit
""" """
user_obj = self.__Irc.User.get_User(uidornickname=uid) user_obj = self.__Irc.User.get_user(uidornickname=uid)
reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid) reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid)
if not user_obj is None: if not user_obj is None:
@@ -418,7 +487,7 @@ class Unrealircd6:
print_log (bool, optional): Write logs. Defaults to True. 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 '' passwordChannel = password if not password is None else ''
if userObj is None: if userObj is None:
@@ -458,7 +527,7 @@ class Unrealircd6:
print_log (bool, optional): Write logs. Defaults to True. 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: if userObj is None:
self.__Logs.error(f"The user [{uidornickname}] is not valid") self.__Logs.error(f"The user [{uidornickname}] is not valid")
@@ -506,7 +575,7 @@ class Unrealircd6:
uid_user_to_edit = serverMsg[2] uid_user_to_edit = serverMsg[2]
umode = serverMsg[3] 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: if userObj is None:
return None return None
@@ -540,7 +609,7 @@ class Unrealircd6:
try: try:
# [':adator_', 'UMODE2', '-iwx'] # [':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] userMode = serverMsg[2]
if userObj is None: # If user is not created if userObj is None: # If user is not created
@@ -794,8 +863,8 @@ class Unrealircd6:
self.__Config.DEFENDER_INIT = 0 self.__Config.DEFENDER_INIT = 0
# Send EOF to other modules # Send EOF to other modules
for classe_name, classe_object in self.__Irc.loaded_classes.items(): for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy():
classe_object.cmd(server_msg_copy) module.class_instance.cmd(server_msg_copy)
return None return None
except IndexError as ie: except IndexError as ie:
@@ -907,27 +976,14 @@ class Unrealircd6:
""" """
try: try:
srv_msg = serverMsg.copy() srv_msg = serverMsg.copy()
cmd = serverMsg.copy() cmd = serverMsg.copy()
# Supprimer la premiere valeur si MTAGS activé # Supprimer la premiere valeur si MTAGS activé
if cmd[0].startswith('@'): if cmd[0].startswith('@'):
cmd.pop(0) cmd.pop(0)
# Hide auth logs
if len(cmd) == 7:
if cmd[2] == 'PRIVMSG' and cmd[4] == ':auth':
data_copy = cmd.copy()
data_copy[6] = '**********'
self.__Logs.debug(f">> {data_copy}")
else:
self.__Logs.debug(f">> {cmd}")
else:
self.__Logs.debug(f">> {cmd}")
get_uid_or_nickname = str(cmd[0].replace(':','')) get_uid_or_nickname = str(cmd[0].replace(':',''))
user_trigger = self.__Irc.User.get_nickname(get_uid_or_nickname) user_trigger = self.__Irc.User.get_nickname(get_uid_or_nickname)
dnickname = self.__Config.SERVICE_NICKNAME dnickname = self.__Config.SERVICE_NICKNAME
pattern = fr'(:\{self.__Config.SERVICE_PREFIX})(.*)$' pattern = fr'(:\{self.__Config.SERVICE_PREFIX})(.*)$'
hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le . hcmds = search(pattern, ' '.join(cmd)) # va matcher avec tout les caractéres aprés le .
@@ -936,7 +992,7 @@ class Unrealircd6:
convert_to_string = ' '.join(liste_des_commandes) convert_to_string = ' '.join(liste_des_commandes)
arg = convert_to_string.split() arg = convert_to_string.split()
arg.remove(f':{self.__Config.SERVICE_PREFIX}') arg.remove(f':{self.__Config.SERVICE_PREFIX}')
if not arg[0].lower() in self.__Irc.module_commands_list: if not self.__Irc.Commands.is_command_exist(arg[0]):
self.__Logs.debug(f"This command {arg[0]} is not available") self.__Logs.debug(f"This command {arg[0]} is not available")
self.send_notice( self.send_notice(
nick_from=self.__Config.SERVICE_NICKNAME, nick_from=self.__Config.SERVICE_NICKNAME,
@@ -945,6 +1001,15 @@ class Unrealircd6:
) )
return None return None
# if not arg[0].lower() in self.__Irc.module_commands_list:
# self.__Logs.debug(f"This command {arg[0]} is not available")
# 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"
# )
# return None
cmd_to_send = convert_to_string.replace(':','') 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)
@@ -963,21 +1028,25 @@ class Unrealircd6:
# Réponse a un CTCP VERSION # Réponse a un CTCP VERSION
if arg[0] == '\x01VERSION\x01': if arg[0] == '\x01VERSION\x01':
self.on_version(srv_msg) self.on_version(srv_msg)
return False return None
# Réponse a un TIME # Réponse a un TIME
if arg[0] == '\x01TIME\x01': if arg[0] == '\x01TIME\x01':
self.on_time(srv_msg) self.on_time(srv_msg)
return False return None
# Réponse a un PING # Réponse a un PING
if arg[0] == '\x01PING': if arg[0] == '\x01PING':
self.on_ping(srv_msg) self.on_ping(srv_msg)
return False return None
if not arg[0].lower() in self.__Irc.module_commands_list: 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") self.__Logs.debug(f"This command {arg[0]} sent by {user_trigger} is not available")
return False 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(':','') 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)
@@ -1011,6 +1080,14 @@ class Unrealircd6:
except Exception as err: 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:
try:
# ['SERVER', 'irc.local.org', '1', ':U6100-Fhn6OoE-001', 'Local', 'Server']
sCopy = serverMsg.copy()
self.__Irc.Settings.MAIN_SERVER_HOSTNAME = sCopy[1]
except Exception as err:
self.__Irc.Logs.error(f'General Error: {err}')
def on_version(self, serverMsg: list[str]) -> None: def on_version(self, serverMsg: list[str]) -> None:
"""Sending Server Version to the server """Sending Server Version to the server
@@ -1105,7 +1182,7 @@ class Unrealircd6:
if '@' in list(serverMsg_copy[0])[0]: if '@' in list(serverMsg_copy[0])[0]:
serverMsg_copy.pop(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: if getUser is None:
return None return None
@@ -1113,7 +1190,7 @@ class Unrealircd6:
response_351 = f"{self.__Config.SERVICE_NAME.capitalize()}-{self.__Config.CURRENT_VERSION} {self.__Config.SERVICE_HOST} {self.name}" 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 {getUser.nickname} {response_351}')
modules = self.__Base.get_all_modules() modules = self.__Irc.ModuleUtils.get_all_available_modules()
response_005 = ' | '.join(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')

115
core/classes/rehash.py Normal file
View File

@@ -0,0 +1,115 @@
import importlib
import sys
import time
from typing import TYPE_CHECKING
import socket
from core.classes.protocol import Protocol
if TYPE_CHECKING:
from core.irc import Irc
# Modules impacted by rehashing!
REHASH_MODULES = [
'core.definition',
'core.utils',
'core.classes.config',
'core.base',
'core.classes.commands',
'core.classes.protocols.unreal6',
'core.classes.protocols.inspircd',
'core.classes.protocol'
]
def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -> None:
# reload modules.
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()
# Reload configuration
uplink.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).get_config_model()
uplink.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
uplink.Protocol = Protocol(uplink.Config.SERVEUR_PROTOCOL, uplink.ircObject).Protocol
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="Defender Power off")
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 ...')
uplink.init_service_user()
uplink.Utils.create_socket(uplink)
uplink.Protocol.send_link()
uplink.join_saved_channels()
uplink.ModuleUtils.db_load_all_existing_modules(uplink)
uplink.Config.DEFENDER_RESTART = 0
def rehash_service(uplink: 'Irc', nickname: str) -> None:
need_a_restart = ["SERVEUR_ID"]
uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS)
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(
nick_from=uplink.Config.SERVICE_NICKNAME,
msg=f'[REHASH] Module [{mod}] reloaded',
channel=uplink.Config.SERVICE_CHANLOG
)
uplink.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).get_config_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
uplink.Config.SSL_VERSION = config_model_bakcup.SSL_VERSION
uplink.Config.CURRENT_VERSION = config_model_bakcup.CURRENT_VERSION
uplink.Config.LATEST_VERSION = config_model_bakcup.LATEST_VERSION
conf_bkp_dict: dict = config_model_bakcup.to_dict()
config_dict: dict = uplink.Config.to_dict()
for key, value in conf_bkp_dict.items():
if config_dict[key] != value and key != 'COLORS':
uplink.Protocol.send_priv_msg(
nick_from=uplink.Config.SERVICE_NICKNAME,
msg=f'[{key}]: {value} ==> {config_dict[key]}',
channel=uplink.Config.SERVICE_CHANLOG
)
if key in need_a_restart:
restart_flag = True
if config_model_bakcup.SERVICE_NICKNAME != uplink.Config.SERVICE_NICKNAME:
uplink.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(
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.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
uplink.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
uplink.Protocol = Protocol(uplink.Config.SERVEUR_PROTOCOL, uplink.ircObject).Protocol
# Reload Service modules
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
uplink.ModuleUtils.reload_one_module(uplink, module.module_name, nickname)
return None

View File

@@ -18,6 +18,7 @@ class Settings:
CONSOLE: bool = False CONSOLE: bool = False
MAIN_SERVER_HOSTNAME: str = None
PROTOCTL_USER_MODES: list[str] = [] PROTOCTL_USER_MODES: list[str] = []
PROTOCTL_PREFIX: list[str] = [] PROTOCTL_PREFIX: list[str] = []

View File

@@ -25,8 +25,7 @@ class User:
bool: True if inserted bool: True if inserted
""" """
user_obj = self.get_User(new_user.uid) user_obj = self.get_user(new_user.uid)
if not user_obj is None: if not user_obj is None:
# User already created return False # User already created return False
return False return False
@@ -45,7 +44,7 @@ class User:
Returns: Returns:
bool: True if updated bool: True if updated
""" """
user_obj = self.get_User(uidornickname=uid) user_obj = self.get_user(uidornickname=uid)
if user_obj is None: if user_obj is None:
return False return False
@@ -65,7 +64,7 @@ class User:
bool: True if user mode has been updaed bool: True if user mode has been updaed
""" """
response = True response = True
user_obj = self.get_User(uidornickname=uidornickname) user_obj = self.get_user(uidornickname=uidornickname)
if user_obj is None: if user_obj is None:
return False return False
@@ -107,7 +106,7 @@ class User:
bool: True if deleted bool: True if deleted
""" """
user_obj = self.get_User(uidornickname=uid) user_obj = self.get_user(uidornickname=uid)
if user_obj is None: if user_obj is None:
return False return False
@@ -116,7 +115,7 @@ class User:
return True return True
def get_User(self, uidornickname: str) -> Optional['MUser']: def get_user(self, uidornickname: str) -> Optional['MUser']:
"""Get The User Object model """Get The User Object model
Args: Args:
@@ -143,7 +142,7 @@ class User:
str|None: Return the UID str|None: Return the UID
""" """
user_obj = self.get_User(uidornickname=uidornickname) user_obj = self.get_user(uidornickname=uidornickname)
if user_obj is None: if user_obj is None:
return None return None
@@ -159,7 +158,7 @@ class User:
Returns: Returns:
str|None: the nickname str|None: the nickname
""" """
user_obj = self.get_User(uidornickname=uidornickname) user_obj = self.get_user(uidornickname=uidornickname)
if user_obj is None: if user_obj is None:
return None return None
@@ -175,7 +174,7 @@ class User:
Returns: Returns:
Union[dict[str, any], None]: User Object as a dictionary or None Union[dict[str, any], None]: User Object as a dictionary or None
""" """
user_obj = self.get_User(uidornickname=uidornickname) user_obj = self.get_user(uidornickname=uidornickname)
if user_obj is None: if user_obj is None:
return None return None
@@ -191,7 +190,7 @@ class User:
Returns: Returns:
bool: True if exist bool: True if exist
""" """
user_obj = self.get_User(uidornickname=uidornikname) user_obj = self.get_user(uidornickname=uidornikname)
if user_obj is None: if user_obj is None:
return False return False
@@ -226,7 +225,7 @@ class User:
int: How long in minutes has the user been connected? int: How long in minutes has the user been connected?
""" """
get_user = self.get_User(uidornickname) get_user = self.get_user(uidornickname)
if get_user is None: if get_user is None:
return 0 return 0

View File

@@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
from json import dumps from json import dumps
from dataclasses import dataclass, field, asdict, fields from dataclasses import dataclass, field, asdict, fields
from typing import Literal, Any from typing import Literal, Any, Optional
from os import sep from os import sep
@dataclass @dataclass
@@ -246,6 +246,9 @@ class MConfig(MainModel):
DEBUG_LEVEL:Literal[10, 20, 30, 40, 50] = 20 DEBUG_LEVEL:Literal[10, 20, 30, 40, 50] = 20
"""Logs level: DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50. (default: 20)""" """Logs level: DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50. (default: 20)"""
DEBUG_HARD: bool = False
"""Adding filename, function name and the line number to the logs. Default False"""
LOGGING_NAME: str = "defender" LOGGING_NAME: str = "defender"
"""The name of the Logging instance""" """The name of the Logging instance"""
@@ -326,3 +329,9 @@ class MCommand(MainModel):
command_name: str = None command_name: str = None
description: str = None description: str = None
command_level: int = 0 command_level: int = 0
@dataclass
class MModule(MainModel):
module_name: str = None
class_name: str = None
class_instance: Optional[Any] = None

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,12 @@
from logging import Logger from logging import Logger
from core.classes import user, admin, client, channel, reputation, settings, commands from core.classes import user, admin, client, channel, reputation, settings
import core.logs as logs import core.logs as logs
import core.definition as df import core.definition as df
import core.utils as utils import core.utils as utils
import core.base as base_module import core.base as base_mod
import core.classes.config as conf_module import core.module as module_mod
import core.classes.commands as commands_mod
import core.classes.config as conf_mod
class Loader: class Loader:
@@ -13,24 +15,26 @@ class Loader:
# Load Main Modules # Load Main Modules
self.Definition: df = df self.Definition: df = df
self.ConfModule: conf_module = conf_module self.ConfModule: conf_mod = conf_mod
self.BaseModule: base_module = base_module self.BaseModule: base_mod = base_mod
self.Utils: utils = utils self.CommandModule: commands_mod = commands_mod
self.LoggingModule: logs = logs self.LoggingModule: logs = logs
self.Utils: utils = utils
# Load Classes # Load Classes
self.ServiceLogging: logs.ServiceLogging = logs.ServiceLogging() self.ServiceLogging: logs.ServiceLogging = self.LoggingModule.ServiceLogging()
self.Logs: Logger = self.ServiceLogging.get_logger() self.Logs: Logger = self.ServiceLogging.get_logger()
self.Settings: settings.Settings = settings.Settings() self.Settings: settings.Settings = settings.Settings()
self.Config: df.MConfig = self.ConfModule.Configuration(self.Logs).ConfigObject self.Config: df.MConfig = self.ConfModule.Configuration(self).get_config_model()
self.Base: base_module.Base = self.BaseModule.Base(self) self.Base: base_mod.Base = self.BaseModule.Base(self)
self.User: user.User = user.User(self) self.User: user.User = user.User(self)
@@ -42,4 +46,8 @@ class Loader:
self.Reputation: reputation.Reputation = reputation.Reputation(self) self.Reputation: reputation.Reputation = reputation.Reputation(self)
self.Commands: commands.Command = commands.Command(self) self.Commands: commands_mod.Command = commands_mod.Command(self)
self.ModuleUtils: module_mod.Module = module_mod.Module(self)
self.Logs.debug("LOADER Success!")

View File

@@ -9,6 +9,8 @@ class ServiceLogging:
""" """
self.OS_SEP = sep self.OS_SEP = sep
self.LOGGING_NAME = loggin_name self.LOGGING_NAME = loggin_name
self.remove_logger(loggin_name) # Remove logger if exists
self.DEBUG_LEVEL, self.DEBUG_FILE_LEVEL, self.DEBUG_STDOUT_LEVEL = (10, 10, 10) self.DEBUG_LEVEL, self.DEBUG_FILE_LEVEL, self.DEBUG_STDOUT_LEVEL = (10, 10, 10)
self.SERVER_PREFIX = None self.SERVER_PREFIX = None
self.LOGGING_CONSOLE = True self.LOGGING_CONSOLE = True
@@ -85,21 +87,77 @@ class ServiceLogging:
# Apply the filter # Apply the filter
logs.addFilter(self.replace_filter) logs.addFilter(self.replace_filter)
logs.info(f'#################### STARTING {self.LOGGING_NAME} ####################') logs.info(f'#################### STARTING {self.LOGGING_NAME} ####################')
return logs return logs
def set_stdout_handler_level(self, level: int) -> None: def set_stdout_handler_level(self, level: int) -> None:
self.logs.debug(f"[STDOUT LEVEL] New level {level}")
self.stdout_handler.setLevel(level) self.stdout_handler.setLevel(level)
def set_file_handler_level(self, level: int) -> None: def set_file_handler_level(self, level: int) -> None:
self.logs.debug(f"[LOG FILE LEVEL] new level {level}")
self.file_handler.setLevel(level) self.file_handler.setLevel(level)
def update_handler_format(self, debug_hard: bool = False) -> None:
"""Updating logging formatter format!
Args:
debug_hard (bool, optional): If true you will have filename,
function name and the line number. Defaults to False.
"""
# Updating logging formatter
if debug_hard:
new_formatter = logging.Formatter(
fmt='%(asctime)s - %(levelname)s - %(message)s (%(filename)s:%(funcName)s:%(lineno)d)',
datefmt='%Y-%m-%d %H:%M:%S'
)
else:
new_formatter = logging.Formatter(
fmt='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
for handler in self.logs.handlers:
handler.setFormatter(new_formatter)
def regenerate_handlers(self, logger: logging.Logger) -> logging.Logger:
os_sep = self.OS_SEP
logging_name = self.LOGGING_NAME
debug_file_level = self.DEBUG_FILE_LEVEL
debug_stdout_level = self.DEBUG_STDOUT_LEVEL
# Add Handlers
self.file_handler = logging.FileHandler(f'logs{os_sep}{logging_name}.log',encoding='UTF-8')
self.file_handler.setLevel(debug_file_level)
self.stdout_handler = logging.StreamHandler()
self.stdout_handler.setLevel(debug_stdout_level)
# Define log format
formatter = logging.Formatter(
fmt='%(asctime)s - %(levelname)s - %(message)s (%(filename)s:%(funcName)s:%(lineno)d)',
datefmt='%Y-%m-%d %H:%M:%S'
)
# Apply log format
self.file_handler.setFormatter(formatter)
self.stdout_handler.setFormatter(formatter)
# Add handler to logs
logger.addHandler(self.file_handler)
logger.addHandler(self.stdout_handler)
# Apply the filter
logger.addFilter(self.replace_filter)
logger.info(f'REGENRATING LOGGER {self.LOGGING_NAME}')
return logger
def replace_filter(self, record: logging.LogRecord) -> bool: def replace_filter(self, record: logging.LogRecord) -> bool:
response = True response = True
filter: list[str] = ['PING', f":{self.SERVER_PREFIX}auth", "['PASS'"] filter: list[str] = self.LOG_FILTERS
# record.msg = record.getMessage().replace("PING", "[REDACTED]") # record.msg = record.getMessage().replace("PING", "[REDACTED]")
# if self.LOGGING_CONSOLE: # if self.LOGGING_CONSOLE:
@@ -109,4 +167,4 @@ class ServiceLogging:
if f in record.getMessage(): if f in record.getMessage():
response = False response = False
return response # Retourne True pour permettre l'affichage du message return response # Retourne True to write the log!

424
core/module.py Normal file
View File

@@ -0,0 +1,424 @@
'''
This is the main operational file to handle modules
'''
from pathlib import Path
import sys
import importlib
from types import ModuleType
from typing import TYPE_CHECKING, Optional
from core.definition import MModule
if TYPE_CHECKING:
from core.loader import Loader
from core.irc import Irc
class Module:
DB_MODULES: list[MModule] = []
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
def get_all_available_modules(self) -> list[str]:
"""Get list of all main modules
using this pattern mod_*.py
all files starting with mod_
Returns:
list[str]: List of all module names.
"""
base_path = Path('mods')
return [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')]
def get_module_information(self, module_name: str) -> tuple[str, str, str]:
# module_name : mod_defender
if not module_name.lower().startswith('mod_'):
return None, None, None
module_name = module_name.lower()
module_folder = module_name.split('_')[1].lower() # --> defender
class_name = module_name.split('_')[1].capitalize() # --> Defender
return module_folder, module_name, class_name
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)
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}")
return False
if self.is_module_exist_in_sys_module(module_name):
self.__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!")
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
)
return False
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
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",
channel=self.__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)
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)
uplink.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME,
msg=f"Module {module_name} chargé",
channel=self.__Config.SERVICE_CHANLOG
)
self.__Logs.debug(f"Module {class_name} has been loaded")
def load_all_modules(self) -> bool:
...
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:
uplink (Irc): The Irc service instance
module_name (str): The module name
nickname (str): The nickname
Returns:
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
try:
if self.is_module_exist_in_sys_module(module_name):
module_model = self.model_get_module(module_name)
if module_model:
module_model.class_instance.unload()
else:
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
)
self.__Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self.__Config.SERVICE_PREFIX}load {module_name}")
return False
# reload module dependencies
self.reload_all_modules_with_all_dependencies(f'mods.{module_folder}')
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)
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(
nick_from=self.__Config.SERVICE_NICKNAME,
msg=f"Module [{module_folder}.{module_name}] has been reloaded!",
channel=self.__Config.SERVICE_CHANLOG
)
self.__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}")
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
)
return False
except (TypeError, AttributeError, KeyError, Exception) as err:
self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}")
uplink.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME,
msg=f"[RELOAD MODULE ERROR]: {err}",
channel=self.__Config.SERVICE_CHANLOG
)
self.db_delete_module(module_name)
def reload_all_modules(self) -> bool:
...
def reload_all_modules_with_all_dependencies(self, prefix: str = 'mods') -> bool:
"""
Reload all modules in sys.modules that start with the given prefix.
Useful for reloading a full package during development.
"""
modules_to_reload = []
# Collect target modules
for name, module in sys.modules.items():
if (
isinstance(module, ModuleType)
and module is not None
and name.startswith(prefix)
):
modules_to_reload.append((name, module))
# Sort to reload submodules before parent modules
for name, module in sorted(modules_to_reload, key=lambda x: x[0], reverse=True):
try:
if 'mod_' not in name and 'schemas' not in name:
importlib.reload(module)
self.__Logs.debug(f'[LOAD_MODULE] Module {module} success')
except Exception as err:
self.__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:
"""Unload a module
Args:
mod_name (str): Module name ex mod_defender
Returns:
bool: True if success
"""
try:
# Le nom du module. exemple: mod_defender
red = self.__Config.COLORS.red
nogc = self.__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!")
uplink.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME,
msg=f"[ {red}UNLOAD MODULE ERROR{nogc} ] This module {module_name} is not loaded!",
channel=self.__Config.SERVICE_CHANLOG
)
return False
if module:
module.class_instance.unload()
self.DB_MODULES.remove(module)
# Delete from the sys.modules.
if sys.modules.get(f'mods.{module_folder}.{module_name}'):
del sys.modules[f"mods.{module_folder}.{module_name}"]
if sys.modules.get(f'mods.{module_folder}.{module_name}'):
self.__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)
uplink.Protocol.send_priv_msg(
nick_from=self.__Config.SERVICE_NICKNAME,
msg=f"[ UNLOAD MODULE INFO ] Module {module_name} has been unloaded!",
channel=self.__Config.SERVICE_CHANLOG
)
self.__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!")
return False
except Exception as err:
self.__Logs.error(f"General Error: {err}")
return False
def unload_all_modules(self) -> bool:
...
def is_module_exist_in_sys_module(self, module_name: str) -> bool:
"""Check if the module exist in the sys.modules
This will check only in the folder mods/
Args:
module_name (str): The module name
Returns:
bool: True if the module exist
"""
module_folder, module_name, class_name = self.get_module_information(module_name)
if "mods." + module_folder + "." + module_name in sys.modules:
return True
return False
'''
ALL METHODS RELATED TO THE MModule MODEL DATACLASS
'''
def model_get_module(self, module_name: str) -> Optional[MModule]:
"""Get The module model object if exist otherwise it returns None
Args:
module_name (str): The module name you want to fetch
Returns:
Optional[MModule]: The Module Model Object
"""
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")
return module
self.__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]:
"""Get the instance of DB_MODULES.
Warning: You should use a copy if you want to loop through the list!
Returns:
list[MModule]: A list of module model object
"""
self.__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:
"""Insert a new module model object
Args:
module_model (MModule): The module model object
Returns:
bool: True if the model has been inserted
"""
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")
return True
self.__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")
return None
def model_is_module_exist(self, module_name: str) -> bool:
"""Check if the module exist in the module model object
Args:
module_name (str): The module name
Returns:
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!")
return True
self.__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
'''
def db_load_all_existing_modules(self, uplink: 'Irc') -> 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}")
for r in result.fetchall():
self.load_one_module(uplink, r[0], 'sys', True)
return True
def db_is_module_exist(self, module_name: str) -> bool:
"""Check if the module exist in the database
Args:
module_name (str): The module name you want to check
Returns:
bool: True if the module exist in the database
"""
query = f"SELECT id FROM {self.__Config.TABLE_MODULE} WHERE module_name = :module_name"
mes_donnes = {'module_name': module_name.lower()}
results = self.__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!")
return True
else:
self.__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:
"""Insert a new module in the database
Args:
module_name (str): The module name
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 insert.rowcount > 0:
self.__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!")
return False
self.__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:
"""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)
if result.rowcount > 0:
self.__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!")
return False
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"
mes_donnees = {'module_name': module_name.lower()}
delete = self.__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!")
return True
self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!")
return False

View File

@@ -2,14 +2,20 @@
Main utils library. Main utils library.
''' '''
import gc import gc
import ssl
import socket
from pathlib import Path from pathlib import Path
from re import sub from re import match, sub
from typing import Literal, Optional, Any import sys
from typing import Literal, Optional, Any, TYPE_CHECKING
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from time import time from time import time
from random import choice from random import choice
from hashlib import md5, sha3_512 from hashlib import md5, sha3_512
if TYPE_CHECKING:
from core.irc import Irc
def convert_to_int(value: Any) -> Optional[int]: def convert_to_int(value: Any) -> Optional[int]:
"""Convert a value to int """Convert a value to int
@@ -51,6 +57,48 @@ def get_datetime() -> datetime:
""" """
return datetime.now() return datetime.now()
def get_ssl_context() -> ssl.SSLContext:
"""Generate the ssl context
Returns:
SSLContext: The SSL Context
"""
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
return ctx
def create_socket(uplink: 'Irc') -> None:
"""Create a socket to connect SSL or Normal connection
"""
try:
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
connexion_information = (uplink.Config.SERVEUR_IP, uplink.Config.SERVEUR_PORT)
if uplink.Config.SERVEUR_SSL:
# Create SSL Context object
ssl_context = get_ssl_context()
ssl_connexion = ssl_context.wrap_socket(soc, server_hostname=uplink.Config.SERVEUR_HOSTNAME)
ssl_connexion.connect(connexion_information)
uplink.IrcSocket = ssl_connexion
uplink.Config.SSL_VERSION = uplink.IrcSocket.version()
uplink.Logs.info(f"-- Connected using SSL : Version = {uplink.Config.SSL_VERSION}")
else:
soc.connect(connexion_information)
uplink.IrcSocket = soc
uplink.Logs.info("-- Connected in a normal mode!")
return None
except (ssl.SSLEOFError, ssl.SSLError) as soe:
uplink.Logs.critical(f"[SSL ERROR]: {soe}")
except OSError as oe:
uplink.Logs.critical(f"[OS Error]: {oe}")
if 'connection refused' in str(oe).lower():
sys.exit(oe)
except AttributeError as ae:
uplink.Logs.critical(f"AttributeError: {ae}")
def run_python_garbage_collector() -> int: def run_python_garbage_collector() -> int:
"""Run Python garbage collector """Run Python garbage collector
@@ -131,3 +179,19 @@ def clean_uid(uid: str) -> Optional[str]:
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:
srv_msg = srvmsg.copy()
privmsg_index = srv_msg.index('PRIVMSG')
auth_index = privmsg_index + 2
if match(r'^:{1}\W?(auth)$', srv_msg[auth_index]) is None:
return srv_msg
for l in range(auth_index + 1, len(srv_msg)):
srv_msg[l] = '*' * len(srv_msg[l])
return srv_msg
except ValueError:
return srvmsg

View File

@@ -177,7 +177,7 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]): def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]):
uid_sender = uplink.Irc.Utils.clean_uid(srvmsg[1]) uid_sender = uplink.Irc.Utils.clean_uid(srvmsg[1])
senderObj = uplink.User.get_User(uid_sender) senderObj = uplink.User.get_user(uid_sender)
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT: if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT:
return return

View File

@@ -277,7 +277,7 @@ class Command:
return None return None
user_uid = self.User.clean_uid(cmd[5]) user_uid = self.User.clean_uid(cmd[5])
userObj: MUser = self.User.get_User(user_uid) userObj: MUser = self.User.get_user(user_uid)
channel_name = cmd[4] if self.Channel.is_valid_channel(cmd[4]) else None channel_name = cmd[4] if self.Channel.is_valid_channel(cmd[4]) else None
client_obj = self.Client.get_Client(user_uid) client_obj = self.Client.get_Client(user_uid)
nickname = userObj.nickname if userObj is not None else None nickname = userObj.nickname if userObj is not None else None
@@ -291,12 +291,13 @@ class Command:
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.Client.is_exist(userObj.uid):
return None return None
db_data: dict[str, str] = {"nickname": nickname, "channel": channel_name} 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 nickname = :nickname AND channel = :channel", db_data) db_query = self.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() db_result = db_query.fetchone()
if db_result is not None: if db_result:
id, mode = db_result id, mode = db_result
self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {channel_name} {mode} {userObj.nickname}") self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {channel_name} {mode} {userObj.nickname}")
except KeyError as ke: except KeyError as ke:
self.Logs.error(f"Key Error: {err}") self.Logs.error(f"Key Error: {err}")
@@ -477,15 +478,18 @@ class Command:
try: try:
self.mod_utils.set_assign_channel_to_service(self, cmd, fromuser) self.mod_utils.set_assign_channel_to_service(self, cmd, fromuser)
except IndexError as ie: 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.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
except Exception as err: except Exception as err:
self.Logs.warning(f'Unknown Error: {str(err)}') self.Logs.warning(f'Unknown Error: {str(err)}')
case 'part' | 'unassign': case 'part' | 'unassign':
try: try:
# Syntax. !part #channel
self.mod_utils.set_unassign_channel_to_service(self, cmd, fromuser) self.mod_utils.set_unassign_channel_to_service(self, cmd, fromuser)
except IndexError as ie: except IndexError as ie:
self.Logs.error(f'{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]")
except Exception as err: except Exception as err:
self.Logs.warning(f'Unknown Error: {str(err)}') self.Logs.warning(f'Unknown Error: {str(err)}')
@@ -668,7 +672,7 @@ class Command:
nickname = str(cmd[1]) nickname = str(cmd[1])
umode = str(cmd[2]) umode = str(cmd[2])
self.Protocol.send_svs_mode(nickname=nickname, user_mode=umode) self.Protocol.send_svsmode(nickname=nickname, user_mode=umode)
except KeyError as ke: except KeyError as ke:
self.Logs.error(ke) self.Logs.error(ke)
except Exception as err: except Exception as err:
@@ -715,34 +719,64 @@ class Command:
case 'svsjoin': case 'svsjoin':
try: try:
# .svsjoin nickname #channel # SVSJOIN <nick> <channel>[,<channel2>..] [key1[,key2[..]]]
nickname = str(cmd[1]) if len(cmd) < 4:
channel = str(cmd[2]) self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN <nick> <channel>[,<channel2>..] [key1[,key2[..]]]")
if len(cmd) != 3:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN nickname #channel")
return None return None
self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSJOIN {nickname} {channel}') nickname = str(cmd[1])
except KeyError as ke: channels = str(cmd[2]).split(',')
keys = str(cmd[3]).split(',')
self.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 <nick> <channel>[,<channel2>..] [key1[,key2[..]]]")
self.Logs.error(ke) self.Logs.error(ke)
except Exception as err: except Exception as err:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN nickname #channel") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN <nick> <channel>[,<channel2>..] [key1[,key2[..]]]")
self.Logs.warning(f'Unknown Error: {str(err)}') self.Logs.warning(f'Unknown Error: {str(err)}')
case 'svspart': case 'svspart':
try: try:
# svspart nickname #channel # SVSPART <nick> <channel>[,<channel2>..] [<comment>]
nickname = str(cmd[1]) if len(cmd) < 4:
channel = str(cmd[2]) self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART <nick> <channel>[,<channel2>..] [<comment>]")
if len(cmd) != 3:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART nickname #channel")
return None return None
self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSPART {nickname} {channel}') nickname = str(cmd[1])
except KeyError as ke: channels = str(cmd[2]).split(',')
reason = ' '.join(cmd[3:])
self.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 <nick> <channel>[,<channel2>..] [<comment>]")
self.Logs.error(ke) self.Logs.error(ke)
except Exception as err: except Exception as err:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART nickname #channel") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART <nick> <channel>[,<channel2>..] [<comment>]")
self.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()
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")
return None
if len(cmd) != 3:
self.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}')
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)
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)}') self.Logs.warning(f'Unknown Error: {str(err)}')
case 'sajoin': case 'sajoin':
@@ -779,29 +813,6 @@ class Command:
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname #channel") 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)}') self.Logs.error(f'Unknown Error: {str(err)}')
case 'svsnick':
try:
# .svsnick nickname newnickname
nickname = str(cmd[1])
newnickname = str(cmd[2])
unixtime = self.MainUtils.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")
return None
if len(cmd) != 3:
self.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}')
except KeyError as ke:
self.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)}')
case 'kill': case 'kill':
try: try:
# 'kill', 'gline', 'ungline', 'shun', 'unshun' # 'kill', 'gline', 'ungline', 'shun', 'unshun'

View File

@@ -201,6 +201,9 @@ def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None:
def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: 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]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.Config.SERVICE_NICKNAME
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
@@ -217,6 +220,9 @@ def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str
def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None: 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]) command = str(cmd[0])
dnickname = uplink.Config.SERVICE_NICKNAME dnickname = uplink.Config.SERVICE_NICKNAME
dchanlog = uplink.Config.SERVICE_CHANLOG dchanlog = uplink.Config.SERVICE_CHANLOG

View File

@@ -273,11 +273,12 @@ class Defender:
return None return None
def cmd(self, data: list[str]) -> None: def cmd(self, data: list[str]) -> None:
try:
if not data or len(data) < 2:
return None
cmd = data.copy() if isinstance(data, list) else list(data).copy() 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.Irc.Protocol.get_ircd_protocol_poisition(cmd)
if index == -1: if index == -1:
return None return None
@@ -398,7 +399,7 @@ class Defender:
self.Protocol.send_sapart(nick_to_sapart=jailed_nickname, channel_name=jailed_salon) 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.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.Protocol.send2socket(f":{link} REPUTATION {jailed_IP} {self.ModConfig.reputation_score_after_release}")
self.User.get_User(jailed_UID).score_connexion = reputation_seuil + 1 self.User.get_user(jailed_UID).score_connexion = reputation_seuil + 1
self.Protocol.send_priv_msg(nick_from=dnickname, 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 !", msg=f"[{color_green} MOT DE PASS CORRECT {color_black}] : You have now the right to enjoy the network !",
nick_to=jailed_nickname) nick_to=jailed_nickname)
@@ -547,7 +548,7 @@ class Defender:
link = self.Config.SERVEUR_LINK link = self.Config.SERVEUR_LINK
jailed_salon = self.Config.SALON_JAIL jailed_salon = self.Config.SALON_JAIL
welcome_salon = self.Config.SALON_LIBERER welcome_salon = self.Config.SALON_LIBERER
client_obj = self.User.get_User(str(cmd[2])) client_obj = self.User.get_user(str(cmd[2]))
if client_obj is None: if client_obj is None:
p.send_notice(nick_from=dnickname, p.send_notice(nick_from=dnickname,
@@ -936,7 +937,7 @@ class Defender:
return None return None
nickoruid = cmd[1] nickoruid = cmd[1]
UserObject = self.User.get_User(nickoruid) UserObject = self.User.get_user(nickoruid)
if UserObject is not None: 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.Channel.UID_CHANNEL_DB for uid_in_chan in chan.uids if self.Loader.Utils.clean_uid(uid_in_chan) == UserObject.uid]

View File

@@ -213,7 +213,7 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
return None return None
# Get User information # Get User information
_User = irc.User.get_User(str(srvmsg[8])) _User = irc.User.get_user(str(srvmsg[8]))
if _User is None: if _User is None:
irc.Logs.warning(f'This UID: [{srvmsg[8]}] is not available please check why') irc.Logs.warning(f'This UID: [{srvmsg[8]}] is not available please check why')
@@ -263,7 +263,7 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
user_trigger = str(srvmsg[1]).replace(':','') user_trigger = str(srvmsg[1]).replace(':','')
channel = srvmsg[3] channel = srvmsg[3]
User = irc.User.get_User(user_trigger) User = irc.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 irc.Channel.is_valid_channel(channel_to_check=channel):
return return

View File

@@ -318,7 +318,7 @@ class Votekick:
nickname_submitted = cmd[2] nickname_submitted = cmd[2]
uid_submitted = self.User.get_uid(nickname_submitted) uid_submitted = self.User.get_uid(nickname_submitted)
user_submitted = self.User.get_User(nickname_submitted) user_submitted = self.User.get_user(nickname_submitted)
ongoing_user = None ongoing_user = None
# check if there is an ongoing vote # check if there is an ongoing vote

View File

@@ -144,7 +144,7 @@ class VotekickManager:
votec = self.get_vote_channel_model(channel_name) votec = self.get_vote_channel_model(channel_name)
if votec: if votec:
client_obj = self.uplink.User.get_User(votec.target_user) client_obj = self.uplink.User.get_user(votec.target_user)
client_to_punish = votec.target_user if client_obj is None else client_obj.nickname client_to_punish = votec.target_user if client_obj is None else client_obj.nickname
if nickname in votec.voter_users: if nickname in votec.voter_users:
self.Logs.debug(f"[VOTEKICK MANAGER] This nickname ({nickname}) has already voted for ({client_to_punish})") self.Logs.debug(f"[VOTEKICK MANAGER] This nickname ({nickname}) has already voted for ({client_to_punish})")

View File

@@ -1,5 +1,5 @@
{ {
"version": "6.2.0", "version": "6.2.1",
"requests": "2.32.3", "requests": "2.32.3",
"psutil": "6.0.0", "psutil": "6.0.0",