mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 11:14:23 +00:00
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,6 @@
|
||||
.pyenv/
|
||||
.venv/
|
||||
.idea/
|
||||
db/
|
||||
logs/
|
||||
__pycache__/
|
||||
|
||||
271
core/base.py
271
core/base.py
@@ -1,6 +1,8 @@
|
||||
import importlib
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
import socket
|
||||
@@ -8,41 +10,44 @@ import hashlib
|
||||
import logging
|
||||
import threading
|
||||
import ipaddress
|
||||
|
||||
import ast
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from dataclasses import fields
|
||||
from typing import Union, Literal, TYPE_CHECKING
|
||||
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
|
||||
from core.definition import MConfig
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.classes.settings import Settings
|
||||
from core.loader import Loader
|
||||
|
||||
class Base:
|
||||
|
||||
def __init__(self, Config: MConfig, settings: 'Settings') -> None:
|
||||
def __init__(self, loader: 'Loader') -> None:
|
||||
|
||||
self.Config = Config # Assigner l'objet de configuration
|
||||
self.Settings: Settings = settings
|
||||
self.init_log_system() # Demarrer le systeme de log
|
||||
self.Loader = loader
|
||||
self.Config = loader.Config
|
||||
self.Settings = loader.Settings
|
||||
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
|
||||
self.running_timers:list[threading.Timer] = self.Settings.RUNNING_TIMERS
|
||||
self.running_timers: list[threading.Timer] = self.Settings.RUNNING_TIMERS
|
||||
|
||||
# Liste des threads en cours
|
||||
self.running_threads:list[threading.Thread] = self.Settings.RUNNING_THREADS
|
||||
self.running_threads: list[threading.Thread] = self.Settings.RUNNING_THREADS
|
||||
|
||||
# Les sockets ouvert
|
||||
self.running_sockets: list[socket.socket] = self.Settings.RUNNING_SOCKETS
|
||||
|
||||
# Liste des fonctions en attentes
|
||||
self.periodic_func:dict[object] = self.Settings.PERIODIC_FUNC
|
||||
self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC
|
||||
|
||||
# Création du lock
|
||||
self.lock = self.Settings.LOCK
|
||||
@@ -136,120 +141,62 @@ class Base:
|
||||
except Exception as err:
|
||||
self.logs.error(f'General Error: {err}')
|
||||
|
||||
def get_unixtime(self) -> int:
|
||||
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.
|
||||
"""
|
||||
Cette fonction retourne un UNIXTIME de type 12365456
|
||||
Return: Current time in seconds since the Epoch (int)
|
||||
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'):
|
||||
"""
|
||||
cet_offset = timezone(timedelta(hours=2))
|
||||
now_cet = datetime.now(cet_offset)
|
||||
unixtime_cet = int(now_cet.timestamp())
|
||||
unixtime = int( time.time() )
|
||||
|
||||
return unixtime
|
||||
|
||||
def get_datetime(self) -> str:
|
||||
Reload all modules in sys.modules that start with the given prefix.
|
||||
Useful for reloading a full package during development.
|
||||
"""
|
||||
Retourne une date au format string (24-12-2023 20:50:59)
|
||||
"""
|
||||
currentdate = datetime.now().strftime('%d-%m-%Y %H:%M:%S')
|
||||
return currentdate
|
||||
modules_to_reload = []
|
||||
|
||||
def get_all_modules(self) -> list:
|
||||
# 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))
|
||||
|
||||
all_files = os.listdir('mods/')
|
||||
all_modules: list = []
|
||||
for module in all_files:
|
||||
if module.endswith('.py') and not module == '__init__.py':
|
||||
all_modules.append(module.replace('.py', '').lower())
|
||||
# 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')
|
||||
|
||||
return all_modules
|
||||
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
|
||||
|
||||
Args:
|
||||
string (str): Le message a enregistrer
|
||||
log_message (str): Le message a enregistrer
|
||||
|
||||
Returns:
|
||||
None: Aucun retour
|
||||
"""
|
||||
sql_insert = f"INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)"
|
||||
mes_donnees = {'datetime': str(self.get_datetime()),'server_msg': f'{log_message}'}
|
||||
mes_donnees = {'datetime': str(self.Utils.get_sdatetime()),'server_msg': f'{log_message}'}
|
||||
self.db_execute_query(sql_insert, mes_donnees)
|
||||
|
||||
return None
|
||||
|
||||
def init_log_system(self) -> None:
|
||||
# Create folder if not available
|
||||
logs_directory = f'logs{self.Config.OS_SEP}'
|
||||
if not os.path.exists(f'{logs_directory}'):
|
||||
os.makedirs(logs_directory)
|
||||
|
||||
# Init logs object
|
||||
self.logs = logging.getLogger(self.Config.LOGGING_NAME)
|
||||
self.logs.setLevel(self.Config.DEBUG_LEVEL)
|
||||
|
||||
# Add Handlers
|
||||
file_hanlder = logging.FileHandler(f'logs{self.Config.OS_SEP}defender.log',encoding='UTF-8')
|
||||
file_hanlder.setLevel(self.Config.DEBUG_LEVEL)
|
||||
|
||||
stdout_handler = logging.StreamHandler()
|
||||
stdout_handler.setLevel(50)
|
||||
|
||||
# Define log format
|
||||
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(funcName)s - %(message)s')
|
||||
|
||||
# Apply log format
|
||||
file_hanlder.setFormatter(formatter)
|
||||
stdout_handler.setFormatter(formatter)
|
||||
|
||||
# Add handler to logs
|
||||
self.logs.addHandler(file_hanlder)
|
||||
self.logs.addHandler(stdout_handler)
|
||||
|
||||
# Apply the filter
|
||||
self.logs.addFilter(self.replace_filter)
|
||||
|
||||
# self.logs.Logger('defender').addFilter(self.replace_filter)
|
||||
self.logs.info('#################### STARTING DEFENDER ####################')
|
||||
|
||||
return None
|
||||
|
||||
def replace_filter(self, record: logging.LogRecord) -> bool:
|
||||
|
||||
response = True
|
||||
filter: list[str] = ['PING', f":{self.Config.SERVICE_PREFIX}auth"]
|
||||
|
||||
# record.msg = record.getMessage().replace("PING", "[REDACTED]")
|
||||
if self.Settings.CONSOLE:
|
||||
print(record.getMessage())
|
||||
|
||||
for f in filter:
|
||||
if f in record.getMessage():
|
||||
response = False
|
||||
|
||||
return response # Retourne True pour permettre l'affichage du message
|
||||
|
||||
def delete_logger(self, logger_name: str) -> None:
|
||||
|
||||
# Récupérer le logger
|
||||
logger = logging.getLogger(logger_name)
|
||||
|
||||
# Retirer tous les gestionnaires du logger et les fermer
|
||||
for handler in logger.handlers[:]: # Utiliser une copie de la liste
|
||||
logger.removeHandler(handler)
|
||||
handler.close()
|
||||
|
||||
# Supprimer le logger du dictionnaire global
|
||||
logging.Logger.manager.loggerDict.pop(logger_name, None)
|
||||
|
||||
return None
|
||||
|
||||
def log_cmd(self, user_cmd:str, cmd:str) -> None:
|
||||
def log_cmd(self, user_cmd: str, cmd: str) -> None:
|
||||
"""Enregistre les commandes envoyées par les utilisateurs
|
||||
|
||||
Args:
|
||||
user_cmd (str): The user who performed the command
|
||||
cmd (str): la commande a enregistrer
|
||||
"""
|
||||
cmd_list = cmd.split()
|
||||
@@ -260,10 +207,10 @@ class Base:
|
||||
cmd = ' '.join(cmd_list)
|
||||
|
||||
insert_cmd_query = f"INSERT INTO {self.Config.TABLE_COMMAND} (datetime, user, commande) VALUES (:datetime, :user, :commande)"
|
||||
mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'commande': cmd}
|
||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'commande': cmd}
|
||||
self.db_execute_query(insert_cmd_query, mes_donnees)
|
||||
|
||||
return False
|
||||
return None
|
||||
|
||||
def db_isModuleExist(self, module_name:str) -> bool:
|
||||
"""Teste si un module existe déja dans la base de données
|
||||
@@ -283,22 +230,24 @@ class Base:
|
||||
else:
|
||||
return False
|
||||
|
||||
def db_record_module(self, user_cmd:str, module_name:str, isdefault:int = 0) -> None:
|
||||
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:
|
||||
cmd (str): le module a enregistrer
|
||||
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.get_datetime(), 'user': user_cmd, 'module_name': module_name, 'isdefault': 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 False
|
||||
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
|
||||
@@ -308,22 +257,22 @@ class Base:
|
||||
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.get_datetime(), 'user': user_cmd, '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 False
|
||||
return None
|
||||
|
||||
def db_delete_module(self, module_name:str) -> None:
|
||||
"""Supprime les modules de la base de données
|
||||
|
||||
Args:
|
||||
cmd (str): le module a supprimer
|
||||
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 False
|
||||
return None
|
||||
|
||||
def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool:
|
||||
"""Sync module local parameters with the database
|
||||
@@ -341,7 +290,7 @@ class Base:
|
||||
"""
|
||||
try:
|
||||
response = True
|
||||
current_date = self.get_datetime()
|
||||
current_date = self.Utils.get_sdatetime()
|
||||
core_table = self.Config.TABLE_CONFIG
|
||||
|
||||
# Add local parameters to DB
|
||||
@@ -391,7 +340,7 @@ class Base:
|
||||
result = response.fetchall()
|
||||
|
||||
for param, value in result:
|
||||
if type(getattr(dataclassObj, param)) == list:
|
||||
if isinstance(getattr(dataclassObj, param), list):
|
||||
value = ast.literal_eval(value)
|
||||
|
||||
setattr(dataclassObj, param, self.int_if_possible(value))
|
||||
@@ -418,7 +367,7 @@ class Base:
|
||||
isParamExist = result.fetchone()
|
||||
|
||||
if not isParamExist is None:
|
||||
mes_donnees = {'datetime': self.get_datetime(),
|
||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(),
|
||||
'module_name': module_name,
|
||||
'param_key': param_key,
|
||||
'param_value': param_value
|
||||
@@ -443,9 +392,9 @@ class Base:
|
||||
user = self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}")
|
||||
if not user.fetchall():
|
||||
admin = self.Config.OWNER
|
||||
password = self.crypt_password(self.Config.PASSWORD)
|
||||
password = self.Utils.hash_password(self.Config.PASSWORD)
|
||||
|
||||
mes_donnees = {'createdOn': self.get_datetime(),
|
||||
mes_donnees = {'createdOn': self.Utils.get_sdatetime(),
|
||||
'user': admin,
|
||||
'password': password,
|
||||
'hostname': '*',
|
||||
@@ -472,8 +421,11 @@ class Base:
|
||||
|
||||
self.logs.debug(f"-- Timer ID : {str(t.ident)} | Running Threads : {len(threading.enumerate())}")
|
||||
|
||||
return None
|
||||
|
||||
except AssertionError as ae:
|
||||
self.logs.error(f'Assertion Error -> {ae}')
|
||||
return None
|
||||
|
||||
def create_thread(self, func:object, func_args: tuple = (), run_once:bool = False, daemon: bool = True) -> None:
|
||||
"""Create a new thread and store it into running_threads variable
|
||||
@@ -500,6 +452,39 @@ class Base:
|
||||
except AssertionError as ae:
|
||||
self.logs.error(f'{ae}')
|
||||
|
||||
def is_thread_alive(self, thread_name: str) -> bool:
|
||||
"""Check if the thread is still running! using the is_alive method of Threads.
|
||||
|
||||
Args:
|
||||
thread_name (str): The thread name
|
||||
|
||||
Returns:
|
||||
bool: True if is alive
|
||||
"""
|
||||
for thread in self.running_threads:
|
||||
if thread.name.lower() == thread_name.lower():
|
||||
if thread.is_alive():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
def is_thread_exist(self, thread_name: str) -> bool:
|
||||
"""Check if the thread exist in the local var (running_threads)
|
||||
|
||||
Args:
|
||||
thread_name (str): The thread name
|
||||
|
||||
Returns:
|
||||
bool: True if the thread exist
|
||||
"""
|
||||
for thread in self.running_threads:
|
||||
if thread.name.lower() == thread_name.lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def thread_count(self, thread_name: str) -> int:
|
||||
"""This method return the number of existing threads
|
||||
currently running or not running
|
||||
@@ -709,19 +694,6 @@ class Base:
|
||||
except AttributeError as ae:
|
||||
self.logs.error(f"Attribute Error : {ae}")
|
||||
|
||||
def crypt_password(self, password:str) -> str:
|
||||
"""Retourne un mot de passe chiffré en MD5
|
||||
|
||||
Args:
|
||||
password (str): Le password en clair
|
||||
|
||||
Returns:
|
||||
str: Le password en MD5
|
||||
"""
|
||||
md5_password = hashlib.md5(password.encode()).hexdigest()
|
||||
|
||||
return md5_password
|
||||
|
||||
def int_if_possible(self, value):
|
||||
"""Convertit la valeur reçue en entier, si possible.
|
||||
Sinon elle retourne la valeur initiale.
|
||||
@@ -740,14 +712,14 @@ class Base:
|
||||
except TypeError:
|
||||
return value
|
||||
|
||||
def convert_to_int(self, value: any) -> Union[int, None]:
|
||||
def convert_to_int(self, value: Any) -> Optional[int]:
|
||||
"""Convert a value to int
|
||||
|
||||
Args:
|
||||
value (any): Value to convert to int if possible
|
||||
|
||||
Returns:
|
||||
Union[int, None]: Return the int value or None if not possible
|
||||
int: Return the int value or None if not possible
|
||||
"""
|
||||
try:
|
||||
response = int(value)
|
||||
@@ -788,7 +760,7 @@ class Base:
|
||||
self.logs.error(f'General Error: {err}')
|
||||
return False
|
||||
|
||||
def decode_ip(self, ip_b64encoded: str) -> Union[str, None]:
|
||||
def decode_ip(self, ip_b64encoded: str) -> Optional[str]:
|
||||
|
||||
binary_ip = b64decode(ip_b64encoded)
|
||||
try:
|
||||
@@ -799,7 +771,7 @@ class Base:
|
||||
self.logs.critical(f'This remote ip is not valid : {ve}')
|
||||
return None
|
||||
|
||||
def encode_ip(self, remote_ip_address: str) -> Union[str, None]:
|
||||
def encode_ip(self, remote_ip_address: str) -> Optional[str]:
|
||||
|
||||
binary_ip = socket.inet_aton(remote_ip_address)
|
||||
try:
|
||||
@@ -813,15 +785,6 @@ class Base:
|
||||
self.logs.critical(f'General Error: {err}')
|
||||
return None
|
||||
|
||||
def get_random(self, lenght:int) -> str:
|
||||
"""
|
||||
Retourn une chaîne aléatoire en fonction de la longueur spécifiée.
|
||||
"""
|
||||
caracteres = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
randomize = ''.join(random.choice(caracteres) for _ in range(lenght))
|
||||
|
||||
return randomize
|
||||
|
||||
def execute_periodic_action(self) -> None:
|
||||
|
||||
if not self.periodic_func:
|
||||
@@ -861,23 +824,3 @@ class Base:
|
||||
|
||||
self.logs.debug(f'Method to execute : {str(self.periodic_func)}')
|
||||
return None
|
||||
|
||||
def clean_uid(self, uid:str) -> Union[str, None]:
|
||||
"""Clean UID by removing @ / % / + / ~ / * / :
|
||||
|
||||
Args:
|
||||
uid (str): The UID to clean
|
||||
|
||||
Returns:
|
||||
str: Clean UID without any sign
|
||||
"""
|
||||
try:
|
||||
if uid is None:
|
||||
return None
|
||||
|
||||
pattern = fr'[:|@|%|\+|~|\*]*'
|
||||
parsed_UID = re.sub(pattern, '', uid)
|
||||
|
||||
return parsed_UID
|
||||
except TypeError as te:
|
||||
self.logs.error(f'Type Error: {te}')
|
||||
|
||||
@@ -1,127 +1,157 @@
|
||||
from typing import Union
|
||||
import core.definition as df
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from core.base import Base
|
||||
from core.definition import MAdmin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
|
||||
class Admin:
|
||||
|
||||
UID_ADMIN_DB: list[df.MAdmin] = []
|
||||
UID_ADMIN_DB: list[MAdmin] = []
|
||||
|
||||
def __init__(self, baseObj: Base) -> None:
|
||||
self.Logs = baseObj.logs
|
||||
pass
|
||||
def __init__(self, loader: 'Loader') -> None:
|
||||
self.Logs = loader.Logs
|
||||
|
||||
def insert(self, newAdmin: df.MAdmin) -> bool:
|
||||
def insert(self, new_admin: MAdmin) -> bool:
|
||||
"""Insert a new admin object model
|
||||
|
||||
result = False
|
||||
exist = False
|
||||
Args:
|
||||
new_admin (MAdmin): The new admin object model to insert
|
||||
|
||||
Returns:
|
||||
bool: True if it was inserted
|
||||
"""
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.uid == newAdmin.uid:
|
||||
if record.uid == new_admin.uid:
|
||||
# If the admin exist then return False and do not go further
|
||||
exist = True
|
||||
self.Logs.debug(f'{record.uid} already exist')
|
||||
return result
|
||||
return False
|
||||
|
||||
if not exist:
|
||||
self.UID_ADMIN_DB.append(newAdmin)
|
||||
result = True
|
||||
self.Logs.debug(f'UID ({newAdmin.uid}) has been created')
|
||||
self.UID_ADMIN_DB.append(new_admin)
|
||||
self.Logs.debug(f'A new admin ({new_admin.nickname}) has been created')
|
||||
return True
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The User Object was not inserted {newAdmin}')
|
||||
def update_nickname(self, uid: str, new_admin_nickname: str) -> bool:
|
||||
"""Update nickname of an admin
|
||||
|
||||
return result
|
||||
Args:
|
||||
uid (str): The Admin UID
|
||||
new_admin_nickname (str): The new nickname of the admin
|
||||
|
||||
def update_nickname(self, uid: str, newNickname: str) -> bool:
|
||||
|
||||
result = False
|
||||
Returns:
|
||||
bool: True if the nickname has been updated.
|
||||
"""
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.uid == uid:
|
||||
# If the admin exist, update and do not go further
|
||||
record.nickname = newNickname
|
||||
result = True
|
||||
self.Logs.debug(f'UID ({record.uid}) has been updated with new nickname {newNickname}')
|
||||
return result
|
||||
record.nickname = new_admin_nickname
|
||||
self.Logs.debug(f'UID ({record.uid}) has been updated with new nickname {new_admin_nickname}')
|
||||
return True
|
||||
|
||||
if not result:
|
||||
self.Logs.debug(f'The new nickname {newNickname} was not updated, uid = {uid} - The Client is not an admin')
|
||||
|
||||
return result
|
||||
self.Logs.debug(f'The new nickname {new_admin_nickname} was not updated, uid = {uid} - The Client is not an admin')
|
||||
return False
|
||||
|
||||
def update_level(self, nickname: str, newLevel: int) -> bool:
|
||||
def update_level(self, nickname: str, new_admin_level: int) -> bool:
|
||||
"""Update the admin level
|
||||
|
||||
result = False
|
||||
Args:
|
||||
nickname (str): The admin nickname
|
||||
new_admin_level (int): The new level of the admin
|
||||
|
||||
Returns:
|
||||
bool: True if the admin level has been updated
|
||||
"""
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.nickname == nickname:
|
||||
# If the admin exist, update and do not go further
|
||||
record.level = newLevel
|
||||
result = True
|
||||
self.Logs.debug(f'Admin ({record.nickname}) has been updated with new level {newLevel}')
|
||||
return result
|
||||
record.level = new_admin_level
|
||||
self.Logs.debug(f'Admin ({record.nickname}) has been updated with new level {new_admin_level}')
|
||||
return True
|
||||
|
||||
if not result:
|
||||
self.Logs.debug(f'The new level {newLevel} was not updated, nickname = {nickname} - The Client is not an admin')
|
||||
self.Logs.debug(f'The new level {new_admin_level} was not updated, nickname = {nickname} - The Client is not an admin')
|
||||
|
||||
return result
|
||||
return False
|
||||
|
||||
def delete(self, uidornickname: str) -> bool:
|
||||
"""Delete admin
|
||||
|
||||
result = False
|
||||
Args:
|
||||
uidornickname (str): The UID or nickname of the admin
|
||||
|
||||
Returns:
|
||||
bool: True if the admin has been deleted
|
||||
"""
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.uid == uidornickname:
|
||||
# If the admin exist, delete and do not go further
|
||||
self.UID_ADMIN_DB.remove(record)
|
||||
result = True
|
||||
self.Logs.debug(f'UID ({record.uid}) has been deleted')
|
||||
return result
|
||||
if record.nickname == uidornickname:
|
||||
return True
|
||||
if record.nickname.lower() == uidornickname.lower():
|
||||
# If the admin exist, delete and do not go further
|
||||
self.UID_ADMIN_DB.remove(record)
|
||||
result = True
|
||||
self.Logs.debug(f'nickname ({record.nickname}) has been deleted')
|
||||
return result
|
||||
return True
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The UID {uidornickname} was not deleted')
|
||||
self.Logs.debug(f'The UID {uidornickname} was not deleted')
|
||||
|
||||
return result
|
||||
return False
|
||||
|
||||
def get_Admin(self, uidornickname: str) -> Union[df.MAdmin, None]:
|
||||
def get_admin(self, uidornickname: str) -> Optional[MAdmin]:
|
||||
"""Get the admin object model
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or Nickname of the admin
|
||||
|
||||
Returns:
|
||||
Optional[MAdmin]: The MAdmin object model if exist
|
||||
"""
|
||||
|
||||
Admin = None
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.uid == uidornickname:
|
||||
Admin = record
|
||||
elif record.nickname == uidornickname:
|
||||
Admin = record
|
||||
return record
|
||||
elif record.nickname.lower() == uidornickname.lower():
|
||||
return record
|
||||
|
||||
#self.Logs.debug(f'Search {uidornickname} -- result = {Admin}')
|
||||
return None
|
||||
|
||||
return Admin
|
||||
def get_uid(self, uidornickname:str) -> Optional[str]:
|
||||
"""Get the UID of the admin
|
||||
|
||||
def get_uid(self, uidornickname:str) -> Union[str, None]:
|
||||
Args:
|
||||
uidornickname (str): The UID or nickname of the admin
|
||||
|
||||
Returns:
|
||||
Optional[str]: The UID of the admin
|
||||
"""
|
||||
|
||||
uid = None
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.uid == uidornickname:
|
||||
uid = record.uid
|
||||
if record.nickname == uidornickname:
|
||||
uid = record.uid
|
||||
return record.uid
|
||||
if record.nickname.lower() == uidornickname.lower():
|
||||
return record.uid
|
||||
|
||||
self.Logs.debug(f'The UID that you are looking for {uidornickname} has been found {uid}')
|
||||
return uid
|
||||
return None
|
||||
|
||||
def get_nickname(self, uidornickname:str) -> Union[str, None]:
|
||||
def get_nickname(self, uidornickname:str) -> Optional[str]:
|
||||
"""Get the nickname of the admin
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or the nickname of the admin
|
||||
|
||||
Returns:
|
||||
Optional[str]: The nickname of the admin
|
||||
"""
|
||||
|
||||
nickname = None
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.nickname == uidornickname:
|
||||
nickname = record.nickname
|
||||
if record.nickname.lower() == uidornickname.lower():
|
||||
return record.nickname
|
||||
if record.uid == uidornickname:
|
||||
nickname = record.nickname
|
||||
self.Logs.debug(f'The value {uidornickname} -- {nickname}')
|
||||
return nickname
|
||||
return record.nickname
|
||||
|
||||
return None
|
||||
@@ -1,12 +1,9 @@
|
||||
from re import findall
|
||||
from typing import Union, Literal, TYPE_CHECKING
|
||||
from dataclasses import asdict
|
||||
|
||||
from core.classes import user
|
||||
from typing import Any, Optional, Literal, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MChannel
|
||||
from core.base import Base
|
||||
from core.loader import Loader
|
||||
|
||||
class Channel:
|
||||
|
||||
@@ -14,18 +11,19 @@ class Channel:
|
||||
"""List that contains all the Channels objects (ChannelModel)
|
||||
"""
|
||||
|
||||
def __init__(self, baseObj: 'Base') -> None:
|
||||
def __init__(self, loader: 'Loader') -> None:
|
||||
|
||||
self.Logs = baseObj.logs
|
||||
self.Base = baseObj
|
||||
self.Logs = loader.Logs
|
||||
self.Base = loader.Base
|
||||
self.Utils = loader.Utils
|
||||
|
||||
return None
|
||||
|
||||
def insert(self, newChan: 'MChannel') -> bool:
|
||||
def insert(self, new_channel: 'MChannel') -> bool:
|
||||
"""This method will insert a new channel and if the channel exist it will update the user list (uids)
|
||||
|
||||
Args:
|
||||
newChan (ChannelModel): The channel model object
|
||||
new_channel (MChannel): The channel model object
|
||||
|
||||
Returns:
|
||||
bool: True if new channel, False if channel exist (However UID could be updated)
|
||||
@@ -33,17 +31,17 @@ class Channel:
|
||||
result = False
|
||||
exist = False
|
||||
|
||||
if not self.Is_Channel(newChan.name):
|
||||
self.Logs.error(f"The channel {newChan.name} is not valid, channel must start with #")
|
||||
if not self.is_valid_channel(new_channel.name):
|
||||
self.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #")
|
||||
return False
|
||||
|
||||
for record in self.UID_CHANNEL_DB:
|
||||
if record.name.lower() == newChan.name.lower():
|
||||
if record.name.lower() == new_channel.name.lower():
|
||||
# If the channel exist, update the user list and do not go further
|
||||
exist = True
|
||||
# self.Logs.debug(f'{record.name} already exist')
|
||||
|
||||
for user in newChan.uids:
|
||||
for user in new_channel.uids:
|
||||
record.uids.append(user)
|
||||
|
||||
# Supprimer les doublons
|
||||
@@ -54,41 +52,58 @@ class Channel:
|
||||
|
||||
if not exist:
|
||||
# If the channel don't exist, then create it
|
||||
newChan.name = newChan.name.lower()
|
||||
self.UID_CHANNEL_DB.append(newChan)
|
||||
new_channel.name = new_channel.name.lower()
|
||||
self.UID_CHANNEL_DB.append(new_channel)
|
||||
result = True
|
||||
# self.Logs.debug(f'New Channel Created: ({newChan})')
|
||||
# self.Logs.debug(f'New Channel Created: ({new_channel})')
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The Channel Object was not inserted {newChan}')
|
||||
self.Logs.critical(f'The Channel Object was not inserted {new_channel}')
|
||||
|
||||
self.clean_channel()
|
||||
|
||||
return result
|
||||
|
||||
def delete(self, channel_name: str) -> bool:
|
||||
"""Delete channel from the UID_CHANNEL_DB
|
||||
|
||||
chanObj = self.get_Channel(channel_name)
|
||||
Args:
|
||||
channel_name (str): The Channel name
|
||||
|
||||
if chanObj is None:
|
||||
Returns:
|
||||
bool: True if it was deleted
|
||||
"""
|
||||
|
||||
chan_obj = self.get_channel(channel_name)
|
||||
|
||||
if chan_obj is None:
|
||||
return False
|
||||
|
||||
self.UID_CHANNEL_DB.remove(chanObj)
|
||||
self.UID_CHANNEL_DB.remove(chan_obj)
|
||||
|
||||
return True
|
||||
|
||||
def delete_user_from_channel(self, channel_name: str, uid:str) -> bool:
|
||||
"""Delete a user from a channel
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel name
|
||||
uid (str): The Client UID
|
||||
|
||||
Returns:
|
||||
bool: True if the client has been deleted from the channel
|
||||
"""
|
||||
try:
|
||||
result = False
|
||||
|
||||
chanObj = self.get_Channel(channel_name.lower())
|
||||
chan_obj = self.get_channel(channel_name.lower())
|
||||
|
||||
if chanObj is None:
|
||||
if chan_obj is None:
|
||||
return result
|
||||
|
||||
for userid in chanObj.uids:
|
||||
if self.Base.clean_uid(userid) == self.Base.clean_uid(uid):
|
||||
chanObj.uids.remove(userid)
|
||||
for userid in chan_obj.uids:
|
||||
if self.Utils.clean_uid(userid) == self.Utils.clean_uid(uid):
|
||||
chan_obj.uids.remove(userid)
|
||||
result = True
|
||||
|
||||
self.clean_channel()
|
||||
@@ -98,14 +113,21 @@ class Channel:
|
||||
self.Logs.error(f'{ve}')
|
||||
|
||||
def delete_user_from_all_channel(self, uid:str) -> bool:
|
||||
"""Delete a client from all channels
|
||||
|
||||
Args:
|
||||
uid (str): The client UID
|
||||
|
||||
Returns:
|
||||
bool: True if the client has been deleted from all channels
|
||||
"""
|
||||
try:
|
||||
result = False
|
||||
|
||||
for record in self.UID_CHANNEL_DB:
|
||||
for user_id in record.uids:
|
||||
if self.Base.clean_uid(user_id) == self.Base.clean_uid(uid):
|
||||
if self.Utils.clean_uid(user_id) == self.Utils.clean_uid(uid):
|
||||
record.uids.remove(user_id)
|
||||
# self.Logs.debug(f'The UID {uid} has been removed, here is the new object: {record}')
|
||||
result = True
|
||||
|
||||
self.clean_channel()
|
||||
@@ -115,104 +137,113 @@ class Channel:
|
||||
self.Logs.error(f'{ve}')
|
||||
|
||||
def add_user_to_a_channel(self, channel_name: str, uid: str) -> bool:
|
||||
"""Add a client to a channel
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel name
|
||||
uid (str): The client UID
|
||||
|
||||
Returns:
|
||||
bool: True is the clien has been added
|
||||
"""
|
||||
try:
|
||||
result = False
|
||||
chanObj = self.get_Channel(channel_name)
|
||||
self.Logs.debug(f"** {__name__}")
|
||||
chan_obj = self.get_channel(channel_name)
|
||||
|
||||
if chanObj is None:
|
||||
result = self.insert(MChannel(channel_name, uids=[uid]))
|
||||
# self.Logs.debug(f"** {__name__} - result: {result}")
|
||||
# self.Logs.debug(f'New Channel Created: ({chanObj})')
|
||||
return result
|
||||
if chan_obj is None:
|
||||
# Create a new channel if the channel don't exist
|
||||
self.Logs.debug(f"New channel will be created ({channel_name} - {uid})")
|
||||
return self.insert(MChannel(channel_name, uids=[uid]))
|
||||
|
||||
chanObj.uids.append(uid)
|
||||
del_duplicates = list(set(chanObj.uids))
|
||||
chanObj.uids = del_duplicates
|
||||
# self.Logs.debug(f'New Channel Created: ({chanObj})')
|
||||
chan_obj.uids.append(uid)
|
||||
del_duplicates = list(set(chan_obj.uids))
|
||||
chan_obj.uids = del_duplicates
|
||||
|
||||
return True
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
return False
|
||||
|
||||
def is_user_present_in_channel(self, channel_name: str, uid: str) -> bool:
|
||||
"""Check if a user is present in the channel
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel to check
|
||||
uid (str): The UID
|
||||
channel_name (str): The channel name to check
|
||||
uid (str): The client UID
|
||||
|
||||
Returns:
|
||||
bool: True if the user is present in the channel
|
||||
"""
|
||||
user_found = False
|
||||
chan = self.get_Channel(channel_name=channel_name)
|
||||
chan = self.get_channel(channel_name=channel_name)
|
||||
if chan is None:
|
||||
return user_found
|
||||
return False
|
||||
|
||||
clean_uid = self.Base.clean_uid(uid=uid)
|
||||
clean_uid = self.Utils.clean_uid(uid=uid)
|
||||
for chan_uid in chan.uids:
|
||||
if self.Base.clean_uid(chan_uid) == clean_uid:
|
||||
user_found = True
|
||||
break
|
||||
if self.Utils.clean_uid(chan_uid) == clean_uid:
|
||||
return True
|
||||
|
||||
return user_found
|
||||
return False
|
||||
|
||||
def clean_channel(self) -> None:
|
||||
"""Remove Channels if empty
|
||||
"""If channel doesn't contain any client this method will remove the channel
|
||||
"""
|
||||
try:
|
||||
for record in self.UID_CHANNEL_DB:
|
||||
if not record.uids:
|
||||
self.UID_CHANNEL_DB.remove(record)
|
||||
# self.Logs.debug(f'The Channel {record.name} has been removed, here is the new object: {record}')
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
|
||||
def get_Channel(self, channel_name: str) -> Union['MChannel', None]:
|
||||
|
||||
Channel = None
|
||||
|
||||
for record in self.UID_CHANNEL_DB:
|
||||
if record.name == channel_name:
|
||||
Channel = record
|
||||
|
||||
return Channel
|
||||
|
||||
def get_Channel_AsDict(self, chan_name: str) -> Union[dict[str, any], None]:
|
||||
|
||||
chanObj = self.get_Channel(chan_name=chan_name)
|
||||
|
||||
if not chanObj is None:
|
||||
chan_as_dict = asdict(chanObj)
|
||||
return chan_as_dict
|
||||
else:
|
||||
return None
|
||||
|
||||
def Is_Channel(self, channelToCheck: str) -> bool:
|
||||
"""Check if the string has the # caractere and return True if this is a channel
|
||||
def get_channel(self, channel_name: str) -> Optional['MChannel']:
|
||||
"""Get the channel object
|
||||
|
||||
Args:
|
||||
channelToCheck (str): The string to test if it is a channel or not
|
||||
channel_name (str): The Channel name
|
||||
|
||||
Returns:
|
||||
MChannel: The channel object model if exist else None
|
||||
"""
|
||||
|
||||
for record in self.UID_CHANNEL_DB:
|
||||
if record.name.lower() == channel_name.lower():
|
||||
return record
|
||||
|
||||
return None
|
||||
|
||||
def get_channel_asdict(self, channel_name: str) -> Optional[dict[str, Any]]:
|
||||
|
||||
channel_obj: Optional['MChannel'] = self.get_channel(channel_name)
|
||||
|
||||
if channel_obj is None:
|
||||
return None
|
||||
|
||||
return channel_obj.to_dict()
|
||||
|
||||
def is_valid_channel(self, channel_to_check: str) -> bool:
|
||||
"""Check if the string has the # caractere and return True if this is a valid channel
|
||||
|
||||
Args:
|
||||
channel_to_check (str): The string to test if it is a channel or not
|
||||
|
||||
Returns:
|
||||
bool: True if the string is a channel / False if this is not a channel
|
||||
"""
|
||||
try:
|
||||
|
||||
if channelToCheck is None:
|
||||
if channel_to_check is None:
|
||||
return False
|
||||
|
||||
pattern = fr'^#'
|
||||
isChannel = findall(pattern, channelToCheck)
|
||||
isChannel = findall(pattern, channel_to_check)
|
||||
|
||||
if not isChannel:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
except TypeError as te:
|
||||
self.Logs.error(f'TypeError: [{channelToCheck}] - {te}')
|
||||
self.Logs.error(f'TypeError: [{channel_to_check}] - {te}')
|
||||
except Exception as err:
|
||||
self.Logs.error(f'Error Not defined: {err}')
|
||||
|
||||
@@ -228,7 +259,7 @@ class Channel:
|
||||
bool: True if action done
|
||||
"""
|
||||
try:
|
||||
channel_name = channel_name.lower() if self.Is_Channel(channel_name) else None
|
||||
channel_name = channel_name.lower() if self.is_valid_channel(channel_name) else None
|
||||
core_table = self.Base.Config.TABLE_CHANNEL
|
||||
|
||||
if not channel_name:
|
||||
@@ -240,10 +271,10 @@ class Channel:
|
||||
case 'add':
|
||||
mes_donnees = {'module_name': module_name, 'channel_name': channel_name}
|
||||
response = self.Base.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees)
|
||||
isChannelExist = response.fetchone()
|
||||
is_channel_exist = response.fetchone()
|
||||
|
||||
if isChannelExist is None:
|
||||
mes_donnees = {'datetime': self.Base.get_datetime(), 'channel_name': channel_name, 'module_name': module_name}
|
||||
if is_channel_exist is None:
|
||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name}
|
||||
insert = self.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees)
|
||||
if insert.rowcount:
|
||||
self.Logs.debug(f'New channel added: channel={channel_name} / module_name={module_name}')
|
||||
@@ -266,4 +297,3 @@ class Channel:
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(err)
|
||||
|
||||
|
||||
@@ -1,39 +1,36 @@
|
||||
from re import sub
|
||||
from typing import Union, TYPE_CHECKING
|
||||
from dataclasses import asdict
|
||||
from typing import Any, Optional, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.base import Base
|
||||
from core.loader import Loader
|
||||
from core.definition import MClient
|
||||
|
||||
class Client:
|
||||
|
||||
CLIENT_DB: list['MClient'] = []
|
||||
|
||||
def __init__(self, baseObj: 'Base') -> None:
|
||||
def __init__(self, loader: 'Loader'):
|
||||
|
||||
self.Logs = baseObj.logs
|
||||
self.Base = baseObj
|
||||
self.Logs = loader.Logs
|
||||
self.Base = loader.Base
|
||||
|
||||
return None
|
||||
|
||||
def insert(self, newUser: 'MClient') -> bool:
|
||||
def insert(self, new_client: 'MClient') -> bool:
|
||||
"""Insert a new User object
|
||||
|
||||
Args:
|
||||
newUser (UserModel): New userModel object
|
||||
new_client (MClient): New Client object
|
||||
|
||||
Returns:
|
||||
bool: True if inserted
|
||||
"""
|
||||
|
||||
userObj = self.get_Client(newUser.uid)
|
||||
client_obj = self.get_Client(new_client.uid)
|
||||
|
||||
if not userObj is None:
|
||||
if not client_obj is None:
|
||||
# User already created return False
|
||||
return False
|
||||
|
||||
self.CLIENT_DB.append(newUser)
|
||||
self.CLIENT_DB.append(new_client)
|
||||
|
||||
return True
|
||||
|
||||
@@ -47,12 +44,12 @@ class Client:
|
||||
Returns:
|
||||
bool: True if updated
|
||||
"""
|
||||
userObj = self.get_Client(uidornickname=uid)
|
||||
user_obj = self.get_Client(uidornickname=uid)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
userObj.nickname = newNickname
|
||||
user_obj.nickname = newNickname
|
||||
|
||||
return True
|
||||
|
||||
@@ -67,16 +64,16 @@ class Client:
|
||||
bool: True if user mode has been updaed
|
||||
"""
|
||||
response = True
|
||||
userObj = self.get_Client(uidornickname=uidornickname)
|
||||
user_obj = self.get_Client(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
action = modes[0]
|
||||
new_modes = modes[1:]
|
||||
|
||||
existing_umodes = userObj.umodes
|
||||
umodes = userObj.umodes
|
||||
existing_umodes = user_obj.umodes
|
||||
umodes = user_obj.umodes
|
||||
|
||||
if action == '+':
|
||||
|
||||
@@ -95,7 +92,7 @@ class Client:
|
||||
final_umodes_liste = [x for x in self.Base.Settings.PROTOCTL_USER_MODES if x in liste_umodes]
|
||||
final_umodes = ''.join(final_umodes_liste)
|
||||
|
||||
userObj.umodes = f"+{final_umodes}"
|
||||
user_obj.umodes = f"+{final_umodes}"
|
||||
|
||||
return response
|
||||
|
||||
@@ -109,16 +106,16 @@ class Client:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
userObj = self.get_Client(uidornickname=uid)
|
||||
user_obj = self.get_Client(uidornickname=uid)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
self.CLIENT_DB.remove(userObj)
|
||||
self.CLIENT_DB.remove(user_obj)
|
||||
|
||||
return True
|
||||
|
||||
def get_Client(self, uidornickname: str) -> Union['MClient', None]:
|
||||
def get_Client(self, uidornickname: str) -> Optional['MClient']:
|
||||
"""Get The Client Object model
|
||||
|
||||
Args:
|
||||
@@ -127,16 +124,15 @@ class Client:
|
||||
Returns:
|
||||
UserModel|None: The UserModel Object | None
|
||||
"""
|
||||
User = None
|
||||
for record in self.CLIENT_DB:
|
||||
if record.uid == uidornickname:
|
||||
User = record
|
||||
return record
|
||||
elif record.nickname == uidornickname:
|
||||
User = record
|
||||
return record
|
||||
|
||||
return User
|
||||
return None
|
||||
|
||||
def get_uid(self, uidornickname:str) -> Union[str, None]:
|
||||
def get_uid(self, uidornickname:str) -> Optional[str]:
|
||||
"""Get the UID of the user starting from the UID or the Nickname
|
||||
|
||||
Args:
|
||||
@@ -146,12 +142,12 @@ class Client:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
|
||||
userObj = self.get_Client(uidornickname=uidornickname)
|
||||
client_obj = self.get_Client(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return userObj.uid
|
||||
return client_obj.uid
|
||||
|
||||
def get_nickname(self, uidornickname:str) -> Union[str, None]:
|
||||
"""Get the Nickname starting from UID or the nickname
|
||||
@@ -162,14 +158,14 @@ class Client:
|
||||
Returns:
|
||||
str|None: the nickname
|
||||
"""
|
||||
userObj = self.get_Client(uidornickname=uidornickname)
|
||||
client_obj = self.get_Client(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return userObj.nickname
|
||||
return client_obj.nickname
|
||||
|
||||
def get_Client_AsDict(self, uidornickname: str) -> Union[dict[str, any], None]:
|
||||
def get_client_asdict(self, uidornickname: str) -> Optional[dict[str, Any]]:
|
||||
"""Transform User Object to a dictionary
|
||||
|
||||
Args:
|
||||
@@ -178,12 +174,12 @@ class Client:
|
||||
Returns:
|
||||
Union[dict[str, any], None]: User Object as a dictionary or None
|
||||
"""
|
||||
userObj = self.get_Client(uidornickname=uidornickname)
|
||||
client_obj = self.get_Client(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return asdict(userObj)
|
||||
return client_obj.to_dict()
|
||||
|
||||
def is_exist(self, uidornikname: str) -> bool:
|
||||
"""Check if the UID or the nickname exist in the USER DB
|
||||
@@ -194,9 +190,9 @@ class Client:
|
||||
Returns:
|
||||
bool: True if exist
|
||||
"""
|
||||
userObj = self.get_Client(uidornickname=uidornikname)
|
||||
user_obj = self.get_Client(uidornickname=uidornikname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
from dataclasses import asdict
|
||||
from core.definition import MClone
|
||||
from typing import Union
|
||||
from core.base import Base
|
||||
|
||||
class Clone:
|
||||
|
||||
UID_CLONE_DB: list[MClone] = []
|
||||
|
||||
def __init__(self, baseObj: Base) -> None:
|
||||
|
||||
self.Logs = baseObj.logs
|
||||
|
||||
return None
|
||||
|
||||
def insert(self, newCloneObject: MClone) -> bool:
|
||||
"""Create new Clone object
|
||||
|
||||
Args:
|
||||
newCloneObject (CloneModel): New CloneModel object
|
||||
|
||||
Returns:
|
||||
bool: True if inserted
|
||||
"""
|
||||
result = False
|
||||
exist = False
|
||||
|
||||
for record in self.UID_CLONE_DB:
|
||||
if record.nickname == newCloneObject.nickname:
|
||||
# If the user exist then return False and do not go further
|
||||
exist = True
|
||||
self.Logs.warning(f'Nickname {record.nickname} already exist')
|
||||
return result
|
||||
if record.uid == newCloneObject.uid:
|
||||
exist = True
|
||||
self.Logs.warning(f'UID: {record.uid} already exist')
|
||||
return result
|
||||
|
||||
if not exist:
|
||||
self.UID_CLONE_DB.append(newCloneObject)
|
||||
result = True
|
||||
# self.Logs.debug(f'New Clone Object Created: ({newCloneObject})')
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The Clone Object was not inserted {newCloneObject}')
|
||||
|
||||
return result
|
||||
|
||||
def delete(self, uidornickname: str) -> bool:
|
||||
"""Delete the Clone Object starting from the nickname or the UID
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or nickname of the clone
|
||||
|
||||
Returns:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
cloneObj = self.get_Clone(uidornickname=uidornickname)
|
||||
|
||||
if cloneObj is None:
|
||||
return False
|
||||
|
||||
self.UID_CLONE_DB.remove(cloneObj)
|
||||
|
||||
return True
|
||||
|
||||
def exists(self, nickname: str) -> bool:
|
||||
"""Check if the nickname exist
|
||||
|
||||
Args:
|
||||
nickname (str): Nickname of the clone
|
||||
|
||||
Returns:
|
||||
bool: True if the nickname exist
|
||||
"""
|
||||
response = False
|
||||
|
||||
for cloneObject in self.UID_CLONE_DB:
|
||||
if cloneObject.nickname == nickname:
|
||||
response = True
|
||||
|
||||
return response
|
||||
|
||||
def uid_exists(self, uid: str) -> bool:
|
||||
"""Check if the nickname exist
|
||||
|
||||
Args:
|
||||
uid (str): uid of the clone
|
||||
|
||||
Returns:
|
||||
bool: True if the nickname exist
|
||||
"""
|
||||
response = False
|
||||
|
||||
for cloneObject in self.UID_CLONE_DB:
|
||||
if cloneObject.uid == uid:
|
||||
response = True
|
||||
|
||||
return response
|
||||
|
||||
def get_Clone(self, uidornickname: str) -> Union[MClone, None]:
|
||||
"""Get MClone object or None
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or the Nickname
|
||||
|
||||
Returns:
|
||||
Union[MClone, None]: Return MClone object or None
|
||||
"""
|
||||
cloneObj = None
|
||||
|
||||
for clone in self.UID_CLONE_DB:
|
||||
if clone.uid == uidornickname:
|
||||
cloneObj = clone
|
||||
if clone.nickname == uidornickname:
|
||||
cloneObj = clone
|
||||
|
||||
return cloneObj
|
||||
|
||||
def get_uid(self, uidornickname: str) -> Union[str, None]:
|
||||
"""Get the UID of the clone starting from the UID or the Nickname
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or Nickname
|
||||
|
||||
Returns:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
uid = None
|
||||
for record in self.UID_CLONE_DB:
|
||||
if record.uid == uidornickname:
|
||||
uid = record.uid
|
||||
if record.nickname == uidornickname:
|
||||
uid = record.uid
|
||||
|
||||
# if not uid is None:
|
||||
# self.Logs.debug(f'The UID that you are looking for {uidornickname} has been found {uid}')
|
||||
|
||||
return uid
|
||||
|
||||
def get_Clone_AsDict(self, uidornickname: str) -> Union[dict[str, any], None]:
|
||||
|
||||
cloneObj = self.get_Clone(uidornickname=uidornickname)
|
||||
|
||||
if not cloneObj is None:
|
||||
cloneObj_as_dict = asdict(cloneObj)
|
||||
return cloneObj_as_dict
|
||||
else:
|
||||
return None
|
||||
|
||||
def kill(self, nickname:str) -> bool:
|
||||
|
||||
response = False
|
||||
|
||||
for cloneObject in self.UID_CLONE_DB:
|
||||
if cloneObject.nickname == nickname:
|
||||
cloneObject.alive = False # Kill the clone
|
||||
response = True
|
||||
|
||||
return response
|
||||
59
core/classes/commands.py
Normal file
59
core/classes/commands.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from core.definition import MCommand
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
|
||||
class Command:
|
||||
|
||||
DB_COMMANDS: list['MCommand'] = []
|
||||
|
||||
def __init__(self, loader: 'Loader'):
|
||||
self.Base = loader.Base
|
||||
|
||||
def build(self, new_command_obj: MCommand) -> bool:
|
||||
|
||||
command = self.get_command(new_command_obj.command_name, new_command_obj.module_name)
|
||||
if command is None:
|
||||
self.DB_COMMANDS.append(new_command_obj)
|
||||
return True
|
||||
|
||||
# Update command if it exist
|
||||
# Removing the object
|
||||
if self.drop_command(command.command_name, command.module_name):
|
||||
# Add the new object
|
||||
self.DB_COMMANDS.append(new_command_obj)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_command(self, command_name: str, module_name: str) -> Optional[MCommand]:
|
||||
|
||||
for command in self.DB_COMMANDS:
|
||||
if command.command_name.lower() == command_name and command.module_name == module_name:
|
||||
return command
|
||||
|
||||
return None
|
||||
|
||||
def drop_command(self, command_name: str, module_name: str) -> bool:
|
||||
|
||||
cmd = self.get_command(command_name, module_name)
|
||||
if cmd is not None:
|
||||
self.DB_COMMANDS.remove(cmd)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_ordered_commands(self) -> list[MCommand]:
|
||||
return sorted(self.DB_COMMANDS, key=lambda c: (c.command_level, c.module_name))
|
||||
|
||||
def get_commands_by_level(self, level: int = 0) -> Optional[list[MCommand]]:
|
||||
|
||||
cmd_list = self.get_ordered_commands()
|
||||
new_list: list[MCommand] = []
|
||||
|
||||
for cmd in cmd_list:
|
||||
if cmd.command_level <= level:
|
||||
new_list.append(cmd)
|
||||
|
||||
return new_list
|
||||
@@ -3,13 +3,13 @@ from sys import exit
|
||||
from os import sep
|
||||
from typing import Union
|
||||
from core.definition import MConfig
|
||||
|
||||
from logging import Logger
|
||||
|
||||
|
||||
class Configuration:
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
def __init__(self, logs: Logger) -> None:
|
||||
self.Logs = logs
|
||||
self.ConfigObject: MConfig = self.__load_service_configuration()
|
||||
return None
|
||||
|
||||
@@ -22,18 +22,18 @@ class Configuration:
|
||||
return configuration
|
||||
|
||||
except FileNotFoundError as fe:
|
||||
print(f'FileNotFound: {fe}')
|
||||
print('Configuration file not found please create config/configuration.json')
|
||||
self.Logs.error(f'FileNotFound: {fe}')
|
||||
self.Logs.error('Configuration file not found please create config/configuration.json')
|
||||
exit(0)
|
||||
except KeyError as ke:
|
||||
print(f'Key Error: {ke}')
|
||||
print('The key must be defined in core/configuration.json')
|
||||
self.Logs.error(f'Key Error: {ke}')
|
||||
self.Logs.error('The key must be defined in core/configuration.json')
|
||||
|
||||
def __load_service_configuration(self) -> MConfig:
|
||||
try:
|
||||
import_config = self.__load_json_service_configuration()
|
||||
|
||||
Model_keys = MConfig().__dict__
|
||||
Model_keys = MConfig().to_dict()
|
||||
model_key_list: list = []
|
||||
json_config_key_list: list = []
|
||||
|
||||
@@ -46,12 +46,13 @@ class Configuration:
|
||||
for json_conf in json_config_key_list:
|
||||
if not json_conf in model_key_list:
|
||||
import_config.pop(json_conf, None)
|
||||
print(f"\!/ The key {json_conf} is not expected, it has been removed from the system ! please remove it from configuration.json file \!/")
|
||||
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
|
||||
|
||||
except TypeError as te:
|
||||
print(te)
|
||||
self.Logs.error(te)
|
||||
@@ -14,8 +14,10 @@ class Inspircd:
|
||||
self.__Irc = ircInstance
|
||||
self.__Config = ircInstance.Config
|
||||
self.__Base = ircInstance.Base
|
||||
self.__Utils = ircInstance.Loader.Utils
|
||||
self.__Logs = ircInstance.Loader.Logs
|
||||
|
||||
self.__Base.logs.info(f"** Loading protocol [{__name__}]")
|
||||
self.__Logs.info(f"** Loading protocol [{__name__}]")
|
||||
|
||||
def send2socket(self, message: str, print_log: bool = True) -> None:
|
||||
"""Envoit les commandes à envoyer au serveur.
|
||||
@@ -27,24 +29,24 @@ class Inspircd:
|
||||
with self.__Base.lock:
|
||||
self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[0]))
|
||||
if print_log:
|
||||
self.__Base.logs.debug(f'<< {message}')
|
||||
self.__Logs.debug(f'<< {message}')
|
||||
|
||||
except UnicodeDecodeError as ude:
|
||||
self.__Base.logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}')
|
||||
self.__Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}')
|
||||
self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace'))
|
||||
except UnicodeEncodeError as uee:
|
||||
self.__Base.logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}')
|
||||
self.__Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}')
|
||||
self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace'))
|
||||
except AssertionError as ae:
|
||||
self.__Base.logs.warning(f'Assertion Error {ae} - message: {message}')
|
||||
self.__Logs.warning(f'Assertion Error {ae} - message: {message}')
|
||||
except SSLEOFError as soe:
|
||||
self.__Base.logs.error(f"SSLEOFError: {soe} - {message}")
|
||||
self.__Logs.error(f"SSLEOFError: {soe} - {message}")
|
||||
except SSLError as se:
|
||||
self.__Base.logs.error(f"SSLError: {se} - {message}")
|
||||
self.__Logs.error(f"SSLError: {se} - {message}")
|
||||
except OSError as oe:
|
||||
self.__Base.logs.error(f"OSError: {oe} - {message}")
|
||||
self.__Logs.error(f"OSError: {oe} - {message}")
|
||||
except AttributeError as ae:
|
||||
self.__Base.logs.critical(f"Attribute Error: {ae}")
|
||||
self.__Logs.critical(f"Attribute Error: {ae}")
|
||||
|
||||
def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None):
|
||||
"""Sending PRIVMSG to a channel or to a nickname by batches
|
||||
@@ -61,7 +63,7 @@ class Inspircd:
|
||||
User_to = self.__Irc.User.get_User(nick_to) if nick_to is None else None
|
||||
|
||||
if User_from is None:
|
||||
self.__Base.logs.error(f"The sender nickname [{nick_from}] do not exist")
|
||||
self.__Logs.error(f"The sender nickname [{nick_from}] do not exist")
|
||||
return None
|
||||
|
||||
if not channel is None:
|
||||
@@ -74,7 +76,7 @@ class Inspircd:
|
||||
batch = str(msg)[i:i+batch_size]
|
||||
self.send2socket(f":{nick_from} PRIVMSG {User_to.uid} :{batch}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"General Error: {err}")
|
||||
self.__Logs.error(f"General Error: {err}")
|
||||
|
||||
def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None:
|
||||
"""Sending NOTICE by batches
|
||||
@@ -90,7 +92,7 @@ class Inspircd:
|
||||
User_to = self.__Irc.User.get_User(nick_to)
|
||||
|
||||
if User_from is None or User_to is None:
|
||||
self.__Base.logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist")
|
||||
self.__Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist")
|
||||
return None
|
||||
|
||||
for i in range(0, len(str(msg)), batch_size):
|
||||
@@ -98,9 +100,9 @@ class Inspircd:
|
||||
self.send2socket(f":{User_from.uid} NOTICE {User_to.uid} :{batch}")
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"General Error: {err}")
|
||||
self.__Logs.error(f"General Error: {err}")
|
||||
|
||||
def link(self):
|
||||
def send_link(self):
|
||||
"""Créer le link et envoyer les informations nécessaires pour la
|
||||
connexion au serveur.
|
||||
"""
|
||||
@@ -122,7 +124,7 @@ class Inspircd:
|
||||
service_id = self.__Config.SERVICE_ID
|
||||
|
||||
version = self.__Config.CURRENT_VERSION
|
||||
unixtime = self.__Base.get_unixtime()
|
||||
unixtime = self.__Utils.get_unixtime()
|
||||
|
||||
|
||||
self.send2socket(f"CAPAB START 1206")
|
||||
@@ -132,7 +134,7 @@ class Inspircd:
|
||||
self.send2socket(f"BURST {unixtime}")
|
||||
self.send2socket(f":{server_id} ENDBURST")
|
||||
|
||||
self.__Base.logs.debug(f'>> {__name__} Link information sent to the server')
|
||||
self.__Logs.debug(f'>> {__name__} Link information sent to the server')
|
||||
|
||||
def gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
# TKL + G user host set_by expire_timestamp set_at_timestamp :reason
|
||||
@@ -141,12 +143,12 @@ class Inspircd:
|
||||
|
||||
return None
|
||||
|
||||
def set_nick(self, newnickname: str) -> None:
|
||||
def send_set_nick(self, newnickname: str) -> None:
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVICE_NICKNAME} NICK {newnickname}")
|
||||
return None
|
||||
|
||||
def squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||
def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||
|
||||
if not reason:
|
||||
reason = 'Service Shutdown'
|
||||
@@ -154,26 +156,26 @@ class Inspircd:
|
||||
self.send2socket(f":{server_id} SQUIT {server_link} :{reason}")
|
||||
return None
|
||||
|
||||
def ungline(self, nickname:str, hostname: str) -> None:
|
||||
def send_ungline(self, nickname:str, hostname: str) -> None:
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}")
|
||||
|
||||
return None
|
||||
|
||||
def kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
# TKL + k user host set_by expire_timestamp set_at_timestamp :reason
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}")
|
||||
|
||||
return None
|
||||
|
||||
def sjoin(self, channel: str) -> None:
|
||||
def send_sjoin(self, channel: str) -> None:
|
||||
|
||||
if not self.__Irc.Channel.Is_Channel(channel):
|
||||
self.__Base.logs.error(f"The channel [{channel}] is not valid")
|
||||
if not self.__Irc.Channel.is_valid_channel(channel):
|
||||
self.__Logs.error(f"The channel [{channel}] is not valid")
|
||||
return None
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} SJOIN {self.__Base.get_unixtime()} {channel} + :{self.__Config.SERVICE_ID}")
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} SJOIN {self.__Utils.get_unixtime()} {channel} + :{self.__Config.SERVICE_ID}")
|
||||
|
||||
# Add defender to the channel uids list
|
||||
self.__Irc.Channel.insert(self.__Irc.Loader.Definition.MChannel(name=channel, uids=[self.__Config.SERVICE_ID]))
|
||||
@@ -186,22 +188,22 @@ class Inspircd:
|
||||
uidornickname (str): The UID or the Nickname
|
||||
reason (str): The reason for the quit
|
||||
"""
|
||||
userObj = self.__Irc.User.get_User(uidornickname=uid)
|
||||
cloneObj = self.__Irc.Clone.get_Clone(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)
|
||||
|
||||
if not userObj is None:
|
||||
self.send2socket(f":{userObj.uid} QUIT :{reason}", print_log=print_log)
|
||||
self.__Irc.User.delete(userObj.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 cloneObj is None:
|
||||
self.__Irc.Clone.delete(cloneObj.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)
|
||||
|
||||
if not self.__Irc.Channel.delete_user_from_all_channel(uid):
|
||||
self.__Base.logs.error(f"The UID [{uid}] has not been deleted from all channels")
|
||||
self.__Logs.error(f"The UID [{uid}] has not been deleted from all channels")
|
||||
|
||||
return None
|
||||
|
||||
@@ -220,9 +222,9 @@ class Inspircd:
|
||||
print_log (bool, optional): print logs if true. Defaults to True.
|
||||
"""
|
||||
# {self.Config.SERVEUR_ID} UID
|
||||
# {clone.nickname} 1 {self.Base.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname}
|
||||
# {clone.nickname} 1 {self.__Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname}
|
||||
try:
|
||||
unixtime = self.__Base.get_unixtime()
|
||||
unixtime = self.__Utils.get_unixtime()
|
||||
encoded_ip = self.__Base.encode_ip(remote_ip)
|
||||
|
||||
# Create the user
|
||||
@@ -241,7 +243,7 @@ class Inspircd:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None:
|
||||
"""Joining a channel
|
||||
@@ -259,8 +261,8 @@ class Inspircd:
|
||||
if userObj is None:
|
||||
return None
|
||||
|
||||
if not self.__Irc.Channel.Is_Channel(channel):
|
||||
self.__Base.logs.error(f"The channel [{channel}] is not valid")
|
||||
if not self.__Irc.Channel.is_valid_channel(channel):
|
||||
self.__Logs.error(f"The channel [{channel}] is not valid")
|
||||
return None
|
||||
|
||||
self.send2socket(f":{userObj.uid} JOIN {channel} {passwordChannel}", print_log=print_log)
|
||||
@@ -281,11 +283,11 @@ class Inspircd:
|
||||
userObj = self.__Irc.User.get_User(uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
self.__Base.logs.error(f"The user [{uidornickname}] is not valid")
|
||||
self.__Logs.error(f"The user [{uidornickname}] is not valid")
|
||||
return None
|
||||
|
||||
if not self.__Irc.Channel.Is_Channel(channel):
|
||||
self.__Base.logs.error(f"The channel [{channel}] is not valid")
|
||||
if not self.__Irc.Channel.is_valid_channel(channel):
|
||||
self.__Logs.error(f"The channel [{channel}] is not valid")
|
||||
return None
|
||||
|
||||
self.send2socket(f":{userObj.uid} PART {channel}", print_log=print_log)
|
||||
@@ -294,7 +296,7 @@ class Inspircd:
|
||||
self.__Irc.Channel.delete_user_from_channel(channel, userObj.uid)
|
||||
return None
|
||||
|
||||
def unkline(self, nickname:str, hostname: str) -> None:
|
||||
def send_unkline(self, nickname:str, hostname: str) -> None:
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}")
|
||||
|
||||
@@ -321,14 +323,14 @@ class Inspircd:
|
||||
# TODO : User object should be able to update user modes
|
||||
if self.__Irc.User.update_mode(userObj.uid, userMode):
|
||||
return None
|
||||
# self.__Base.logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]")
|
||||
# self.__Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]")
|
||||
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_quit(self, serverMsg: list[str]) -> None:
|
||||
"""Handle quit coming from a server
|
||||
@@ -349,9 +351,9 @@ class Inspircd:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_squit(self, serverMsg: list[str]) -> None:
|
||||
"""Handle squit coming from a server
|
||||
@@ -408,9 +410,9 @@ class Inspircd:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_sjoin(self, serverMsg: list[str]) -> None:
|
||||
"""Handle sjoin coming from a server
|
||||
@@ -443,7 +445,7 @@ class Inspircd:
|
||||
# Boucle qui va ajouter l'ensemble des users (UID)
|
||||
for i in range(start_boucle, len(serverMsg)):
|
||||
parsed_UID = str(serverMsg[i])
|
||||
clean_uid = self.__Irc.User.clean_uid(parsed_UID)
|
||||
clean_uid = self.__Utils.clean_uid(parsed_UID)
|
||||
if not clean_uid is None and len(clean_uid) == 9:
|
||||
list_users.append(parsed_UID)
|
||||
|
||||
@@ -457,9 +459,9 @@ class Inspircd:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_part(self, serverMsg: list[str]) -> None:
|
||||
"""Handle part coming from a server
|
||||
@@ -478,9 +480,9 @@ class Inspircd:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_uid(self, serverMsg: list[str]) -> None:
|
||||
"""Handle uid message coming from the server
|
||||
@@ -541,9 +543,9 @@ class Inspircd:
|
||||
)
|
||||
return None
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_server_ping(self, serverMsg: list[str]) -> None:
|
||||
"""Send a PONG message to the server
|
||||
@@ -561,7 +563,7 @@ class Inspircd:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_version(self, serverMsg: list[str]) -> None:
|
||||
"""Sending Server Version to the server
|
||||
@@ -573,7 +575,7 @@ class Inspircd:
|
||||
# Réponse a un CTCP VERSION
|
||||
try:
|
||||
|
||||
nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1]))
|
||||
nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1]))
|
||||
dnickname = self.__Config.SERVICE_NICKNAME
|
||||
arg = serverMsg[4].replace(':', '')
|
||||
|
||||
@@ -585,7 +587,7 @@ class Inspircd:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_time(self, serverMsg: list[str]) -> None:
|
||||
"""Sending TIME answer to a requestor
|
||||
@@ -597,10 +599,10 @@ class Inspircd:
|
||||
# Réponse a un CTCP VERSION
|
||||
try:
|
||||
|
||||
nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1]))
|
||||
nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1]))
|
||||
dnickname = self.__Config.SERVICE_NICKNAME
|
||||
arg = serverMsg[4].replace(':', '')
|
||||
current_datetime = self.__Base.get_datetime()
|
||||
current_datetime = self.__Utils.get_sdatetime()
|
||||
|
||||
if nickname is None:
|
||||
return None
|
||||
@@ -610,7 +612,7 @@ class Inspircd:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_ping(self, serverMsg: list[str]) -> None:
|
||||
"""Sending a PING answer to requestor
|
||||
@@ -622,7 +624,7 @@ class Inspircd:
|
||||
# Réponse a un CTCP VERSION
|
||||
try:
|
||||
|
||||
nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1]))
|
||||
nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1]))
|
||||
dnickname = self.__Config.SERVICE_NICKNAME
|
||||
arg = serverMsg[4].replace(':', '')
|
||||
|
||||
@@ -631,7 +633,7 @@ class Inspircd:
|
||||
|
||||
if arg == '\x01PING':
|
||||
recieved_unixtime = int(serverMsg[5].replace('\x01',''))
|
||||
current_unixtime = self.__Base.get_unixtime()
|
||||
current_unixtime = self.__Utils.get_unixtime()
|
||||
ping_response = current_unixtime - recieved_unixtime
|
||||
|
||||
# self.__Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01')
|
||||
@@ -643,7 +645,7 @@ class Inspircd:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_version_msg(self, serverMsg: list[str]) -> None:
|
||||
"""Handle version coming from the server
|
||||
@@ -653,7 +655,7 @@ class Inspircd:
|
||||
"""
|
||||
try:
|
||||
# ['@label=0073', ':0014E7P06', 'VERSION', 'PyDefender']
|
||||
getUser = self.__Irc.User.get_User(self.__Irc.User.clean_uid(serverMsg[1]))
|
||||
getUser = self.__Irc.User.get_User(self.__Utils.clean_uid(serverMsg[1]))
|
||||
|
||||
if getUser is None:
|
||||
return None
|
||||
@@ -668,4 +670,4 @@ class Inspircd:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from re import match, findall, search
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Union
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from ssl import SSLEOFError, SSLError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -16,14 +16,33 @@ class Unrealircd6:
|
||||
self.__Config = ircInstance.Config
|
||||
self.__Base = ircInstance.Base
|
||||
self.__Settings = ircInstance.Base.Settings
|
||||
self.__Utils = ircInstance.Loader.Utils
|
||||
self.__Logs = ircInstance.Loader.Logs
|
||||
|
||||
self.known_protocol = ['SJOIN', 'UID', 'MD', 'QUIT', 'SQUIT',
|
||||
self.known_protocol: set[str] = {'SJOIN', 'UID', 'MD', 'QUIT', 'SQUIT',
|
||||
'EOS', 'PRIVMSG', 'MODE', 'UMODE2',
|
||||
'VERSION', 'REPUTATION', 'SVS2MODE',
|
||||
'SLOG', 'NICK', 'PART', 'PONG'
|
||||
]
|
||||
'SLOG', 'NICK', 'PART', 'PONG',
|
||||
'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO'}
|
||||
|
||||
self.__Base.logs.info(f"** Loading protocol [{__name__}]")
|
||||
self.__Logs.info(f"** Loading protocol [{__name__}]")
|
||||
|
||||
def get_ircd_protocol_poisition(self, cmd: list[str]) -> tuple[int, Optional[str]]:
|
||||
"""Get the position of known commands
|
||||
|
||||
Args:
|
||||
cmd (list[str]): The server response
|
||||
|
||||
Returns:
|
||||
tuple[int, Optional[str]]: The position and the command.
|
||||
"""
|
||||
for index, token in enumerate(cmd):
|
||||
if token.upper() in self.known_protocol:
|
||||
return index, token.upper()
|
||||
|
||||
self.__Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}")
|
||||
|
||||
return (-1, None)
|
||||
|
||||
def send2socket(self, message: str, print_log: bool = True) -> None:
|
||||
"""Envoit les commandes à envoyer au serveur.
|
||||
@@ -35,24 +54,24 @@ class Unrealircd6:
|
||||
with self.__Base.lock:
|
||||
self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[0]))
|
||||
if print_log:
|
||||
self.__Base.logs.debug(f'<< {message}')
|
||||
self.__Logs.debug(f'<< {message}')
|
||||
|
||||
except UnicodeDecodeError as ude:
|
||||
self.__Base.logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}')
|
||||
self.__Logs.error(f'Decode Error try iso-8859-1 - {ude} - {message}')
|
||||
self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace'))
|
||||
except UnicodeEncodeError as uee:
|
||||
self.__Base.logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}')
|
||||
self.__Logs.error(f'Encode Error try iso-8859-1 - {uee} - {message}')
|
||||
self.__Irc.IrcSocket.send(f"{message}\r\n".encode(self.__Config.SERVEUR_CHARSET[1],'replace'))
|
||||
except AssertionError as ae:
|
||||
self.__Base.logs.warning(f'Assertion Error {ae} - message: {message}')
|
||||
self.__Logs.warning(f'Assertion Error {ae} - message: {message}')
|
||||
except SSLEOFError as soe:
|
||||
self.__Base.logs.error(f"SSLEOFError: {soe} - {message}")
|
||||
self.__Logs.error(f"SSLEOFError: {soe} - {message}")
|
||||
except SSLError as se:
|
||||
self.__Base.logs.error(f"SSLError: {se} - {message}")
|
||||
self.__Logs.error(f"SSLError: {se} - {message}")
|
||||
except OSError as oe:
|
||||
self.__Base.logs.error(f"OSError: {oe} - {message}")
|
||||
self.__Logs.error(f"OSError: {oe} - {message}")
|
||||
except AttributeError as ae:
|
||||
self.__Base.logs.critical(f"Attribute Error: {ae}")
|
||||
self.__Logs.critical(f"Attribute Error: {ae}")
|
||||
|
||||
def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None):
|
||||
"""Sending PRIVMSG to a channel or to a nickname by batches
|
||||
@@ -69,7 +88,7 @@ class Unrealircd6:
|
||||
User_to = self.__Irc.User.get_User(nick_to) if not nick_to is None else None
|
||||
|
||||
if User_from is None:
|
||||
self.__Base.logs.error(f"The sender nickname [{nick_from}] do not exist")
|
||||
self.__Logs.error(f"The sender nickname [{nick_from}] do not exist")
|
||||
return None
|
||||
|
||||
if not channel is None:
|
||||
@@ -83,8 +102,8 @@ class Unrealircd6:
|
||||
self.send2socket(f":{nick_from} PRIVMSG {User_to.uid} :{batch}")
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"General Error: {err}")
|
||||
self.__Base.logs.error(f"General Error: {nick_from} - {channel} - {nick_to}")
|
||||
self.__Logs.error(f"General Error: {err}")
|
||||
self.__Logs.error(f"General Error: {nick_from} - {channel} - {nick_to}")
|
||||
|
||||
def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None:
|
||||
"""Sending NOTICE by batches
|
||||
@@ -100,7 +119,7 @@ class Unrealircd6:
|
||||
User_to = self.__Irc.User.get_User(nick_to)
|
||||
|
||||
if User_from is None or User_to is None:
|
||||
self.__Base.logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist")
|
||||
self.__Logs.error(f"The sender [{nick_from}] or the Reciever [{nick_to}] do not exist")
|
||||
return None
|
||||
|
||||
for i in range(0, len(str(msg)), batch_size):
|
||||
@@ -108,9 +127,9 @@ class Unrealircd6:
|
||||
self.send2socket(f":{User_from.uid} NOTICE {User_to.uid} :{batch}")
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"General Error: {err}")
|
||||
self.__Logs.error(f"General Error: {err}")
|
||||
|
||||
def parse_server_msg(self, server_msg: list[str]) -> Union[str, None]:
|
||||
def parse_server_msg(self, server_msg: list[str]) -> Optional[str]:
|
||||
"""Parse the server message and return the command
|
||||
|
||||
Args:
|
||||
@@ -144,7 +163,7 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
|
||||
def link(self):
|
||||
def send_link(self):
|
||||
"""Créer le link et envoyer les informations nécessaires pour la
|
||||
connexion au serveur.
|
||||
"""
|
||||
@@ -167,7 +186,7 @@ class Unrealircd6:
|
||||
service_id = self.__Config.SERVICE_ID
|
||||
|
||||
version = self.__Config.CURRENT_VERSION
|
||||
unixtime = self.__Base.get_unixtime()
|
||||
unixtime = self.__Utils.get_unixtime()
|
||||
|
||||
self.send2socket(f":{server_id} PASS :{password}", print_log=False)
|
||||
self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS")
|
||||
@@ -177,20 +196,20 @@ class Unrealircd6:
|
||||
self.send2socket(f":{server_id} SERVER {link} 1 :{info}")
|
||||
self.send2socket(f":{server_id} {nickname} :Reserved for services")
|
||||
self.send2socket(f":{server_id} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * fwAAAQ== :{realname}")
|
||||
self.sjoin(chan)
|
||||
self.send_sjoin(chan)
|
||||
self.send2socket(f":{server_id} TKL + Q * {nickname} {host} 0 {unixtime} :Reserved for services")
|
||||
self.send2socket(f":{service_id} MODE {chan} {cmodes}")
|
||||
|
||||
self.__Base.logs.debug(f'>> {__name__} Link information sent to the server')
|
||||
self.__Logs.debug(f'>> {__name__} Link information sent to the server')
|
||||
|
||||
def gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
# TKL + G user host set_by expire_timestamp set_at_timestamp :reason
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}")
|
||||
|
||||
return None
|
||||
|
||||
def set_nick(self, newnickname: str) -> None:
|
||||
def send_set_nick(self, newnickname: str) -> None:
|
||||
"""Change nickname of the server
|
||||
\n This method will also update the User object
|
||||
Args:
|
||||
@@ -202,7 +221,7 @@ class Unrealircd6:
|
||||
self.__Irc.User.update_nickname(userObj.uid, newnickname)
|
||||
return None
|
||||
|
||||
def squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||
def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||
|
||||
if not reason:
|
||||
reason = 'Service Shutdown'
|
||||
@@ -210,36 +229,36 @@ class Unrealircd6:
|
||||
self.send2socket(f":{server_id} SQUIT {server_link} :{reason}")
|
||||
return None
|
||||
|
||||
def ungline(self, nickname:str, hostname: str) -> None:
|
||||
def send_ungline(self, nickname:str, hostname: str) -> None:
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - G {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}")
|
||||
|
||||
return None
|
||||
|
||||
def kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||
# TKL + k user host set_by expire_timestamp set_at_timestamp :reason
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + k {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}")
|
||||
|
||||
return None
|
||||
|
||||
def unkline(self, nickname:str, hostname: str) -> None:
|
||||
def send_unkline(self, nickname:str, hostname: str) -> None:
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL - K {nickname} {hostname} {self.__Config.SERVICE_NICKNAME}")
|
||||
|
||||
return None
|
||||
|
||||
def sjoin(self, channel: str) -> None:
|
||||
def send_sjoin(self, channel: str) -> None:
|
||||
"""Server will join a channel with pre defined umodes
|
||||
|
||||
Args:
|
||||
channel (str): Channel to join
|
||||
"""
|
||||
if not self.__Irc.Channel.Is_Channel(channel):
|
||||
self.__Base.logs.error(f"The channel [{channel}] is not valid")
|
||||
if not self.__Irc.Channel.is_valid_channel(channel):
|
||||
self.__Logs.error(f"The channel [{channel}] is not valid")
|
||||
return None
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} SJOIN {self.__Base.get_unixtime()} {channel} {self.__Config.SERVICE_UMODES} :{self.__Config.SERVICE_ID}")
|
||||
self.send2socket(f":{self.__Config.SERVEUR_ID} SJOIN {self.__Utils.get_unixtime()} {channel} {self.__Config.SERVICE_UMODES} :{self.__Config.SERVICE_ID}")
|
||||
self.send2socket(f":{self.__Config.SERVICE_ID} MODE {channel} {self.__Config.SERVICE_UMODES} {self.__Config.SERVICE_ID}")
|
||||
|
||||
# Add defender to the channel uids list
|
||||
@@ -257,7 +276,7 @@ class Unrealircd6:
|
||||
try:
|
||||
|
||||
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
|
||||
|
||||
if userObj is None or chanObj is None:
|
||||
@@ -269,7 +288,7 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None:
|
||||
"""_summary_
|
||||
@@ -281,7 +300,7 @@ class Unrealircd6:
|
||||
try:
|
||||
|
||||
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
|
||||
|
||||
if userObj is None:
|
||||
@@ -290,7 +309,7 @@ class Unrealircd6:
|
||||
|
||||
if chanObj is None:
|
||||
# Channel not exist
|
||||
if not self.__Irc.Channel.Is_Channel(channel_name):
|
||||
if not self.__Irc.Channel.is_valid_channel(channel_name):
|
||||
# Incorrect channel: leave
|
||||
return None
|
||||
|
||||
@@ -306,7 +325,7 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.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:
|
||||
try:
|
||||
@@ -325,34 +344,29 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def send_quit(self, uid: str, reason: str, print_log: True) -> None:
|
||||
"""Send quit message
|
||||
- Delete uid from User object
|
||||
- Delete uid from Clone object
|
||||
- Delete uid from Reputation object
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or the Nickname
|
||||
reason (str): The reason for the quit
|
||||
"""
|
||||
userObj = self.__Irc.User.get_User(uidornickname=uid)
|
||||
cloneObj = 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 userObj is None:
|
||||
self.send2socket(f":{userObj.uid} QUIT :{reason}", print_log=print_log)
|
||||
self.__Irc.User.delete(userObj.uid)
|
||||
|
||||
if not cloneObj is None:
|
||||
self.__Irc.Clone.delete(cloneObj.uid)
|
||||
if not user_obj is None:
|
||||
self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log)
|
||||
self.__Irc.User.delete(user_obj.uid)
|
||||
|
||||
if not reputationObj is None:
|
||||
self.__Irc.Reputation.delete(reputationObj.uid)
|
||||
|
||||
if not self.__Irc.Channel.delete_user_from_all_channel(uid):
|
||||
self.__Base.logs.error(f"The UID [{uid}] has not been deleted from all channels")
|
||||
self.__Logs.error(f"The UID [{uid}] has not been deleted from all channels")
|
||||
|
||||
return None
|
||||
|
||||
@@ -371,9 +385,9 @@ class Unrealircd6:
|
||||
print_log (bool, optional): print logs if true. Defaults to True.
|
||||
"""
|
||||
# {self.Config.SERVEUR_ID} UID
|
||||
# {clone.nickname} 1 {self.Base.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname}
|
||||
# {clone.nickname} 1 {self.__Utils.get_unixtime()} {clone.username} {clone.hostname} {clone.uid} * {clone.umodes} {clone.vhost} * {self.Base.encode_ip(clone.remote_ip)} :{clone.realname}
|
||||
try:
|
||||
unixtime = self.__Base.get_unixtime()
|
||||
unixtime = self.__Utils.get_unixtime()
|
||||
encoded_ip = self.__Base.encode_ip(remote_ip)
|
||||
|
||||
# Create the user
|
||||
@@ -392,7 +406,7 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None:
|
||||
"""Joining a channel
|
||||
@@ -410,8 +424,8 @@ class Unrealircd6:
|
||||
if userObj is None:
|
||||
return None
|
||||
|
||||
if not self.__Irc.Channel.Is_Channel(channel):
|
||||
self.__Base.logs.error(f"The channel [{channel}] is not valid")
|
||||
if not self.__Irc.Channel.is_valid_channel(channel):
|
||||
self.__Logs.error(f"The channel [{channel}] is not valid")
|
||||
return None
|
||||
|
||||
self.send2socket(f":{userObj.uid} JOIN {channel} {passwordChannel}", print_log=print_log)
|
||||
@@ -447,11 +461,11 @@ class Unrealircd6:
|
||||
userObj = self.__Irc.User.get_User(uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
self.__Base.logs.error(f"The user [{uidornickname}] is not valid")
|
||||
self.__Logs.error(f"The user [{uidornickname}] is not valid")
|
||||
return None
|
||||
|
||||
if not self.__Irc.Channel.Is_Channel(channel):
|
||||
self.__Base.logs.error(f"The channel [{channel}] is not valid")
|
||||
if not self.__Irc.Channel.is_valid_channel(channel):
|
||||
self.__Logs.error(f"The channel [{channel}] is not valid")
|
||||
return None
|
||||
|
||||
self.send2socket(f":{userObj.uid} PART {channel}", print_log=print_log)
|
||||
@@ -462,9 +476,9 @@ class Unrealircd6:
|
||||
|
||||
def send_mode_chan(self, channel_name: str, channel_mode: str) -> None:
|
||||
|
||||
channel = self.__Irc.Channel.Is_Channel(channelToCheck=channel_name)
|
||||
channel = self.__Irc.Channel.is_valid_channel(channel_name)
|
||||
if not channel:
|
||||
self.__Base.logs.error(f'The channel [{channel_name}] is not correct')
|
||||
self.__Logs.error(f'The channel [{channel_name}] is not correct')
|
||||
return None
|
||||
|
||||
self.send2socket(f":{self.__Config.SERVICE_NICKNAME} MODE {channel_name} {channel_mode}")
|
||||
@@ -502,9 +516,9 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_mode(self, serverMsg: list[str]) -> None:
|
||||
"""Handle mode coming from a server
|
||||
@@ -538,14 +552,14 @@ class Unrealircd6:
|
||||
# TODO : User object should be able to update user modes
|
||||
if self.__Irc.User.update_mode(userObj.uid, userMode):
|
||||
return None
|
||||
# self.__Base.logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]")
|
||||
# self.__Logs.debug(f"Updating user mode for [{userObj.nickname}] [{old_umodes}] => [{userObj.umodes}]")
|
||||
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_quit(self, serverMsg: list[str]) -> None:
|
||||
"""Handle quit coming from a server
|
||||
@@ -562,14 +576,13 @@ class Unrealircd6:
|
||||
self.__Irc.User.delete(uid_who_quit)
|
||||
self.__Irc.Client.delete(uid_who_quit)
|
||||
self.__Irc.Reputation.delete(uid_who_quit)
|
||||
self.__Irc.Clone.delete(uid_who_quit)
|
||||
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_squit(self, serverMsg: list[str]) -> None:
|
||||
"""Handle squit coming from a server
|
||||
@@ -649,9 +662,9 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_sjoin(self, serverMsg: list[str]) -> None:
|
||||
"""Handle sjoin coming from a server
|
||||
@@ -688,7 +701,7 @@ class Unrealircd6:
|
||||
# Boucle qui va ajouter l'ensemble des users (UID)
|
||||
for i in range(start_boucle, len(serverMsg_copy)):
|
||||
parsed_UID = str(serverMsg_copy[i])
|
||||
clean_uid = self.__Irc.User.clean_uid(parsed_UID)
|
||||
clean_uid = self.__Utils.clean_uid(parsed_UID)
|
||||
if not clean_uid is None and len(clean_uid) == 9:
|
||||
list_users.append(clean_uid)
|
||||
|
||||
@@ -702,9 +715,9 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_part(self, serverMsg: list[str]) -> None:
|
||||
"""Handle part coming from a server
|
||||
@@ -723,9 +736,9 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_eos(self, serverMsg: list[str]) -> None:
|
||||
"""Handle EOS coming from a server
|
||||
@@ -757,16 +770,16 @@ class Unrealircd6:
|
||||
print(f"# VERSION : {version} ")
|
||||
print(f"################################################")
|
||||
|
||||
self.__Base.logs.info(f"################### DEFENDER ###################")
|
||||
self.__Base.logs.info(f"# SERVICE CONNECTE ")
|
||||
self.__Base.logs.info(f"# SERVEUR : {self.__Config.SERVEUR_IP} ")
|
||||
self.__Base.logs.info(f"# PORT : {self.__Config.SERVEUR_PORT} ")
|
||||
self.__Base.logs.info(f"# SSL : {self.__Config.SERVEUR_SSL} ")
|
||||
self.__Base.logs.info(f"# SSL VER : {self.__Config.SSL_VERSION} ")
|
||||
self.__Base.logs.info(f"# NICKNAME : {self.__Config.SERVICE_NICKNAME} ")
|
||||
self.__Base.logs.info(f"# CHANNEL : {self.__Config.SERVICE_CHANLOG} ")
|
||||
self.__Base.logs.info(f"# VERSION : {version} ")
|
||||
self.__Base.logs.info(f"################################################")
|
||||
self.__Logs.info(f"################### DEFENDER ###################")
|
||||
self.__Logs.info(f"# SERVICE CONNECTE ")
|
||||
self.__Logs.info(f"# SERVEUR : {self.__Config.SERVEUR_IP} ")
|
||||
self.__Logs.info(f"# PORT : {self.__Config.SERVEUR_PORT} ")
|
||||
self.__Logs.info(f"# SSL : {self.__Config.SERVEUR_SSL} ")
|
||||
self.__Logs.info(f"# SSL VER : {self.__Config.SSL_VERSION} ")
|
||||
self.__Logs.info(f"# NICKNAME : {self.__Config.SERVICE_NICKNAME} ")
|
||||
self.__Logs.info(f"# CHANNEL : {self.__Config.SERVICE_CHANLOG} ")
|
||||
self.__Logs.info(f"# VERSION : {version} ")
|
||||
self.__Logs.info(f"################################################")
|
||||
|
||||
if self.__Base.check_for_new_version(False):
|
||||
self.send_priv_msg(
|
||||
@@ -789,11 +802,11 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Key Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Key Error: {ie}")
|
||||
except KeyError as ke:
|
||||
self.__Base.logs.error(f"{__name__} - Key Error: {ke}")
|
||||
self.__Logs.error(f"{__name__} - Key Error: {ke}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_reputation(self, serverMsg: list[str]) -> None:
|
||||
"""Handle REPUTATION coming from a server
|
||||
@@ -824,7 +837,7 @@ class Unrealircd6:
|
||||
self.__Irc.first_score = 0
|
||||
self.Logs.error(f'Value Error {__name__}: {ve}')
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_uid(self, serverMsg: list[str]) -> None:
|
||||
"""Handle uid message coming from the server
|
||||
@@ -885,9 +898,9 @@ class Unrealircd6:
|
||||
)
|
||||
return None
|
||||
except IndexError as ie:
|
||||
self.__Base.logs.error(f"{__name__} - Index Error: {ie}")
|
||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_privmsg(self, serverMsg: list[str]) -> None:
|
||||
"""Handle PRIVMSG message coming from the server
|
||||
@@ -908,11 +921,11 @@ class Unrealircd6:
|
||||
if cmd[2] == 'PRIVMSG' and cmd[4] == ':auth':
|
||||
data_copy = cmd.copy()
|
||||
data_copy[6] = '**********'
|
||||
self.__Base.logs.debug(f">> {data_copy}")
|
||||
self.__Logs.debug(f">> {data_copy}")
|
||||
else:
|
||||
self.__Base.logs.debug(f">> {cmd}")
|
||||
self.__Logs.debug(f">> {cmd}")
|
||||
else:
|
||||
self.__Base.logs.debug(f">> {cmd}")
|
||||
self.__Logs.debug(f">> {cmd}")
|
||||
|
||||
get_uid_or_nickname = str(cmd[0].replace(':',''))
|
||||
user_trigger = self.__Irc.User.get_nickname(get_uid_or_nickname)
|
||||
@@ -927,7 +940,7 @@ class Unrealircd6:
|
||||
arg = convert_to_string.split()
|
||||
arg.remove(f':{self.__Config.SERVICE_PREFIX}')
|
||||
if not arg[0].lower() in self.__Irc.module_commands_list:
|
||||
self.__Base.logs.debug(f"This command {arg[0]} is not available")
|
||||
self.__Logs.debug(f"This command {arg[0]} is not available")
|
||||
self.send_notice(
|
||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
||||
nick_to=user_trigger,
|
||||
@@ -938,7 +951,7 @@ class Unrealircd6:
|
||||
cmd_to_send = convert_to_string.replace(':','')
|
||||
self.__Base.log_cmd(user_trigger, cmd_to_send)
|
||||
|
||||
fromchannel = str(cmd[2]).lower() if self.__Irc.Channel.Is_Channel(cmd[2]) else None
|
||||
fromchannel = str(cmd[2]).lower() if self.__Irc.Channel.is_valid_channel(cmd[2]) else None
|
||||
self.__Irc.hcmds(user_trigger, fromchannel, arg, cmd)
|
||||
|
||||
if cmd[2] == self.__Config.SERVICE_ID:
|
||||
@@ -966,7 +979,7 @@ class Unrealircd6:
|
||||
return False
|
||||
|
||||
if not arg[0].lower() in self.__Irc.module_commands_list:
|
||||
self.__Base.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
|
||||
|
||||
cmd_to_send = convert_to_string.replace(':','')
|
||||
@@ -974,17 +987,17 @@ class Unrealircd6:
|
||||
|
||||
fromchannel = None
|
||||
if len(arg) >= 2:
|
||||
fromchannel = str(arg[1]).lower() if self.__Irc.Channel.Is_Channel(arg[1]) else None
|
||||
fromchannel = str(arg[1]).lower() if self.__Irc.Channel.is_valid_channel(arg[1]) else None
|
||||
|
||||
self.__Irc.hcmds(user_trigger, fromchannel, arg, cmd)
|
||||
return None
|
||||
|
||||
except KeyError as ke:
|
||||
self.__Base.logs.error(f"Key Error: {ke}")
|
||||
self.__Logs.error(f"Key Error: {ke}")
|
||||
except AttributeError as ae:
|
||||
self.__Base.logs.error(f"Attribute Error: {ae}")
|
||||
self.__Logs.error(f"Attribute Error: {ae}")
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"General Error: {err} - {srv_msg}")
|
||||
self.__Logs.error(f"General Error: {err} - {srv_msg}")
|
||||
|
||||
def on_server_ping(self, serverMsg: list[str]) -> None:
|
||||
"""Send a PONG message to the server
|
||||
@@ -999,7 +1012,7 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_version(self, serverMsg: list[str]) -> None:
|
||||
"""Sending Server Version to the server
|
||||
@@ -1011,7 +1024,7 @@ class Unrealircd6:
|
||||
# Réponse a un CTCP VERSION
|
||||
try:
|
||||
|
||||
nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1]))
|
||||
nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1]))
|
||||
dnickname = self.__Config.SERVICE_NICKNAME
|
||||
arg = serverMsg[4].replace(':', '')
|
||||
|
||||
@@ -1023,7 +1036,7 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_time(self, serverMsg: list[str]) -> None:
|
||||
"""Sending TIME answer to a requestor
|
||||
@@ -1035,10 +1048,10 @@ class Unrealircd6:
|
||||
# Réponse a un CTCP VERSION
|
||||
try:
|
||||
|
||||
nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1]))
|
||||
nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1]))
|
||||
dnickname = self.__Config.SERVICE_NICKNAME
|
||||
arg = serverMsg[4].replace(':', '')
|
||||
current_datetime = self.__Base.get_datetime()
|
||||
current_datetime = self.__Utils.get_sdatetime()
|
||||
|
||||
if nickname is None:
|
||||
return None
|
||||
@@ -1048,7 +1061,7 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_ping(self, serverMsg: list[str]) -> None:
|
||||
"""Sending a PING answer to requestor
|
||||
@@ -1060,7 +1073,7 @@ class Unrealircd6:
|
||||
# Réponse a un CTCP VERSION
|
||||
try:
|
||||
|
||||
nickname = self.__Irc.User.get_nickname(self.__Base.clean_uid(serverMsg[1]))
|
||||
nickname = self.__Irc.User.get_nickname(self.__Utils.clean_uid(serverMsg[1]))
|
||||
dnickname = self.__Config.SERVICE_NICKNAME
|
||||
arg = serverMsg[4].replace(':', '')
|
||||
|
||||
@@ -1069,7 +1082,7 @@ class Unrealircd6:
|
||||
|
||||
if arg == '\x01PING':
|
||||
recieved_unixtime = int(serverMsg[5].replace('\x01',''))
|
||||
current_unixtime = self.__Base.get_unixtime()
|
||||
current_unixtime = self.__Utils.get_unixtime()
|
||||
ping_response = current_unixtime - recieved_unixtime
|
||||
|
||||
# self.__Irc.send2socket(f':{dnickname} NOTICE {nickname} :\x01PING {ping_response} secs\x01')
|
||||
@@ -1081,7 +1094,7 @@ class Unrealircd6:
|
||||
|
||||
return None
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
def on_version_msg(self, serverMsg: list[str]) -> None:
|
||||
"""Handle version coming from the server
|
||||
@@ -1095,7 +1108,7 @@ class Unrealircd6:
|
||||
if '@' in list(serverMsg_copy[0])[0]:
|
||||
serverMsg_copy.pop(0)
|
||||
|
||||
getUser = self.__Irc.User.get_User(self.__Irc.User.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,4 +1126,4 @@ class Unrealircd6:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.__Base.logs.error(f"{__name__} - General Error: {err}")
|
||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
from typing import Union
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from core.definition import MReputation
|
||||
from core.base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
|
||||
class Reputation:
|
||||
|
||||
UID_REPUTATION_DB: list[MReputation] = []
|
||||
|
||||
def __init__(self, baseObj: Base) -> None:
|
||||
def __init__(self, loader: 'Loader'):
|
||||
|
||||
self.Logs = baseObj.logs
|
||||
self.Logs = loader.Logs
|
||||
self.MReputation: MReputation = MReputation
|
||||
|
||||
return None
|
||||
|
||||
def insert(self, newReputationUser: MReputation) -> bool:
|
||||
def insert(self, new_reputation_user: MReputation) -> bool:
|
||||
"""Insert a new Reputation User object
|
||||
|
||||
Args:
|
||||
newReputationUser (MReputation): New Reputation Model object
|
||||
new_reputation_user (MReputation): New Reputation Model object
|
||||
|
||||
Returns:
|
||||
bool: True if inserted
|
||||
@@ -26,23 +26,23 @@ class Reputation:
|
||||
exist = False
|
||||
|
||||
for record in self.UID_REPUTATION_DB:
|
||||
if record.uid == newReputationUser.uid:
|
||||
if record.uid == new_reputation_user.uid:
|
||||
# If the user exist then return False and do not go further
|
||||
exist = True
|
||||
self.Logs.debug(f'{record.uid} already exist')
|
||||
return result
|
||||
|
||||
if not exist:
|
||||
self.UID_REPUTATION_DB.append(newReputationUser)
|
||||
self.UID_REPUTATION_DB.append(new_reputation_user)
|
||||
result = True
|
||||
self.Logs.debug(f'New Reputation User Captured: ({newReputationUser})')
|
||||
self.Logs.debug(f'New Reputation User Captured: ({new_reputation_user})')
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The Reputation User Object was not inserted {newReputationUser}')
|
||||
self.Logs.critical(f'The Reputation User Object was not inserted {new_reputation_user}')
|
||||
|
||||
return result
|
||||
|
||||
def update(self, uid: str, newNickname: str) -> bool:
|
||||
def update(self, uid: str, new_nickname: str) -> bool:
|
||||
"""Update the nickname starting from the UID
|
||||
|
||||
Args:
|
||||
@@ -53,12 +53,12 @@ class Reputation:
|
||||
bool: True if updated
|
||||
"""
|
||||
|
||||
reputationObj = self.get_Reputation(uid)
|
||||
reputation_obj = self.get_Reputation(uid)
|
||||
|
||||
if reputationObj is None:
|
||||
if reputation_obj is None:
|
||||
return False
|
||||
|
||||
reputationObj.nickname = newNickname
|
||||
reputation_obj.nickname = new_nickname
|
||||
|
||||
return True
|
||||
|
||||
@@ -89,7 +89,7 @@ class Reputation:
|
||||
|
||||
return result
|
||||
|
||||
def get_Reputation(self, uidornickname: str) -> Union[MReputation, None]:
|
||||
def get_Reputation(self, uidornickname: str) -> Optional[MReputation]:
|
||||
"""Get The User Object model
|
||||
|
||||
Args:
|
||||
@@ -98,16 +98,15 @@ class Reputation:
|
||||
Returns:
|
||||
UserModel|None: The UserModel Object | None
|
||||
"""
|
||||
User = None
|
||||
for record in self.UID_REPUTATION_DB:
|
||||
if record.uid == uidornickname:
|
||||
User = record
|
||||
return record
|
||||
elif record.nickname == uidornickname:
|
||||
User = record
|
||||
return record
|
||||
|
||||
return User
|
||||
return None
|
||||
|
||||
def get_uid(self, uidornickname:str) -> Union[str, None]:
|
||||
def get_uid(self, uidornickname: str) -> Optional[str]:
|
||||
"""Get the UID of the user starting from the UID or the Nickname
|
||||
|
||||
Args:
|
||||
@@ -117,14 +116,14 @@ class Reputation:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
|
||||
reputationObj = self.get_Reputation(uidornickname)
|
||||
reputation_obj = self.get_Reputation(uidornickname)
|
||||
|
||||
if reputationObj is None:
|
||||
if reputation_obj is None:
|
||||
return None
|
||||
|
||||
return reputationObj.uid
|
||||
return reputation_obj.uid
|
||||
|
||||
def get_nickname(self, uidornickname:str) -> Union[str, None]:
|
||||
def get_nickname(self, uidornickname: str) -> Optional[str]:
|
||||
"""Get the Nickname starting from UID or the nickname
|
||||
|
||||
Args:
|
||||
@@ -133,12 +132,12 @@ class Reputation:
|
||||
Returns:
|
||||
str|None: the nickname
|
||||
"""
|
||||
reputationObj = self.get_Reputation(uidornickname)
|
||||
reputation_obj = self.get_Reputation(uidornickname)
|
||||
|
||||
if reputationObj is None:
|
||||
if reputation_obj is None:
|
||||
return None
|
||||
|
||||
return reputationObj.nickname
|
||||
return reputation_obj.nickname
|
||||
|
||||
def is_exist(self, uidornickname: str) -> bool:
|
||||
"""Check if the UID or the nickname exist in the reputation DB
|
||||
@@ -150,9 +149,9 @@ class Reputation:
|
||||
bool: True if exist
|
||||
"""
|
||||
|
||||
reputationObj = self.get_Reputation(uidornickname)
|
||||
reputation_obj = self.get_Reputation(uidornickname)
|
||||
|
||||
if reputationObj is None:
|
||||
return False
|
||||
else:
|
||||
if isinstance(reputation_obj, MReputation):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
'''This class should never be reloaded.
|
||||
'''
|
||||
from threading import Timer, Thread, RLock
|
||||
from socket import socket
|
||||
from typing import Any, Optional
|
||||
|
||||
class Settings:
|
||||
"""This Class will never be reloaded.
|
||||
Means that the variables are available during
|
||||
the whole life of the app
|
||||
"""
|
||||
|
||||
RUNNING_TIMERS: list[Timer] = []
|
||||
RUNNING_THREADS: list[Thread] = []
|
||||
@@ -13,3 +20,30 @@ class Settings:
|
||||
|
||||
PROTOCTL_USER_MODES: list[str] = []
|
||||
PROTOCTL_PREFIX: list[str] = []
|
||||
|
||||
__CACHE: dict[str, Any] = {}
|
||||
"""Use set_cache or get_cache instead"""
|
||||
|
||||
def set_cache(self, key: str, value_to_cache: Any):
|
||||
"""When you want to store a variable
|
||||
|
||||
Ex.
|
||||
```python
|
||||
set_cache('MY_KEY', {'key1': 'value1', 'key2', 'value2'})
|
||||
```
|
||||
Args:
|
||||
key (str): The key you want to add.
|
||||
value_to_cache (Any): The Value you want to store.
|
||||
"""
|
||||
self.__CACHE[key] = value_to_cache
|
||||
|
||||
def get_cache(self, key) -> Optional[Any]:
|
||||
"""It returns the value associated to the key and finally it removes the entry"""
|
||||
if self.__CACHE.get(key):
|
||||
return self.__CACHE.pop(key)
|
||||
|
||||
return None
|
||||
|
||||
def get_cache_size(self) -> int:
|
||||
return len(self.__CACHE)
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
from re import sub
|
||||
from typing import Union, TYPE_CHECKING
|
||||
from dataclasses import asdict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.base import Base
|
||||
from core.loader import Loader
|
||||
from core.definition import MUser
|
||||
|
||||
class User:
|
||||
|
||||
UID_DB: list['MUser'] = []
|
||||
|
||||
def __init__(self, baseObj: 'Base') -> None:
|
||||
def __init__(self, loader: 'Loader'):
|
||||
|
||||
self.Logs = baseObj.logs
|
||||
self.Base = baseObj
|
||||
self.Logs = loader.Logs
|
||||
self.Base = loader.Base
|
||||
|
||||
return None
|
||||
|
||||
def insert(self, newUser: 'MUser') -> bool:
|
||||
def insert(self, new_user: 'MUser') -> bool:
|
||||
"""Insert a new User object
|
||||
|
||||
Args:
|
||||
@@ -27,32 +25,32 @@ class User:
|
||||
bool: True if inserted
|
||||
"""
|
||||
|
||||
userObj = self.get_User(newUser.uid)
|
||||
user_obj = self.get_User(new_user.uid)
|
||||
|
||||
if not userObj is None:
|
||||
if not user_obj is None:
|
||||
# User already created return False
|
||||
return False
|
||||
|
||||
self.UID_DB.append(newUser)
|
||||
self.UID_DB.append(new_user)
|
||||
|
||||
return True
|
||||
|
||||
def update_nickname(self, uid: str, newNickname: str) -> bool:
|
||||
def update_nickname(self, uid: str, new_nickname: str) -> bool:
|
||||
"""Update the nickname starting from the UID
|
||||
|
||||
Args:
|
||||
uid (str): UID of the user
|
||||
newNickname (str): New nickname
|
||||
new_nickname (str): New nickname
|
||||
|
||||
Returns:
|
||||
bool: True if updated
|
||||
"""
|
||||
userObj = self.get_User(uidornickname=uid)
|
||||
user_obj = self.get_User(uidornickname=uid)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
userObj.nickname = newNickname
|
||||
user_obj.nickname = new_nickname
|
||||
|
||||
return True
|
||||
|
||||
@@ -67,16 +65,16 @@ class User:
|
||||
bool: True if user mode has been updaed
|
||||
"""
|
||||
response = True
|
||||
userObj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
action = modes[0]
|
||||
new_modes = modes[1:]
|
||||
|
||||
existing_umodes = userObj.umodes
|
||||
umodes = userObj.umodes
|
||||
existing_umodes = user_obj.umodes
|
||||
umodes = user_obj.umodes
|
||||
|
||||
if action == '+':
|
||||
|
||||
@@ -95,7 +93,7 @@ class User:
|
||||
final_umodes_liste = [x for x in self.Base.Settings.PROTOCTL_USER_MODES if x in liste_umodes]
|
||||
final_umodes = ''.join(final_umodes_liste)
|
||||
|
||||
userObj.umodes = f"+{final_umodes}"
|
||||
user_obj.umodes = f"+{final_umodes}"
|
||||
|
||||
return response
|
||||
|
||||
@@ -109,16 +107,16 @@ class User:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
userObj = self.get_User(uidornickname=uid)
|
||||
user_obj = self.get_User(uidornickname=uid)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
self.UID_DB.remove(userObj)
|
||||
self.UID_DB.remove(user_obj)
|
||||
|
||||
return True
|
||||
|
||||
def get_User(self, uidornickname: str) -> Union['MUser', None]:
|
||||
def get_User(self, uidornickname: str) -> Optional['MUser']:
|
||||
"""Get The User Object model
|
||||
|
||||
Args:
|
||||
@@ -127,16 +125,15 @@ class User:
|
||||
Returns:
|
||||
UserModel|None: The UserModel Object | None
|
||||
"""
|
||||
User = None
|
||||
for record in self.UID_DB:
|
||||
if record.uid == uidornickname:
|
||||
User = record
|
||||
return record
|
||||
elif record.nickname == uidornickname:
|
||||
User = record
|
||||
return record
|
||||
|
||||
return User
|
||||
return None
|
||||
|
||||
def get_uid(self, uidornickname:str) -> Union[str, None]:
|
||||
def get_uid(self, uidornickname:str) -> Optional[str]:
|
||||
"""Get the UID of the user starting from the UID or the Nickname
|
||||
|
||||
Args:
|
||||
@@ -146,14 +143,14 @@ class User:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
|
||||
userObj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return None
|
||||
|
||||
return userObj.uid
|
||||
return user_obj.uid
|
||||
|
||||
def get_nickname(self, uidornickname:str) -> Union[str, None]:
|
||||
def get_nickname(self, uidornickname:str) -> Optional[str]:
|
||||
"""Get the Nickname starting from UID or the nickname
|
||||
|
||||
Args:
|
||||
@@ -162,14 +159,14 @@ class User:
|
||||
Returns:
|
||||
str|None: the nickname
|
||||
"""
|
||||
userObj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return None
|
||||
|
||||
return userObj.nickname
|
||||
return user_obj.nickname
|
||||
|
||||
def get_User_AsDict(self, uidornickname: str) -> Union[dict[str, any], None]:
|
||||
def get_user_asdict(self, uidornickname: str) -> Optional[dict[str, Any]]:
|
||||
"""Transform User Object to a dictionary
|
||||
|
||||
Args:
|
||||
@@ -178,12 +175,12 @@ class User:
|
||||
Returns:
|
||||
Union[dict[str, any], None]: User Object as a dictionary or None
|
||||
"""
|
||||
userObj = self.get_User(uidornickname=uidornickname)
|
||||
user_obj = self.get_User(uidornickname=uidornickname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return None
|
||||
|
||||
return asdict(userObj)
|
||||
return user_obj.to_dict()
|
||||
|
||||
def is_exist(self, uidornikname: str) -> bool:
|
||||
"""Check if the UID or the nickname exist in the USER DB
|
||||
@@ -194,14 +191,14 @@ class User:
|
||||
Returns:
|
||||
bool: True if exist
|
||||
"""
|
||||
userObj = self.get_User(uidornickname=uidornikname)
|
||||
user_obj = self.get_User(uidornickname=uidornikname)
|
||||
|
||||
if userObj is None:
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def clean_uid(self, uid: str) -> Union[str, None]:
|
||||
def clean_uid(self, uid: str) -> Optional[str]:
|
||||
"""Clean UID by removing @ / % / + / ~ / * / :
|
||||
|
||||
Args:
|
||||
@@ -217,4 +214,35 @@ class User:
|
||||
if not parsed_UID:
|
||||
return None
|
||||
|
||||
return parsed_UID
|
||||
return parsed_UID
|
||||
|
||||
def get_user_uptime_in_minutes(self, uidornickname: str) -> float:
|
||||
"""Retourne depuis quand l'utilisateur est connecté (in minutes).
|
||||
|
||||
Args:
|
||||
uid (str): The uid or le nickname
|
||||
|
||||
Returns:
|
||||
int: How long in minutes has the user been connected?
|
||||
"""
|
||||
|
||||
get_user = self.get_User(uidornickname)
|
||||
if get_user is None:
|
||||
return 0
|
||||
|
||||
# Convertir la date enregistrée dans UID_DB en un objet {datetime}
|
||||
connected_time_string = get_user.connexion_datetime
|
||||
|
||||
if isinstance(connected_time_string, datetime):
|
||||
connected_time = connected_time_string
|
||||
else:
|
||||
connected_time = datetime.strptime(connected_time_string, "%Y-%m-%d %H:%M:%S.%f")
|
||||
|
||||
# What time is it ?
|
||||
current_datetime = datetime.now()
|
||||
|
||||
uptime = current_datetime - connected_time
|
||||
convert_to_minutes = uptime.seconds / 60
|
||||
uptime_minutes = round(number=convert_to_minutes, ndigits=2)
|
||||
|
||||
return uptime_minutes
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
from datetime import datetime
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Literal
|
||||
from json import dumps
|
||||
from dataclasses import dataclass, field, asdict, fields
|
||||
from typing import Literal, Any
|
||||
from os import sep
|
||||
|
||||
@dataclass
|
||||
class MClient:
|
||||
class MainModel:
|
||||
"""Parent Model contains important methods"""
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""Return the fields of a dataclass instance as a new dictionary mapping field names to field values."""
|
||||
return asdict(self)
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Return the object of a dataclass a json str."""
|
||||
return dumps(self.to_dict())
|
||||
|
||||
def get_attributes(self) -> list[str]:
|
||||
"""Return a list of attributes name"""
|
||||
return [f.name for f in fields(self)]
|
||||
|
||||
@dataclass
|
||||
class MClient(MainModel):
|
||||
"""Model Client for registred nickname"""
|
||||
uid: str = None
|
||||
account: str = None
|
||||
@@ -22,7 +38,7 @@ class MClient:
|
||||
connexion_datetime: datetime = field(default=datetime.now())
|
||||
|
||||
@dataclass
|
||||
class MUser:
|
||||
class MUser(MainModel):
|
||||
"""Model User"""
|
||||
|
||||
uid: str = None
|
||||
@@ -40,7 +56,7 @@ class MUser:
|
||||
connexion_datetime: datetime = field(default=datetime.now())
|
||||
|
||||
@dataclass
|
||||
class MAdmin:
|
||||
class MAdmin(MainModel):
|
||||
"""Model Admin"""
|
||||
|
||||
uid: str = None
|
||||
@@ -59,7 +75,7 @@ class MAdmin:
|
||||
level: int = 0
|
||||
|
||||
@dataclass
|
||||
class MReputation:
|
||||
class MReputation(MainModel):
|
||||
"""Model Reputation"""
|
||||
uid: str = None
|
||||
nickname: str = None
|
||||
@@ -77,7 +93,7 @@ class MReputation:
|
||||
secret_code: str = None
|
||||
|
||||
@dataclass
|
||||
class MChannel:
|
||||
class MChannel(MainModel):
|
||||
"""Model Channel"""
|
||||
|
||||
name: str = None
|
||||
@@ -92,7 +108,7 @@ class MChannel:
|
||||
"""
|
||||
|
||||
@dataclass
|
||||
class ColorModel:
|
||||
class ColorModel(MainModel):
|
||||
white: str = "\x0300"
|
||||
black: str = "\x0301"
|
||||
blue: str = "\x0302"
|
||||
@@ -104,7 +120,7 @@ class ColorModel:
|
||||
underline: str = "\x1F"
|
||||
|
||||
@dataclass
|
||||
class MConfig:
|
||||
class MConfig(MainModel):
|
||||
"""Model Configuration"""
|
||||
|
||||
SERVEUR_IP: str = "127.0.0.1"
|
||||
@@ -305,16 +321,8 @@ class MConfig:
|
||||
"""0: utf-8 | 1: iso-8859-1"""
|
||||
|
||||
@dataclass
|
||||
class MClone:
|
||||
"""Model Clone"""
|
||||
connected: bool = False
|
||||
uid: str = None
|
||||
nickname: str = None
|
||||
username: str = None
|
||||
realname: str = None
|
||||
channels: list = field(default_factory=list)
|
||||
vhost: str = None
|
||||
hostname: str = 'localhost'
|
||||
umodes: str = None
|
||||
remote_ip: str = '127.0.0.1'
|
||||
group: str = 'Default'
|
||||
class MCommand(MainModel):
|
||||
module_name: str = None
|
||||
command_name: str = None
|
||||
description: str = None
|
||||
command_level: int = 0
|
||||
|
||||
@@ -261,21 +261,21 @@ class Install:
|
||||
if not do_install:
|
||||
return None
|
||||
|
||||
print("===> Vider le cache de pip")
|
||||
print("===> Clean pip cache")
|
||||
self.run_subprocess([self.config.venv_pip_executable, 'cache', 'purge'])
|
||||
|
||||
print("===> Verifier si pip est a jour")
|
||||
print("===> Check if pip is up to date")
|
||||
self.run_subprocess([self.config.venv_python_executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
|
||||
|
||||
if not self.check_package('greenlet'):
|
||||
self.run_subprocess([self.config.venv_pip_executable, 'install', '--only-binary', ':all:', 'greenlet'])
|
||||
print('====> Module Greenlet installé')
|
||||
print('====> Greenlet installed')
|
||||
|
||||
for module in self.config.venv_cmd_requirements:
|
||||
if not self.check_package(module):
|
||||
print("### Trying to install missing python packages ###")
|
||||
self.run_subprocess([self.config.venv_pip_executable, 'install', module])
|
||||
print(f"====> Module {module} installé")
|
||||
print(f"====> Module {module} installed!")
|
||||
else:
|
||||
print(f"==> {module} already installed")
|
||||
|
||||
@@ -307,8 +307,8 @@ WantedBy=default.target
|
||||
with open(full_service_file_path, 'w+') as servicefile:
|
||||
servicefile.write(contain)
|
||||
servicefile.close()
|
||||
print(f'Service file generated with current configuration')
|
||||
print(f'Running Defender IRC Service ...')
|
||||
print('Service file generated with current configuration')
|
||||
print('Running IRC Service ...')
|
||||
self.run_subprocess(self.config.service_cmd_daemon_reload)
|
||||
self.run_subprocess(self.config.service_cmd_executable)
|
||||
|
||||
@@ -316,8 +316,8 @@ WantedBy=default.target
|
||||
with open(full_service_file_path, 'w+') as servicefile:
|
||||
servicefile.write(contain)
|
||||
servicefile.close()
|
||||
print(f'Service file generated with current configuration')
|
||||
print(f'Running Defender IRC Service ...')
|
||||
print('Service file generated with current configuration')
|
||||
print('Running IRC Service ...')
|
||||
self.run_subprocess(self.config.service_cmd_daemon_reload)
|
||||
self.run_subprocess(self.config.service_cmd_executable)
|
||||
|
||||
|
||||
195
core/irc.py
195
core/irc.py
@@ -8,9 +8,10 @@ import time
|
||||
import traceback
|
||||
from ssl import SSLSocket
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Union
|
||||
from typing import Optional, Union
|
||||
from core.loader import Loader
|
||||
from core.classes.protocol import Protocol
|
||||
from core.classes.commands import Command
|
||||
|
||||
class Irc:
|
||||
_instance = None
|
||||
@@ -30,6 +31,9 @@ class Irc:
|
||||
# Load the configuration
|
||||
self.Config = self.Loader.Config
|
||||
|
||||
# Load Main utils functions
|
||||
self.Utils = self.Loader.Utils
|
||||
|
||||
# Date et heure de la premiere connexion de Defender
|
||||
self.defender_connexion_datetime = self.Config.DEFENDER_CONNEXION_DATETIME
|
||||
|
||||
@@ -50,7 +54,7 @@ class Irc:
|
||||
self.Base = self.Loader.Base
|
||||
|
||||
# Logger
|
||||
self.Logs = self.Loader.Base.logs
|
||||
self.Logs = self.Loader.Logs
|
||||
|
||||
# Get Settings.
|
||||
self.Settings = self.Base.Settings
|
||||
@@ -67,9 +71,6 @@ class Irc:
|
||||
# Use Channel Instance
|
||||
self.Channel = self.Loader.Channel
|
||||
|
||||
# Use Clones Instance
|
||||
self.Clone = self.Loader.Clone
|
||||
|
||||
# Use Reputation Instance
|
||||
self.Reputation = self.Loader.Reputation
|
||||
|
||||
@@ -83,7 +84,11 @@ class Irc:
|
||||
self.first_connexion_ip: str = None
|
||||
|
||||
# Define the dict that will contain all loaded modules
|
||||
self.loaded_classes:dict[str, 'Irc'] = {} # Definir la variable qui contiendra la liste modules chargés
|
||||
self.loaded_classes:dict[str, 'Irc'] = {}
|
||||
|
||||
# Load Commands Utils
|
||||
self.Commands = self.Loader.Commands
|
||||
"""Command utils"""
|
||||
|
||||
# Global full module commands that contains level, module name, commands and description
|
||||
self.module_commands: dict[int, dict[str, dict[str, str]]] = {}
|
||||
@@ -122,7 +127,7 @@ class Irc:
|
||||
|
||||
|
||||
# Define the IrcSocket object
|
||||
self.IrcSocket:Union[socket.socket, SSLSocket] = None
|
||||
self.IrcSocket: Union[socket.socket, SSLSocket] = None
|
||||
|
||||
self.__create_table()
|
||||
self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, ))
|
||||
@@ -140,6 +145,7 @@ class Irc:
|
||||
self.init_service_user()
|
||||
self.__create_socket()
|
||||
self.__connect_to_irc(ircInstance)
|
||||
|
||||
except AssertionError as ae:
|
||||
self.Logs.critical(f'Assertion error: {ae}')
|
||||
|
||||
@@ -192,6 +198,7 @@ class Irc:
|
||||
self.Logs.critical(f"AttributeError: {ae} - {soc.fileno()}")
|
||||
|
||||
def __ssl_context(self) -> ssl.SSLContext:
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
@@ -209,7 +216,7 @@ class Irc:
|
||||
protocol=self.Config.SERVEUR_PROTOCOL,
|
||||
ircInstance=self.ircObject
|
||||
).Protocol
|
||||
self.Protocol.link() # Etablir le link en fonction du protocol choisi
|
||||
self.Protocol.send_link() # Etablir le link en fonction du protocol choisi
|
||||
self.signal = True # Une variable pour initier la boucle infinie
|
||||
self.__join_saved_channels() # Join existing channels
|
||||
self.load_existing_modules() # Charger les modules existant dans la base de données
|
||||
@@ -226,14 +233,15 @@ class Irc:
|
||||
self.Logs.warning('--* Waiting for socket to close ...')
|
||||
|
||||
# Reload configuration
|
||||
self.Loader.Logs = self.Loader.LoggingModule.ServiceLogging().get_logger()
|
||||
self.Logs.debug('Reloading configuration')
|
||||
self.Config = self.Loader.ConfModule.Configuration().ConfigObject
|
||||
self.Base = self.Loader.BaseModule.Base(self.Config, self.Settings)
|
||||
self.Config = self.Loader.ConfModule.Configuration(self.Logs).ConfigObject
|
||||
self.Base = self.Loader.BaseModule.Base(self.Loader)
|
||||
self.Protocol = Protocol(self.Config.SERVEUR_PROTOCOL, ircInstance).Protocol
|
||||
|
||||
self.init_service_user()
|
||||
self.__create_socket()
|
||||
self.Protocol.link()
|
||||
self.Protocol.send_link()
|
||||
self.__join_saved_channels()
|
||||
self.load_existing_modules()
|
||||
self.Config.DEFENDER_RESTART = 0
|
||||
@@ -295,7 +303,7 @@ class Irc:
|
||||
if result_query:
|
||||
for chan_name in result_query:
|
||||
chan = chan_name[0]
|
||||
self.Protocol.sjoin(channel=chan)
|
||||
self.Protocol.send_sjoin(channel=chan)
|
||||
|
||||
def send_response(self, responses:list[bytes]) -> None:
|
||||
try:
|
||||
@@ -341,12 +349,43 @@ class Irc:
|
||||
self.module_commands.setdefault(level, {}).setdefault(module_name, {}).update({command_name: command_description})
|
||||
self.module_commands_list.append(command_name)
|
||||
|
||||
# Build Model.
|
||||
self.Commands.build(self.Loader.Definition.MCommand(module_name, command_name, command_description, level))
|
||||
|
||||
return None
|
||||
|
||||
def generate_help_menu(self, nickname: str) -> None:
|
||||
def generate_help_menu(self, nickname: str, module: Optional[str] = None) -> None:
|
||||
|
||||
# Check if the nickname is an admin
|
||||
admin_obj = self.Admin.get_Admin(nickname)
|
||||
p = self.Protocol
|
||||
admin_obj = self.Admin.get_admin(nickname)
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
color_nogc = self.Config.COLORS.nogc
|
||||
color_black = self.Config.COLORS.black
|
||||
current_level = 0
|
||||
|
||||
if admin_obj is not None:
|
||||
current_level = admin_obj.level
|
||||
|
||||
p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" ***************** LISTE DES COMMANDES *****************")
|
||||
header = f" {'Level':<8}| {'Command':<25}| {'Module':<15}| {'Description':<35}"
|
||||
line = "-"*75
|
||||
p.send_notice(nick_from=dnickname,nick_to=nickname, msg=header)
|
||||
p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" {line}")
|
||||
for cmd in self.Commands.get_commands_by_level(current_level):
|
||||
if module is None or cmd.module_name.lower() == module.lower():
|
||||
p.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=nickname,
|
||||
msg=f" {color_black}{cmd.command_level:<8}{color_nogc}| {cmd.command_name:<25}| {cmd.module_name:<15}| {cmd.description:<35}"
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def generate_help_menu_bakcup(self, nickname: str) -> None:
|
||||
|
||||
# Check if the nickname is an admin
|
||||
admin_obj = self.Admin.get_admin(nickname)
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
color_bold = self.Config.COLORS.bold
|
||||
color_nogc = self.Config.COLORS.nogc
|
||||
@@ -380,7 +419,7 @@ class Irc:
|
||||
|
||||
def is_cmd_allowed(self, nickname: str, command_name: str) -> bool:
|
||||
|
||||
admin_obj = self.Admin.get_Admin(nickname)
|
||||
admin_obj = self.Admin.get_admin(nickname)
|
||||
current_level = 0
|
||||
|
||||
if admin_obj is not None:
|
||||
@@ -494,16 +533,15 @@ class Irc:
|
||||
try:
|
||||
# module_name : mod_voice
|
||||
module_name = module_name.lower()
|
||||
class_name = module_name.split('_')[1].capitalize() # ==> Voice
|
||||
module_folder = module_name.split('_')[1].lower() # ==> voice
|
||||
class_name = module_name.split('_')[1].capitalize() # ==> Voice
|
||||
|
||||
# print(self.loaded_classes)
|
||||
|
||||
# Si le module est déja chargé
|
||||
if 'mods.' + module_name in sys.modules:
|
||||
self.Logs.info("Module déja chargé ...")
|
||||
self.Logs.info('module name = ' + module_name)
|
||||
# Check if the module is already loaded.
|
||||
if 'mods.' + module_folder + '.' + module_name in sys.modules:
|
||||
self.Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!")
|
||||
if class_name in self.loaded_classes:
|
||||
# Si le module existe dans la variable globale retourne False
|
||||
self.Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!")
|
||||
self.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}",
|
||||
@@ -511,7 +549,7 @@ class Irc:
|
||||
)
|
||||
return False
|
||||
|
||||
the_module = sys.modules['mods.' + module_name]
|
||||
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(self.ircObject)
|
||||
@@ -526,11 +564,11 @@ class Irc:
|
||||
msg=f"Module {module_name} chargé",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
return False
|
||||
self.Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!")
|
||||
return True
|
||||
|
||||
# Charger le module
|
||||
loaded_module = importlib.import_module(f"mods.{module_name}")
|
||||
|
||||
loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}')
|
||||
my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe
|
||||
create_instance_of_the_class = my_class(self.ircObject) # Créer une nouvelle instance de la classe
|
||||
|
||||
@@ -557,7 +595,7 @@ class Irc:
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
|
||||
self.Logs.info(f"Module {class_name} has been loaded")
|
||||
self.Logs.debug(f"Module {class_name} has been loaded")
|
||||
|
||||
return True
|
||||
|
||||
@@ -565,18 +603,21 @@ class Irc:
|
||||
self.Logs.error(f"MODULE_NOT_FOUND: {moduleNotFound}")
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[ {self.Config.COLORS.red}MODULE_NOT_FOUND{self.Config.COLORS.black} ]: {moduleNotFound}",
|
||||
msg=f"[ {self.Config.COLORS.red}MODULE ERROR{self.Config.COLORS.black} ]: {moduleNotFound}",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self.Base.db_delete_module(module_name)
|
||||
return False
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f"Something went wrong with a module you want to load : {err}")
|
||||
self.Logs.error(f"[LOAD MODULE ERROR]: {err}", exc_info=True)
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[ {self.Config.COLORS.red}ERROR{self.Config.COLORS.black} ]: {err}",
|
||||
msg=f"[ {self.Config.COLORS.red}MODULE ERROR{self.Config.COLORS.black} ]: {err}",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self.Base.db_delete_module(module_name)
|
||||
return False
|
||||
|
||||
def unload_module(self, mod_name: str) -> bool:
|
||||
"""Unload a module
|
||||
@@ -588,21 +629,28 @@ class Irc:
|
||||
bool: True if success
|
||||
"""
|
||||
try:
|
||||
module_name = mod_name.lower() # Le nom du module. exemple: mod_defender
|
||||
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender
|
||||
# Le nom du module. exemple: mod_defender
|
||||
module_name = mod_name.lower()
|
||||
module_folder = module_name.split('_')[1].lower() # ==> defender
|
||||
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender
|
||||
|
||||
if class_name in self.loaded_classes:
|
||||
self.loaded_classes[class_name].unload()
|
||||
del self.loaded_classes[class_name]
|
||||
|
||||
# Delete from the sys.
|
||||
if sys.modules.get(f'{module_folder}.{module_name}'):
|
||||
del sys.modules[f"{module_folder}.{module_name}"]
|
||||
|
||||
# Supprimer le module de la base de données
|
||||
self.Base.db_delete_module(module_name)
|
||||
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"Module {module_name} supprimé",
|
||||
msg=f"[ MODULE INFO ] Module {module_name} has been deleted!",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self.Logs.debug(f"[ MODULE ] {module_name} has been deleted!")
|
||||
return True
|
||||
|
||||
except Exception as err:
|
||||
@@ -612,13 +660,17 @@ class Irc:
|
||||
def reload_module(self, from_user: str, mod_name: str) -> bool:
|
||||
try:
|
||||
module_name = mod_name.lower() # ==> mod_defender
|
||||
module_folder = module_name.split('_')[1].lower() # ==> defender
|
||||
class_name = module_name.split('_')[1].capitalize() # ==> Defender
|
||||
|
||||
if 'mods.' + module_name in sys.modules:
|
||||
if f'mods.{module_folder}.{module_name}' in sys.modules:
|
||||
self.Logs.info('Unload the module ...')
|
||||
self.loaded_classes[class_name].unload()
|
||||
self.Logs.info('Module Already Loaded ... reloading the module ...')
|
||||
the_module = sys.modules['mods.' + module_name]
|
||||
|
||||
# Load dependencies
|
||||
self.Base.reload_modules_with_dependencies(f'mods.{module_folder}')
|
||||
the_module = sys.modules[f'mods.{module_folder}.{module_name}']
|
||||
importlib.reload(the_module)
|
||||
|
||||
# Supprimer la class déja instancier
|
||||
@@ -681,7 +733,7 @@ class Irc:
|
||||
if self.User.get_User(uid) is None:
|
||||
return None
|
||||
|
||||
getUser = self.User.get_User_AsDict(uid)
|
||||
getUser = self.User.get_user_asdict(uid)
|
||||
|
||||
level = int(level)
|
||||
|
||||
@@ -696,7 +748,7 @@ class Irc:
|
||||
|
||||
def delete_db_admin(self, uid:str) -> None:
|
||||
|
||||
if self.Admin.get_Admin(uid) is None:
|
||||
if self.Admin.get_admin(uid) is None:
|
||||
return None
|
||||
|
||||
if not self.Admin.delete(uid):
|
||||
@@ -732,7 +784,7 @@ class Irc:
|
||||
|
||||
hostname = get_user.hostname
|
||||
vhost = get_user.vhost
|
||||
spassword = self.Base.crypt_password(password)
|
||||
spassword = self.Loader.Utils.hash_password(password)
|
||||
|
||||
mes_donnees = {'admin': nickname}
|
||||
query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user=:admin"
|
||||
@@ -741,7 +793,7 @@ class Irc:
|
||||
|
||||
# On verifie si le user exist dans la base
|
||||
if not exist_user:
|
||||
mes_donnees = {'datetime': self.Base.get_datetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level}
|
||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level}
|
||||
self.Base.db_execute_query(f'''INSERT INTO {self.Config.TABLE_ADMIN}
|
||||
(createdOn, user, password, hostname, vhost, level) VALUES
|
||||
(:datetime, :user, :password, :hostname, :vhost, :level)
|
||||
@@ -763,7 +815,7 @@ class Irc:
|
||||
log_msg (str): the message to log
|
||||
"""
|
||||
try:
|
||||
mes_donnees = {'datetime': self.Base.get_datetime(), 'server_msg': log_msg}
|
||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'server_msg': log_msg}
|
||||
self.Base.db_execute_query(f'INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)', mes_donnees)
|
||||
|
||||
return None
|
||||
@@ -813,16 +865,13 @@ class Irc:
|
||||
|
||||
case 'PING':
|
||||
self.Protocol.on_server_ping(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
return None
|
||||
|
||||
case 'SJOIN':
|
||||
self.Protocol.on_sjoin(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'EOS':
|
||||
self.Protocol.on_eos(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'UID':
|
||||
try:
|
||||
@@ -831,48 +880,37 @@ class Irc:
|
||||
for classe_name, classe_object in self.loaded_classes.items():
|
||||
classe_object.cmd(original_response)
|
||||
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'General Error: {err}')
|
||||
|
||||
case 'QUIT':
|
||||
self.Protocol.on_quit(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'PROTOCTL':
|
||||
self.Protocol.on_protoctl(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'SVS2MODE':
|
||||
# >> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r']
|
||||
self.Protocol.on_svs2mode(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'SQUIT':
|
||||
self.Protocol.on_squit(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'PART':
|
||||
self.Protocol.on_part(serverMsg=parsed_protocol)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'VERSION':
|
||||
self.Protocol.on_version_msg(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'UMODE2':
|
||||
# [':adator_', 'UMODE2', '-i']
|
||||
self.Protocol.on_umode2(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'NICK':
|
||||
self.Protocol.on_nick(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'REPUTATION':
|
||||
self.Protocol.on_reputation(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'SLOG': # TODO
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
@@ -882,7 +920,6 @@ class Irc:
|
||||
|
||||
case 'PRIVMSG':
|
||||
self.Protocol.on_privmsg(serverMsg=original_response)
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
|
||||
case 'PONG': # TODO
|
||||
self.Logs.debug(f"** handle {parsed_protocol}")
|
||||
@@ -910,10 +947,9 @@ class Irc:
|
||||
classe_object.cmd(original_response)
|
||||
|
||||
except IndexError as ie:
|
||||
self.Logs.error(f"{ie} / {original_response} / length {str(len(original_response))}")
|
||||
self.Logs.error(f"IndexError: {ie}")
|
||||
except Exception as err:
|
||||
self.Logs.error(f"General Error: {err}")
|
||||
self.Logs.error(f"General Error: {traceback.format_exc()}")
|
||||
self.Logs.error(f"General Error: {err}", exc_info=True)
|
||||
|
||||
def hcmds(self, user: str, channel: Union[str, None], cmd: list, fullcmd: list = []) -> None:
|
||||
"""Create
|
||||
@@ -1081,7 +1117,7 @@ class Irc:
|
||||
return False
|
||||
|
||||
if not user_to_log is None:
|
||||
mes_donnees = {'user': user_to_log, 'password': self.Base.crypt_password(password)}
|
||||
mes_donnees = {'user': user_to_log, 'password': self.Loader.Utils.hash_password(password)}
|
||||
query = f"SELECT id, level FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
||||
result = self.Base.db_execute_query(query, mes_donnees)
|
||||
user_from_db = result.fetchone()
|
||||
@@ -1134,9 +1170,9 @@ class Irc:
|
||||
return None
|
||||
|
||||
user_to_edit = cmd[1]
|
||||
user_password = self.Base.crypt_password(cmd[2])
|
||||
user_password = self.Loader.Utils.hash_password(cmd[2])
|
||||
|
||||
get_admin = self.Admin.get_Admin(fromuser)
|
||||
get_admin = self.Admin.get_admin(fromuser)
|
||||
if get_admin is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no Admin access")
|
||||
return None
|
||||
@@ -1200,7 +1236,7 @@ class Irc:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}delaccess [USER] [CONFIRMUSER]")
|
||||
return None
|
||||
|
||||
get_admin = self.Admin.get_Admin(fromuser)
|
||||
get_admin = self.Admin.get_admin(fromuser)
|
||||
|
||||
if get_admin is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no admin access")
|
||||
@@ -1273,9 +1309,9 @@ class Irc:
|
||||
|
||||
# If the account doesn't exist then insert into database
|
||||
data_to_record = {
|
||||
'createdOn': self.Base.get_datetime(), 'account': fromuser,
|
||||
'createdOn': self.Utils.get_sdatetime(), 'account': fromuser,
|
||||
'nickname': user_obj.nickname, 'hostname': user_obj.hostname, 'vhost': user_obj.vhost, 'realname': user_obj.realname, 'email': email,
|
||||
'password': self.Base.crypt_password(password=password), 'level': 0
|
||||
'password': self.Loader.Utils.hash_password(password=password), 'level': 0
|
||||
}
|
||||
|
||||
insert_to_db = self.Base.db_execute_query(f"""
|
||||
@@ -1310,7 +1346,7 @@ class Irc:
|
||||
return None
|
||||
|
||||
account = str(cmd[1]) # account
|
||||
encrypted_password = self.Base.crypt_password(cmd[2])
|
||||
encrypted_password = self.Loader.Utils.hash_password(cmd[2])
|
||||
user_obj = self.User.get_User(fromuser)
|
||||
client_obj = self.Client.get_Client(user_obj.uid)
|
||||
|
||||
@@ -1382,9 +1418,10 @@ class Irc:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} <account>")
|
||||
|
||||
case 'help':
|
||||
|
||||
self.generate_help_menu(nickname=fromuser)
|
||||
|
||||
# Syntax. !help [module_name]
|
||||
module_name = str(cmd[1]) if len(cmd) == 2 else None
|
||||
self.generate_help_menu(nickname=fromuser, module=module_name)
|
||||
|
||||
case 'load':
|
||||
try:
|
||||
# Load a module ex: .load mod_defender
|
||||
@@ -1434,7 +1471,7 @@ class Irc:
|
||||
nick_to=fromuser,
|
||||
msg=f"Arrêt du service {dnickname}"
|
||||
)
|
||||
self.Protocol.squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason)
|
||||
self.Protocol.send_squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason)
|
||||
self.Logs.info(f'Arrêt du server {dnickname}')
|
||||
self.Config.DEFENDER_RESTART = 0
|
||||
self.signal = False
|
||||
@@ -1459,18 +1496,23 @@ class Irc:
|
||||
|
||||
self.User.UID_DB.clear() # Clear User Object
|
||||
self.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object
|
||||
self.Base.delete_logger(self.Config.LOGGING_NAME)
|
||||
self.Base.garbage_collector_thread()
|
||||
|
||||
self.Protocol.squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason)
|
||||
self.Protocol.send_squit(server_id=self.Config.SERVEUR_ID, server_link=self.Config.SERVEUR_LINK, reason=final_reason)
|
||||
self.Logs.info(f'Redémarrage du server {dnickname}')
|
||||
self.loaded_classes.clear()
|
||||
self.Config.DEFENDER_RESTART = 1 # Set restart status to 1 saying that the service will restart
|
||||
self.Config.DEFENDER_INIT = 1 # set init to 1 saying that the service will be re initiated
|
||||
self.Loader.ServiceLogging.remove_logger()
|
||||
|
||||
case 'rehash':
|
||||
self.Loader.ServiceLogging.remove_logger()
|
||||
self.Loader.ServiceLogging = self.Loader.LoggingModule.ServiceLogging()
|
||||
self.Loader.Logs = self.Loader.ServiceLogging.get_logger()
|
||||
|
||||
need_a_restart = ["SERVEUR_ID"]
|
||||
restart_flag = False
|
||||
Config_bakcup = self.Config.__dict__.copy()
|
||||
Config_bakcup = self.Config.to_dict().copy()
|
||||
serveur_id = self.Config.SERVEUR_ID
|
||||
service_nickname = self.Config.SERVICE_NICKNAME
|
||||
hsid = self.Config.HSID
|
||||
@@ -1490,7 +1532,7 @@ class Irc:
|
||||
|
||||
importlib.reload(mod_definition)
|
||||
importlib.reload(mod_config)
|
||||
self.Config = self.Loader.ConfModule.Configuration().ConfigObject
|
||||
self.Config = self.Loader.ConfModule.Configuration(self.Loader.Logs).ConfigObject
|
||||
self.Config.HSID = hsid
|
||||
self.Config.DEFENDER_INIT = defender_init
|
||||
self.Config.DEFENDER_RESTART = defender_restart
|
||||
@@ -1500,7 +1542,7 @@ class Irc:
|
||||
importlib.reload(mod_base)
|
||||
|
||||
conf_bkp_dict: dict = Config_bakcup
|
||||
config_dict: dict = self.Config.__dict__
|
||||
config_dict: dict = self.Config.to_dict()
|
||||
|
||||
for key, value in conf_bkp_dict.items():
|
||||
if config_dict[key] != value and key != 'COLORS':
|
||||
@@ -1513,14 +1555,13 @@ class Irc:
|
||||
restart_flag = True
|
||||
|
||||
if service_nickname != self.Config.SERVICE_NICKNAME:
|
||||
self.Protocol.set_nick(self.Config.SERVICE_NICKNAME)
|
||||
self.Protocol.send_set_nick(self.Config.SERVICE_NICKNAME)
|
||||
|
||||
if restart_flag:
|
||||
self.Config.SERVEUR_ID = serveur_id
|
||||
self.Protocol.send_priv_msg(nick_from=self.Config.SERVICE_NICKNAME, msg='You need to restart defender !', channel=self.Config.SERVICE_CHANLOG)
|
||||
|
||||
self.Base.delete_logger(self.Config.LOGGING_NAME)
|
||||
self.Base = self.Loader.BaseModule.Base(self.Config, self.Settings)
|
||||
self.Base = self.Loader.BaseModule.Base(self.Loader)
|
||||
|
||||
importlib.reload(mod_unreal6)
|
||||
importlib.reload(mod_protocol)
|
||||
|
||||
@@ -1,34 +1,45 @@
|
||||
from core.classes import user, admin, client, channel, clone, reputation, settings
|
||||
from logging import Logger
|
||||
from core.classes import user, admin, client, channel, reputation, settings, commands
|
||||
import core.logs as logs
|
||||
import core.definition as df
|
||||
import core.base as baseModule
|
||||
import core.classes.config as confModule
|
||||
import core.utils as utils
|
||||
import core.base as base_module
|
||||
import core.classes.config as conf_module
|
||||
|
||||
class Loader:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Load Modules
|
||||
# Load Main Modules
|
||||
self.Definition: df = df
|
||||
|
||||
self.ConfModule: confModule = confModule
|
||||
self.ConfModule: conf_module = conf_module
|
||||
|
||||
self.BaseModule: baseModule = baseModule
|
||||
self.BaseModule: base_module = base_module
|
||||
|
||||
self.Utils: utils = utils
|
||||
|
||||
self.LoggingModule: logs = logs
|
||||
|
||||
# Load Classes
|
||||
self.Settings: settings = settings.Settings()
|
||||
self.ServiceLogging: logs.ServiceLogging = logs.ServiceLogging()
|
||||
|
||||
self.Config: df.MConfig = self.ConfModule.Configuration().ConfigObject
|
||||
self.Logs: Logger = self.ServiceLogging.get_logger()
|
||||
|
||||
self.Base: baseModule.Base = self.BaseModule.Base(self.Config, self.Settings)
|
||||
self.Settings: settings.Settings = settings.Settings()
|
||||
|
||||
self.User: user.User = user.User(self.Base)
|
||||
self.Config: df.MConfig = self.ConfModule.Configuration(self.Logs).ConfigObject
|
||||
|
||||
self.Client: client.Client = client.Client(self.Base)
|
||||
self.Base: base_module.Base = self.BaseModule.Base(self)
|
||||
|
||||
self.Admin: admin.Admin = admin.Admin(self.Base)
|
||||
self.User: user.User = user.User(self)
|
||||
|
||||
self.Channel: channel.Channel = channel.Channel(self.Base)
|
||||
self.Client: client.Client = client.Client(self)
|
||||
|
||||
self.Clone: clone.Clone = clone.Clone(self.Base)
|
||||
self.Admin: admin.Admin = admin.Admin(self)
|
||||
|
||||
self.Reputation: reputation.Reputation = reputation.Reputation(self.Base)
|
||||
self.Channel: channel.Channel = channel.Channel(self)
|
||||
|
||||
self.Reputation: reputation.Reputation = reputation.Reputation(self)
|
||||
|
||||
self.Commands: commands.Command = commands.Command(self)
|
||||
|
||||
112
core/logs.py
Normal file
112
core/logs.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import logging
|
||||
from os import path, makedirs, sep
|
||||
from typing import Optional
|
||||
|
||||
class ServiceLogging:
|
||||
|
||||
def __init__(self, loggin_name: str = "defender"):
|
||||
"""Create the Logging object
|
||||
"""
|
||||
self.OS_SEP = sep
|
||||
self.LOGGING_NAME = loggin_name
|
||||
self.DEBUG_LEVEL, self.DEBUG_FILE_LEVEL, self.DEBUG_STDOUT_LEVEL = (10, 10, 10)
|
||||
self.SERVER_PREFIX = None
|
||||
self.LOGGING_CONSOLE = True
|
||||
|
||||
self.LOG_FILTERS: list[str] = ['PING', f":{self.SERVER_PREFIX}auth", "['PASS'"]
|
||||
|
||||
self.file_handler = None
|
||||
self.stdout_handler = None
|
||||
|
||||
self.logs: logging.Logger = self.start_log_system()
|
||||
|
||||
def get_logger(self) -> logging.Logger:
|
||||
|
||||
logs_obj: logging.Logger = self.logs
|
||||
|
||||
return logs_obj
|
||||
|
||||
def remove_logger(self, logger_name: Optional[str] = None) -> None:
|
||||
|
||||
if logger_name is None:
|
||||
logger_name = self.LOGGING_NAME
|
||||
|
||||
# Récupérer le logger
|
||||
logger = logging.getLogger(logger_name)
|
||||
|
||||
# Retirer tous les gestionnaires du logger et les fermer
|
||||
for handler in logger.handlers[:]: # Utiliser une copie de la liste
|
||||
# print(handler)
|
||||
logger.removeHandler(handler)
|
||||
handler.close()
|
||||
|
||||
# Supprimer le logger du dictionnaire global
|
||||
logging.Logger.manager.loggerDict.pop(logger_name, None)
|
||||
|
||||
return None
|
||||
|
||||
def start_log_system(self) -> logging.Logger:
|
||||
|
||||
os_sep = self.OS_SEP
|
||||
logging_name = self.LOGGING_NAME
|
||||
debug_level = self.DEBUG_LEVEL
|
||||
debug_file_level = self.DEBUG_FILE_LEVEL
|
||||
debug_stdout_level = self.DEBUG_STDOUT_LEVEL
|
||||
|
||||
# Create folder if not available
|
||||
logs_directory = f'logs{os_sep}'
|
||||
if not path.exists(f'{logs_directory}'):
|
||||
makedirs(logs_directory)
|
||||
|
||||
# Init logs object
|
||||
logs = logging.getLogger(logging_name)
|
||||
logs.setLevel(debug_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
|
||||
logs.addHandler(self.file_handler)
|
||||
logs.addHandler(self.stdout_handler)
|
||||
|
||||
# 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.stdout_handler.setLevel(level)
|
||||
|
||||
def set_file_handler_level(self, level: int) -> None:
|
||||
self.file_handler.setLevel(level)
|
||||
|
||||
def replace_filter(self, record: logging.LogRecord) -> bool:
|
||||
|
||||
response = True
|
||||
filter: list[str] = ['PING', f":{self.SERVER_PREFIX}auth", "['PASS'"]
|
||||
|
||||
# record.msg = record.getMessage().replace("PING", "[REDACTED]")
|
||||
# if self.LOGGING_CONSOLE:
|
||||
# print(record.getMessage())
|
||||
|
||||
for f in filter:
|
||||
if f in record.getMessage():
|
||||
response = False
|
||||
|
||||
return response # Retourne True pour permettre l'affichage du message
|
||||
@@ -1,25 +1,29 @@
|
||||
from typing import Literal, Union
|
||||
from datetime import datetime
|
||||
'''
|
||||
Main utils library.
|
||||
'''
|
||||
import gc
|
||||
from pathlib import Path
|
||||
from re import sub
|
||||
from typing import Literal, Optional, Any
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from time import time
|
||||
from random import choice
|
||||
from hashlib import md5, sha3_512
|
||||
|
||||
def convert_to_int(value: any) -> Union[int, None]:
|
||||
def convert_to_int(value: Any) -> Optional[int]:
|
||||
"""Convert a value to int
|
||||
|
||||
Args:
|
||||
value (any): Value to convert to int if possible
|
||||
value (Any): Value to convert to int if possible
|
||||
|
||||
Returns:
|
||||
Union[int, None]: Return the int value or None if not possible
|
||||
int: Return the int value or None if not possible
|
||||
"""
|
||||
try:
|
||||
value_to_int = int(value)
|
||||
return value_to_int
|
||||
except ValueError:
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_unixtime() -> int:
|
||||
"""Cette fonction retourne un UNIXTIME de type 12365456
|
||||
@@ -27,9 +31,12 @@ def get_unixtime() -> int:
|
||||
Returns:
|
||||
int: Current time in seconds since the Epoch (int)
|
||||
"""
|
||||
cet_offset = timezone(timedelta(hours=2))
|
||||
now_cet = datetime.now(cet_offset)
|
||||
unixtime_cet = int(now_cet.timestamp())
|
||||
return int(time())
|
||||
|
||||
def get_datetime() -> str:
|
||||
def get_sdatetime() -> str:
|
||||
"""Retourne une date au format string (24-12-2023 20:50:59)
|
||||
|
||||
Returns:
|
||||
@@ -38,6 +45,31 @@ def get_datetime() -> str:
|
||||
currentdate = datetime.now().strftime('%d-%m-%Y %H:%M:%S')
|
||||
return currentdate
|
||||
|
||||
def get_datetime() -> datetime:
|
||||
"""
|
||||
Return the current datetime in a datetime object
|
||||
"""
|
||||
return datetime.now()
|
||||
|
||||
def run_python_garbage_collector() -> int:
|
||||
"""Run Python garbage collector
|
||||
|
||||
Returns:
|
||||
int: The number of unreachable objects is returned.
|
||||
"""
|
||||
return gc.collect()
|
||||
|
||||
def get_number_gc_objects(your_object_to_count: Optional[Any] = None) -> int:
|
||||
"""Get The number of objects tracked by the collector (excluding the list returned).
|
||||
|
||||
Returns:
|
||||
int: Number of tracked objects by the collector
|
||||
"""
|
||||
if your_object_to_count is None:
|
||||
return len(gc.get_objects())
|
||||
|
||||
return sum(1 for obj in gc.get_objects() if isinstance(obj, your_object_to_count))
|
||||
|
||||
def generate_random_string(lenght: int) -> str:
|
||||
"""Retourn une chaîne aléatoire en fonction de la longueur spécifiée.
|
||||
|
||||
@@ -49,15 +81,15 @@ def generate_random_string(lenght: int) -> str:
|
||||
|
||||
return randomize
|
||||
|
||||
def hash(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') -> str:
|
||||
"""Retourne un mot de passe chiffré en fonction de l'algorithme utilisé
|
||||
def hash_password(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') -> str:
|
||||
"""Return the crypted password following the selected algorithm
|
||||
|
||||
Args:
|
||||
password (str): Le password en clair
|
||||
algorithm (str): L'algorithm a utilisé
|
||||
password (str): The plain text password
|
||||
algorithm (str): The algorithm to use
|
||||
|
||||
Returns:
|
||||
str: Le password haché
|
||||
str: The crypted password, default md5
|
||||
"""
|
||||
|
||||
match algorithm:
|
||||
@@ -72,3 +104,30 @@ def hash(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') -> str:
|
||||
case _:
|
||||
password = md5(password.encode()).hexdigest()
|
||||
return password
|
||||
|
||||
def get_all_modules() -> 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 clean_uid(uid: str) -> Optional[str]:
|
||||
"""Clean UID by removing @ / % / + / ~ / * / :
|
||||
|
||||
Args:
|
||||
uid (str): The UID to clean
|
||||
|
||||
Returns:
|
||||
str: Clean UID without any sign
|
||||
"""
|
||||
if uid is None:
|
||||
return None
|
||||
|
||||
pattern = fr'[:|@|%|\+|~|\*]*'
|
||||
parsed_UID = sub(pattern, '', uid)
|
||||
|
||||
return parsed_UID
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from core import installation
|
||||
|
||||
#############################################
|
||||
# @Version : 6 #
|
||||
# @Version : 6.2 #
|
||||
# Requierements : #
|
||||
# Python3.10 or higher #
|
||||
# SQLAlchemy, requests, psutil #
|
||||
# unrealircd-rpc-py #
|
||||
# UnrealIRCD 6.2.2 or higher #
|
||||
#############################################
|
||||
|
||||
@@ -14,7 +15,6 @@ try:
|
||||
|
||||
from core.loader import Loader
|
||||
from core.irc import Irc
|
||||
# loader = Loader()
|
||||
ircInstance = Irc(Loader())
|
||||
ircInstance.init_irc(ircInstance)
|
||||
|
||||
|
||||
163
mods/clone/clone_manager.py
Normal file
163
mods/clone/clone_manager.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from mods.clone.schemas import MClone
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.clone.mod_clone import Clone
|
||||
|
||||
class CloneManager:
|
||||
|
||||
UID_CLONE_DB: list[MClone] = []
|
||||
|
||||
def __init__(self, uplink: 'Clone'):
|
||||
|
||||
self.Logs = uplink.Logs
|
||||
|
||||
def insert(self, new_clone_object: MClone) -> bool:
|
||||
"""Create new Clone object
|
||||
|
||||
Args:
|
||||
new_clone_object (MClone): New Clone object
|
||||
|
||||
Returns:
|
||||
bool: True if inserted
|
||||
"""
|
||||
if new_clone_object is None:
|
||||
self.Logs.debug('New Clone object must not be None')
|
||||
return False
|
||||
|
||||
for record in self.UID_CLONE_DB:
|
||||
if record.nickname == new_clone_object.nickname or record.uid == new_clone_object.uid:
|
||||
# If the user exist then return False and do not go further
|
||||
self.Logs.debug(f'Nickname/UID {record.nickname}/{record.uid} already exist')
|
||||
return False
|
||||
|
||||
self.UID_CLONE_DB.append(new_clone_object)
|
||||
self.Logs.debug(f'New Clone object created: {new_clone_object}')
|
||||
return True
|
||||
|
||||
def delete(self, uidornickname: str) -> bool:
|
||||
"""Delete the Clone Object starting from the nickname or the UID
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or nickname of the clone
|
||||
|
||||
Returns:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
clone_obj = self.get_clone(uidornickname=uidornickname)
|
||||
|
||||
if clone_obj is None:
|
||||
return False
|
||||
|
||||
self.UID_CLONE_DB.remove(clone_obj)
|
||||
|
||||
return True
|
||||
|
||||
def nickname_exists(self, nickname: str) -> bool:
|
||||
"""Check if the nickname exist
|
||||
|
||||
Args:
|
||||
nickname (str): Nickname of the clone
|
||||
|
||||
Returns:
|
||||
bool: True if the nickname exist
|
||||
"""
|
||||
clone = self.get_clone(nickname)
|
||||
if isinstance(clone, MClone):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def uid_exists(self, uid: str) -> bool:
|
||||
"""Check if the nickname exist
|
||||
|
||||
Args:
|
||||
uid (str): uid of the clone
|
||||
|
||||
Returns:
|
||||
bool: True if the nickname exist
|
||||
"""
|
||||
clone = self.get_clone(uid)
|
||||
if isinstance(clone, MClone):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def group_exists(self, groupname: str) -> bool:
|
||||
"""Verify if a group exist
|
||||
|
||||
Args:
|
||||
groupname (str): The group name
|
||||
|
||||
Returns:
|
||||
bool: _description_
|
||||
"""
|
||||
for clone in self.UID_CLONE_DB:
|
||||
if clone.group.strip().lower() == groupname.strip().lower():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_clone(self, uidornickname: str) -> Optional[MClone]:
|
||||
"""Get MClone object or None
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or the Nickname
|
||||
|
||||
Returns:
|
||||
Union[MClone, None]: Return MClone object or None
|
||||
"""
|
||||
for clone in self.UID_CLONE_DB:
|
||||
if clone.uid == uidornickname:
|
||||
return clone
|
||||
if clone.nickname == uidornickname:
|
||||
return clone
|
||||
|
||||
return None
|
||||
|
||||
def get_clones_from_groupname(self, groupname: str) -> list[MClone]:
|
||||
"""Get list of clone objects by group name
|
||||
|
||||
Args:
|
||||
groupname (str): The group name
|
||||
|
||||
Returns:
|
||||
list[MClone]: List of clones in the group
|
||||
"""
|
||||
group_of_clone: list[MClone] = []
|
||||
|
||||
if self.group_exists(groupname):
|
||||
for clone in self.UID_CLONE_DB:
|
||||
if clone.group.strip().lower() == groupname.strip().lower():
|
||||
group_of_clone.append(clone)
|
||||
|
||||
return group_of_clone
|
||||
|
||||
def get_uid(self, uidornickname: str) -> Optional[str]:
|
||||
"""Get the UID of the clone starting from the UID or the Nickname
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or Nickname
|
||||
|
||||
Returns:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
for record in self.UID_CLONE_DB:
|
||||
if record.uid == uidornickname:
|
||||
return record.uid
|
||||
if record.nickname == uidornickname:
|
||||
return record.uid
|
||||
|
||||
return None
|
||||
|
||||
def kill(self, nickname:str) -> bool:
|
||||
|
||||
response = False
|
||||
|
||||
for clone in self.UID_CLONE_DB:
|
||||
if clone.nickname == nickname:
|
||||
clone.alive = False # Kill the clone
|
||||
response = True
|
||||
|
||||
return response
|
||||
@@ -1,46 +1,62 @@
|
||||
from dataclasses import dataclass
|
||||
import random, faker, time, logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Optional, Any
|
||||
import mods.clone.utils as utils
|
||||
import mods.clone.threads as thds
|
||||
import mods.clone.schemas as schemas
|
||||
from mods.clone.clone_manager import CloneManager
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.irc import Irc
|
||||
from faker import Faker
|
||||
|
||||
class Clone():
|
||||
class Clone:
|
||||
|
||||
@dataclass
|
||||
class ModConfModel:
|
||||
clone_nicknames: list[str]
|
||||
|
||||
def __init__(self, ircInstance: 'Irc') -> None:
|
||||
def __init__(self, irc_instance: 'Irc') -> None:
|
||||
|
||||
# Module name (Mandatory)
|
||||
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
||||
|
||||
# Add Irc Object to the module (Mandatory)
|
||||
self.Irc = ircInstance
|
||||
self.Irc = irc_instance
|
||||
|
||||
# Add Irc Protocol Object to the module (Mandatory)
|
||||
self.Protocol = ircInstance.Protocol
|
||||
self.Protocol = irc_instance.Protocol
|
||||
|
||||
# Add Global Configuration to the module (Mandatory)
|
||||
self.Config = ircInstance.Config
|
||||
self.Config = irc_instance.Config
|
||||
|
||||
# Add Base object to the module (Mandatory)
|
||||
self.Base = ircInstance.Base
|
||||
self.Base = irc_instance.Base
|
||||
|
||||
# Add logs object to the module (Mandatory)
|
||||
self.Logs = ircInstance.Base.logs
|
||||
self.Logs = irc_instance.Loader.Logs
|
||||
|
||||
# Add User object to the module (Mandatory)
|
||||
self.User = ircInstance.User
|
||||
self.User = irc_instance.User
|
||||
|
||||
# Add Channel object to the module (Mandatory)
|
||||
self.Channel = ircInstance.Channel
|
||||
self.Channel = irc_instance.Channel
|
||||
|
||||
# Add global definitions
|
||||
self.Definition = irc_instance.Loader.Definition
|
||||
|
||||
# Add clone object to the module (Optionnal)
|
||||
self.Clone = ircInstance.Clone
|
||||
# The Global Settings
|
||||
self.Settings = irc_instance.Loader.Settings
|
||||
|
||||
self.Definition = ircInstance.Loader.Definition
|
||||
self.Schemas = schemas
|
||||
|
||||
self.Utils = utils
|
||||
|
||||
self.Threads = thds
|
||||
|
||||
self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB')
|
||||
|
||||
self.Clone = CloneManager(self)
|
||||
|
||||
metadata = self.Settings.get_cache('UID_CLONE_DB')
|
||||
|
||||
if metadata is not None:
|
||||
self.Clone.UID_CLONE_DB = metadata
|
||||
self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}")
|
||||
|
||||
# Créer les nouvelles commandes du module
|
||||
self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
||||
@@ -57,10 +73,6 @@ class Clone():
|
||||
self.__create_tables()
|
||||
|
||||
self.stop = False
|
||||
logging.getLogger('faker').setLevel(logging.CRITICAL)
|
||||
|
||||
self.fakeEN = faker.Faker('en_GB')
|
||||
self.fakeFR = faker.Faker('fr_FR')
|
||||
|
||||
# Load module configuration (Mandatory)
|
||||
self.__load_module_configuration()
|
||||
@@ -75,8 +87,6 @@ class Clone():
|
||||
def __create_tables(self) -> None:
|
||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||
Args:
|
||||
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
|
||||
|
||||
Returns:
|
||||
None: Aucun retour n'es attendu
|
||||
@@ -99,9 +109,7 @@ class Clone():
|
||||
"""
|
||||
try:
|
||||
# Variable qui va contenir les options de configuration du module Defender
|
||||
self.ModConfig = self.ModConfModel(
|
||||
clone_nicknames=[]
|
||||
)
|
||||
self.ModConfig = self.Schemas.ModConfModel()
|
||||
|
||||
# Sync the configuration with core configuration (Mandatory)
|
||||
# self.Base.db_sync_core_config(self.module_name, self.ModConfig)
|
||||
@@ -115,6 +123,8 @@ class Clone():
|
||||
"""Cette methode sera executée a chaque désactivation ou
|
||||
rechargement de module
|
||||
"""
|
||||
# Store Clones DB into the global Settings to retrieve it after the reload.
|
||||
self.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB)
|
||||
|
||||
self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -nts")
|
||||
@@ -123,175 +133,41 @@ class Clone():
|
||||
|
||||
return None
|
||||
|
||||
def generate_vhost(self) -> str:
|
||||
|
||||
fake = self.fakeEN
|
||||
|
||||
rand_1 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||
rand_2 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||
rand_3 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||
|
||||
vhost = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP'
|
||||
return vhost
|
||||
|
||||
def generate_clones(self, group: str = 'Default', auto_remote_ip: bool = False) -> None:
|
||||
try:
|
||||
|
||||
fakeEN = self.fakeEN
|
||||
fakeFR = self.fakeFR
|
||||
unixtime = self.Base.get_unixtime()
|
||||
|
||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
generate_uid = fakeEN.random_sample(chaine, 6)
|
||||
uid = self.Config.SERVEUR_ID + ''.join(generate_uid)
|
||||
|
||||
umodes = self.Config.CLONE_UMODES
|
||||
|
||||
# Generate Username
|
||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
new_username = fakeEN.random_sample(chaine, 9)
|
||||
username = ''.join(new_username)
|
||||
|
||||
# Create realname XX F|M Department
|
||||
gender = fakeEN.random_choices(['F','M'], 1)
|
||||
gender = ''.join(gender)
|
||||
|
||||
if gender == 'F':
|
||||
nickname = fakeEN.first_name_female()
|
||||
elif gender == 'M':
|
||||
nickname = fakeEN.first_name_male()
|
||||
else:
|
||||
nickname = fakeEN.first_name()
|
||||
|
||||
age = random.randint(20, 60)
|
||||
department = fakeFR.department_name()
|
||||
realname = f'{age} {gender} {department}'
|
||||
|
||||
decoded_ip = fakeEN.ipv4_private() if auto_remote_ip else '127.0.0.1'
|
||||
hostname = fakeEN.hostname()
|
||||
|
||||
vhost = self.generate_vhost()
|
||||
|
||||
checkNickname = self.Clone.exists(nickname=nickname)
|
||||
checkUid = self.Clone.uid_exists(uid=uid)
|
||||
|
||||
while checkNickname:
|
||||
caracteres = '0123456789'
|
||||
randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
||||
nickname = nickname + str(randomize)
|
||||
checkNickname = self.Clone.exists(nickname=nickname)
|
||||
|
||||
while checkUid:
|
||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
generate_uid = fakeEN.random_sample(chaine, 6)
|
||||
uid = self.Config.SERVEUR_ID + ''.join(generate_uid)
|
||||
checkUid = self.Clone.uid_exists(uid=uid)
|
||||
|
||||
clone = self.Definition.MClone(
|
||||
connected=False,
|
||||
nickname=nickname,
|
||||
username=username,
|
||||
realname=realname,
|
||||
hostname=hostname,
|
||||
umodes=umodes,
|
||||
uid=uid,
|
||||
remote_ip=decoded_ip,
|
||||
vhost=vhost,
|
||||
group=group,
|
||||
channels=[]
|
||||
)
|
||||
|
||||
self.Clone.insert(clone)
|
||||
|
||||
return None
|
||||
|
||||
except AttributeError as ae:
|
||||
self.Logs.error(f'Attribute Error : {ae}')
|
||||
except Exception as err:
|
||||
self.Logs.error(f"General Error: {err}")
|
||||
|
||||
def thread_connect_clones(self, number_of_clones:int , group: str = 'Default', auto_remote_ip: bool = False, interval: float = 0.2) -> None:
|
||||
|
||||
for i in range(0, number_of_clones):
|
||||
self.generate_clones(group=group, auto_remote_ip=auto_remote_ip)
|
||||
|
||||
for clone in self.Clone.UID_CLONE_DB:
|
||||
|
||||
if self.stop:
|
||||
print(f"Stop creating clones ...")
|
||||
self.stop = False
|
||||
break
|
||||
|
||||
if not clone.connected:
|
||||
self.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
||||
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=self.Config.CLONE_CHANNEL, password=self.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
||||
|
||||
time.sleep(interval)
|
||||
clone.connected = True
|
||||
|
||||
def thread_kill_clones(self, fromuser: str) -> None:
|
||||
|
||||
clone_to_kill: list[str] = []
|
||||
for clone in self.Clone.UID_CLONE_DB:
|
||||
clone_to_kill.append(clone.uid)
|
||||
|
||||
for clone_uid in clone_to_kill:
|
||||
self.Protocol.send_quit(clone_uid, 'Gooood bye', print_log=False)
|
||||
|
||||
del clone_to_kill
|
||||
|
||||
return None
|
||||
|
||||
def cmd(self, data:list) -> None:
|
||||
try:
|
||||
service_id = self.Config.SERVICE_ID # Defender serveur id
|
||||
cmd = list(data).copy()
|
||||
|
||||
if len(cmd) < 2:
|
||||
if not data or len(data) < 2:
|
||||
return None
|
||||
|
||||
match cmd[1]:
|
||||
|
||||
case 'REPUTATION':
|
||||
pass
|
||||
|
||||
if len(cmd) < 3:
|
||||
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
||||
index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
||||
if index == -1:
|
||||
return None
|
||||
|
||||
match cmd[2]:
|
||||
match command:
|
||||
|
||||
case 'PRIVMSG':
|
||||
# print(cmd)
|
||||
uid_sender = self.User.clean_uid(cmd[1])
|
||||
senderObj = self.User.get_User(uid_sender)
|
||||
return self.Utils.handle_on_privmsg(self, cmd)
|
||||
|
||||
if senderObj.hostname in self.Config.CLONE_LOG_HOST_EXEMPT:
|
||||
return None
|
||||
case 'QUIT':
|
||||
return None
|
||||
|
||||
if not senderObj is None:
|
||||
senderMsg = ' '.join(cmd[4:])
|
||||
getClone = self.Clone.get_Clone(cmd[3])
|
||||
|
||||
if getClone is None:
|
||||
return None
|
||||
|
||||
if getClone.uid != self.Config.SERVICE_ID:
|
||||
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=getClone.uid,
|
||||
msg=final_message,
|
||||
channel=self.Config.CLONE_CHANNEL
|
||||
)
|
||||
case _:
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'General Error: {err}')
|
||||
self.Logs.error(f'General Error: {err}', exc_info=True)
|
||||
return None
|
||||
|
||||
def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
||||
def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None:
|
||||
|
||||
try:
|
||||
|
||||
if len(cmd) < 1:
|
||||
return
|
||||
|
||||
command = str(cmd[0]).lower()
|
||||
fromuser = user
|
||||
|
||||
dnickname = self.Config.SERVICE_NICKNAME # Defender nickname
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
|
||||
match command:
|
||||
|
||||
@@ -299,10 +175,11 @@ class Clone():
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | nickname]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list")
|
||||
return None
|
||||
|
||||
option = str(cmd[1]).lower()
|
||||
|
||||
@@ -317,8 +194,8 @@ class Clone():
|
||||
connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2
|
||||
|
||||
self.Base.create_thread(
|
||||
func=self.thread_connect_clones,
|
||||
func_args=(number_of_clones, group, False, connection_interval)
|
||||
func=self.Threads.thread_connect_clones,
|
||||
func_args=(self, number_of_clones, group, False, connection_interval)
|
||||
)
|
||||
|
||||
except Exception as err:
|
||||
@@ -328,18 +205,28 @@ class Clone():
|
||||
|
||||
case 'kill':
|
||||
try:
|
||||
# clone kill [all | nickname]
|
||||
# clone kill [ALL | group name | nickname]
|
||||
self.stop = True
|
||||
clone_name = str(cmd[2])
|
||||
clone_to_kill: list[str] = []
|
||||
option = str(cmd[2])
|
||||
|
||||
if clone_name.lower() == 'all':
|
||||
self.Base.create_thread(func=self.thread_kill_clones, func_args=(fromuser, ))
|
||||
if option.lower() == 'all':
|
||||
self.Base.create_thread(func=self.Threads.thread_kill_clones, func_args=(self, ))
|
||||
|
||||
elif self.Clone.group_exists(option):
|
||||
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||
|
||||
if len(list_of_clones_in_group) > 0:
|
||||
self.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}")
|
||||
|
||||
for clone in list_of_clones_in_group:
|
||||
self.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False)
|
||||
self.Clone.delete(clone.uid)
|
||||
|
||||
else:
|
||||
cloneObj = self.Clone.get_Clone(clone_name)
|
||||
if not cloneObj is None:
|
||||
self.Protocol.send_quit(cloneObj.uid, 'Goood bye', print_log=False)
|
||||
clone_obj = self.Clone.get_clone(option)
|
||||
if not clone_obj is None:
|
||||
self.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False)
|
||||
self.Clone.delete(clone_obj.uid)
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
@@ -348,19 +235,28 @@ class Clone():
|
||||
|
||||
case 'join':
|
||||
try:
|
||||
# clone join [all | nickname] #channel
|
||||
clone_name = str(cmd[2])
|
||||
# clone join [all | group name | nickname] #channel
|
||||
option = str(cmd[2])
|
||||
clone_channel_to_join = str(cmd[3])
|
||||
|
||||
if clone_name.lower() == 'all':
|
||||
if option.lower() == 'all':
|
||||
|
||||
for clone in self.Clone.UID_CLONE_DB:
|
||||
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False)
|
||||
|
||||
elif self.Clone.group_exists(option):
|
||||
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||
|
||||
if len(list_of_clones_in_group) > 0:
|
||||
self.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}")
|
||||
|
||||
for clone in list_of_clones_in_group:
|
||||
self.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False)
|
||||
|
||||
else:
|
||||
if self.Clone.exists(clone_name):
|
||||
if not self.Clone.get_uid(clone_name) is None:
|
||||
self.Protocol.send_join_chan(uidornickname=clone_name, channel=clone_channel_to_join, print_log=False)
|
||||
if self.Clone.nickname_exists(option):
|
||||
clone_uid = self.Clone.get_clone(option).uid
|
||||
self.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False)
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
@@ -369,18 +265,27 @@ class Clone():
|
||||
|
||||
case 'part':
|
||||
try:
|
||||
# clone part [all | nickname] #channel
|
||||
clone_name = str(cmd[2])
|
||||
# clone part [all | nickname] #channel
|
||||
option = str(cmd[2])
|
||||
clone_channel_to_part = str(cmd[3])
|
||||
|
||||
if clone_name.lower() == 'all':
|
||||
if option.lower() == 'all':
|
||||
|
||||
for clone in self.Clone.UID_CLONE_DB:
|
||||
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
||||
|
||||
elif self.Clone.group_exists(option):
|
||||
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||
|
||||
if len(list_of_clones_in_group) > 0:
|
||||
self.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}")
|
||||
|
||||
for clone in list_of_clones_in_group:
|
||||
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
||||
|
||||
else:
|
||||
if self.Clone.exists(clone_name):
|
||||
clone_uid = self.Clone.get_uid(clone_name)
|
||||
if self.Clone.nickname_exists(option):
|
||||
clone_uid = self.Clone.get_uid(option)
|
||||
if not clone_uid is None:
|
||||
self.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False)
|
||||
|
||||
@@ -391,11 +296,31 @@ class Clone():
|
||||
|
||||
case 'list':
|
||||
try:
|
||||
clone_count = len(self.Clone.UID_CLONE_DB)
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f">> Number of connected clones: {clone_count}")
|
||||
for clone_name in self.Clone.UID_CLONE_DB:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||
msg=f">> Nickname: {clone_name.nickname} | Username: {clone_name.username} | Realname: {clone_name.realname} | Vhost: {clone_name.vhost} | UID: {clone_name.uid} | Group: {clone_name.group} | Connected: {clone_name.connected}")
|
||||
# Syntax. /msg defender clone list <group_name>
|
||||
header = f" {'Nickname':<12}| {'Real name':<25}| {'Group name':<15}| {'Connected':<35}"
|
||||
line = "-"*67
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header)
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
||||
group_name = cmd[2] if len(cmd) > 2 else None
|
||||
|
||||
if group_name is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
||||
for clone_name in self.Clone.UID_CLONE_DB:
|
||||
self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f" {clone_name.nickname:<12}| {clone_name.realname:<25}| {clone_name.group:<15}| {clone_name.connected:<35}")
|
||||
else:
|
||||
if not self.Clone.group_exists(group_name):
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!")
|
||||
return None
|
||||
clones = self.Clone.get_clones_from_groupname(group_name)
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
||||
for clone in clones:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||
msg=f" {clone.nickname:<12}| {clone.realname:<25}| {clone.group:<15}| {clone.connected:<35}")
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
|
||||
@@ -403,11 +328,11 @@ class Clone():
|
||||
try:
|
||||
# clone say clone_nickname #channel message
|
||||
clone_name = str(cmd[2])
|
||||
clone_channel = str(cmd[3]) if self.Channel.Is_Channel(str(cmd[3])) else None
|
||||
clone_channel = str(cmd[3]) if self.Channel.is_valid_channel(str(cmd[3])) else None
|
||||
|
||||
final_message = ' '.join(cmd[4:])
|
||||
|
||||
if clone_channel is None or not self.Clone.exists(clone_name):
|
||||
if clone_channel is None or not self.Clone.nickname_exists(clone_name):
|
||||
self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
@@ -415,7 +340,7 @@ class Clone():
|
||||
)
|
||||
return None
|
||||
|
||||
if self.Clone.exists(clone_name):
|
||||
if self.Clone.nickname_exists(clone_name):
|
||||
self.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel)
|
||||
|
||||
except Exception as err:
|
||||
@@ -428,12 +353,12 @@ class Clone():
|
||||
|
||||
case _:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | nickname]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list")
|
||||
|
||||
except IndexError as ie:
|
||||
self.Logs.error(f'Index Error: {ie}')
|
||||
except Exception as err:
|
||||
self.Logs.error(f'Index Error: {err}')
|
||||
self.Logs.error(f'General Error: {err}')
|
||||
22
mods/clone/schemas.py
Normal file
22
mods/clone/schemas.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from core.definition import MainModel, dataclass, field
|
||||
|
||||
@dataclass
|
||||
class ModConfModel(MainModel):
|
||||
clone_nicknames: list[str] = field(default_factory=list)
|
||||
|
||||
@dataclass
|
||||
class MClone(MainModel):
|
||||
"""Model Clone"""
|
||||
connected: bool = False
|
||||
uid: str = None
|
||||
nickname: str = None
|
||||
username: str = None
|
||||
realname: str = None
|
||||
channels: list = field(default_factory=list)
|
||||
vhost: str = None
|
||||
hostname: str = 'localhost'
|
||||
umodes: str = None
|
||||
remote_ip: str = '127.0.0.1'
|
||||
group: str = 'Default'
|
||||
|
||||
DB_CLONES: list[MClone] = []
|
||||
44
mods/clone/threads.py
Normal file
44
mods/clone/threads.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from typing import TYPE_CHECKING
|
||||
from time import sleep
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.clone.mod_clone import Clone
|
||||
|
||||
def thread_connect_clones(uplink: 'Clone',
|
||||
number_of_clones:int ,
|
||||
group: str = 'Default',
|
||||
auto_remote_ip: bool = False,
|
||||
interval: float = 0.2
|
||||
):
|
||||
|
||||
for i in range(0, number_of_clones):
|
||||
uplink.Utils.create_new_clone(
|
||||
uplink=uplink,
|
||||
faker_instance=uplink.Faker,
|
||||
group=group,
|
||||
auto_remote_ip=auto_remote_ip
|
||||
)
|
||||
|
||||
for clone in uplink.Clone.UID_CLONE_DB:
|
||||
|
||||
if uplink.stop:
|
||||
print(f"Stop creating clones ...")
|
||||
uplink.stop = False
|
||||
break
|
||||
|
||||
if not clone.connected:
|
||||
uplink.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
||||
uplink.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.Config.CLONE_CHANNEL, password=uplink.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
||||
|
||||
sleep(interval)
|
||||
clone.connected = True
|
||||
|
||||
def thread_kill_clones(uplink: 'Clone'):
|
||||
|
||||
clone_to_kill = uplink.Clone.UID_CLONE_DB.copy()
|
||||
|
||||
for clone in clone_to_kill:
|
||||
uplink.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False)
|
||||
uplink.Clone.delete(clone.uid)
|
||||
|
||||
del clone_to_kill
|
||||
198
mods/clone/utils.py
Normal file
198
mods/clone/utils.py
Normal file
@@ -0,0 +1,198 @@
|
||||
import logging
|
||||
import random
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from faker import Faker
|
||||
|
||||
logging.getLogger('faker').setLevel(logging.CRITICAL)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.clone.mod_clone import Clone
|
||||
|
||||
def create_faker_object(faker_local: Optional[str] = 'en_GB') -> Faker:
|
||||
"""Create a new faker object
|
||||
|
||||
Args:
|
||||
faker_local (Optional[str], optional): _description_. Defaults to 'en_GB'.
|
||||
|
||||
Returns:
|
||||
Faker: The Faker Object
|
||||
"""
|
||||
if faker_local not in ['en_GB', 'fr_FR']:
|
||||
faker_local = 'en_GB'
|
||||
|
||||
return Faker(faker_local)
|
||||
|
||||
def generate_uid_for_clone(faker_instance: 'Faker', server_id: str) -> str:
|
||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
return server_id + ''.join(faker_instance.random_sample(chaine, 6))
|
||||
|
||||
def generate_vhost_for_clone(faker_instance: 'Faker') -> str:
|
||||
"""Generate new vhost for the clone
|
||||
|
||||
Args:
|
||||
faker_instance (Faker): The Faker instance
|
||||
|
||||
Returns:
|
||||
str: _description_
|
||||
"""
|
||||
rand_1 = faker_instance.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||
rand_2 = faker_instance.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||
rand_3 = faker_instance.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||
|
||||
vhost = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP'
|
||||
return vhost
|
||||
|
||||
def generate_username_for_clone(faker_instance: 'Faker') -> str:
|
||||
"""Generate vhosts for clones
|
||||
|
||||
Returns:
|
||||
str: The vhost
|
||||
"""
|
||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
return ''.join(faker_instance.random_sample(chaine, 9))
|
||||
|
||||
def generate_realname_for_clone(faker_instance: 'Faker') -> tuple[int, str, str]:
|
||||
"""Generate realname for clone
|
||||
Ex: XX F|M Department
|
||||
Args:
|
||||
faker_instance (Faker): _description_
|
||||
|
||||
Returns:
|
||||
tuple: Age | Gender | Department
|
||||
"""
|
||||
# Create realname XX F|M Department
|
||||
gender = faker_instance.random_choices(['F','M'], 1)
|
||||
gender = ''.join(gender)
|
||||
age = random.randint(20, 60)
|
||||
if faker_instance.locales[0] == 'fr_FR':
|
||||
department = faker_instance.department_name()
|
||||
else:
|
||||
department = faker_instance.city()
|
||||
|
||||
return (age, gender, department)
|
||||
|
||||
def generate_nickname_for_clone(faker_instance: 'Faker', gender: Optional[str] = 'AUTO') -> str:
|
||||
"""Generate nickname for clone
|
||||
|
||||
Args:
|
||||
faker_instance (Faker): The Faker Instance
|
||||
gender (str): The Gender.Default F
|
||||
|
||||
Returns:
|
||||
str: Nickname Based on the Gender
|
||||
"""
|
||||
if gender.upper() == 'AUTO' or gender.upper() not in ['F', 'M']:
|
||||
# Generate new gender
|
||||
gender = faker_instance.random_choices(['F','M'], 1)
|
||||
gender = ''.join(gender)
|
||||
|
||||
if gender.upper() == 'F':
|
||||
return faker_instance.first_name_female()
|
||||
elif gender.upper() == 'M':
|
||||
return faker_instance.first_name_male()
|
||||
|
||||
def generate_ipv4_for_clone(faker_instance: 'Faker', auto: bool = True) -> str:
|
||||
"""Generate remote ipv4 for clone
|
||||
|
||||
Args:
|
||||
faker_instance (Faker): The Faker Instance
|
||||
auto (bool): Set auto generation of ip or 127.0.0.1 will be returned
|
||||
|
||||
Returns:
|
||||
str: Remote IPV4
|
||||
"""
|
||||
return faker_instance.ipv4_private() if auto else '127.0.0.1'
|
||||
|
||||
def generate_hostname_for_clone(faker_instance: 'Faker') -> str:
|
||||
"""Generate hostname for clone
|
||||
|
||||
Args:
|
||||
faker_instance (Faker): The Faker Instance
|
||||
|
||||
Returns:
|
||||
str: New hostname
|
||||
"""
|
||||
return faker_instance.hostname()
|
||||
|
||||
def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Default', auto_remote_ip: bool = False) -> bool:
|
||||
"""Create a new Clone object in the DB_CLONES.
|
||||
|
||||
Args:
|
||||
faker_instance (Faker): The Faker instance
|
||||
|
||||
Returns:
|
||||
bool: True if it was created
|
||||
"""
|
||||
faker = faker_instance
|
||||
|
||||
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID)
|
||||
umodes = uplink.Config.CLONE_UMODES
|
||||
|
||||
# Generate Username
|
||||
username = generate_username_for_clone(faker)
|
||||
|
||||
# Generate realname (XX F|M Department)
|
||||
age, gender, department = generate_realname_for_clone(faker)
|
||||
realname = f'{age} {gender} {department}'
|
||||
|
||||
# Generate nickname
|
||||
nickname = generate_nickname_for_clone(faker, gender)
|
||||
|
||||
# Generate decoded ipv4 and hostname
|
||||
decoded_ip = generate_ipv4_for_clone(faker, auto_remote_ip)
|
||||
hostname = generate_hostname_for_clone(faker)
|
||||
vhost = generate_vhost_for_clone(faker)
|
||||
|
||||
checkNickname = uplink.Clone.nickname_exists(nickname)
|
||||
checkUid = uplink.Clone.uid_exists(uid=uid)
|
||||
|
||||
while checkNickname:
|
||||
caracteres = '0123456789'
|
||||
randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
||||
nickname = nickname + str(randomize)
|
||||
checkNickname = uplink.Clone.nickname_exists(nickname)
|
||||
|
||||
while checkUid:
|
||||
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID)
|
||||
checkUid = uplink.Clone.uid_exists(uid=uid)
|
||||
|
||||
clone = uplink.Schemas.MClone(
|
||||
connected=False,
|
||||
nickname=nickname,
|
||||
username=username,
|
||||
realname=realname,
|
||||
hostname=hostname,
|
||||
umodes=umodes,
|
||||
uid=uid,
|
||||
remote_ip=decoded_ip,
|
||||
vhost=vhost,
|
||||
group=group,
|
||||
channels=[]
|
||||
)
|
||||
|
||||
uplink.Clone.insert(clone)
|
||||
|
||||
return True
|
||||
|
||||
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)
|
||||
|
||||
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT:
|
||||
return
|
||||
|
||||
if not senderObj is None:
|
||||
senderMsg = ' '.join(srvmsg[4:])
|
||||
clone_obj = uplink.Clone.get_clone(srvmsg[3])
|
||||
|
||||
if clone_obj is None:
|
||||
return
|
||||
|
||||
if clone_obj.uid != uplink.Config.SERVICE_ID:
|
||||
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
|
||||
uplink.Protocol.send_priv_msg(
|
||||
nick_from=clone_obj.uid,
|
||||
msg=final_message,
|
||||
channel=uplink.Config.CLONE_CHANNEL
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
from typing import Union, TYPE_CHECKING
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
import mods.command.utils as utils
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.irc import Irc
|
||||
@@ -34,8 +35,11 @@ class Command:
|
||||
# Add Base object to the module (Mandatory)
|
||||
self.Base = ircInstance.Base
|
||||
|
||||
# Add main Utils to the module
|
||||
self.MainUtils = ircInstance.Utils
|
||||
|
||||
# Add logs object to the module (Mandatory)
|
||||
self.Logs = ircInstance.Base.logs
|
||||
self.Logs = ircInstance.Loader.Logs
|
||||
|
||||
# Add User object to the module (Mandatory)
|
||||
self.User = ircInstance.User
|
||||
@@ -46,6 +50,9 @@ class Command:
|
||||
# Add Channel object to the module (Mandatory)
|
||||
self.Channel = ircInstance.Channel
|
||||
|
||||
# Module Utils
|
||||
self.mod_utils = utils
|
||||
|
||||
self.Irc.build_command(1, self.module_name, 'join', 'Join a channel')
|
||||
self.Irc.build_command(1, self.module_name, 'assign', 'Assign a user to a role or task')
|
||||
self.Irc.build_command(1, self.module_name, 'part', 'Leave a channel')
|
||||
@@ -271,7 +278,7 @@ class Command:
|
||||
|
||||
user_uid = self.User.clean_uid(cmd[5])
|
||||
userObj: MUser = self.User.get_User(user_uid)
|
||||
channel_name = cmd[4] if self.Channel.Is_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)
|
||||
nickname = userObj.nickname if userObj is not None else None
|
||||
|
||||
@@ -296,7 +303,7 @@ class Command:
|
||||
except Exception as err:
|
||||
self.Logs.error(f"General Error: {err}")
|
||||
|
||||
def hcmds(self, uidornickname: str, channel_name: Union[str, None], cmd: list, fullcmd: list = []) -> None:
|
||||
def hcmds(self, uidornickname: str, channel_name: Optional[str], cmd: list, fullcmd: list = []):
|
||||
|
||||
command = str(cmd[0]).lower()
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
@@ -307,293 +314,78 @@ class Command:
|
||||
fromchannel = channel_name
|
||||
|
||||
match command:
|
||||
case "automode":
|
||||
# automode set nickname [+/-mode] #channel
|
||||
# automode set adator +o #channel
|
||||
|
||||
case 'automode':
|
||||
try:
|
||||
option: str = str(cmd[1]).lower()
|
||||
match option:
|
||||
case 'set':
|
||||
allowed_modes: list[str] = self.Base.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v']
|
||||
|
||||
if len(cmd) < 5:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}")
|
||||
return None
|
||||
|
||||
# userObj: MUser = self.User.get_User(str(cmd[2]))
|
||||
nickname = str(cmd[2])
|
||||
mode = str(cmd[3])
|
||||
chan: str = str(cmd[4]).lower() if self.Channel.Is_Channel(cmd[4]) else None
|
||||
sign = mode[0] if mode.startswith( ('+', '-')) else None
|
||||
clean_mode = mode[1:] if len(mode) > 0 else None
|
||||
|
||||
if sign is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -")
|
||||
return None
|
||||
|
||||
if clean_mode not in allowed_modes:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
||||
return None
|
||||
|
||||
if chan is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
||||
return None
|
||||
|
||||
db_data: dict[str, str] = {"nickname": nickname, "channel": chan}
|
||||
db_query = self.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data)
|
||||
db_result = db_query.fetchone()
|
||||
|
||||
if db_result is not None:
|
||||
if sign == '+':
|
||||
db_data = {"updated_on": self.Base.get_datetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
||||
db_result = self.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel",
|
||||
params=db_data)
|
||||
if db_result.rowcount > 0:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}")
|
||||
elif sign == '-':
|
||||
db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"}
|
||||
db_result = self.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode",
|
||||
params=db_data)
|
||||
if db_result.rowcount > 0:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}")
|
||||
else:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}")
|
||||
|
||||
return None
|
||||
|
||||
# Instert a new automode
|
||||
if sign == '+':
|
||||
db_data = {"created_on": self.Base.get_datetime(), "updated_on": self.Base.get_datetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
||||
db_query = self.Base.db_execute_query(
|
||||
query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)",
|
||||
params=db_data
|
||||
)
|
||||
|
||||
if db_query.rowcount > 0:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}")
|
||||
if self.Channel.is_user_present_in_channel(chan, self.User.get_uid(nickname)):
|
||||
self.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}")
|
||||
else:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist")
|
||||
|
||||
case 'list':
|
||||
db_query: CursorResult = self.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode")
|
||||
db_results: Sequence[Row] = db_query.fetchall()
|
||||
|
||||
if not db_results:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||
msg="There is no automode to display.")
|
||||
|
||||
for db_result in db_results:
|
||||
db_nickname, db_channel, db_mode = db_result
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||
msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}")
|
||||
|
||||
case _:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}")
|
||||
|
||||
self.mod_utils.set_automode(self, cmd, fromuser)
|
||||
except IndexError:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(self.Base.Settings.PROTOCTL_PREFIX)}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(self.Loader.Settings.PROTOCTL_PREFIX)}")
|
||||
except Exception as err:
|
||||
self.Logs.error(f"General Error: {err}")
|
||||
|
||||
case 'deopall':
|
||||
try:
|
||||
self.Protocol.send2socket(f":{service_id} SVSMODE {fromchannel} -o")
|
||||
|
||||
except IndexError as ie:
|
||||
self.Logs.warning(f'_hcmd OP: {str(ie)}')
|
||||
self.mod_utils.set_deopall(self, fromchannel)
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
self.Logs.error(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'devoiceall':
|
||||
try:
|
||||
self.Protocol.send2socket(f":{service_id} SVSMODE {fromchannel} -v")
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OP: {str(e)}')
|
||||
self.mod_utils.set_devoiceall(self, fromchannel)
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
self.Logs.error(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'voiceall':
|
||||
try:
|
||||
chan_info = self.Channel.get_Channel(fromchannel)
|
||||
set_mode = 'v'
|
||||
mode:str = ''
|
||||
users:str = ''
|
||||
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}")
|
||||
for uid in uids_split:
|
||||
for i in range(0, len(uid)):
|
||||
mode += set_mode
|
||||
users += f'{self.User.get_nickname(self.Base.clean_uid(uid[i]))} '
|
||||
if i == len(uid) - 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}")
|
||||
mode = ''
|
||||
users = ''
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OP: {str(e)}')
|
||||
self.mod_utils.set_mode_to_all(self, fromchannel, '+', 'v')
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'opall':
|
||||
try:
|
||||
chan_info = self.Channel.get_Channel(fromchannel)
|
||||
set_mode = 'o'
|
||||
mode:str = ''
|
||||
users:str = ''
|
||||
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}")
|
||||
for uid in uids_split:
|
||||
for i in range(0, len(uid)):
|
||||
mode += set_mode
|
||||
users += f'{self.User.get_nickname(self.Base.clean_uid(uid[i]))} '
|
||||
if i == len(uid) - 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}")
|
||||
mode = ''
|
||||
users = ''
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OP: {str(e)}')
|
||||
self.mod_utils.set_mode_to_all(self, fromchannel, '+', 'o')
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'op':
|
||||
# /mode #channel +o user
|
||||
# .op #channel user
|
||||
# /msg dnickname op #channel user
|
||||
# [':adator', 'PRIVMSG', '#services', ':.o', '#services', 'dktmb']
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} op [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{dnickname} MODE {fromchannel} +o {fromuser}")
|
||||
return True
|
||||
|
||||
# deop nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +o {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +o {nickname}")
|
||||
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+o')
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OP: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} op [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'deop':
|
||||
# /mode #channel -o user
|
||||
# .deop #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deop [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -o {fromuser}")
|
||||
return True
|
||||
|
||||
# deop nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -o {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -o {nickname}")
|
||||
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-o')
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd DEOP: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deop [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'owner':
|
||||
# /mode #channel +q user
|
||||
# .owner #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} owner [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +q {fromuser}")
|
||||
return True
|
||||
|
||||
# owner nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +q {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +q {nickname}")
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+q')
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OWNER: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} owner [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'deowner':
|
||||
# /mode #channel -q user
|
||||
# .deowner #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -q {fromuser}")
|
||||
return True
|
||||
|
||||
# deowner nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -q {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -q {nickname}")
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-q')
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd DEOWNER: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'protect':
|
||||
# /mode #channel +a user
|
||||
# .protect #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +a {fromuser}")
|
||||
return True
|
||||
|
||||
# deowner nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +a {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +a {nickname}")
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+a')
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd DEOWNER: {str(e)}')
|
||||
@@ -602,25 +394,8 @@ class Command:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'deprotect':
|
||||
# /mode #channel -a user
|
||||
# .deprotect #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -a {fromuser}")
|
||||
return True
|
||||
|
||||
# deowner nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -a {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -a {nickname}")
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-a')
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd DEOWNER: {str(e)}')
|
||||
@@ -629,125 +404,42 @@ class Command:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'halfop':
|
||||
# /mode #channel +h user
|
||||
# .halfop #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +h {fromuser}")
|
||||
return True
|
||||
|
||||
# deop nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +h {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +h {nickname}")
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+h')
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd halfop: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'dehalfop':
|
||||
# /mode #channel -h user
|
||||
# .dehalfop #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -h {fromuser}")
|
||||
return True
|
||||
|
||||
# dehalfop nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -h {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -h {nickname}")
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-h')
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd DEHALFOP: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'voice':
|
||||
# /mode #channel +v user
|
||||
# .voice #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} voice [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +v {fromuser}")
|
||||
return True
|
||||
|
||||
# voice nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +v {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} +v {nickname}")
|
||||
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '+v')
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd VOICE: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} voice [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'devoice':
|
||||
# /mode #channel -v user
|
||||
# .devoice #channel user
|
||||
try:
|
||||
if fromchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -v {fromuser}")
|
||||
return True
|
||||
|
||||
# dehalfop nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -v {nickname}")
|
||||
return True
|
||||
|
||||
nickname = cmd[2]
|
||||
self.Protocol.send2socket(f":{service_id} MODE {fromchannel} -v {nickname}")
|
||||
|
||||
self.mod_utils.set_operation(self, cmd, fromchannel, fromuser, '-v')
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd DEVOICE: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'ban':
|
||||
# .ban #channel nickname
|
||||
try:
|
||||
sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None
|
||||
if sentchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
nickname = cmd[2]
|
||||
|
||||
self.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*")
|
||||
self.Logs.debug(f'{fromuser} has banned {nickname} from {sentchannel}')
|
||||
self.mod_utils.set_ban(self, cmd, '+', fromuser)
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd BAN: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||
@@ -755,97 +447,43 @@ class Command:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'unban':
|
||||
# .unban #channel nickname
|
||||
try:
|
||||
sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None
|
||||
if sentchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} ban [#SALON] [NICKNAME]")
|
||||
return False
|
||||
nickname = cmd[2]
|
||||
|
||||
self.Protocol.send2socket(f":{service_id} MODE {sentchannel} -b {nickname}!*@*")
|
||||
self.Logs.debug(f'{fromuser} has unbanned {nickname} from {sentchannel}')
|
||||
|
||||
self.mod_utils.set_ban(self, cmd, '-', fromuser)
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd UNBAN: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} unban [#SALON] [NICKNAME]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'kick':
|
||||
# .kick #channel nickname reason
|
||||
try:
|
||||
sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None
|
||||
if sentchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} ban [#SALON] [NICKNAME]")
|
||||
return False
|
||||
nickname = cmd[2]
|
||||
final_reason = ' '.join(cmd[3:])
|
||||
|
||||
self.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
||||
self.Logs.debug(f'{fromuser} has kicked {nickname} from {sentchannel} : {final_reason}')
|
||||
|
||||
self.mod_utils.set_kick(self, cmd, fromuser)
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd KICK: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} kick [#SALON] [NICKNAME] [REASON]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME] [REASON]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'kickban':
|
||||
# .kickban #channel nickname reason
|
||||
try:
|
||||
sentchannel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None
|
||||
if sentchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} ban [#SALON] [NICKNAME]")
|
||||
return False
|
||||
nickname = cmd[2]
|
||||
final_reason = ' '.join(cmd[3:])
|
||||
|
||||
self.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
||||
self.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*")
|
||||
self.Logs.debug(f'{fromuser} has kicked and banned {nickname} from {sentchannel} : {final_reason}')
|
||||
|
||||
self.mod_utils.set_kickban(self, cmd, fromuser)
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd KICKBAN: {str(e)}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} kickban [#SALON] [NICKNAME] [REASON]")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME] [REASON]")
|
||||
except Exception as err:
|
||||
self.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'join' | 'assign':
|
||||
|
||||
try:
|
||||
sent_channel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None
|
||||
if sent_channel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}JOIN #channel")
|
||||
return False
|
||||
|
||||
# self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}')
|
||||
self.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel)
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} JOINED {sent_channel}")
|
||||
self.Channel.db_query_channel('add', self.module_name, sent_channel)
|
||||
|
||||
self.mod_utils.set_assign_channel_to_service(self, cmd, fromuser)
|
||||
except IndexError as ie:
|
||||
self.Logs.error(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:
|
||||
sent_channel = str(cmd[1]) if self.Channel.Is_Channel(cmd[1]) else None
|
||||
if sent_channel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}PART #channel")
|
||||
return False
|
||||
|
||||
if sent_channel == dchanlog:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL")
|
||||
return False
|
||||
|
||||
self.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel)
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} LEFT {sent_channel}")
|
||||
|
||||
self.Channel.db_query_channel('del', self.module_name, sent_channel)
|
||||
|
||||
self.mod_utils.set_unassign_channel_to_service(self, cmd, fromuser)
|
||||
except IndexError as ie:
|
||||
self.Logs.error(f'{ie}')
|
||||
except Exception as err:
|
||||
@@ -859,7 +497,7 @@ class Command:
|
||||
return None
|
||||
|
||||
chan = str(cmd[1])
|
||||
if not self.Channel.Is_Channel(chan):
|
||||
if not self.Channel.is_valid_channel(chan):
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE")
|
||||
return None
|
||||
@@ -959,7 +597,7 @@ class Command:
|
||||
|
||||
chan = str(cmd[1])
|
||||
|
||||
if not self.Channel.Is_Channel(chan):
|
||||
if not self.Channel.is_valid_channel(chan):
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel")
|
||||
return None
|
||||
@@ -980,7 +618,7 @@ class Command:
|
||||
nickname = str(cmd[1])
|
||||
chan = str(cmd[2])
|
||||
|
||||
if not self.Channel.Is_Channel(chan):
|
||||
if not self.Channel.is_valid_channel(chan):
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL")
|
||||
return None
|
||||
@@ -1051,7 +689,7 @@ class Command:
|
||||
|
||||
if len(cmd) == 2:
|
||||
channel_mode = cmd[1]
|
||||
if self.Channel.Is_Channel(fromchannel):
|
||||
if self.Channel.is_valid_channel(fromchannel):
|
||||
self.Protocol.send2socket(f":{dnickname} MODE {fromchannel} {channel_mode}")
|
||||
else:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Right command : Channel [{fromchannel}] is not correct should start with #")
|
||||
@@ -1146,7 +784,7 @@ class Command:
|
||||
# .svsnick nickname newnickname
|
||||
nickname = str(cmd[1])
|
||||
newnickname = str(cmd[2])
|
||||
unixtime = self.Base.get_unixtime()
|
||||
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")
|
||||
@@ -1192,7 +830,7 @@ class Command:
|
||||
|
||||
nickname = str(cmd[1])
|
||||
hostname = str(cmd[2])
|
||||
set_at_timestamp = self.Base.get_unixtime()
|
||||
set_at_timestamp = self.MainUtils.get_unixtime()
|
||||
expire_time = (60 * 60 * 24) + set_at_timestamp
|
||||
gline_reason = ' '.join(cmd[3:])
|
||||
|
||||
@@ -1201,7 +839,7 @@ class Command:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason")
|
||||
return None
|
||||
|
||||
self.Protocol.gline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason)
|
||||
self.Protocol.send_gline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason)
|
||||
|
||||
except KeyError as ke:
|
||||
self.Logs.error(ke)
|
||||
@@ -1222,7 +860,7 @@ class Command:
|
||||
hostname = str(cmd[2])
|
||||
|
||||
# self.Protocol.send2socket(f":{self.Config.SERVEUR_ID} TKL - G {nickname} {hostname} {dnickname}")
|
||||
self.Protocol.ungline(nickname=nickname, hostname=hostname)
|
||||
self.Protocol.send_ungline(nickname=nickname, hostname=hostname)
|
||||
|
||||
except KeyError as ke:
|
||||
self.Logs.error(ke)
|
||||
@@ -1240,7 +878,7 @@ class Command:
|
||||
|
||||
nickname = str(cmd[1])
|
||||
hostname = str(cmd[2])
|
||||
set_at_timestamp = self.Base.get_unixtime()
|
||||
set_at_timestamp = self.MainUtils.get_unixtime()
|
||||
expire_time = (60 * 60 * 24) + set_at_timestamp
|
||||
gline_reason = ' '.join(cmd[3:])
|
||||
|
||||
@@ -1249,7 +887,7 @@ class Command:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" /msg {dnickname} {command.upper()} nickname host reason")
|
||||
return None
|
||||
|
||||
self.Protocol.kline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason)
|
||||
self.Protocol.send_kline(nickname=nickname, hostname=hostname, set_by=dnickname, expire_timestamp=expire_time, set_at_timestamp=set_at_timestamp, reason=gline_reason)
|
||||
|
||||
except KeyError as ke:
|
||||
self.Logs.error(ke)
|
||||
@@ -1269,7 +907,7 @@ class Command:
|
||||
nickname = str(cmd[1])
|
||||
hostname = str(cmd[2])
|
||||
|
||||
self.Protocol.unkline(nickname=nickname, hostname=hostname)
|
||||
self.Protocol.send_unkline(nickname=nickname, hostname=hostname)
|
||||
|
||||
except KeyError as ke:
|
||||
self.Logs.error(ke)
|
||||
@@ -1288,7 +926,7 @@ class Command:
|
||||
|
||||
nickname = str(cmd[1])
|
||||
hostname = str(cmd[2])
|
||||
set_at_timestamp = self.Base.get_unixtime()
|
||||
set_at_timestamp = self.MainUtils.get_unixtime()
|
||||
expire_time = (60 * 60 * 24) + set_at_timestamp
|
||||
shun_reason = ' '.join(cmd[3:])
|
||||
|
||||
237
mods/command/utils.py
Normal file
237
mods/command/utils.py
Normal file
@@ -0,0 +1,237 @@
|
||||
from typing import TYPE_CHECKING, Literal, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.command.mod_command import Command
|
||||
|
||||
|
||||
def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||
|
||||
command: str = str(cmd[0]).lower()
|
||||
option: str = str(cmd[1]).lower()
|
||||
allowed_modes: list[str] = uplink.Loader.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v']
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
fromuser = client
|
||||
|
||||
match option:
|
||||
case 'set':
|
||||
if len(cmd) < 5:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]")
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}")
|
||||
return None
|
||||
|
||||
nickname = str(cmd[2])
|
||||
mode = str(cmd[3])
|
||||
chan: str = str(cmd[4]).lower() if uplink.Channel.is_valid_channel(cmd[4]) else None
|
||||
sign = mode[0] if mode.startswith( ('+', '-')) else None
|
||||
clean_mode = mode[1:] if len(mode) > 0 else None
|
||||
|
||||
if sign is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -")
|
||||
return None
|
||||
|
||||
if clean_mode not in allowed_modes:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
||||
return None
|
||||
|
||||
if chan is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
||||
return None
|
||||
|
||||
db_data: dict[str, str] = {"nickname": nickname, "channel": chan}
|
||||
db_query = uplink.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data)
|
||||
db_result = db_query.fetchone()
|
||||
|
||||
if db_result is not None:
|
||||
if sign == '+':
|
||||
db_data = {"updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
||||
db_result = uplink.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel",
|
||||
params=db_data)
|
||||
if db_result.rowcount > 0:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}")
|
||||
elif sign == '-':
|
||||
db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"}
|
||||
db_result = uplink.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode",
|
||||
params=db_data)
|
||||
if db_result.rowcount > 0:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}")
|
||||
else:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}")
|
||||
|
||||
return None
|
||||
|
||||
# Instert a new automode
|
||||
if sign == '+':
|
||||
db_data = {"created_on": uplink.MainUtils.get_sdatetime(), "updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
||||
db_query = uplink.Base.db_execute_query(
|
||||
query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)",
|
||||
params=db_data
|
||||
)
|
||||
|
||||
if db_query.rowcount > 0:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}")
|
||||
if uplink.Channel.is_user_present_in_channel(chan, uplink.User.get_uid(nickname)):
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}")
|
||||
else:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist")
|
||||
|
||||
case 'list':
|
||||
db_query = uplink.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode")
|
||||
db_results = db_query.fetchall()
|
||||
|
||||
if not db_results:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||
msg="There is no automode to display.")
|
||||
|
||||
for db_result in db_results:
|
||||
db_nickname, db_channel, db_mode = db_result
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||
msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}")
|
||||
|
||||
case _:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]")
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST")
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}")
|
||||
|
||||
def set_deopall(uplink: 'Command', channel_name: str) -> None:
|
||||
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o")
|
||||
return None
|
||||
|
||||
def set_devoiceall(uplink: 'Command', channel_name: str) -> None:
|
||||
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v")
|
||||
return None
|
||||
|
||||
def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None:
|
||||
|
||||
chan_info = uplink.Channel.get_channel(channel_name)
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
set_mode = pmode
|
||||
mode:str = ''
|
||||
users:str = ''
|
||||
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}")
|
||||
for uid in uids_split:
|
||||
for i in range(0, len(uid)):
|
||||
mode += set_mode
|
||||
users += f'{uplink.User.get_nickname(uplink.MainUtils.clean_uid(uid[i]))} '
|
||||
if i == len(uid) - 1:
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}")
|
||||
mode = ''
|
||||
users = ''
|
||||
|
||||
def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None:
|
||||
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
if channel_name is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
if len(cmd) == 1:
|
||||
uplink.Protocol.send2socket(f":{dnickname} MODE {channel_name} {mode} {client}")
|
||||
return None
|
||||
|
||||
# deop nickname
|
||||
if len(cmd) == 2:
|
||||
nickname = cmd[1]
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
||||
return None
|
||||
|
||||
nickname = cmd[2]
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
||||
return None
|
||||
|
||||
def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None:
|
||||
|
||||
command = str(cmd[0])
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
||||
|
||||
if sentchannel is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||
return None
|
||||
|
||||
nickname = cmd[2]
|
||||
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*")
|
||||
uplink.Logs.debug(f'{client} has banned {nickname} from {sentchannel}')
|
||||
return None
|
||||
|
||||
def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||
|
||||
command = str(cmd[0])
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
|
||||
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
||||
if sentchannel is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
||||
return False
|
||||
|
||||
nickname = cmd[2]
|
||||
final_reason = ' '.join(cmd[3:])
|
||||
|
||||
uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
||||
uplink.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}')
|
||||
return None
|
||||
|
||||
def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||
|
||||
command = str(cmd[0])
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
|
||||
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
||||
if sentchannel is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
||||
return False
|
||||
nickname = cmd[2]
|
||||
final_reason = ' '.join(cmd[3:])
|
||||
|
||||
uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*")
|
||||
uplink.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}')
|
||||
|
||||
def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||
|
||||
command = str(cmd[0])
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
||||
if sent_channel is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
|
||||
return None
|
||||
|
||||
# self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}')
|
||||
uplink.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel)
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}")
|
||||
uplink.Channel.db_query_channel('add', uplink.module_name, sent_channel)
|
||||
|
||||
return None
|
||||
|
||||
def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||
|
||||
command = str(cmd[0])
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
dchanlog = uplink.Config.SERVICE_CHANLOG
|
||||
|
||||
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
||||
if sent_channel is None:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
|
||||
return None
|
||||
|
||||
if sent_channel == dchanlog:
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]")
|
||||
return None
|
||||
|
||||
uplink.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel)
|
||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}")
|
||||
|
||||
uplink.Channel.db_query_channel('del', uplink.module_name, sent_channel)
|
||||
return None
|
||||
File diff suppressed because it is too large
Load Diff
35
mods/defender/schemas.py
Normal file
35
mods/defender/schemas.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from core.definition import MainModel, dataclass, MUser
|
||||
|
||||
@dataclass
|
||||
class ModConfModel(MainModel):
|
||||
reputation: int = 0
|
||||
reputation_timer: int = 1
|
||||
reputation_seuil: int = 26
|
||||
reputation_score_after_release: int = 27
|
||||
reputation_ban_all_chan: int = 0
|
||||
reputation_sg: int = 1
|
||||
local_scan: int = 0
|
||||
psutil_scan: int = 0
|
||||
abuseipdb_scan: int = 0
|
||||
freeipapi_scan: int = 0
|
||||
cloudfilt_scan: int = 0
|
||||
flood: int = 0
|
||||
flood_message: int = 5
|
||||
flood_time: int = 1
|
||||
flood_timer: int = 20
|
||||
autolimit: int = 0
|
||||
autolimit_amount: int = 3
|
||||
autolimit_interval: int = 3
|
||||
|
||||
@dataclass
|
||||
class FloodUser(MainModel):
|
||||
uid: str = None
|
||||
nbr_msg: int = 0
|
||||
first_msg_time: int = 0
|
||||
|
||||
DB_FLOOD_USERS: list[FloodUser] = []
|
||||
DB_ABUSEIPDB_USERS: list[MUser] = []
|
||||
DB_FREEIPAPI_USERS: list[MUser] = []
|
||||
DB_CLOUDFILT_USERS: list[MUser] = []
|
||||
DB_PSUTIL_USERS: list[MUser] = []
|
||||
DB_LOCALSCAN_USERS: list[MUser] = []
|
||||
167
mods/defender/threads.py
Normal file
167
mods/defender/threads.py
Normal file
@@ -0,0 +1,167 @@
|
||||
from typing import TYPE_CHECKING
|
||||
from time import sleep
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.defender.mod_defender import Defender
|
||||
|
||||
def thread_apply_reputation_sanctions(uplink: 'Defender'):
|
||||
while uplink.reputationTimer_isRunning:
|
||||
uplink.Utils.action_apply_reputation_santions(uplink)
|
||||
sleep(5)
|
||||
|
||||
def thread_cloudfilt_scan(uplink: 'Defender'):
|
||||
|
||||
while uplink.cloudfilt_isRunning:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_CLOUDFILT_USERS:
|
||||
uplink.Utils.action_scan_client_with_cloudfilt(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model)
|
||||
|
||||
sleep(1)
|
||||
|
||||
def thread_freeipapi_scan(uplink: 'Defender'):
|
||||
|
||||
while uplink.freeipapi_isRunning:
|
||||
|
||||
list_to_remove: list = []
|
||||
for user in uplink.Schemas.DB_FREEIPAPI_USERS:
|
||||
uplink.Utils.action_scan_client_with_freeipapi(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model)
|
||||
|
||||
sleep(1)
|
||||
|
||||
def thread_abuseipdb_scan(uplink: 'Defender'):
|
||||
|
||||
while uplink.abuseipdb_isRunning:
|
||||
|
||||
list_to_remove: list = []
|
||||
for user in uplink.Schemas.DB_ABUSEIPDB_USERS:
|
||||
uplink.Utils.action_scan_client_with_abuseipdb(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model)
|
||||
|
||||
sleep(1)
|
||||
|
||||
def thread_local_scan(uplink: 'Defender'):
|
||||
|
||||
while uplink.localscan_isRunning:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_LOCALSCAN_USERS:
|
||||
uplink.Utils.action_scan_client_with_local_socket(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model)
|
||||
|
||||
sleep(1)
|
||||
|
||||
def thread_psutil_scan(uplink: 'Defender'):
|
||||
|
||||
while uplink.psutil_isRunning:
|
||||
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_PSUTIL_USERS:
|
||||
uplink.Utils.action_scan_client_with_psutil(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_PSUTIL_USERS.remove(user_model)
|
||||
|
||||
sleep(1)
|
||||
|
||||
def thread_autolimit(uplink: 'Defender'):
|
||||
|
||||
if uplink.ModConfig.autolimit == 0:
|
||||
uplink.Logs.debug("autolimit deactivated ... canceling the thread")
|
||||
return None
|
||||
|
||||
while uplink.Irc.autolimit_started:
|
||||
sleep(0.2)
|
||||
|
||||
uplink.Irc.autolimit_started = True
|
||||
init_amount = uplink.ModConfig.autolimit_amount
|
||||
p = uplink.Protocol
|
||||
INIT = 1
|
||||
|
||||
# Copy Channels to a list of dict
|
||||
chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in uplink.Channel.UID_CHANNEL_DB]
|
||||
chan_list: list[str] = [c.name for c in uplink.Channel.UID_CHANNEL_DB]
|
||||
|
||||
while uplink.autolimit_isRunning:
|
||||
|
||||
if uplink.ModConfig.autolimit == 0:
|
||||
uplink.Logs.debug("autolimit deactivated ... stopping the current thread")
|
||||
break
|
||||
|
||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
||||
for chan_copy in chanObj_copy:
|
||||
if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]:
|
||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}")
|
||||
chan_copy["uids_count"] = len(chan.uids)
|
||||
|
||||
if chan.name not in chan_list:
|
||||
chan_list.append(chan.name)
|
||||
chanObj_copy.append({"name": chan.name, "uids_count": 0})
|
||||
|
||||
# Verifier si un salon a été vidé
|
||||
current_chan_in_list = [d.name for d in uplink.Channel.UID_CHANNEL_DB]
|
||||
for c in chan_list:
|
||||
if c not in current_chan_in_list:
|
||||
chan_list.remove(c)
|
||||
|
||||
# Si c'est la premiere execution
|
||||
if INIT == 1:
|
||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}")
|
||||
|
||||
# Si le nouveau amount est différent de l'initial
|
||||
if init_amount != uplink.ModConfig.autolimit_amount:
|
||||
init_amount = uplink.ModConfig.autolimit_amount
|
||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}")
|
||||
|
||||
INIT = 0
|
||||
|
||||
if uplink.autolimit_isRunning:
|
||||
sleep(uplink.ModConfig.autolimit_interval)
|
||||
|
||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} -l")
|
||||
|
||||
uplink.Irc.autolimit_started = False
|
||||
|
||||
return None
|
||||
|
||||
def timer_release_mode_mute(uplink: 'Defender', action: str, channel: str):
|
||||
"""DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING
|
||||
|
||||
Args:
|
||||
action (str): _description_
|
||||
channel (str): The related channel
|
||||
|
||||
"""
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
|
||||
if not uplink.Channel.is_valid_channel(channel):
|
||||
uplink.Logs.debug(f"Channel is not valid {channel}")
|
||||
return
|
||||
|
||||
match action:
|
||||
case 'mode-m':
|
||||
# Action -m sur le salon
|
||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel} -m")
|
||||
case _:
|
||||
pass
|
||||
710
mods/defender/utils.py
Normal file
710
mods/defender/utils.py
Normal file
@@ -0,0 +1,710 @@
|
||||
from calendar import c
|
||||
import socket
|
||||
import psutil
|
||||
import requests
|
||||
import mods.defender.threads as dthreads
|
||||
from json import loads
|
||||
from re import match
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from mods.defender.schemas import FloodUser
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MUser
|
||||
from mods.defender.mod_defender import Defender
|
||||
|
||||
def handle_on_reputation(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""Handle reputation server message
|
||||
>>> srvmsg = [':001', 'REPUTATION', '128.128.128.128', '0']
|
||||
>>> srvmsg = [':001', 'REPUTATION', '128.128.128.128', '*0']
|
||||
Args:
|
||||
irc_instance (Irc): The Irc instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
"""
|
||||
ip = srvmsg[2]
|
||||
score = srvmsg[3]
|
||||
|
||||
if str(ip).find('*') != -1:
|
||||
# If the reputation changed, we do not need to scan the IP
|
||||
return
|
||||
|
||||
# Possibilité de déclancher les bans a ce niveau.
|
||||
if not uplink.Base.is_valid_ip(ip):
|
||||
return
|
||||
|
||||
def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""_summary_
|
||||
>>> srvmsg = ['@unrealircd.org/...', ':001C0MF01', 'MODE', '#services', '+l', '1']
|
||||
>>> srvmsg = ['...', ':001XSCU0Q', 'MODE', '#jail', '+b', '~security-group:unknown-users']
|
||||
Args:
|
||||
irc_instance (Irc): The Irc instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
confmodel (ModConfModel): The Module Configuration
|
||||
"""
|
||||
irc = uplink.Irc
|
||||
gconfig = uplink.Config
|
||||
p = uplink.Protocol
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
channel = str(srvmsg[3])
|
||||
mode = str(srvmsg[4])
|
||||
group_to_check = str(srvmsg[5:])
|
||||
group_to_unban = '~security-group:unknown-users'
|
||||
|
||||
if confmodel.autolimit == 1:
|
||||
if mode == '+l' or mode == '-l':
|
||||
chan = irc.Channel.get_channel(channel)
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}")
|
||||
|
||||
if gconfig.SALON_JAIL == channel:
|
||||
if mode == '+b' and group_to_unban in group_to_check:
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users")
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
||||
|
||||
def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]):
|
||||
# ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg']
|
||||
action_on_flood(uplink, srvmsg)
|
||||
return None
|
||||
|
||||
def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""If Joining a new channel, it applies group bans.
|
||||
|
||||
>>> srvmsg = ['@msgid..', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL']
|
||||
|
||||
Args:
|
||||
irc_instance (Irc): The Irc instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
confmodel (ModConfModel): The Module Configuration
|
||||
"""
|
||||
irc = uplink.Irc
|
||||
p = irc.Protocol
|
||||
gconfig = uplink.Config
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
parsed_chan = srvmsg[4] if irc.Channel.is_valid_channel(srvmsg[4]) else None
|
||||
parsed_UID = uplink.Loader.Utils.clean_uid(srvmsg[5])
|
||||
|
||||
if parsed_chan is None or parsed_UID is None:
|
||||
return
|
||||
|
||||
if confmodel.reputation == 1:
|
||||
get_reputation = irc.Reputation.get_Reputation(parsed_UID)
|
||||
|
||||
if parsed_chan != gconfig.SALON_JAIL:
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users")
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
||||
|
||||
if get_reputation is not None:
|
||||
isWebirc = get_reputation.isWebirc
|
||||
|
||||
if not isWebirc:
|
||||
if parsed_chan != gconfig.SALON_JAIL:
|
||||
p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan)
|
||||
|
||||
if confmodel.reputation_ban_all_chan == 1 and not isWebirc:
|
||||
if parsed_chan != gconfig.SALON_JAIL:
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*")
|
||||
p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}")
|
||||
|
||||
irc.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}')
|
||||
|
||||
def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""Handling SLOG messages
|
||||
>>> srvmsg = ['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)']
|
||||
Args:
|
||||
irc_instance (Irc): The Irc instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
confmodel (ModConfModel): The Module Configuration
|
||||
"""
|
||||
['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)']
|
||||
|
||||
if not uplink.Base.is_valid_ip(srvmsg[8]):
|
||||
return None
|
||||
|
||||
# if self.ModConfig.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||
# self.localscan_remote_ip.append(cmd[7])
|
||||
|
||||
# if self.ModConfig.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||
# self.psutil_remote_ip.append(cmd[7])
|
||||
|
||||
# if self.ModConfig.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||
# self.abuseipdb_remote_ip.append(cmd[7])
|
||||
|
||||
# if self.ModConfig.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||
# self.freeipapi_remote_ip.append(cmd[7])
|
||||
|
||||
# if self.ModConfig.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||
# self.cloudfilt_remote_ip.append(cmd[7])
|
||||
|
||||
return None
|
||||
|
||||
def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""_summary_
|
||||
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712']
|
||||
Args:
|
||||
irc_instance (Irc): The Irc instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
confmodel (ModConfModel): The Module Configuration
|
||||
"""
|
||||
uid = uplink.Loader.Utils.clean_uid(str(srvmsg[1]))
|
||||
p = uplink.Protocol
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
get_reputation = uplink.Reputation.get_Reputation(uid)
|
||||
jail_salon = uplink.Config.SALON_JAIL
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
|
||||
if get_reputation is None:
|
||||
uplink.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass')
|
||||
return None
|
||||
|
||||
# Update the new nickname
|
||||
oldnick = get_reputation.nickname
|
||||
newnickname = srvmsg[3]
|
||||
get_reputation.nickname = newnickname
|
||||
|
||||
# If ban in all channel is ON then unban old nickname an ban the new nickname
|
||||
if confmodel.reputation_ban_all_chan == 1:
|
||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != jail_salon:
|
||||
p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*")
|
||||
p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*")
|
||||
|
||||
def handle_on_quit(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""_summary_
|
||||
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'QUIT', ':Quit:', 'quit message']
|
||||
Args:
|
||||
uplink (Irc): The Defender Module instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
"""
|
||||
p = uplink.Protocol
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan)
|
||||
final_UID = uplink.Loader.Utils.clean_uid(str(srvmsg[1]))
|
||||
jail_salon = uplink.Config.SALON_JAIL
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
get_user_reputation = uplink.Reputation.get_Reputation(final_UID)
|
||||
|
||||
if get_user_reputation is not None:
|
||||
final_nickname = get_user_reputation.nickname
|
||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != jail_salon and ban_all_chan == 1:
|
||||
p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*")
|
||||
uplink.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}")
|
||||
|
||||
uplink.Reputation.delete(final_UID)
|
||||
uplink.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB")
|
||||
|
||||
def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
||||
"""_summary_
|
||||
>>> ['@s2s-md...', ':001', 'UID', 'nickname', '0', '1754675249', '...', '125-168-141-239.hostname.net', '001BAPN8M',
|
||||
'0', '+iwx', '*', '32001BBE.25ACEFE7.429FE90D.IP', 'ZA2ic7w==', ':realname']
|
||||
|
||||
Args:
|
||||
uplink (Defender): The Defender instance
|
||||
srvmsg (list[str]): The Server MSG
|
||||
"""
|
||||
gconfig = uplink.Config
|
||||
irc = uplink.Irc
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
# If Init then do nothing
|
||||
if gconfig.DEFENDER_INIT == 1:
|
||||
return None
|
||||
|
||||
# Get User information
|
||||
_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')
|
||||
return
|
||||
|
||||
# If user is not service or IrcOp then scan them
|
||||
if not match(r'^.*[S|o?].*$', _User.umodes):
|
||||
uplink.Schemas.DB_ABUSEIPDB_USERS.append(_User) if confmodel.abuseipdb_scan == 1 and _User.remote_ip not in gconfig.WHITELISTED_IP else None
|
||||
uplink.Schemas.DB_FREEIPAPI_USERS.append(_User) if confmodel.freeipapi_scan == 1 and _User.remote_ip not in gconfig.WHITELISTED_IP else None
|
||||
uplink.Schemas.DB_CLOUDFILT_USERS.append(_User) if confmodel.cloudfilt_scan == 1 and _User.remote_ip not in gconfig.WHITELISTED_IP else None
|
||||
uplink.Schemas.DB_PSUTIL_USERS.append(_User) if confmodel.psutil_scan == 1 and _User.remote_ip not in gconfig.WHITELISTED_IP else None
|
||||
uplink.Schemas.DB_LOCALSCAN_USERS.append(_User) if confmodel.local_scan == 1 and _User.remote_ip not in gconfig.WHITELISTED_IP else None
|
||||
|
||||
reputation_flag = confmodel.reputation
|
||||
reputation_seuil = confmodel.reputation_seuil
|
||||
|
||||
if gconfig.DEFENDER_INIT == 0:
|
||||
# Si le user n'es pas un service ni un IrcOP
|
||||
if not match(r'^.*[S|o?].*$', _User.umodes):
|
||||
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
|
||||
# currentDateTime = self.Base.get_datetime()
|
||||
irc.Reputation.insert(
|
||||
irc.Loader.Definition.MReputation(
|
||||
**_User.to_dict(),
|
||||
secret_code=irc.Utils.generate_random_string(8)
|
||||
)
|
||||
)
|
||||
if irc.Reputation.is_exist(_User.uid):
|
||||
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
|
||||
action_add_reputation_sanctions(uplink, _User.uid)
|
||||
irc.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})')
|
||||
|
||||
####################
|
||||
# ACTION FUNCTIONS #
|
||||
####################
|
||||
|
||||
def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
||||
|
||||
confmodel = uplink.ModConfig
|
||||
if confmodel.flood == 0:
|
||||
return None
|
||||
|
||||
irc = uplink.Irc
|
||||
gconfig = uplink.Config
|
||||
p = uplink.Protocol
|
||||
flood_users = uplink.Schemas.DB_FLOOD_USERS
|
||||
|
||||
user_trigger = str(srvmsg[1]).replace(':','')
|
||||
channel = srvmsg[3]
|
||||
User = irc.User.get_User(user_trigger)
|
||||
|
||||
if User is None or not irc.Channel.is_valid_channel(channel_to_check=channel):
|
||||
return
|
||||
|
||||
flood_time = confmodel.flood_time
|
||||
flood_message = confmodel.flood_message
|
||||
flood_timer = confmodel.flood_timer
|
||||
service_id = gconfig.SERVICE_ID
|
||||
dnickname = gconfig.SERVICE_NICKNAME
|
||||
color_red = gconfig.COLORS.red
|
||||
color_bold = gconfig.COLORS.bold
|
||||
|
||||
get_detected_uid = User.uid
|
||||
get_detected_nickname = User.nickname
|
||||
unixtime = irc.Utils.get_unixtime()
|
||||
get_diff_secondes = 0
|
||||
|
||||
def get_flood_user(uid: str) -> Optional[FloodUser]:
|
||||
for flood_user in flood_users:
|
||||
if flood_user.uid == uid:
|
||||
return flood_user
|
||||
|
||||
fu = get_flood_user(get_detected_uid)
|
||||
if fu is None:
|
||||
fu = FloodUser(get_detected_uid, 0, unixtime)
|
||||
flood_users.append(fu)
|
||||
|
||||
fu.nbr_msg += 1
|
||||
|
||||
get_diff_secondes = unixtime - fu.first_msg_time
|
||||
if get_diff_secondes > flood_time:
|
||||
fu.first_msg_time = unixtime
|
||||
fu.nbr_msg = 0
|
||||
get_diff_secondes = unixtime - fu.first_msg_time
|
||||
elif fu.nbr_msg > flood_message:
|
||||
irc.Logs.info('system de flood detecté')
|
||||
p.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)",
|
||||
channel=channel
|
||||
)
|
||||
p.send2socket(f":{service_id} MODE {channel} +m")
|
||||
irc.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}')
|
||||
fu.nbr_msg = 0
|
||||
fu.first_msg_time = unixtime
|
||||
irc.Base.create_timer(flood_timer, dthreads.timer_release_mode_mute, (uplink, 'mode-m', channel))
|
||||
|
||||
def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
||||
|
||||
irc = uplink.Irc
|
||||
gconfig = uplink.Config
|
||||
p = uplink.Protocol
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
get_reputation = irc.Reputation.get_Reputation(jailed_uid)
|
||||
|
||||
if get_reputation is None:
|
||||
irc.Logs.warning(f'UID {jailed_uid} has not been found')
|
||||
return
|
||||
|
||||
salon_logs = gconfig.SERVICE_CHANLOG
|
||||
salon_jail = gconfig.SALON_JAIL
|
||||
|
||||
code = get_reputation.secret_code
|
||||
jailed_nickname = get_reputation.nickname
|
||||
jailed_score = get_reputation.score_connexion
|
||||
|
||||
color_red = gconfig.COLORS.red
|
||||
color_black = gconfig.COLORS.black
|
||||
color_bold = gconfig.COLORS.bold
|
||||
nogc = gconfig.COLORS.nogc
|
||||
service_id = gconfig.SERVICE_ID
|
||||
service_prefix = gconfig.SERVICE_PREFIX
|
||||
reputation_ban_all_chan = confmodel.reputation_ban_all_chan
|
||||
|
||||
if not get_reputation.isWebirc:
|
||||
# Si le user ne vient pas de webIrc
|
||||
p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail)
|
||||
p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME,
|
||||
msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}",
|
||||
channel=salon_logs
|
||||
)
|
||||
p.send_notice(
|
||||
nick_from=gconfig.SERVICE_NICKNAME,
|
||||
nick_to=jailed_nickname,
|
||||
msg=f"[{color_red} {jailed_nickname} {color_black}] : Merci de tapez la commande suivante {color_bold}{service_prefix}code {code}{color_bold}"
|
||||
)
|
||||
if reputation_ban_all_chan == 1:
|
||||
for chan in irc.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != salon_jail:
|
||||
p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*")
|
||||
p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}")
|
||||
|
||||
irc.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})")
|
||||
else:
|
||||
irc.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)")
|
||||
irc.Reputation.delete(jailed_uid)
|
||||
|
||||
def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
||||
|
||||
irc = uplink.Irc
|
||||
gconfig = uplink.Config
|
||||
p = uplink.Protocol
|
||||
confmodel = uplink.ModConfig
|
||||
|
||||
reputation_flag = confmodel.reputation
|
||||
reputation_timer = confmodel.reputation_timer
|
||||
reputation_seuil = confmodel.reputation_seuil
|
||||
ban_all_chan = confmodel.reputation_ban_all_chan
|
||||
service_id = gconfig.SERVICE_ID
|
||||
dchanlog = gconfig.SERVICE_CHANLOG
|
||||
color_red = gconfig.COLORS.red
|
||||
nogc = gconfig.COLORS.nogc
|
||||
salon_jail = gconfig.SALON_JAIL
|
||||
|
||||
if reputation_flag == 0:
|
||||
return None
|
||||
elif reputation_timer == 0:
|
||||
return None
|
||||
|
||||
uid_to_clean = []
|
||||
|
||||
for user in irc.Reputation.UID_REPUTATION_DB:
|
||||
if not user.isWebirc: # Si il ne vient pas de WebIRC
|
||||
if irc.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil):
|
||||
p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité",
|
||||
channel=dchanlog
|
||||
)
|
||||
p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code")
|
||||
p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0")
|
||||
|
||||
irc.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity")
|
||||
uid_to_clean.append(user.uid)
|
||||
|
||||
for uid in uid_to_clean:
|
||||
# Suppression des éléments dans {UID_DB} et {REPUTATION_DB}
|
||||
for chan in irc.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != salon_jail and ban_all_chan == 1:
|
||||
get_user_reputation = irc.Reputation.get_Reputation(uid)
|
||||
p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*")
|
||||
|
||||
# Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}.
|
||||
irc.Channel.delete_user_from_all_channel(uid)
|
||||
irc.Reputation.delete(uid)
|
||||
irc.User.delete(uid)
|
||||
|
||||
def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""Analyse l'ip avec cloudfilt
|
||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||
Args:
|
||||
uplink (Defender): Defender Instance
|
||||
|
||||
Returns:
|
||||
dict[str, any] | None: les informations du provider
|
||||
keys : 'countryCode', 'isProxy'
|
||||
"""
|
||||
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
p = uplink.Protocol
|
||||
|
||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.ModConfig.cloudfilt_scan == 0:
|
||||
return None
|
||||
if uplink.cloudfilt_key == '':
|
||||
return None
|
||||
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
service_chanlog = uplink.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.Config.COLORS.red
|
||||
nogc = uplink.Config.COLORS.nogc
|
||||
|
||||
url = "https://developers18334.cloudfilt.com/"
|
||||
|
||||
data = {
|
||||
'ip': remote_ip,
|
||||
'key': uplink.cloudfilt_key
|
||||
}
|
||||
|
||||
response = requests.post(url=url, data=data)
|
||||
# Formatted output
|
||||
decoded_response: dict = loads(response.text)
|
||||
status_code = response.status_code
|
||||
if status_code != 200:
|
||||
uplink.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
|
||||
return
|
||||
|
||||
result = {
|
||||
'countryiso': decoded_response.get('countryiso', None),
|
||||
'listed': decoded_response.get('listed', None),
|
||||
'listed_by': decoded_response.get('listed_by', None),
|
||||
'host': decoded_response.get('host', None)
|
||||
}
|
||||
|
||||
# pseudo!ident@host
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}",
|
||||
channel=service_chanlog)
|
||||
|
||||
uplink.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}")
|
||||
|
||||
if result['listed']:
|
||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
|
||||
uplink.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}")
|
||||
|
||||
response.close()
|
||||
|
||||
return result
|
||||
|
||||
def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""Analyse l'ip avec Freeipapi
|
||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||
Args:
|
||||
uplink (Defender): The Defender object Instance
|
||||
|
||||
Returns:
|
||||
dict[str, any] | None: les informations du provider
|
||||
keys : 'countryCode', 'isProxy'
|
||||
"""
|
||||
p = uplink.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
|
||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.ModConfig.freeipapi_scan == 0:
|
||||
return None
|
||||
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
service_chanlog = uplink.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.Config.COLORS.red
|
||||
nogc = uplink.Config.COLORS.nogc
|
||||
|
||||
url = f'https://freeipapi.com/api/json/{remote_ip}'
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
|
||||
response = requests.request(method='GET', url=url, headers=headers, timeout=uplink.timeout)
|
||||
|
||||
# Formatted output
|
||||
decoded_response: dict = loads(response.text)
|
||||
|
||||
status_code = response.status_code
|
||||
if status_code == 429:
|
||||
uplink.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.')
|
||||
return None
|
||||
elif status_code != 200:
|
||||
uplink.Logs.warning(f'status code = {str(status_code)}')
|
||||
return None
|
||||
|
||||
result = {
|
||||
'countryCode': decoded_response.get('countryCode', None),
|
||||
'isProxy': decoded_response.get('isProxy', None)
|
||||
}
|
||||
|
||||
# pseudo!ident@host
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}",
|
||||
channel=service_chanlog)
|
||||
uplink.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}")
|
||||
|
||||
if result['isProxy']:
|
||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
|
||||
uplink.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}")
|
||||
|
||||
response.close()
|
||||
|
||||
return result
|
||||
|
||||
def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""Analyse l'ip avec AbuseIpDB
|
||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||
Args:
|
||||
uplink (Defender): Defender instance object
|
||||
user_model (MUser): l'objet User qui contient l'ip
|
||||
|
||||
Returns:
|
||||
dict[str, str] | None: les informations du provider
|
||||
"""
|
||||
p = uplink.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
|
||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.ModConfig.abuseipdb_scan == 0:
|
||||
return None
|
||||
|
||||
if uplink.abuseipdb_key == '':
|
||||
return None
|
||||
|
||||
url = 'https://api.abuseipdb.com/api/v2/check'
|
||||
querystring = {
|
||||
'ipAddress': remote_ip,
|
||||
'maxAgeInDays': '90'
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
'Key': uplink.abuseipdb_key
|
||||
}
|
||||
|
||||
response = requests.request(method='GET', url=url, headers=headers, params=querystring, timeout=uplink.timeout)
|
||||
|
||||
# Formatted output
|
||||
decoded_response: dict[str, dict] = loads(response.text)
|
||||
|
||||
if 'data' not in decoded_response:
|
||||
return None
|
||||
|
||||
result = {
|
||||
'score': decoded_response.get('data', {}).get('abuseConfidenceScore', 0),
|
||||
'country': decoded_response.get('data', {}).get('countryCode', None),
|
||||
'isTor': decoded_response.get('data', {}).get('isTor', None),
|
||||
'totalReports': decoded_response.get('data', {}).get('totalReports', 0)
|
||||
}
|
||||
|
||||
service_id = uplink.Config.SERVICE_ID
|
||||
service_chanlog = uplink.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.Config.COLORS.red
|
||||
nogc = uplink.Config.COLORS.nogc
|
||||
|
||||
# pseudo!ident@host
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}",
|
||||
channel=service_chanlog
|
||||
)
|
||||
uplink.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}")
|
||||
|
||||
if result['isTor']:
|
||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
|
||||
uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}")
|
||||
elif result['score'] >= 95:
|
||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
|
||||
uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}")
|
||||
|
||||
response.close()
|
||||
|
||||
return result
|
||||
|
||||
def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'):
|
||||
"""local_scan
|
||||
|
||||
Args:
|
||||
uplink (Defender): Defender instance object
|
||||
user_model (MUser): l'objet User qui contient l'ip
|
||||
"""
|
||||
p = uplink.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
||||
return None
|
||||
|
||||
for port in uplink.Config.PORTS_TO_SCAN:
|
||||
try:
|
||||
newSocket = ''
|
||||
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
|
||||
newSocket.settimeout(0.5)
|
||||
|
||||
connection = (remote_ip, uplink.Base.int_if_possible(port))
|
||||
newSocket.connect(connection)
|
||||
|
||||
p.send_priv_msg(
|
||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
||||
msg=f"[ {uplink.Config.COLORS.red}PROXY_SCAN{uplink.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]",
|
||||
channel=uplink.Config.SERVICE_CHANLOG
|
||||
)
|
||||
# print(f"=======> Le port {str(port)} est ouvert !!")
|
||||
uplink.Base.running_sockets.append(newSocket)
|
||||
# print(newSocket)
|
||||
newSocket.shutdown(socket.SHUT_RDWR)
|
||||
newSocket.close()
|
||||
|
||||
except (socket.timeout, ConnectionRefusedError):
|
||||
uplink.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé")
|
||||
except AttributeError as ae:
|
||||
uplink.Logs.warning(f"AttributeError ({remote_ip}): {ae}")
|
||||
except socket.gaierror as err:
|
||||
uplink.Logs.warning(f"Address Info Error ({remote_ip}): {err}")
|
||||
finally:
|
||||
# newSocket.shutdown(socket.SHUT_RDWR)
|
||||
newSocket.close()
|
||||
uplink.Logs.info('=======> Fermeture de la socket')
|
||||
|
||||
def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]:
|
||||
"""psutil_scan for Linux (should be run on the same location as the unrealircd server)
|
||||
|
||||
Args:
|
||||
userModel (UserModel): The User Model Object
|
||||
|
||||
Returns:
|
||||
list[int]: list of ports
|
||||
"""
|
||||
p = uplink.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
|
||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
||||
return None
|
||||
|
||||
try:
|
||||
connections = psutil.net_connections(kind='inet')
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
|
||||
uplink.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}")
|
||||
|
||||
if matching_ports:
|
||||
p.send_priv_msg(
|
||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
||||
msg=f"[ {uplink.Config.COLORS.red}PSUTIL_SCAN{uplink.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}",
|
||||
channel=uplink.Config.SERVICE_CHANLOG
|
||||
)
|
||||
|
||||
return matching_ports
|
||||
|
||||
except psutil.AccessDenied as ad:
|
||||
uplink.Logs.critical(f'psutil_scan: Permission error: {ad}')
|
||||
@@ -1,7 +1,12 @@
|
||||
import logging
|
||||
import asyncio
|
||||
import mods.jsonrpc.utils as utils
|
||||
import mods.jsonrpc.threads as thds
|
||||
from time import sleep
|
||||
from types import SimpleNamespace
|
||||
from typing import TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
from unrealircd_rpc_py.Live import LiveWebsocket
|
||||
from unrealircd_rpc_py.Live import LiveWebsocket, LiveUnixSocket
|
||||
from unrealircd_rpc_py.Loader import Loader
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -32,8 +37,11 @@ class Jsonrpc():
|
||||
# Add Base object to the module (Mandatory)
|
||||
self.Base = ircInstance.Base
|
||||
|
||||
# Add Main Utils (Mandatory)
|
||||
self.MainUtils = ircInstance.Utils
|
||||
|
||||
# Add logs object to the module (Mandatory)
|
||||
self.Logs = ircInstance.Base.logs
|
||||
self.Logs = ircInstance.Loader.Logs
|
||||
|
||||
# Add User object to the module (Mandatory)
|
||||
self.User = ircInstance.User
|
||||
@@ -41,9 +49,22 @@ class Jsonrpc():
|
||||
# Add Channel object to the module (Mandatory)
|
||||
self.Channel = ircInstance.Channel
|
||||
|
||||
# Is RPC Active?
|
||||
self.is_streaming = False
|
||||
|
||||
# Module Utils
|
||||
self.Utils = utils
|
||||
|
||||
# Module threads
|
||||
self.Threads = thds
|
||||
|
||||
# Run Garbage collector.
|
||||
self.Base.create_timer(10, self.MainUtils.run_python_garbage_collector)
|
||||
|
||||
# Create module commands (Mandatory)
|
||||
self.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]')
|
||||
self.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC')
|
||||
self.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances')
|
||||
|
||||
# Init the module
|
||||
self.__init_module()
|
||||
@@ -55,6 +76,7 @@ class Jsonrpc():
|
||||
|
||||
logging.getLogger('websockets').setLevel(logging.WARNING)
|
||||
logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('unrealircd-liverpc-py').setLevel(logging.CRITICAL)
|
||||
|
||||
# Create you own tables (Mandatory)
|
||||
# self.__create_tables()
|
||||
@@ -70,15 +92,15 @@ class Jsonrpc():
|
||||
callback_object_instance=self,
|
||||
callback_method_or_function_name='callback_sent_to_irc'
|
||||
)
|
||||
|
||||
|
||||
if self.UnrealIrcdRpcLive.get_error.code != 0:
|
||||
self.Logs.error(self.UnrealIrcdRpcLive.get_error.code, self.UnrealIrcdRpcLive.get_error.message)
|
||||
self.Logs.error(f"{self.UnrealIrcdRpcLive.get_error.message} ({self.UnrealIrcdRpcLive.get_error.code})")
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.get_error.message}",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
return
|
||||
raise Exception(f"[LIVE-JSONRPC ERROR] {self.UnrealIrcdRpcLive.get_error.message}")
|
||||
|
||||
self.Rpc: Loader = Loader(
|
||||
req_method=self.Config.JSONRPC_METHOD,
|
||||
@@ -88,18 +110,17 @@ class Jsonrpc():
|
||||
)
|
||||
|
||||
if self.Rpc.get_error.code != 0:
|
||||
self.Logs.error(self.Rpc.get_error.code, self.Rpc.get_error.message)
|
||||
self.Logs.error(f"{self.Rpc.get_error.message} ({self.Rpc.get_error.code})")
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.Rpc.get_error.message}",
|
||||
msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {self.Rpc.get_error.message}",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
|
||||
self.subscribed = False
|
||||
raise Exception(f"[JSONRPC ERROR] {self.Rpc.get_error.message}")
|
||||
|
||||
if self.ModConfig.jsonrpc == 1:
|
||||
self.Base.create_thread(self.thread_start_jsonrpc, run_once=True)
|
||||
|
||||
self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True)
|
||||
|
||||
return None
|
||||
|
||||
def __create_tables(self) -> None:
|
||||
@@ -122,7 +143,7 @@ class Jsonrpc():
|
||||
self.Base.db_execute_query(table_logs)
|
||||
return None
|
||||
|
||||
def callback_sent_to_irc(self, response):
|
||||
def callback_sent_to_irc(self, response: SimpleNamespace) -> None:
|
||||
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
dchanlog = self.Config.SERVICE_CHANLOG
|
||||
@@ -131,13 +152,29 @@ class Jsonrpc():
|
||||
bold = self.Config.COLORS.bold
|
||||
red = self.Config.COLORS.red
|
||||
|
||||
if hasattr(response, 'result'):
|
||||
if isinstance(response.result, bool) and response.result:
|
||||
if self.UnrealIrcdRpcLive.get_error.code != 0:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"[{bold}{red}JSONRPC ERROR{nogc}{bold}] {self.UnrealIrcdRpcLive.get_error.message}",
|
||||
channel=dchanlog)
|
||||
return None
|
||||
|
||||
if hasattr(response, 'error'):
|
||||
if response.error.code != 0:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{bold}{green}JSONRPC{nogc}{bold}] Event activated",
|
||||
channel=dchanlog)
|
||||
return None
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{bold}{red}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.Config.JSONRPC_URL}",
|
||||
channel=dchanlog)
|
||||
|
||||
return None
|
||||
|
||||
if hasattr(response, 'result'):
|
||||
if isinstance(response.result, bool):
|
||||
if response.result:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{bold}{green}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.Config.JSONRPC_URL}",
|
||||
channel=dchanlog)
|
||||
return None
|
||||
|
||||
level = response.result.level if hasattr(response.result, 'level') else ''
|
||||
subsystem = response.result.subsystem if hasattr(response.result, 'subsystem') else ''
|
||||
@@ -146,24 +183,9 @@ class Jsonrpc():
|
||||
msg = response.result.msg if hasattr(response.result, 'msg') else ''
|
||||
|
||||
build_msg = f"{green}{log_source}{nogc}: [{bold}{level}{bold}] {subsystem}.{event_id} - {msg}"
|
||||
|
||||
# Check if there is an error
|
||||
if self.UnrealIrcdRpcLive.get_error.code != 0:
|
||||
self.Logs.error(f"RpcLiveError: {self.UnrealIrcdRpcLive.get_error.message}")
|
||||
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg=build_msg, channel=dchanlog)
|
||||
|
||||
def thread_start_jsonrpc(self):
|
||||
|
||||
if self.UnrealIrcdRpcLive.get_error.code == 0:
|
||||
self.UnrealIrcdRpcLive.subscribe(["all"])
|
||||
self.subscribed = True
|
||||
else:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.get_error.message}",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def __load_module_configuration(self) -> None:
|
||||
"""### Load Module Configuration
|
||||
@@ -180,7 +202,7 @@ class Jsonrpc():
|
||||
except TypeError as te:
|
||||
self.Logs.critical(te)
|
||||
|
||||
def __update_configuration(self, param_key: str, param_value: str):
|
||||
def update_configuration(self, param_key: str, param_value: str) -> None:
|
||||
"""Update the local and core configuration
|
||||
|
||||
Args:
|
||||
@@ -190,11 +212,18 @@ class Jsonrpc():
|
||||
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value)
|
||||
|
||||
def unload(self) -> None:
|
||||
if self.UnrealIrcdRpcLive.Error.code != -1:
|
||||
self.UnrealIrcdRpcLive.unsubscribe()
|
||||
if self.is_streaming:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"[{self.Config.COLORS.green}JSONRPC INFO{self.Config.COLORS.nogc}] Shutting down RPC system!",
|
||||
channel=self.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True)
|
||||
self.update_configuration('jsonrpc', 0)
|
||||
self.Logs.debug(f"Unloading {self.module_name}")
|
||||
return None
|
||||
|
||||
def cmd(self, data:list) -> None:
|
||||
def cmd(self, data: list) -> None:
|
||||
|
||||
return None
|
||||
|
||||
@@ -210,54 +239,42 @@ class Jsonrpc():
|
||||
|
||||
case 'jsonrpc':
|
||||
try:
|
||||
option = str(cmd[1]).lower()
|
||||
|
||||
if len(command) == 1:
|
||||
if len(cmd) < 2:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc on')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc off')
|
||||
return None
|
||||
|
||||
option = str(cmd[1]).lower()
|
||||
match option:
|
||||
|
||||
case 'on':
|
||||
thread_name = 'thread_subscribe'
|
||||
if self.Base.is_thread_alive(thread_name):
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, channel=dchannel, msg=f"The Subscription is running")
|
||||
return None
|
||||
elif self.Base.is_thread_exist(thread_name):
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=dnickname, channel=dchannel,
|
||||
msg=f"The subscription is not running, wait untill the process will be cleaned up"
|
||||
)
|
||||
return None
|
||||
|
||||
# for logger_name, logger in logging.root.manager.loggerDict.items():
|
||||
# if isinstance(logger, logging.Logger):
|
||||
# self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{logger_name} - {logger.level}")
|
||||
|
||||
for thread in self.Base.running_threads:
|
||||
if thread.name == 'thread_start_jsonrpc':
|
||||
if thread.is_alive():
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"Thread {thread.name} is running",
|
||||
channel=dchannel
|
||||
)
|
||||
else:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=self.Config.SERVICE_NICKNAME,
|
||||
msg=f"Thread {thread.name} is not running, wait untill the process will be cleaned up",
|
||||
channel=dchannel
|
||||
)
|
||||
|
||||
self.Base.create_thread(self.thread_start_jsonrpc, run_once=True)
|
||||
self.__update_configuration('jsonrpc', 1)
|
||||
self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True)
|
||||
self.update_configuration('jsonrpc', 1)
|
||||
|
||||
case 'off':
|
||||
self.UnrealIrcdRpcLive.unsubscribe()
|
||||
self.__update_configuration('jsonrpc', 0)
|
||||
self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True)
|
||||
self.update_configuration('jsonrpc', 0)
|
||||
|
||||
except IndexError as ie:
|
||||
self.Logs.error(ie)
|
||||
|
||||
case 'jruser':
|
||||
try:
|
||||
option = str(cmd[1]).lower()
|
||||
|
||||
if len(command) == 1:
|
||||
if len(cmd) < 2:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jruser get nickname')
|
||||
|
||||
option = str(cmd[1]).lower()
|
||||
match option:
|
||||
|
||||
case 'get':
|
||||
nickname = str(cmd[2])
|
||||
uid_to_get = self.User.get_uid(nickname)
|
||||
@@ -271,16 +288,13 @@ class Jsonrpc():
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'{rpc.get_error.message}')
|
||||
return None
|
||||
|
||||
chan_list = []
|
||||
for chan in UserInfo.user.channels:
|
||||
chan_list.append(chan.name)
|
||||
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'UID : {UserInfo.id}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'NICKNAME : {UserInfo.name}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REALNAME : {UserInfo.user.realname}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'MODES : {UserInfo.user.modes}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {chan_list}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {[chan.name for chan in UserInfo.user.channels]}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SECURITY GROUP : {UserInfo.user.security_groups}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REPUTATION : {UserInfo.user.reputation}')
|
||||
|
||||
@@ -303,22 +317,12 @@ class Jsonrpc():
|
||||
except IndexError as ie:
|
||||
self.Logs.error(ie)
|
||||
|
||||
case 'ia':
|
||||
case 'jrinstances':
|
||||
try:
|
||||
|
||||
self.Base.create_thread(self.thread_ask_ia, ('',))
|
||||
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" This is a notice to the sender ...")
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="This is private message to the sender ...", nick_to=fromuser)
|
||||
|
||||
if not fromchannel is None:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="This is channel message to the sender ...", channel=fromchannel)
|
||||
|
||||
# How to update your module configuration
|
||||
self.__update_configuration('param_exemple2', 7)
|
||||
|
||||
# Log if you want the result
|
||||
self.Logs.debug(f"Test logs ready")
|
||||
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"GC Collect: {self.MainUtils.run_python_garbage_collector()}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveWebsock: {self.MainUtils.get_number_gc_objects(LiveWebsocket)}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveUnixSocket: {self.MainUtils.get_number_gc_objects(LiveUnixSocket)}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance Loader: {self.MainUtils.get_number_gc_objects(Loader)}")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.MainUtils.get_number_gc_objects()}")
|
||||
except Exception as err:
|
||||
self.Logs.error(f"Unknown Error: {err}")
|
||||
60
mods/jsonrpc/threads.py
Normal file
60
mods/jsonrpc/threads.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.jsonrpc.mod_jsonrpc import Jsonrpc
|
||||
|
||||
def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
||||
response: dict[str, dict] = {}
|
||||
snickname = uplink.Config.SERVICE_NICKNAME
|
||||
schannel = uplink.Config.SERVICE_CHANLOG
|
||||
|
||||
if uplink.UnrealIrcdRpcLive.get_error.code == 0:
|
||||
uplink.is_streaming = True
|
||||
response = asyncio.run(uplink.UnrealIrcdRpcLive.subscribe(["all"]))
|
||||
else:
|
||||
uplink.Protocol.send_priv_msg(nick_from=snickname,
|
||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {uplink.UnrealIrcdRpcLive.get_error.message}",
|
||||
channel=schannel
|
||||
)
|
||||
|
||||
if response is None:
|
||||
return
|
||||
|
||||
code = response.get('error', {}).get('code', 0)
|
||||
message = response.get('error', {}).get('message', None)
|
||||
|
||||
if code == 0:
|
||||
uplink.Protocol.send_priv_msg(
|
||||
nick_from=snickname,
|
||||
msg=f"[{uplink.Config.COLORS.green}JSONRPC{uplink.Config.COLORS.nogc}] Stream is OFF",
|
||||
channel=schannel
|
||||
)
|
||||
else:
|
||||
uplink.Protocol.send_priv_msg(
|
||||
nick_from=snickname,
|
||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC{uplink.Config.COLORS.nogc}] Stream has crashed! {code} - {message}",
|
||||
channel=schannel
|
||||
)
|
||||
|
||||
def thread_unsubscribe(uplink: 'Jsonrpc') -> None:
|
||||
|
||||
response: dict[str, dict] = asyncio.run(uplink.UnrealIrcdRpcLive.unsubscribe())
|
||||
uplink.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!")
|
||||
uplink.is_streaming = False
|
||||
uplink.update_configuration('jsonrpc', 0)
|
||||
snickname = uplink.Config.SERVICE_NICKNAME
|
||||
schannel = uplink.Config.SERVICE_CHANLOG
|
||||
|
||||
if response is None:
|
||||
return None
|
||||
|
||||
code = response.get('error', {}).get('code', 0)
|
||||
message = response.get('error', {}).get('message', None)
|
||||
|
||||
if code != 0:
|
||||
uplink.Protocol.send_priv_msg(
|
||||
nick_from=snickname,
|
||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {message} ({code})",
|
||||
channel=schannel
|
||||
)
|
||||
0
mods/jsonrpc/utils.py
Normal file
0
mods/jsonrpc/utils.py
Normal file
@@ -34,7 +34,7 @@ class Test():
|
||||
self.Base = ircInstance.Base
|
||||
|
||||
# Add logs object to the module (Mandatory)
|
||||
self.Logs = ircInstance.Base.logs
|
||||
self.Logs = ircInstance.Loader.Logs
|
||||
|
||||
# Add User object to the module (Mandatory)
|
||||
self.User = ircInstance.User
|
||||
@@ -1,59 +1,75 @@
|
||||
from typing import TYPE_CHECKING
|
||||
"""
|
||||
File : mod_votekick.py
|
||||
Version : 1.0.0
|
||||
Description : Manages votekick sessions for multiple channels.
|
||||
Handles activation, ongoing vote checks, and cleanup.
|
||||
Author : adator
|
||||
Created : 2025-08-16
|
||||
Last Updated: 2025-08-16
|
||||
-----------------------------------------
|
||||
"""
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
import mods.votekick.schemas as schemas
|
||||
import mods.votekick.utils as utils
|
||||
from mods.votekick.votekick_manager import VotekickManager
|
||||
import mods.votekick.threads as thds
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.irc import Irc
|
||||
|
||||
# Activer le systeme sur un salon (activate #salon)
|
||||
# Le service devra se connecter au salon
|
||||
# Le service devra se mettre en op
|
||||
# Soumettre un nom de user (submit nickname)
|
||||
# voter pour un ban (vote_for)
|
||||
# voter contre un ban (vote_against)
|
||||
|
||||
class Votekick:
|
||||
|
||||
|
||||
class Votekick():
|
||||
|
||||
@dataclass
|
||||
class VoteChannelModel:
|
||||
channel_name: str
|
||||
target_user: str
|
||||
voter_users: list
|
||||
vote_for: int
|
||||
vote_against: int
|
||||
|
||||
VOTE_CHANNEL_DB:list[VoteChannelModel] = []
|
||||
|
||||
def __init__(self, ircInstance: 'Irc') -> None:
|
||||
def __init__(self, uplink: 'Irc') -> None:
|
||||
|
||||
# Module name (Mandatory)
|
||||
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
||||
|
||||
# Add Irc Object to the module
|
||||
self.Irc = ircInstance
|
||||
self.Irc = uplink
|
||||
|
||||
# Add Loader Object to the module (Mandatory)
|
||||
self.Loader = ircInstance.Loader
|
||||
self.Loader = uplink.Loader
|
||||
|
||||
# Add server protocol Object to the module (Mandatory)
|
||||
self.Protocol = ircInstance.Protocol
|
||||
self.Protocol = uplink.Protocol
|
||||
|
||||
# Add Global Configuration to the module
|
||||
self.Config = ircInstance.Config
|
||||
self.Config = uplink.Config
|
||||
|
||||
# Add Base object to the module
|
||||
self.Base = ircInstance.Base
|
||||
self.Base = uplink.Base
|
||||
|
||||
# Add logs object to the module
|
||||
self.Logs = ircInstance.Base.logs
|
||||
self.Logs = uplink.Logs
|
||||
|
||||
# Add User object to the module
|
||||
self.User = ircInstance.User
|
||||
self.User = uplink.User
|
||||
|
||||
# Add Channel object to the module
|
||||
self.Channel = ircInstance.Channel
|
||||
self.Channel = uplink.Channel
|
||||
|
||||
# Add Utils.
|
||||
self.Utils = uplink.Utils
|
||||
|
||||
# Add Utils module
|
||||
self.ModUtils = utils
|
||||
|
||||
# Add Schemas module
|
||||
self.Schemas = schemas
|
||||
|
||||
# Add Threads module
|
||||
self.Threads = thds
|
||||
|
||||
# Add VoteKick Manager
|
||||
self.VoteKickManager = VotekickManager(self)
|
||||
|
||||
metadata = uplink.Loader.Settings.get_cache('VOTEKICK')
|
||||
|
||||
if metadata is not None:
|
||||
self.VoteKickManager.VOTE_CHANNEL_DB = metadata
|
||||
# self.VOTE_CHANNEL_DB = metadata
|
||||
|
||||
# Créer les nouvelles commandes du module
|
||||
self.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module')
|
||||
@@ -69,15 +85,13 @@ class Votekick():
|
||||
# Add admin object to retrieve admin users
|
||||
self.Admin = self.Irc.Admin
|
||||
self.__create_tables()
|
||||
self.join_saved_channels()
|
||||
self.ModUtils.join_saved_channels(self)
|
||||
|
||||
return None
|
||||
|
||||
def __create_tables(self) -> None:
|
||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||
Args:
|
||||
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
|
||||
|
||||
Returns:
|
||||
None: Aucun retour n'es attendu
|
||||
@@ -103,11 +117,14 @@ class Votekick():
|
||||
|
||||
def unload(self) -> None:
|
||||
try:
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
# Cache the local DB with current votes.
|
||||
self.Loader.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB)
|
||||
|
||||
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||
self.Protocol.send_part_chan(uidornickname=self.Config.SERVICE_ID, channel=chan.channel_name)
|
||||
|
||||
self.VOTE_CHANNEL_DB = []
|
||||
self.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VOTE_CHANNEL_DB}')
|
||||
self.VoteKickManager.VOTE_CHANNEL_DB = []
|
||||
self.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VoteKickManager.VOTE_CHANNEL_DB}')
|
||||
|
||||
return None
|
||||
except UnboundLocalError as ne:
|
||||
@@ -117,137 +134,28 @@ class Votekick():
|
||||
except Exception as err:
|
||||
self.Logs.error(f'General Error: {err}')
|
||||
|
||||
def init_vote_system(self, channel: str) -> bool:
|
||||
def cmd(self, data: list) -> None:
|
||||
|
||||
response = False
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
chan.target_user = ''
|
||||
chan.voter_users = []
|
||||
chan.vote_against = 0
|
||||
chan.vote_for = 0
|
||||
response = True
|
||||
if not data or len(data) < 2:
|
||||
return None
|
||||
|
||||
return response
|
||||
|
||||
def insert_vote_channel(self, ChannelObject: VoteChannelModel) -> bool:
|
||||
result = False
|
||||
found = False
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == ChannelObject.channel_name:
|
||||
found = True
|
||||
|
||||
if not found:
|
||||
self.VOTE_CHANNEL_DB.append(ChannelObject)
|
||||
self.Logs.debug(f"The channel has been added {ChannelObject}")
|
||||
# self.db_add_vote_channel(ChannelObject.channel_name)
|
||||
|
||||
return result
|
||||
|
||||
def db_add_vote_channel(self, channel:str) -> bool:
|
||||
"""Cette fonction ajoute les salons ou seront autoriser les votes
|
||||
|
||||
Args:
|
||||
channel (str): le salon à enregistrer.
|
||||
"""
|
||||
current_datetime = self.Base.get_datetime()
|
||||
mes_donnees = {'channel': channel}
|
||||
|
||||
response = self.Base.db_execute_query("SELECT id FROM votekick_channel WHERE channel = :channel", mes_donnees)
|
||||
|
||||
isChannelExist = response.fetchone()
|
||||
|
||||
if isChannelExist is None:
|
||||
mes_donnees = {'datetime': current_datetime, 'channel': channel}
|
||||
insert = self.Base.db_execute_query(f"INSERT INTO votekick_channel (datetime, channel) VALUES (:datetime, :channel)", mes_donnees)
|
||||
if insert.rowcount > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def db_delete_vote_channel(self, channel: str) -> bool:
|
||||
"""Cette fonction supprime les salons de join de Defender
|
||||
|
||||
Args:
|
||||
channel (str): le salon à enregistrer.
|
||||
"""
|
||||
mes_donnes = {'channel': channel}
|
||||
response = self.Base.db_execute_query("DELETE FROM votekick_channel WHERE channel = :channel", mes_donnes)
|
||||
|
||||
affected_row = response.rowcount
|
||||
|
||||
if affected_row > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def join_saved_channels(self) -> None:
|
||||
|
||||
param = {'module_name': self.module_name}
|
||||
result = self.Base.db_execute_query(f"SELECT id, channel_name FROM {self.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param)
|
||||
|
||||
channels = result.fetchall()
|
||||
unixtime = self.Base.get_unixtime()
|
||||
|
||||
for channel in channels:
|
||||
id, chan = channel
|
||||
self.insert_vote_channel(self.VoteChannelModel(channel_name=chan, target_user='', voter_users=[], vote_for=0, vote_against=0))
|
||||
self.Protocol.sjoin(channel=chan)
|
||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {chan} +o {self.Config.SERVICE_NICKNAME}")
|
||||
|
||||
return None
|
||||
|
||||
def is_vote_ongoing(self, channel: str) -> bool:
|
||||
|
||||
response = False
|
||||
for vote in self.VOTE_CHANNEL_DB:
|
||||
if vote.channel_name == channel:
|
||||
if vote.target_user:
|
||||
response = True
|
||||
|
||||
return response
|
||||
|
||||
def timer_vote_verdict(self, channel: str) -> None:
|
||||
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
|
||||
if not self.is_vote_ongoing(channel):
|
||||
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
||||
index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
||||
if index == -1:
|
||||
return None
|
||||
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
target_user = self.User.get_nickname(chan.target_user)
|
||||
if chan.vote_for > chan.vote_against:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it'll be kicked from the channel",
|
||||
channel=channel
|
||||
)
|
||||
self.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||
self.Channel.delete_user_from_channel(channel, self.User.get_uid(target_user))
|
||||
elif chan.vote_for <= chan.vote_against:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
||||
channel=channel
|
||||
)
|
||||
|
||||
# Init the system
|
||||
if self.init_vote_system(channel):
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg="System vote re initiated",
|
||||
channel=channel
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def cmd(self, data:list) -> None:
|
||||
try:
|
||||
cmd = list(data).copy()
|
||||
return None
|
||||
|
||||
match command:
|
||||
|
||||
case 'PRIVMSG':
|
||||
return None
|
||||
|
||||
case 'QUIT':
|
||||
return None
|
||||
|
||||
case _:
|
||||
return None
|
||||
|
||||
except KeyError as ke:
|
||||
self.Logs.error(f"Key Error: {ke}")
|
||||
@@ -256,11 +164,12 @@ class Votekick():
|
||||
except Exception as err:
|
||||
self.Logs.error(f"General Error: {err}")
|
||||
|
||||
def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
||||
def hcmds(self, user:str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None:
|
||||
# cmd is the command starting from the user command
|
||||
# full cmd is sending the entire server response
|
||||
|
||||
command = str(cmd[0]).lower()
|
||||
fullcmd = fullcmd
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
fromuser = user
|
||||
fromchannel = channel
|
||||
@@ -287,32 +196,25 @@ class Votekick():
|
||||
case 'activate':
|
||||
try:
|
||||
# vote activate #channel
|
||||
if self.Admin.get_Admin(fromuser) is None:
|
||||
if self.Admin.get_admin(fromuser) is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' :Your are not allowed to execute this command')
|
||||
return None
|
||||
|
||||
sentchannel = str(cmd[2]).lower() if self.Channel.Is_Channel(str(cmd[2]).lower()) else None
|
||||
sentchannel = str(cmd[2]).lower() if self.Channel.is_valid_channel(str(cmd[2]).lower()) else None
|
||||
if sentchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
||||
|
||||
self.insert_vote_channel(
|
||||
self.VoteChannelModel(
|
||||
channel_name=sentchannel,
|
||||
target_user='',
|
||||
voter_users=[],
|
||||
vote_for=0,
|
||||
vote_against=0
|
||||
)
|
||||
)
|
||||
if self.VoteKickManager.activate_new_channel(sentchannel):
|
||||
self.Channel.db_query_channel('add', self.module_name, sentchannel)
|
||||
self.Protocol.send_join_chan(uidornickname=dnickname, channel=sentchannel)
|
||||
self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}")
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="You can now use !submit <nickname> to decide if he will stay or not on this channel ",
|
||||
channel=sentchannel
|
||||
)
|
||||
|
||||
self.Channel.db_query_channel('add', self.module_name, sentchannel)
|
||||
return None
|
||||
|
||||
self.Protocol.send_join_chan(uidornickname=dnickname, channel=sentchannel)
|
||||
self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}")
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="You can now use !submit <nickname> to decide if he will stay or not on this channel ",
|
||||
channel=sentchannel
|
||||
)
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} #channel')
|
||||
@@ -321,23 +223,21 @@ class Votekick():
|
||||
case 'deactivate':
|
||||
try:
|
||||
# vote deactivate #channel
|
||||
if self.Admin.get_Admin(fromuser) is None:
|
||||
if self.Admin.get_admin(fromuser) is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Your are not allowed to execute this command")
|
||||
return None
|
||||
|
||||
sentchannel = str(cmd[2]).lower() if self.Channel.Is_Channel(str(cmd[2]).lower()) else None
|
||||
sentchannel = str(cmd[2]).lower() if self.Channel.is_valid_channel(str(cmd[2]).lower()) else None
|
||||
if sentchannel is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
||||
|
||||
self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}")
|
||||
self.Protocol.send_part_chan(uidornickname=dnickname, channel=sentchannel)
|
||||
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == sentchannel:
|
||||
self.VOTE_CHANNEL_DB.remove(chan)
|
||||
self.Channel.db_query_channel('del', self.module_name, chan.channel_name)
|
||||
if self.VoteKickManager.drop_vote_channel_model(sentchannel):
|
||||
self.Channel.db_query_channel('del', self.module_name, sentchannel)
|
||||
return None
|
||||
|
||||
self.Logs.debug(f"The Channel {sentchannel} has been deactivated from the vote system")
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" /msg {dnickname} {command} {option} #channel")
|
||||
@@ -347,20 +247,11 @@ class Votekick():
|
||||
try:
|
||||
# vote +
|
||||
channel = fromchannel
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
if fromuser in chan.voter_users:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="You already submitted a vote",
|
||||
channel=channel
|
||||
)
|
||||
else:
|
||||
chan.vote_for += 1
|
||||
chan.voter_users.append(fromuser)
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="Vote recorded, thank you",
|
||||
channel=channel
|
||||
)
|
||||
if self.VoteKickManager.action_vote(channel, fromuser, '+'):
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel)
|
||||
else:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel)
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||
@@ -370,20 +261,11 @@ class Votekick():
|
||||
try:
|
||||
# vote -
|
||||
channel = fromchannel
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
if fromuser in chan.voter_users:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="You already submitted a vote",
|
||||
channel=channel
|
||||
)
|
||||
else:
|
||||
chan.vote_against += 1
|
||||
chan.voter_users.append(fromuser)
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="Vote recorded, thank you",
|
||||
channel=channel
|
||||
)
|
||||
if self.VoteKickManager.action_vote(channel, fromuser, '-'):
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel)
|
||||
else:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel)
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||
@@ -392,7 +274,7 @@ class Votekick():
|
||||
case 'cancel':
|
||||
try:
|
||||
# vote cancel
|
||||
if self.Admin.get_Admin(fromuser) is None:
|
||||
if self.Admin.get_admin(fromuser) is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command')
|
||||
return None
|
||||
|
||||
@@ -400,13 +282,13 @@ class Votekick():
|
||||
self.Logs.error(f"The channel is not known, defender can't cancel the vote")
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' You need to specify the channel => /msg {dnickname} vote_cancel #channel')
|
||||
|
||||
for vote in self.VOTE_CHANNEL_DB:
|
||||
for vote in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||
if vote.channel_name == channel:
|
||||
self.init_vote_system(channel)
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="Vote system re-initiated",
|
||||
channel=channel
|
||||
)
|
||||
if self.VoteKickManager.init_vote_system(channel):
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="Vote system re-initiated",
|
||||
channel=channel
|
||||
)
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
@@ -416,7 +298,7 @@ class Votekick():
|
||||
case 'status':
|
||||
try:
|
||||
# vote status
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"Channel: {chan.channel_name} | Target: {self.User.get_nickname(chan.target_user)} | For: {chan.vote_for} | Against: {chan.vote_against} | Number of voters: {str(len(chan.voter_users))}",
|
||||
@@ -430,25 +312,25 @@ class Votekick():
|
||||
case 'submit':
|
||||
try:
|
||||
# vote submit nickname
|
||||
if self.Admin.get_Admin(fromuser) is None:
|
||||
if self.Admin.get_admin(fromuser) is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command')
|
||||
return None
|
||||
|
||||
nickname_submitted = cmd[2]
|
||||
uid_submitted = self.User.get_uid(nickname_submitted)
|
||||
user_submitted = self.User.get_User(nickname_submitted)
|
||||
ongoing_user = None
|
||||
|
||||
# check if there is an ongoing vote
|
||||
if self.is_vote_ongoing(channel):
|
||||
for vote in self.VOTE_CHANNEL_DB:
|
||||
if vote.channel_name == channel:
|
||||
ongoing_user = self.User.get_nickname(vote.target_user)
|
||||
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"There is an ongoing vote on {ongoing_user}",
|
||||
channel=channel
|
||||
)
|
||||
return False
|
||||
if self.VoteKickManager.is_vote_ongoing(channel):
|
||||
votec = self.VoteKickManager.get_vote_channel_model(channel)
|
||||
if votec:
|
||||
ongoing_user = self.User.get_nickname(votec.target_user)
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"There is an ongoing vote on {ongoing_user}",
|
||||
channel=channel
|
||||
)
|
||||
return None
|
||||
|
||||
# check if the user exist
|
||||
if user_submitted is None:
|
||||
@@ -456,24 +338,24 @@ class Votekick():
|
||||
msg=f"This nickname <{nickname_submitted}> do not exist",
|
||||
channel=channel
|
||||
)
|
||||
return False
|
||||
return None
|
||||
|
||||
uid_cleaned = self.Base.clean_uid(uid_submitted)
|
||||
ChannelInfo = self.Channel.get_Channel(channel)
|
||||
if ChannelInfo is None:
|
||||
uid_cleaned = self.Loader.Utils.clean_uid(uid_submitted)
|
||||
channel_obj = self.Channel.get_channel(channel)
|
||||
if channel_obj is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' This channel [{channel}] do not exist in the Channel Object')
|
||||
return False
|
||||
return None
|
||||
|
||||
clean_uids_in_channel: list = []
|
||||
for uid in ChannelInfo.uids:
|
||||
clean_uids_in_channel.append(self.Base.clean_uid(uid))
|
||||
for uid in channel_obj.uids:
|
||||
clean_uids_in_channel.append(self.Loader.Utils.clean_uid(uid))
|
||||
|
||||
if not uid_cleaned in clean_uids_in_channel:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"This nickname <{nickname_submitted}> is not available in this channel",
|
||||
channel=channel
|
||||
)
|
||||
return False
|
||||
return None
|
||||
|
||||
# check if Ircop or Service or Bot
|
||||
pattern = fr'[o|B|S]'
|
||||
@@ -483,9 +365,9 @@ class Votekick():
|
||||
msg="You cant vote for this user ! he/she is protected",
|
||||
channel=channel
|
||||
)
|
||||
return False
|
||||
return None
|
||||
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
chan.target_user = self.User.get_uid(nickname_submitted)
|
||||
|
||||
@@ -494,7 +376,7 @@ class Votekick():
|
||||
channel=channel
|
||||
)
|
||||
|
||||
self.Base.create_timer(60, self.timer_vote_verdict, (channel, ))
|
||||
self.Base.create_timer(60, self.Threads.timer_vote_verdict, (self, channel))
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg="This vote will end after 60 secondes",
|
||||
channel=channel
|
||||
@@ -508,33 +390,34 @@ class Votekick():
|
||||
case 'verdict':
|
||||
try:
|
||||
# vote verdict
|
||||
if self.Admin.get_Admin(fromuser) is None:
|
||||
if self.Admin.get_admin(fromuser) is None:
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f'Your are not allowed to execute this command')
|
||||
return None
|
||||
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
target_user = self.User.get_nickname(chan.target_user)
|
||||
if chan.vote_for > chan.vote_against:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
||||
|
||||
votec = self.VoteKickManager.get_vote_channel_model(channel)
|
||||
if votec:
|
||||
target_user = self.User.get_nickname(votec.target_user)
|
||||
if votec.vote_for >= votec.vote_against:
|
||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
||||
channel=channel
|
||||
)
|
||||
self.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||
elif chan.vote_for <= chan.vote_against:
|
||||
self.Protocol.send_priv_msg(
|
||||
self.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||
else:
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
||||
channel=channel
|
||||
)
|
||||
|
||||
# Init the system
|
||||
if self.init_vote_system(channel):
|
||||
self.Protocol.send_priv_msg(
|
||||
|
||||
if self.VoteKickManager.init_vote_system(channel):
|
||||
self.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg="System vote re initiated",
|
||||
channel=channel
|
||||
)
|
||||
return None
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'{err}')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||
@@ -548,4 +431,8 @@ class Votekick():
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict')
|
||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict')
|
||||
return None
|
||||
|
||||
case _:
|
||||
return None
|
||||
11
mods/votekick/schemas.py
Normal file
11
mods/votekick/schemas.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from typing import Optional
|
||||
from core.definition import MainModel
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
@dataclass
|
||||
class VoteChannelModel(MainModel):
|
||||
channel_name: Optional[str] = None
|
||||
target_user: Optional[str] = None
|
||||
voter_users: list = field(default_factory=list)
|
||||
vote_for: int = 0
|
||||
vote_against: int = 0
|
||||
40
mods/votekick/threads.py
Normal file
40
mods/votekick/threads.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.votekick.mod_votekick import Votekick
|
||||
|
||||
def timer_vote_verdict(uplink: 'Votekick', channel: str) -> None:
|
||||
|
||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
||||
|
||||
if not uplink.VoteKickManager.is_vote_ongoing(channel):
|
||||
return None
|
||||
|
||||
votec = uplink.VoteKickManager.get_vote_channel_model(channel)
|
||||
if votec:
|
||||
target_user = uplink.User.get_nickname(votec.target_user)
|
||||
|
||||
if votec.vote_for >= votec.vote_against and votec.vote_for != 0:
|
||||
uplink.Protocol.send_priv_msg(nick_from=dnickname,
|
||||
msg=f"User {uplink.Config.COLORS.bold}{target_user}{uplink.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
||||
channel=channel
|
||||
)
|
||||
uplink.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||
else:
|
||||
uplink.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"User {uplink.Config.COLORS.bold}{target_user}{uplink.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
||||
channel=channel
|
||||
)
|
||||
|
||||
if uplink.VoteKickManager.init_vote_system(channel):
|
||||
uplink.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg="System vote re initiated",
|
||||
channel=channel
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
return None
|
||||
74
mods/votekick/utils.py
Normal file
74
mods/votekick/utils.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.votekick.mod_votekick import Votekick
|
||||
|
||||
def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool:
|
||||
"""Adds a new channel to the votekick database if it doesn't already exist.
|
||||
|
||||
This function checks if the specified channel is already registered in the
|
||||
`votekick_channel` table. If not, it inserts a new entry with the current timestamp.
|
||||
|
||||
Args:
|
||||
uplink (Votekick): The main votekick system instance that provides access to utilities and database operations.
|
||||
channel (str): The name of the channel to be added to the database.
|
||||
|
||||
Returns:
|
||||
bool: True if the channel was successfully inserted into the database.
|
||||
False if the channel already exists or the insertion failed.
|
||||
"""
|
||||
current_datetime = uplink.Utils.get_sdatetime()
|
||||
mes_donnees = {'channel': channel}
|
||||
|
||||
response = uplink.Base.db_execute_query("SELECT id FROM votekick_channel WHERE channel = :channel", mes_donnees)
|
||||
|
||||
is_channel_exist = response.fetchone()
|
||||
|
||||
if is_channel_exist is None:
|
||||
mes_donnees = {'datetime': current_datetime, 'channel': channel}
|
||||
insert = uplink.Base.db_execute_query(f"INSERT INTO votekick_channel (datetime, channel) VALUES (:datetime, :channel)", mes_donnees)
|
||||
if insert.rowcount > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool:
|
||||
"""Deletes a channel entry from the votekick database.
|
||||
|
||||
This function removes the specified channel from the `votekick_channel` table
|
||||
if it exists. It returns True if the deletion was successful.
|
||||
|
||||
Args:
|
||||
uplink (Votekick): The main votekick system instance used to execute the database operation.
|
||||
channel (str): The name of the channel to be removed from the database.
|
||||
|
||||
Returns:
|
||||
bool: True if the channel was successfully deleted, False if no rows were affected.
|
||||
"""
|
||||
mes_donnes = {'channel': channel}
|
||||
response = uplink.Base.db_execute_query("DELETE FROM votekick_channel WHERE channel = :channel", mes_donnes)
|
||||
|
||||
affected_row = response.rowcount
|
||||
|
||||
if affected_row > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def join_saved_channels(uplink: 'Votekick') -> None:
|
||||
|
||||
param = {'module_name': uplink.module_name}
|
||||
result = uplink.Base.db_execute_query(f"SELECT id, channel_name FROM {uplink.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param)
|
||||
|
||||
channels = result.fetchall()
|
||||
|
||||
for channel in channels:
|
||||
id_, chan = channel
|
||||
uplink.VoteKickManager.activate_new_channel(chan)
|
||||
uplink.Protocol.send_sjoin(channel=chan)
|
||||
uplink.Protocol.send2socket(f":{uplink.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.Config.SERVICE_NICKNAME}")
|
||||
|
||||
return None
|
||||
163
mods/votekick/votekick_manager.py
Normal file
163
mods/votekick/votekick_manager.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from typing import TYPE_CHECKING, Literal, Optional
|
||||
from mods.votekick.schemas import VoteChannelModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.votekick.mod_votekick import Votekick
|
||||
|
||||
class VotekickManager:
|
||||
|
||||
VOTE_CHANNEL_DB:list[VoteChannelModel] = []
|
||||
|
||||
def __init__(self, uplink: 'Votekick'):
|
||||
self.uplink = uplink
|
||||
self.Logs = uplink.Logs
|
||||
self.Utils = uplink.Utils
|
||||
|
||||
def activate_new_channel(self, channel_name: str) -> bool:
|
||||
"""Activate a new channel in the votekick systeme
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel name you want to activate
|
||||
|
||||
Returns:
|
||||
bool: True if it was activated
|
||||
"""
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
if votec is None:
|
||||
self.VOTE_CHANNEL_DB.append(
|
||||
VoteChannelModel(
|
||||
channel_name=channel_name,
|
||||
target_user='',
|
||||
voter_users=[],
|
||||
vote_for=0,
|
||||
vote_against=0
|
||||
)
|
||||
)
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] {channel_name} has been activated.")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def init_vote_system(self, channel_name: str) -> bool:
|
||||
"""Initializes or resets the votekick system for a given channel.
|
||||
|
||||
This method clears the current target, voter list, and vote counts
|
||||
in preparation for a new votekick session.
|
||||
|
||||
Args:
|
||||
channel_name (str): The name of the channel for which the votekick system should be initialized.
|
||||
|
||||
Returns:
|
||||
bool: True if the votekick system was successfully initialized, False if the channel is not found.
|
||||
"""
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
if votec is None:
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] The channel ({channel_name}) is not active!")
|
||||
return False
|
||||
|
||||
votec.target_user = ''
|
||||
votec.voter_users = []
|
||||
votec.vote_for = 0
|
||||
votec.vote_against = 0
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] The channel ({channel_name}) has been successfully initialized!")
|
||||
return True
|
||||
|
||||
def get_vote_channel_model(self, channel_name: str) -> Optional[VoteChannelModel]:
|
||||
"""Get Vote Channel Object model
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel name you want to activate
|
||||
|
||||
Returns:
|
||||
(VoteChannelModel | None): The VoteChannelModel if exist
|
||||
"""
|
||||
for vote in self.VOTE_CHANNEL_DB:
|
||||
if vote.channel_name.lower() == channel_name.lower():
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] {channel_name} has been found in the VOTE_CHANNEL_DB")
|
||||
return vote
|
||||
|
||||
return None
|
||||
|
||||
def drop_vote_channel_model(self, channel_name: str) -> bool:
|
||||
"""Drop a channel from the votekick system.
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel name you want to drop
|
||||
|
||||
Returns:
|
||||
bool: True if the channel has been droped.
|
||||
"""
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
if votec:
|
||||
self.VOTE_CHANNEL_DB.remove(votec)
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] {channel_name} has been removed from the VOTE_CHANNEL_DB")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def is_vote_ongoing(self, channel_name: str) -> bool:
|
||||
"""Check if there is an angoing vote on the channel provided
|
||||
|
||||
Args:
|
||||
channel_name (str): The channel name to check
|
||||
|
||||
Returns:
|
||||
bool: True if there is an ongoing vote on the channel provided.
|
||||
"""
|
||||
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
if votec is None:
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] {channel_name} is not activated!")
|
||||
return False
|
||||
|
||||
if votec.target_user:
|
||||
self.Logs.debug(f'[VOTEKICK MANAGER] A vote is ongoing on {channel_name}')
|
||||
return True
|
||||
|
||||
self.Logs.debug(f'[VOTEKICK MANAGER] {channel_name} is activated but there is no ongoing vote!')
|
||||
|
||||
return False
|
||||
|
||||
def action_vote(self, channel_name: str, nickname: str, action: Literal['+', '-']) -> bool:
|
||||
"""
|
||||
Registers a vote (for or against) in an active votekick session on a channel.
|
||||
|
||||
Args:
|
||||
channel_name (str): The name of the channel where the votekick session is active.
|
||||
nickname (str): The nickname of the user casting the vote.
|
||||
action (Literal['+', '-']): The vote action. Use '+' to vote for kicking, '-' to vote against.
|
||||
|
||||
Returns:
|
||||
bool: True if the vote was successfully registered, False otherwise.
|
||||
This can fail if:
|
||||
- The action is invalid (not '+' or '-')
|
||||
- The user has already voted
|
||||
- The channel has no active votekick session
|
||||
"""
|
||||
if action not in ['+', '-']:
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] The action must be + or - while you have provided ({action})")
|
||||
return False
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
if votec:
|
||||
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})")
|
||||
return False
|
||||
else:
|
||||
if action == '+':
|
||||
votec.vote_for += 1
|
||||
elif action == '-':
|
||||
votec.vote_against += 1
|
||||
|
||||
votec.voter_users.append(nickname)
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] The ({nickname}) has voted to ban ({client_to_punish})")
|
||||
return True
|
||||
else:
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] This channel {channel_name} is not active!")
|
||||
return False
|
||||
14
requirements.txt
Normal file
14
requirements.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
certifi==2024.12.14
|
||||
charset-normalizer==3.4.1
|
||||
Faker==33.1.2
|
||||
greenlet==3.1.1
|
||||
idna==3.10
|
||||
psutil==6.1.1
|
||||
python-dateutil==2.9.0.post0
|
||||
requests==2.32.3
|
||||
six==1.17.0
|
||||
SQLAlchemy==2.0.36
|
||||
typing_extensions==4.12.2
|
||||
unrealircd-rpc-py==2.0.4
|
||||
urllib3==2.3.0
|
||||
websockets==14.1
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"version": "6.1.4",
|
||||
"version": "6.2.0",
|
||||
|
||||
"requests": "2.32.3",
|
||||
"psutil": "6.0.0",
|
||||
"unrealircd_rpc_py": "2.0.0",
|
||||
"unrealircd_rpc_py": "2.0.4",
|
||||
"sqlalchemy": "2.0.35",
|
||||
"faker": "30.1.0"
|
||||
}
|
||||
Reference in New Issue
Block a user