mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 11:14:23 +00:00
V6.2.1 Adding main module utils and rehash utils to manager reload/rehash/restart
This commit is contained in:
107
core/base.py
107
core/base.py
@@ -4,10 +4,7 @@ import re
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import socket
|
||||
import hashlib
|
||||
import logging
|
||||
import threading
|
||||
import ipaddress
|
||||
import ast
|
||||
@@ -17,7 +14,6 @@ from types import ModuleType
|
||||
from dataclasses import fields
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
from base64 import b64decode, b64encode
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from sqlalchemy import create_engine, Engine, Connection, CursorResult
|
||||
from sqlalchemy.sql import text
|
||||
|
||||
@@ -34,7 +30,6 @@ class Base:
|
||||
self.Utils = loader.Utils
|
||||
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
|
||||
|
||||
# Liste des timers en cours
|
||||
@@ -141,42 +136,6 @@ class Base:
|
||||
except Exception as 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:
|
||||
"""Enregiste les logs
|
||||
|
||||
@@ -212,68 +171,6 @@ class Base:
|
||||
|
||||
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:
|
||||
"""Sync module local parameters with 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)
|
||||
|
||||
if self.install:
|
||||
self.db_record_module('sys', 'mod_command', 1)
|
||||
self.db_record_module('sys', 'mod_defender', 1)
|
||||
self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True)
|
||||
self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
|
||||
self.install = False
|
||||
|
||||
return None
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from core.base import Base
|
||||
from core.definition import MAdmin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -24,7 +23,6 @@ class Admin:
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
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')
|
||||
return False
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ class Command:
|
||||
DB_COMMANDS: list['MCommand'] = []
|
||||
|
||||
def __init__(self, loader: 'Loader'):
|
||||
self.Loader = loader
|
||||
self.Base = loader.Base
|
||||
|
||||
def build(self, new_command_obj: MCommand) -> bool:
|
||||
@@ -57,3 +58,26 @@ class Command:
|
||||
new_list.append(cmd)
|
||||
|
||||
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
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
from json import load
|
||||
from sys import exit
|
||||
from os import sep
|
||||
from typing import Union
|
||||
from typing import Any, Optional, Union, TYPE_CHECKING
|
||||
from core.definition import MConfig
|
||||
from logging import Logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
|
||||
class Configuration:
|
||||
|
||||
def __init__(self, logs: Logger) -> None:
|
||||
self.Logs = logs
|
||||
self.ConfigObject: MConfig = self.__load_service_configuration()
|
||||
def __init__(self, loader: 'Loader') -> None:
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
conf_filename = f'config{sep}configuration.json'
|
||||
with open(conf_filename, 'r') as configuration_data:
|
||||
configuration:dict[str, Union[str, int, list, dict]] = load(configuration_data)
|
||||
configuration: dict[str, Union[str, int, list, dict]] = load(configuration_data)
|
||||
|
||||
return configuration
|
||||
|
||||
@@ -48,11 +57,8 @@ class Configuration:
|
||||
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 [!]")
|
||||
|
||||
ConfigObject: MConfig = MConfig(
|
||||
**import_config
|
||||
)
|
||||
|
||||
return ConfigObject
|
||||
self.Logs.debug(f"[LOADING CONFIGURATION]: Loading configuration with {len(import_config)} parameters!")
|
||||
return MConfig(**import_config)
|
||||
|
||||
except TypeError as te:
|
||||
self.Logs.error(te)
|
||||
@@ -59,8 +59,8 @@ class Inspircd:
|
||||
"""
|
||||
try:
|
||||
batch_size = self.__Config.BATCH_SIZE
|
||||
User_from = self.__Irc.User.get_User(nick_from)
|
||||
User_to = self.__Irc.User.get_User(nick_to) if nick_to is None else None
|
||||
User_from = self.__Irc.User.get_user(nick_from)
|
||||
User_to = self.__Irc.User.get_user(nick_to) if nick_to is None else None
|
||||
|
||||
if User_from is None:
|
||||
self.__Logs.error(f"The sender nickname [{nick_from}] do not exist")
|
||||
@@ -88,8 +88,8 @@ class Inspircd:
|
||||
"""
|
||||
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:
|
||||
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
|
||||
reason (str): The reason for the quit
|
||||
"""
|
||||
user_obj = self.__Irc.User.get_User(uidornickname=uid)
|
||||
clone_obj = self.__Irc.Clone.get_clone(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)
|
||||
|
||||
if not clone_obj is None:
|
||||
self.__Irc.Clone.delete(clone_obj.uid)
|
||||
|
||||
if not reputationObj is None:
|
||||
self.__Irc.Reputation.delete(reputationObj.uid)
|
||||
|
||||
@@ -255,7 +251,7 @@ class Inspircd:
|
||||
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:
|
||||
@@ -280,7 +276,7 @@ class Inspircd:
|
||||
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")
|
||||
@@ -311,7 +307,7 @@ class Inspircd:
|
||||
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
|
||||
@@ -346,7 +342,6 @@ class Inspircd:
|
||||
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.Clone.delete(uid_who_quit)
|
||||
|
||||
return None
|
||||
|
||||
@@ -655,7 +650,7 @@ class Inspircd:
|
||||
"""
|
||||
try:
|
||||
# ['@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:
|
||||
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}"
|
||||
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)
|
||||
self.send2socket(f':{self.__Config.SERVICE_HOST} 005 {getUser.nickname} {response_005} are supported by this server')
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from ssl import SSLEOFError, SSLError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.irc import Irc
|
||||
from core.definition import MClient
|
||||
|
||||
class Unrealircd6:
|
||||
|
||||
@@ -23,7 +24,8 @@ class Unrealircd6:
|
||||
'EOS', 'PRIVMSG', 'MODE', 'UMODE2',
|
||||
'VERSION', 'REPUTATION', 'SVS2MODE',
|
||||
'SLOG', 'NICK', 'PART', 'PONG',
|
||||
'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO'}
|
||||
'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO',
|
||||
'006', '007', '018'}
|
||||
|
||||
self.__Logs.info(f"** Loading protocol [{__name__}]")
|
||||
|
||||
@@ -44,6 +46,40 @@ class Unrealircd6:
|
||||
|
||||
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:
|
||||
"""Envoit les commandes à envoyer au serveur.
|
||||
|
||||
@@ -84,8 +120,8 @@ class Unrealircd6:
|
||||
"""
|
||||
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:
|
||||
self.__Logs.error(f"The sender nickname [{nick_from}] do not exist")
|
||||
@@ -115,8 +151,8 @@ class Unrealircd6:
|
||||
"""
|
||||
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:
|
||||
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:
|
||||
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):
|
||||
"""Créer le link et envoyer les informations nécessaires pour la
|
||||
connexion au serveur.
|
||||
@@ -217,7 +219,7 @@ class Unrealircd6:
|
||||
"""
|
||||
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)
|
||||
return None
|
||||
|
||||
@@ -275,7 +277,7 @@ class Unrealircd6:
|
||||
"""
|
||||
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)
|
||||
service_uid = self.__Config.SERVICE_ID
|
||||
|
||||
@@ -299,7 +301,7 @@ class Unrealircd6:
|
||||
"""
|
||||
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)
|
||||
service_uid = self.__Config.SERVICE_ID
|
||||
|
||||
@@ -327,25 +329,92 @@ class Unrealircd6:
|
||||
except Exception as err:
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def send_svs_mode(self, nickname: str, user_mode: str) -> None:
|
||||
try:
|
||||
def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None:
|
||||
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
|
||||
|
||||
if userObj is None:
|
||||
# User not exist: leave
|
||||
if user_obj is None:
|
||||
return None
|
||||
|
||||
self.send2socket(f':{service_uid} SVSMODE {nickname} {user_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
|
||||
except Exception as 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:
|
||||
"""Send quit message
|
||||
- Delete uid from User object
|
||||
@@ -355,7 +424,7 @@ class Unrealircd6:
|
||||
uidornickname (str): The UID or the Nickname
|
||||
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)
|
||||
|
||||
if not user_obj is None:
|
||||
@@ -418,7 +487,7 @@ class Unrealircd6:
|
||||
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:
|
||||
@@ -458,7 +527,7 @@ class Unrealircd6:
|
||||
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")
|
||||
@@ -506,7 +575,7 @@ class Unrealircd6:
|
||||
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
|
||||
@@ -540,7 +609,7 @@ class Unrealircd6:
|
||||
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
|
||||
@@ -794,8 +863,8 @@ class Unrealircd6:
|
||||
self.__Config.DEFENDER_INIT = 0
|
||||
|
||||
# Send EOF to other modules
|
||||
for classe_name, classe_object in self.__Irc.loaded_classes.items():
|
||||
classe_object.cmd(server_msg_copy)
|
||||
for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy():
|
||||
module.class_instance.cmd(server_msg_copy)
|
||||
|
||||
return None
|
||||
except IndexError as ie:
|
||||
@@ -907,27 +976,14 @@ class Unrealircd6:
|
||||
"""
|
||||
try:
|
||||
srv_msg = serverMsg.copy()
|
||||
|
||||
cmd = serverMsg.copy()
|
||||
# Supprimer la premiere valeur si MTAGS activé
|
||||
if cmd[0].startswith('@'):
|
||||
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(':',''))
|
||||
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 .
|
||||
|
||||
@@ -936,7 +992,7 @@ class Unrealircd6:
|
||||
convert_to_string = ' '.join(liste_des_commandes)
|
||||
arg = convert_to_string.split()
|
||||
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.send_notice(
|
||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
||||
@@ -945,6 +1001,15 @@ class Unrealircd6:
|
||||
)
|
||||
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(':','')
|
||||
self.__Base.log_cmd(user_trigger, cmd_to_send)
|
||||
|
||||
@@ -963,21 +1028,25 @@ class Unrealircd6:
|
||||
# Réponse a un CTCP VERSION
|
||||
if arg[0] == '\x01VERSION\x01':
|
||||
self.on_version(srv_msg)
|
||||
return False
|
||||
return None
|
||||
|
||||
# Réponse a un TIME
|
||||
if arg[0] == '\x01TIME\x01':
|
||||
self.on_time(srv_msg)
|
||||
return False
|
||||
return None
|
||||
|
||||
# Réponse a un PING
|
||||
if arg[0] == '\x01PING':
|
||||
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")
|
||||
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(':','')
|
||||
self.__Base.log_cmd(user_trigger, cmd_to_send)
|
||||
@@ -1011,6 +1080,14 @@ class Unrealircd6:
|
||||
except Exception as 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:
|
||||
"""Sending Server Version to the server
|
||||
|
||||
@@ -1105,7 +1182,7 @@ class Unrealircd6:
|
||||
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
|
||||
@@ -1113,7 +1190,7 @@ class Unrealircd6:
|
||||
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.__Base.get_all_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')
|
||||
|
||||
|
||||
115
core/classes/rehash.py
Normal file
115
core/classes/rehash.py
Normal 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
|
||||
@@ -18,6 +18,7 @@ class Settings:
|
||||
|
||||
CONSOLE: bool = False
|
||||
|
||||
MAIN_SERVER_HOSTNAME: str = None
|
||||
PROTOCTL_USER_MODES: list[str] = []
|
||||
PROTOCTL_PREFIX: list[str] = []
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ class User:
|
||||
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:
|
||||
# User already created return False
|
||||
return False
|
||||
@@ -45,7 +44,7 @@ class User:
|
||||
Returns:
|
||||
bool: True if updated
|
||||
"""
|
||||
user_obj = self.get_User(uidornickname=uid)
|
||||
user_obj = self.get_user(uidornickname=uid)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -65,7 +64,7 @@ class User:
|
||||
bool: True if user mode has been updaed
|
||||
"""
|
||||
response = True
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_user(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -107,7 +106,7 @@ class User:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
user_obj = self.get_User(uidornickname=uid)
|
||||
user_obj = self.get_user(uidornickname=uid)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -116,7 +115,7 @@ class User:
|
||||
|
||||
return True
|
||||
|
||||
def get_User(self, uidornickname: str) -> Optional['MUser']:
|
||||
def get_user(self, uidornickname: str) -> Optional['MUser']:
|
||||
"""Get The User Object model
|
||||
|
||||
Args:
|
||||
@@ -143,7 +142,7 @@ class User:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_user(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return None
|
||||
@@ -159,7 +158,7 @@ class User:
|
||||
Returns:
|
||||
str|None: the nickname
|
||||
"""
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_user(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return None
|
||||
@@ -175,7 +174,7 @@ class User:
|
||||
Returns:
|
||||
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:
|
||||
return None
|
||||
@@ -191,7 +190,7 @@ class User:
|
||||
Returns:
|
||||
bool: True if exist
|
||||
"""
|
||||
user_obj = self.get_User(uidornickname=uidornikname)
|
||||
user_obj = self.get_user(uidornickname=uidornikname)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -226,7 +225,7 @@ class User:
|
||||
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:
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from datetime import datetime
|
||||
from json import dumps
|
||||
from dataclasses import dataclass, field, asdict, fields
|
||||
from typing import Literal, Any
|
||||
from typing import Literal, Any, Optional
|
||||
from os import sep
|
||||
|
||||
@dataclass
|
||||
@@ -246,6 +246,9 @@ class MConfig(MainModel):
|
||||
DEBUG_LEVEL:Literal[10, 20, 30, 40, 50] = 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"
|
||||
"""The name of the Logging instance"""
|
||||
|
||||
@@ -326,3 +329,9 @@ class MCommand(MainModel):
|
||||
command_name: str = None
|
||||
description: str = None
|
||||
command_level: int = 0
|
||||
|
||||
@dataclass
|
||||
class MModule(MainModel):
|
||||
module_name: str = None
|
||||
class_name: str = None
|
||||
class_instance: Optional[Any] = None
|
||||
708
core/irc.py
708
core/irc.py
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,12 @@
|
||||
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.definition as df
|
||||
import core.utils as utils
|
||||
import core.base as base_module
|
||||
import core.classes.config as conf_module
|
||||
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
|
||||
|
||||
class Loader:
|
||||
|
||||
@@ -13,24 +15,26 @@ class Loader:
|
||||
# Load Main Modules
|
||||
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.Utils: utils = utils
|
||||
|
||||
# Load Classes
|
||||
self.ServiceLogging: logs.ServiceLogging = logs.ServiceLogging()
|
||||
self.ServiceLogging: logs.ServiceLogging = self.LoggingModule.ServiceLogging()
|
||||
|
||||
self.Logs: Logger = self.ServiceLogging.get_logger()
|
||||
|
||||
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)
|
||||
|
||||
@@ -42,4 +46,8 @@ class Loader:
|
||||
|
||||
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!")
|
||||
|
||||
64
core/logs.py
64
core/logs.py
@@ -9,6 +9,8 @@ class ServiceLogging:
|
||||
"""
|
||||
self.OS_SEP = sep
|
||||
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.SERVER_PREFIX = None
|
||||
self.LOGGING_CONSOLE = True
|
||||
@@ -85,21 +87,77 @@ class ServiceLogging:
|
||||
|
||||
# Apply the filter
|
||||
logs.addFilter(self.replace_filter)
|
||||
|
||||
logs.info(f'#################### STARTING {self.LOGGING_NAME} ####################')
|
||||
|
||||
return logs
|
||||
|
||||
def set_stdout_handler_level(self, level: int) -> None:
|
||||
self.logs.debug(f"[STDOUT LEVEL] New level {level}")
|
||||
self.stdout_handler.setLevel(level)
|
||||
|
||||
def set_file_handler_level(self, level: int) -> None:
|
||||
self.logs.debug(f"[LOG FILE LEVEL] new level {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:
|
||||
|
||||
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]")
|
||||
# if self.LOGGING_CONSOLE:
|
||||
@@ -109,4 +167,4 @@ class ServiceLogging:
|
||||
if f in record.getMessage():
|
||||
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
424
core/module.py
Normal 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
|
||||
@@ -2,14 +2,20 @@
|
||||
Main utils library.
|
||||
'''
|
||||
import gc
|
||||
import ssl
|
||||
import socket
|
||||
from pathlib import Path
|
||||
from re import sub
|
||||
from typing import Literal, Optional, Any
|
||||
from re import match, sub
|
||||
import sys
|
||||
from typing import Literal, Optional, Any, TYPE_CHECKING
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from time import time
|
||||
from random import choice
|
||||
from hashlib import md5, sha3_512
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.irc import Irc
|
||||
|
||||
def convert_to_int(value: Any) -> Optional[int]:
|
||||
"""Convert a value to int
|
||||
|
||||
@@ -51,6 +57,48 @@ def get_datetime() -> datetime:
|
||||
"""
|
||||
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:
|
||||
"""Run Python garbage collector
|
||||
|
||||
@@ -131,3 +179,19 @@ def clean_uid(uid: str) -> Optional[str]:
|
||||
parsed_UID = sub(pattern, '', 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
|
||||
@@ -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]):
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
@@ -277,7 +277,7 @@ class Command:
|
||||
return None
|
||||
|
||||
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
|
||||
client_obj = self.Client.get_Client(user_uid)
|
||||
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):
|
||||
return None
|
||||
|
||||
db_data: dict[str, str] = {"nickname": nickname, "channel": channel_name}
|
||||
db_query = self.Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data)
|
||||
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_result = db_query.fetchone()
|
||||
if db_result is not None:
|
||||
if db_result:
|
||||
id, mode = db_result
|
||||
self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {channel_name} {mode} {userObj.nickname}")
|
||||
|
||||
except KeyError as ke:
|
||||
self.Logs.error(f"Key Error: {err}")
|
||||
|
||||
@@ -477,15 +478,18 @@ class Command:
|
||||
try:
|
||||
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]")
|
||||
except Exception as err:
|
||||
self.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)
|
||||
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:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
@@ -668,7 +672,7 @@ class Command:
|
||||
nickname = str(cmd[1])
|
||||
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:
|
||||
self.Logs.error(ke)
|
||||
except Exception as err:
|
||||
@@ -715,34 +719,64 @@ class Command:
|
||||
|
||||
case 'svsjoin':
|
||||
try:
|
||||
# .svsjoin nickname #channel
|
||||
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} SVSJOIN nickname #channel")
|
||||
# SVSJOIN <nick> <channel>[,<channel2>..] [key1[,key2[..]]]
|
||||
if len(cmd) < 4:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSJOIN <nick> <channel>[,<channel2>..] [key1[,key2[..]]]")
|
||||
return None
|
||||
|
||||
self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSJOIN {nickname} {channel}')
|
||||
except KeyError as ke:
|
||||
nickname = str(cmd[1])
|
||||
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)
|
||||
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)}')
|
||||
|
||||
case 'svspart':
|
||||
try:
|
||||
# svspart nickname #channel
|
||||
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} SVSPART nickname #channel")
|
||||
# SVSPART <nick> <channel>[,<channel2>..] [<comment>]
|
||||
if len(cmd) < 4:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} SVSPART <nick> <channel>[,<channel2>..] [<comment>]")
|
||||
return None
|
||||
|
||||
self.Protocol.send2socket(f':{self.Config.SERVEUR_ID} SVSPART {nickname} {channel}')
|
||||
except KeyError as ke:
|
||||
nickname = str(cmd[1])
|
||||
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)
|
||||
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)}')
|
||||
|
||||
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.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':
|
||||
try:
|
||||
# 'kill', 'gline', 'ungline', 'shun', 'unshun'
|
||||
|
||||
@@ -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:
|
||||
|
||||
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
|
||||
@@ -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:
|
||||
|
||||
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
|
||||
|
||||
@@ -273,11 +273,12 @@ class Defender:
|
||||
return 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)
|
||||
if index == -1:
|
||||
return None
|
||||
@@ -398,7 +399,7 @@ class Defender:
|
||||
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
|
||||
self.User.get_user(jailed_UID).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)
|
||||
@@ -547,7 +548,7 @@ class Defender:
|
||||
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]))
|
||||
client_obj = self.User.get_user(str(cmd[2]))
|
||||
|
||||
if client_obj is None:
|
||||
p.send_notice(nick_from=dnickname,
|
||||
@@ -936,7 +937,7 @@ class Defender:
|
||||
return None
|
||||
|
||||
nickoruid = cmd[1]
|
||||
UserObject = self.User.get_User(nickoruid)
|
||||
UserObject = self.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]
|
||||
|
||||
@@ -213,7 +213,7 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
||||
return None
|
||||
|
||||
# Get User information
|
||||
_User = irc.User.get_User(str(srvmsg[8]))
|
||||
_User = irc.User.get_user(str(srvmsg[8]))
|
||||
|
||||
if _User is None:
|
||||
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(':','')
|
||||
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):
|
||||
return
|
||||
|
||||
@@ -318,7 +318,7 @@ class Votekick:
|
||||
|
||||
nickname_submitted = cmd[2]
|
||||
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
|
||||
|
||||
# check if there is an ongoing vote
|
||||
|
||||
@@ -144,7 +144,7 @@ class VotekickManager:
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
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
|
||||
if nickname in votec.voter_users:
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] This nickname ({nickname}) has already voted for ({client_to_punish})")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "6.2.0",
|
||||
"version": "6.2.1",
|
||||
|
||||
"requests": "2.32.3",
|
||||
"psutil": "6.0.0",
|
||||
|
||||
Reference in New Issue
Block a user