43 Commits

Author SHA1 Message Date
adator
b0325d4db5 Merge pull request #14 from adator85/dev
V4.1.0 change configuration systeme
2024-08-04 00:37:43 +02:00
adator
b9e4878764 V4.1.0 change configuration systeme 2024-08-04 00:37:03 +02:00
adator
22cec8a0ef Merge pull request #13 from adator85/dev
patch V4.0.4
2024-08-03 21:14:53 +02:00
adator
1837edf1c2 patch V4.0.4 2024-08-03 21:14:28 +02:00
adator
62b10313a4 Merge pull request #12 from adator85/dev
Patch V4.0.3
2024-08-03 21:05:56 +02:00
adator
c369d86a22 Patch V4.0.3 2024-08-03 21:04:38 +02:00
adator
61813e38ae Merge pull request #11 from adator85/dev
convert version string to int
2024-08-03 20:25:37 +02:00
adator
743069f8e0 convert version string to int 2024-08-03 20:24:58 +02:00
adator
de69a1af63 Merge pull request #10 from adator85/dev
Move checkversion command to admin commands
2024-08-03 20:13:03 +02:00
adator
c8c5f782d7 Move checkversion command to admin commands 2024-08-03 20:12:19 +02:00
adator
a639964701 Merge pull request #9 from adator85/dev
Dev
2024-08-03 19:22:30 +02:00
adator
ff0f880fcd V4.0.0 2024-08-03 19:21:30 +02:00
adator
41b9582e43 Merge pull request #8 from adator85/main
align main to dev
2024-08-03 17:04:26 +02:00
adator
dba0301190 Delete version.json 2024-08-03 17:03:42 +02:00
adator
6e6d001605 New Version 2024-08-03 17:01:19 +02:00
adator
e27a027ae9 Create version.json 2024-08-03 15:29:19 +02:00
adator85
19b7f85ec7 . 2024-03-24 01:01:18 +01:00
adator85
7068d88168 . 2024-03-23 03:40:50 +01:00
adator85
884c5bf0cd . 2024-03-23 02:43:24 +01:00
adator85
7e24d7cf4c . 2024-03-23 01:50:55 +01:00
adator85
d16b73656f . 2024-03-21 21:31:24 +01:00
adator85
8acbb7187c . 2024-03-20 23:57:23 +01:00
adator85
51bea90e6f . 2024-03-20 23:53:46 +01:00
adator85
4cb54b5b2e . 2024-03-20 23:49:14 +01:00
adator85
310f732a5b . 2024-03-20 23:46:23 +01:00
adator85
018fd8d959 . 2024-03-20 23:45:44 +01:00
adator85
07fa518fcc . 2024-03-20 23:19:28 +01:00
adator85
37dcd23353 . 2024-03-20 21:39:42 +01:00
adator85
748e7bffc9 Correction du status 2024-03-20 21:16:10 +01:00
adator85
681e0da041 Mise en forme du code 2024-03-20 20:33:50 +01:00
adator85
667281ffb4 Ajout de quelques param de config 2024-03-20 20:12:51 +01:00
adator85
4b18675e8b . 2024-03-20 01:26:30 +01:00
adator85
f63aabfb7a . 2024-03-20 00:54:37 +01:00
adator85
b4c1df7f4a . 2024-03-19 23:37:58 +01:00
adator85
4c1a929867 Adding freeipapi scan 2024-03-19 23:34:21 +01:00
adator
0f1aa6f946 Merge pull request #7 from adator85/dev
Fix KeyError when a user change nickname
2024-02-20 01:12:32 +01:00
adator85
20684339d3 Fix KeyError when a user change nickname 2024-02-20 01:10:54 +01:00
adator
d53a3c58c9 Merge pull request #6 from adator85/dev
Corriger les commandes qui ce dupliquent lors du rechargement du mod
2024-02-02 23:24:13 +01:00
adator85
5c7f0e3ad0 Corriger les commandes qui ce dupliquent lors du rechargement du mod 2024-02-02 23:22:49 +01:00
adator
168f8db5ab Merge pull request #5 from adator85/dev
Bug - Correction de la commande .code
2024-02-02 22:54:28 +01:00
adator85
91a6218692 Bug - Correction de la commande .code 2024-02-02 22:52:06 +01:00
adator
02164e4580 Merge pull request #4 from adator85/dev
V3.2.0
2024-01-02 22:59:44 +01:00
adator85
5595530977 V3.2.0 2024-01-02 22:58:28 +01:00
10 changed files with 1208 additions and 431 deletions

View File

@@ -26,6 +26,7 @@ Lancement de Defender :
# VERSION 1 # VERSION 1
[02.01.2024] [02.01.2024]
- Rajout de l'activation de la commande flood
- Les deux variables RESTART et INIT ont été déplacées vers le module Irc - Les deux variables RESTART et INIT ont été déplacées vers le module Irc
- Nouvelle class Install: - Nouvelle class Install:
- Le programme va vérifier si les 3 librairies sont installées (SQLAlchemy & requests & psutil) - Le programme va vérifier si les 3 librairies sont installées (SQLAlchemy & requests & psutil)

View File

@@ -1,8 +1,8 @@
import time, threading, os, random, socket, hashlib import time, threading, os, random, socket, hashlib, ipaddress, logging, requests, json, sys
from datetime import datetime from datetime import datetime
from sqlalchemy import create_engine, Engine, Connection, CursorResult from sqlalchemy import create_engine, Engine, Connection, CursorResult
from sqlalchemy.sql import text from sqlalchemy.sql import text
from core.configuration import Config from core.loadConf import Config
class Base: class Base:
@@ -16,9 +16,16 @@ class Base:
'modules': 'sys_modules' 'modules': 'sys_modules'
} }
DEFENDER_VERSION = '' # MAJOR.MINOR.BATCH
LATEST_DEFENDER_VERSION = '' # Latest Version of Defender in git
DEFENDER_DB_PATH = 'db' + os.sep # Séparateur en fonction de l'OS
DEFENDER_DB_NAME = 'defender' # Le nom de la base de données principale
def __init__(self, Config: Config) -> None: def __init__(self, Config: Config) -> None:
self.Config = Config # Assigner l'objet de configuration self.Config = Config # Assigner l'objet de configuration
self.init_log_system() # Demarrer le systeme de log
self.check_for_new_version() # Verifier si une nouvelle version est disponible
self.running_timers:list[threading.Timer] = [] # Liste des timers en cours self.running_timers:list[threading.Timer] = [] # Liste des timers en cours
self.running_threads:list[threading.Thread] = [] # Liste des threads en cours self.running_threads:list[threading.Thread] = [] # Liste des threads en cours
@@ -32,7 +39,74 @@ class Base:
self.db_create_first_admin() # Créer un nouvel admin si la base de données est vide self.db_create_first_admin() # Créer un nouvel admin si la base de données est vide
def get_unixtime(self)->int: def __set_current_defender_version(self) -> None:
"""This will put the current version of Defender
located in version.json
"""
version_filename = f'.{os.sep}version.json'
with open(version_filename, 'r') as version_data:
current_version:dict[str, str] = json.load(version_data)
self.DEFENDER_VERSION = current_version["version"]
return None
def __get_latest_defender_version(self) -> None:
try:
token = ''
json_url = f'https://raw.githubusercontent.com/adator85/IRC_DEFENDER_MODULES/main/version.json'
headers = {
'Authorization': f'token {token}',
'Accept': 'application/vnd.github.v3.raw' # Indique à GitHub que nous voulons le contenu brut du fichier
}
if token == '':
response = requests.get(json_url)
else:
response = requests.get(json_url, headers=headers)
response.raise_for_status() # Vérifie si la requête a réussi
json_response:dict = response.json()
self.LATEST_DEFENDER_VERSION = json_response["version"]
return None
except requests.HTTPError as err:
self.logs.error(f'Github not available to fetch latest version: {err}')
except:
self.logs.warning(f'Github not available to fetch latest version')
def check_for_new_version(self) -> bool:
try:
# Assigner la version actuelle de Defender
self.__set_current_defender_version()
# Récuperer la dernier version disponible dans github
self.__get_latest_defender_version()
isNewVersion = False
latest_version = self.LATEST_DEFENDER_VERSION
current_version = self.DEFENDER_VERSION
curr_major , curr_minor, curr_patch = current_version.split('.')
last_major, last_minor, last_patch = latest_version.split('.')
if int(last_major) > int(curr_major):
self.logs.info(f'New version available: {current_version} >>> {latest_version}')
isNewVersion = True
elif int(last_major) == int(curr_major) and int(last_minor) > int(curr_minor):
self.logs.info(f'New version available: {current_version} >>> {latest_version}')
isNewVersion = True
elif int(last_major) == int(curr_major) and int(last_minor) == int(curr_minor) and int(last_patch) > int(curr_patch):
self.logs.info(f'New version available: {current_version} >>> {latest_version}')
isNewVersion = True
else:
isNewVersion = False
return isNewVersion
except ValueError as ve:
self.logs.error(f'Impossible to convert in version number : {ve}')
def get_unixtime(self) -> int:
""" """
Cette fonction retourne un UNIXTIME de type 12365456 Cette fonction retourne un UNIXTIME de type 12365456
Return: Current time in seconds since the Epoch (int) Return: Current time in seconds since the Epoch (int)
@@ -40,7 +114,7 @@ class Base:
unixtime = int( time.time() ) unixtime = int( time.time() )
return unixtime return unixtime
def get_datetime(self)->str: def get_datetime(self) -> str:
""" """
Retourne une date au format string (24-12-2023 20:50:59) Retourne une date au format string (24-12-2023 20:50:59)
""" """
@@ -62,12 +136,36 @@ class Base:
return None return None
def init_log_system(self) -> None:
# Create folder if not available
logs_directory = f'logs{os.sep}'
if not os.path.exists(f'{logs_directory}'):
os.makedirs(logs_directory)
# Init logs object
self.logs = logging
self.logs.basicConfig(level=self.Config.DEBUG_LEVEL,
filename='logs/defender.log',
encoding='UTF-8',
format='%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(funcName)s - %(message)s')
self.logs.info('#################### STARTING INTERCEPTOR HQ ####################')
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 """Enregistre les commandes envoyées par les utilisateurs
Args: Args:
cmd (str): la commande a enregistrer cmd (str): la commande a enregistrer
""" """
cmd_list = cmd.split()
if len(cmd_list) == 3:
if cmd_list[0].replace('.', '') == 'auth':
cmd_list[1] = '*******'
cmd_list[2] = '*******'
cmd = ' '.join(cmd_list)
insert_cmd_query = f"INSERT INTO {self.DB_SCHEMA['commandes']} (datetime, user, commande) VALUES (:datetime, :user, :commande)" insert_cmd_query = f"INSERT INTO {self.DB_SCHEMA['commandes']} (datetime, user, commande) VALUES (:datetime, :user, :commande)"
mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'commande': cmd} mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'commande': cmd}
self.db_execute_query(insert_cmd_query, mes_donnees) self.db_execute_query(insert_cmd_query, mes_donnees)
@@ -100,13 +198,13 @@ class Base:
""" """
if not self.db_isModuleExist(module_name): if not self.db_isModuleExist(module_name):
self.__debug(f"Le module {module_name} n'existe pas alors ont le créer") self.logs.debug(f"Le module {module_name} n'existe pas alors ont le créer")
insert_cmd_query = f"INSERT INTO {self.DB_SCHEMA['modules']} (datetime, user, module) VALUES (:datetime, :user, :module)" insert_cmd_query = f"INSERT INTO {self.DB_SCHEMA['modules']} (datetime, user, module) VALUES (:datetime, :user, :module)"
mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'module': module_name} mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'module': module_name}
self.db_execute_query(insert_cmd_query, mes_donnees) self.db_execute_query(insert_cmd_query, mes_donnees)
# self.db_close_session(self.session) # self.db_close_session(self.session)
else: else:
self.__debug(f"Le module {module_name} existe déja dans la base de données") self.logs.debug(f"Le module {module_name} existe déja dans la base de données")
return False return False
@@ -137,7 +235,7 @@ class Base:
(:createdOn, :user, :password, :hostname, :vhost, :level)""" (:createdOn, :user, :password, :hostname, :vhost, :level)"""
, mes_donnees) , mes_donnees)
pass return None
def create_timer(self, time_to_wait: float, func: object, func_args: tuple = ()) -> None: def create_timer(self, time_to_wait: float, func: object, func_args: tuple = ()) -> None:
@@ -148,14 +246,20 @@ class Base:
self.running_timers.append(t) self.running_timers.append(t)
self.__debug(f"Timer ID : {str(t.ident)} | Running Threads : {len(threading.enumerate())}") self.logs.debug(f"Timer ID : {str(t.ident)} | Running Threads : {len(threading.enumerate())}")
except AssertionError as ae: except AssertionError as ae:
self.__debug(f'Assertion Error -> {ae}') self.logs.error(f'Assertion Error -> {ae}')
def create_thread(self, func:object, func_args: tuple = ()) -> None: def create_thread(self, func:object, func_args: tuple = (), run_once:bool = False) -> None:
try: try:
func_name = func.__name__ func_name = func.__name__
if run_once:
for thread in self.running_threads:
if thread.getName() == func_name:
return None
# if func_name in self.running_threads: # if func_name in self.running_threads:
# print(f"HeartBeat is running") # print(f"HeartBeat is running")
# return None # return None
@@ -164,98 +268,95 @@ class Base:
th.start() th.start()
self.running_threads.append(th) self.running_threads.append(th)
self.__debug(f"Thread ID : {str(th.ident)} | Thread name : {th.getName()} | Running Threads : {len(threading.enumerate())}") self.logs.debug(f"Thread ID : {str(th.ident)} | Thread name : {th.getName()} | Running Threads : {len(threading.enumerate())}")
except AssertionError as ae: except AssertionError as ae:
self.__debug(f'Assertion Error -> {ae}') self.logs.error(f'{ae}')
def garbage_collector_timer(self) -> None: def garbage_collector_timer(self) -> None:
"""Methode qui supprime les timers qui ont finis leurs job """Methode qui supprime les timers qui ont finis leurs job
""" """
try: try:
self.__debug(f"=======> Checking for Timers to stop")
# print(f"{self.running_timers}")
for timer in self.running_timers: for timer in self.running_timers:
if not timer.is_alive(): if not timer.is_alive():
timer.cancel() timer.cancel()
self.running_timers.remove(timer) self.running_timers.remove(timer)
self.__debug(f"Timer {str(timer)} removed") self.logs.info(f"Timer {str(timer)} removed")
else: else:
self.__debug(f"===> Timer {str(timer)} Still running ...") self.logs.debug(f"===> Timer {str(timer)} Still running ...")
except AssertionError as ae: except AssertionError as ae:
print(f'Assertion Error -> {ae}') self.logs.error(f'Assertion Error -> {ae}')
def garbage_collector_thread(self) -> None: def garbage_collector_thread(self) -> None:
"""Methode qui supprime les threads qui ont finis leurs job """Methode qui supprime les threads qui ont finis leurs job
""" """
try: try:
self.__debug(f"=======> Checking for Threads to stop")
for thread in self.running_threads: for thread in self.running_threads:
if thread.getName() != 'heartbeat': if thread.getName() != 'heartbeat':
if not thread.is_alive(): if not thread.is_alive():
self.running_threads.remove(thread) self.running_threads.remove(thread)
self.__debug(f"Thread {str(thread.getName())} {str(thread.native_id)} removed") self.logs.debug(f"Thread {str(thread.getName())} {str(thread.native_id)} removed")
# print(threading.enumerate()) # print(threading.enumerate())
except AssertionError as ae: except AssertionError as ae:
self.__debug(f'Assertion Error -> {ae}') self.logs.error(f'Assertion Error -> {ae}')
def garbage_collector_sockets(self) -> None: def garbage_collector_sockets(self) -> None:
self.__debug(f"=======> Checking for Sockets to stop")
for soc in self.running_sockets: for soc in self.running_sockets:
while soc.fileno() != -1: while soc.fileno() != -1:
self.__debug(soc.fileno()) self.logs.debug(soc.fileno())
soc.close() soc.close()
soc.close() soc.close()
self.running_sockets.remove(soc) self.running_sockets.remove(soc)
self.__debug(f"Socket ==> closed {str(soc.fileno())}") self.logs.debug(f"Socket ==> closed {str(soc.fileno())}")
def shutdown(self) -> None: def shutdown(self) -> None:
"""Methode qui va préparer l'arrêt complêt du service """Methode qui va préparer l'arrêt complêt du service
""" """
# Nettoyage des timers # Nettoyage des timers
print(f"=======> Checking for Timers to stop") self.logs.debug(f"=======> Checking for Timers to stop")
for timer in self.running_timers: for timer in self.running_timers:
while timer.is_alive(): while timer.is_alive():
print(f"> waiting for {timer.getName()} to close") self.logs.debug(f"> waiting for {timer.getName()} to close")
timer.cancel() timer.cancel()
time.sleep(0.2) time.sleep(0.2)
self.running_timers.remove(timer) self.running_timers.remove(timer)
print(f"> Cancelling {timer.getName()} {timer.native_id}") self.logs.debug(f"> Cancelling {timer.getName()} {timer.native_id}")
print(f"=======> Checking for Threads to stop") self.logs.debug(f"=======> Checking for Threads to stop")
for thread in self.running_threads: for thread in self.running_threads:
if thread.getName() == 'heartbeat' and thread.is_alive(): if thread.getName() == 'heartbeat' and thread.is_alive():
self.execute_periodic_action() self.execute_periodic_action()
print(f"> Running the last periodic action") self.logs.debug(f"> Running the last periodic action")
self.running_threads.remove(thread) self.running_threads.remove(thread)
print(f"> Cancelling {thread.getName()} {thread.native_id}") self.logs.debug(f"> Cancelling {thread.getName()} {thread.native_id}")
print(f"=======> Checking for Sockets to stop") self.logs.debug(f"=======> Checking for Sockets to stop")
for soc in self.running_sockets: for soc in self.running_sockets:
soc.close() soc.close()
while soc.fileno() != -1: while soc.fileno() != -1:
soc.close() soc.close()
self.running_sockets.remove(soc) self.running_sockets.remove(soc)
print(f"> Socket ==> closed {str(soc.fileno())}") self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}")
pass return None
def db_init(self) -> tuple[Engine, Connection]: def db_init(self) -> tuple[Engine, Connection]:
db_directory = self.Config.DEFENDER_DB_PATH db_directory = self.DEFENDER_DB_PATH
full_path_db = self.Config.DEFENDER_DB_PATH + self.Config.DEFENDER_DB_NAME full_path_db = self.DEFENDER_DB_PATH + self.DEFENDER_DB_NAME
if not os.path.exists(db_directory): if not os.path.exists(db_directory):
os.makedirs(db_directory) os.makedirs(db_directory)
engine = create_engine(f'sqlite:///{full_path_db}.db', echo=False) engine = create_engine(f'sqlite:///{full_path_db}.db', echo=False)
cursor = engine.connect() cursor = engine.connect()
self.logs.info("database connexion has been initiated")
return engine, cursor return engine, cursor
def __create_db(self) -> None: def __create_db(self) -> None:
@@ -319,7 +420,7 @@ class Base:
try: try:
self.cursor.close() self.cursor.close()
except AttributeError as ae: except AttributeError as ae:
self.__debug(f"Attribute Error : {ae}") self.logs.error(f"Attribute Error : {ae}")
def crypt_password(self, password:str) -> str: def crypt_password(self, password:str) -> str:
"""Retourne un mot de passe chiffré en MD5 """Retourne un mot de passe chiffré en MD5
@@ -352,6 +453,17 @@ class Base:
except TypeError: except TypeError:
return value return value
def is_valid_ip(self, ip_to_control:str) -> bool:
try:
if ip_to_control in self.Config.WHITELISTED_IP:
return False
ipaddress.ip_address(ip_to_control)
return True
except ValueError:
return False
def get_random(self, lenght:int) -> str: def get_random(self, lenght:int) -> str:
""" """
Retourn une chaîne aléatoire en fonction de la longueur spécifiée. Retourn une chaîne aléatoire en fonction de la longueur spécifiée.
@@ -367,7 +479,7 @@ class Base:
# Run Garbage Collector Timer # Run Garbage Collector Timer
self.garbage_collector_timer() self.garbage_collector_timer()
self.garbage_collector_thread() self.garbage_collector_thread()
self.garbage_collector_sockets() # self.garbage_collector_sockets()
return None return None
for key, value in self.periodic_func.items(): for key, value in self.periodic_func.items():
@@ -379,10 +491,3 @@ class Base:
# Vider le dictionnaire de fonction # Vider le dictionnaire de fonction
self.periodic_func.clear() self.periodic_func.clear()
def __debug(self, debug_msg:str) -> None:
if self.Config.DEBUG == 1:
print(f"[{self.get_datetime()}] - {debug_msg}")
return None

View File

@@ -0,0 +1,48 @@
{
"SERVEUR_IP": "0.0.0.0",
"SERVEUR_HOSTNAME": "your.host.name",
"SERVEUR_LINK": "your.link.to.server",
"SERVEUR_PORT": 7002,
"SERVEUR_PASSWORD": "link_password",
"SERVEUR_ID": "006",
"SERVEUR_SSL": true,
"SERVICE_NAME": "defender",
"SERVICE_NICKNAME": "BotNickname",
"SERVICE_REALNAME": "BotRealname",
"SERVICE_USERNAME": "BotUsername",
"SERVICE_HOST": "your.service.hostname",
"SERVICE_INFO": "Network IRC Service",
"SERVICE_CHANLOG": "#services",
"SERVICE_SMODES": "+ioqBS",
"SERVICE_CMODES": "ntsO",
"SERVICE_UMODES": "o",
"SERVICE_PREFIX": "!",
"OWNER": "admin",
"PASSWORD": "password",
"SALON_JAIL": "#jail",
"SALON_JAIL_MODES": "sS",
"SALON_LIBERER": "#welcome",
"API_TIMEOUT": 2,
"PORTS_TO_SCAN": [3028, 8080, 1080, 1085, 4145, 9050],
"WHITELISTED_IP": ["127.0.0.1"],
"GLINE_DURATION": "30",
"DEBUG_LEVEL": 20,
"CONFIG_COLOR": {
"blanche": "\\u0003\\u0030",
"noire": "\\u0003\\u0031",
"bleue": "\\u0003\\u0020",
"verte": "\\u0003\\u0033",
"rouge": "\\u0003\\u0034",
"jaune": "\\u0003\\u0036",
"gras": "\\u0002",
"nogc": "\\u0002\\u0003"
}
}

View File

@@ -1,53 +0,0 @@
import os
##########################################
# CONFIGURATION FILE : #
# Rename file to : configuration.py #
##########################################
class Config:
DEFENDER_VERSION = '1.1.0' # MAJOR.MINOR.BATCH
DEFENDER_DB_PATH = 'db' + os.sep # Séparateur en fonction de l'OS
DEFENDER_DB_NAME = 'defender' # Le nom de la base de données principale
SERVICE_NAME = 'defender' # Le nom du service
SERVEUR_IP = '8.8.8.8' # IP ou host du serveur à rejoindre
SERVEUR_HOSTNAME = 'your hostname' # Le hostname du serveur IRC
SERVEUR_LINK = 'your link' # Host attendu par votre IRCd (ex. dans votre link block pour Unrealircd)
SERVEUR_PORT = 6666 # Port du link
SERVEUR_PASSWORD = 'your link password' # Mot de passe du link (Privilégiez argon2 sur Unrealircd)
SERVEUR_ID = '002' # SID (identification) du bot en tant que Services
SERVICE_NICKNAME = 'BotName' # Nick du bot sur IRC
SERVICE_REALNAME = 'BotRealname' # Realname du bot
SERVICE_USERNAME = 'BotIdent' # Ident du bot
SERVICE_HOST = 'your service host' # Host du bot
SERVICE_INFO = 'Network IRC Service' # swhois du bot
SERVICE_CHANLOG = '#services' # Salon des logs et autres messages issus du bot
SERVICE_SMODES = '+ioqBS' # Mode du service
SERVICE_CMODES = 'ntsO' # Mode du salon (#ChanLog) que le bot appliquera à son entrée
SERVICE_UMODES = 'o' # Mode que le bot pourra se donner à sa connexion au salon chanlog
SERVICE_PREFIX = '.' # Prefix pour envoyer les commandes au bot
SERVICE_ID = SERVEUR_ID + 'AAAAAB' # L'identifiant du service
OWNER = 'admin' # Identifiant du compte admin
PASSWORD = 'password' # Mot de passe du compte admin
SALON_JAIL = '#JAIL' # Salon pot de miel
SALON_JAIL_MODES = 'sS' # Mode du salon pot de miel
SALON_LIBERER = '#welcome' # Le salon ou sera envoyé l'utilisateur clean
PORTS_TO_SCAN = [3028, 8080, 1080, 1085, 4145, 9050] # Liste des ports a scanné pour une detection de proxy
DEBUG = 0 # Afficher l'ensemble des messages du serveurs dans la console
CONFIG_COLOR = {
'blanche': '\x0300', # Couleur blanche
'noire': '\x0301', # Couleur noire
'bleue': '\x0302', # Couleur Bleue
'verte': '\x0303', # Couleur Verte
'rouge': '\x0304', # Couleur rouge
'jaune': '\x0306', # Couleur jaune
'gras': '\x02', # Gras
'nogc': '\x02\x03' # Retirer gras et couleur
}

View File

@@ -1,7 +1,8 @@
import ssl, re, importlib, sys, time, threading, socket import ssl, re, importlib, sys, time, threading, socket
from ssl import SSLSocket
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Union
from core.configuration import Config from core.loadConf import Config
from core.base import Base from core.base import Base
class Irc: class Irc:
@@ -16,18 +17,20 @@ class Irc:
self.beat = 30 # Lancer toutes les 30 secondes des actions de nettoyages self.beat = 30 # Lancer toutes les 30 secondes des actions de nettoyages
self.hb_active = True # Heartbeat active self.hb_active = True # Heartbeat active
self.HSID = '' # ID du serveur qui accueil le service ( Host Serveur Id ) self.HSID = '' # ID du serveur qui accueil le service ( Host Serveur Id )
self.IrcSocket:Union[socket.socket, SSLSocket] = None
self.INIT = 1 # Variable d'intialisation | 1 -> indique si le programme est en cours d'initialisation self.INIT = 1 # Variable d'intialisation | 1 -> indique si le programme est en cours d'initialisation
self.RESTART = 0 # Variable pour le redemarrage du bot | 0 -> indique que le programme n'es pas en cours de redemarrage self.RESTART = 0 # Variable pour le redemarrage du bot | 0 -> indique que le programme n'es pas en cours de redemarrage
self.CHARSET = ['utf-8', 'iso-8859-1'] # Charset utiliser pour décoder/encoder les messages self.CHARSET = ['utf-8', 'iso-8859-1'] # Charset utiliser pour décoder/encoder les messages
self.SSL_VERSION = None # Version SSL
self.Config = Config() self.Config = Config().ConfigModel
# Liste des commandes internes du bot # Liste des commandes internes du bot
self.commands_level = { self.commands_level = {
0: ['help', 'auth', 'copyright'], 0: ['help', 'auth', 'copyright'],
1: ['load','reload','unload', 'deauth', 'uptime'], 1: ['load','reload','unload', 'deauth', 'uptime', 'checkversion'],
2: ['show_sessions','show_modules', 'show_timers', 'show_threads'], 2: ['show_modules', 'show_timers', 'show_threads', 'sentinel'],
3: ['quit', 'restart','addaccess','editaccess', 'delaccess'] 3: ['quit', 'restart','addaccess','editaccess', 'delaccess']
} }
@@ -38,7 +41,7 @@ class Irc:
self.commands.append(command) self.commands.append(command)
self.Base = Base(self.Config) self.Base = Base(self.Config)
self.Base.create_thread(self.heartbeat, (self.beat, )) self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, ))
############################################## ##############################################
# CONNEXION IRC # # CONNEXION IRC #
@@ -48,26 +51,46 @@ class Irc:
self.__create_socket() self.__create_socket()
self.__connect_to_irc(ircInstance) self.__connect_to_irc(ircInstance)
except AssertionError as ae: except AssertionError as ae:
self.debug(f'Assertion error : {ae}') self.Base.logs.critical(f'Assertion error: {ae}')
def __create_socket(self) -> None: def __create_socket(self) -> None:
self.IrcSocket: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try:
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
connexion_information = (self.Config.SERVEUR_IP, self.Config.SERVEUR_PORT) connexion_information = (self.Config.SERVEUR_IP, self.Config.SERVEUR_PORT)
self.IrcSocket.connect(connexion_information)
if self.Config.SERVEUR_SSL:
# Créer un object ssl # Créer un object ssl
ssl_context = self.__ssl_context() ssl_context = self.__ssl_context()
ssl_connexion = ssl_context.wrap_socket(self.IrcSocket, server_hostname=self.Config.SERVEUR_HOSTNAME) ssl_connexion = ssl_context.wrap_socket(soc, server_hostname=self.Config.SERVEUR_HOSTNAME)
self.IrcSocket = ssl_connexion ssl_connexion.connect(connexion_information)
self.IrcSocket:SSLSocket = ssl_connexion
self.Base.logs.info(f"Connexion en mode SSL : Version = {self.IrcSocket.version()}")
self.SSL_VERSION = self.IrcSocket.version()
else:
soc.connect(connexion_information)
self.IrcSocket:socket.socket = soc
self.Base.logs.info("Connexion en mode normal")
return None return None
except ssl.SSLEOFError as soe:
self.Base.logs.critical(f"SSLEOFError __create_socket: {soe} - {soc.fileno()}")
except ssl.SSLError as se:
self.Base.logs.critical(f"SSLError __create_socket: {se} - {soc.fileno()}")
except OSError as oe:
self.Base.logs.critical(f"OSError __create_socket: {oe} - {soc.fileno()}")
except AttributeError as ae:
self.Base.logs.critical(f"OSError __create_socket: {oe} - {soc.fileno()}")
def __ssl_context(self) -> ssl.SSLContext: def __ssl_context(self) -> ssl.SSLContext:
ctx = ssl.create_default_context() ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE ctx.verify_mode = ssl.CERT_NONE
self.Base.logs.debug(f'SSLContext initiated with verified mode {ctx.verify_mode}')
return ctx return ctx
def __connect_to_irc(self, ircInstance: 'Irc') -> None: def __connect_to_irc(self, ircInstance: 'Irc') -> None:
@@ -78,23 +101,30 @@ class Irc:
self.load_existing_modules() # Charger les modules existant dans la base de données self.load_existing_modules() # Charger les modules existant dans la base de données
while self.signal: while self.signal:
try:
if self.RESTART == 1: if self.RESTART == 1:
self.Base.logs.debug('Restarting Defender ...')
self.IrcSocket.shutdown(socket.SHUT_RDWR) self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close() self.IrcSocket.close()
while self.IrcSocket.fileno() != -1: while self.IrcSocket.fileno() != -1:
time.sleep(0.5) time.sleep(0.5)
self.debug("--> En attente de la fermeture du socket ...") self.Base.logs.warning('--> Waiting for socket to close ...')
# Reload configuration
self.Base.logs.debug('Reloading configuration')
self.Config = Config().ConfigModel
self.Base = Base(self.Config)
self.__create_socket() self.__create_socket()
self.__link(self.IrcSocket) self.__link(self.IrcSocket)
self.load_existing_modules() self.load_existing_modules()
self.RESTART = 0 self.RESTART = 0
# 4072 max what the socket can grab # 4072 max what the socket can grab
buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF) buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
# data = self.IrcSocket.recv(buffer_size).splitlines(True)
data_in_bytes = self.IrcSocket.recv(buffer_size) data_in_bytes = self.IrcSocket.recv(buffer_size)
data = data_in_bytes.splitlines(True)
count_bytes = len(data_in_bytes) count_bytes = len(data_in_bytes)
while count_bytes > 4070: while count_bytes > 4070:
@@ -102,26 +132,35 @@ class Irc:
new_data = self.IrcSocket.recv(buffer_size) new_data = self.IrcSocket.recv(buffer_size)
data_in_bytes += new_data data_in_bytes += new_data
count_bytes = len(new_data) count_bytes = len(new_data)
# print("========================================================")
data = data_in_bytes.splitlines() data = data_in_bytes.splitlines(True)
# print(f"{str(buffer_size)} - {str(len(data_in_bytes))}")
if not data: if not data:
break break
self.send_response(data) self.send_response(data)
except ssl.SSLEOFError as soe:
self.Base.logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}")
except ssl.SSLError as se:
self.Base.logs.error(f"SSLError __connect_to_irc: {se} - {data}")
except OSError as oe:
self.Base.logs.error(f"SSLError __connect_to_irc: {oe} - {data}")
self.IrcSocket.shutdown(socket.SHUT_RDWR) self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close() self.IrcSocket.close()
self.Base.logs.info("--> Fermeture de Defender ...")
except AssertionError as ae: except AssertionError as ae:
self.debug(f'Assertion error : {ae}') self.Base.logs.error(f'Assertion error : {ae}')
except ValueError as ve: except ValueError as ve:
self.debug(f'Value Error : {ve}') self.Base.logs.error(f'Value Error : {ve}')
except OSError as oe: except ssl.SSLEOFError as soe:
self.debug(f"OS Error : {oe}") self.Base.logs.error(f"OS Error __connect_to_irc: {soe}")
except AttributeError as atte:
self.Base.logs.critical(f"{atte}")
# except Exception as e:
# self.debug(f"Exception: {e}")
def __link(self, writer:socket.socket) -> None: def __link(self, writer:socket.socket) -> None:
"""Créer le link et envoyer les informations nécessaires pour la """Créer le link et envoyer les informations nécessaires pour la
@@ -130,7 +169,7 @@ class Irc:
Args: Args:
writer (StreamWriter): permet l'envoi des informations au serveur. writer (StreamWriter): permet l'envoi des informations au serveur.
""" """
try:
nickname = self.Config.SERVICE_NICKNAME nickname = self.Config.SERVICE_NICKNAME
username = self.Config.SERVICE_USERNAME username = self.Config.SERVICE_USERNAME
realname = self.Config.SERVICE_REALNAME realname = self.Config.SERVICE_REALNAME
@@ -147,12 +186,10 @@ class Irc:
sid = self.Config.SERVEUR_ID sid = self.Config.SERVEUR_ID
service_id = self.Config.SERVICE_ID service_id = self.Config.SERVICE_ID
version = self.Config.DEFENDER_VERSION version = self.Base.DEFENDER_VERSION
unixtime = self.Base.get_unixtime() unixtime = self.Base.get_unixtime()
# Envoyer un message d'identification # Envoyer un message d'identification
# strtobytes = bytes(":" + sid + " PASS :" + password + "\r\n", 'utf-8')
# self.IrcSocket.send(strtobytes)
writer.send(f":{sid} PASS :{password}\r\n".encode('utf-8')) writer.send(f":{sid} PASS :{password}\r\n".encode('utf-8'))
writer.send(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS\r\n".encode('utf-8')) writer.send(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS\r\n".encode('utf-8'))
writer.send(f":{sid} PROTOCTL EAUTH={link},,,{service_name}-v{version}\r\n".encode('utf-8')) writer.send(f":{sid} PROTOCTL EAUTH={link},,,{service_name}-v{version}\r\n".encode('utf-8'))
@@ -164,29 +201,38 @@ class Irc:
writer.send(f":{sid} MODE {chan} +{cmodes}\r\n".encode('utf-8')) writer.send(f":{sid} MODE {chan} +{cmodes}\r\n".encode('utf-8'))
writer.send(f":{service_id} SAMODE {chan} +{umodes} {nickname}\r\n".encode('utf-8')) writer.send(f":{service_id} SAMODE {chan} +{umodes} {nickname}\r\n".encode('utf-8'))
# writer.write(f"USER {nickname} {username} {username} {nickname} {username} :{username}\r\n".encode('utf-8')) self.Base.logs.debug('Link information sent to the server')
# writer.write(f"USER {username} {username} {username} :{username}\r\n".encode('utf-8'))
# writer.write(f"NICK {nickname}\r\n".encode('utf-8'))
def send2socket(self, send_message:str)->None: return None
except AttributeError as ae:
self.Base.logs.critical(f'{ae}')
def send2socket(self, send_message:str) -> None:
"""Envoit les commandes à envoyer au serveur. """Envoit les commandes à envoyer au serveur.
Args: Args:
string (Str): contient la commande à envoyer au serveur. string (Str): contient la commande à envoyer au serveur.
""" """
try: try:
with self.Base.lock:
# print(f">{str(send_message)}")
self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0])) self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0]))
self.Base.logs.debug(f'{send_message}')
except UnicodeDecodeError: except UnicodeDecodeError:
self.debug('Write Decode impossible try iso-8859-1') self.Base.logs.error(f'Decode Error try iso-8859-1 - message: {send_message}')
self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace')) self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace'))
except UnicodeEncodeError: except UnicodeEncodeError:
self.debug('Write Encode impossible ... try iso-8859-1') self.Base.logs.error(f'Encode Error try iso-8859-1 - message: {send_message}')
self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace')) self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace'))
except AssertionError as ae: except AssertionError as ae:
self.debug(f"Assertion error : {ae}") self.Base.logs.warning(f'Assertion Error {ae} - message: {send_message}')
except ssl.SSLEOFError as soe:
self.Base.logs.error(f"SSLEOFError: {soe} - {send_message}")
except ssl.SSLError as se:
self.Base.logs.error(f"SSLError: {se} - {send_message}")
except OSError as oe: except OSError as oe:
self.debug(f"OS Error : {oe}") self.Base.logs.error(f"OSError: {oe} - {send_message}")
def send_response(self, responses:list[bytes]) -> None: def send_response(self, responses:list[bytes]) -> None:
try: try:
@@ -194,6 +240,7 @@ class Irc:
for data in responses: for data in responses:
response = data.decode(self.CHARSET[0]).split() response = data.decode(self.CHARSET[0]).split()
self.cmd(response) self.cmd(response)
except UnicodeEncodeError: except UnicodeEncodeError:
for data in responses: for data in responses:
response = data.decode(self.CHARSET[1],'replace').split() response = data.decode(self.CHARSET[1],'replace').split()
@@ -203,10 +250,12 @@ class Irc:
response = data.decode(self.CHARSET[1],'replace').split() response = data.decode(self.CHARSET[1],'replace').split()
self.cmd(response) self.cmd(response)
except AssertionError as ae: except AssertionError as ae:
self.debug(f"Assertion error : {ae}") self.Base.logs.error(f"Assertion error : {ae}")
############################################## ##############################################
# FIN CONNEXION IRC # # FIN CONNEXION IRC #
############################################## ##############################################
def load_existing_modules(self) -> None: def load_existing_modules(self) -> None:
"""Charge les modules qui existe déja dans la base de données """Charge les modules qui existe déja dans la base de données
@@ -219,7 +268,7 @@ class Irc:
return None return None
def get_defender_uptime(self)->str: def get_defender_uptime(self) -> str:
"""Savoir depuis quand Defender est connecté """Savoir depuis quand Defender est connecté
Returns: Returns:
@@ -252,7 +301,7 @@ class Irc:
# 2. Executer la fonction # 2. Executer la fonction
try: try:
if not class_name in self.loaded_classes: if not class_name in self.loaded_classes:
self.debug(f"La class [{class_name} n'existe pas !!]") self.Base.logs.error(f"La class [{class_name} n'existe pas !!]")
return False return False
class_instance = self.loaded_classes[class_name] class_instance = self.loaded_classes[class_name]
@@ -262,12 +311,12 @@ class Irc:
self.Base.running_timers.append(t) self.Base.running_timers.append(t)
self.debug(f"Timer ID : {str(t.ident)} | Running Threads : {len(threading.enumerate())}") self.Base.logs.debug(f"Timer ID : {str(t.ident)} | Running Threads : {len(threading.enumerate())}")
except AssertionError as ae: except AssertionError as ae:
self.debug(f'Assertion Error -> {ae}') self.Base.logs.error(f'Assertion Error -> {ae}')
except TypeError as te: except TypeError as te:
self.debug(f"Type error -> {te}") self.Base.logs.error(f"Type error -> {te}")
def __create_tasks(self, obj: object, method_name: str, param:list) -> None: def __create_tasks(self, obj: object, method_name: str, param:list) -> None:
"""#### Ajouter les méthodes a éxecuter dans un dictionnaire """#### Ajouter les méthodes a éxecuter dans un dictionnaire
@@ -286,7 +335,7 @@ class Irc:
'param': param 'param': param
} }
self.debug(f'Function to execute : {str(self.Base.periodic_func)}') self.Base.logs.debug(f'Function to execute : {str(self.Base.periodic_func)}')
self.send_ping_to_sereur() self.send_ping_to_sereur()
return None return None
@@ -300,7 +349,6 @@ class Irc:
return None return None
def load_module(self, fromuser:str, module_name:str, init:bool = False) -> bool: def load_module(self, fromuser:str, module_name:str, init:bool = False) -> bool:
try: try:
# module_name : mod_voice # module_name : mod_voice
module_name = module_name.lower() module_name = module_name.lower()
@@ -310,8 +358,8 @@ class Irc:
# Si le module est déja chargé # Si le module est déja chargé
if 'mods.' + module_name in sys.modules: if 'mods.' + module_name in sys.modules:
self.debug("Module déja chargé ...") self.Base.logs.info("Module déja chargé ...")
self.debug('module name = ' + module_name) self.Base.logs.info('module name = ' + module_name)
if class_name in self.loaded_classes: if class_name in self.loaded_classes:
# Si le module existe dans la variable globale retourne False # Si le module existe dans la variable globale retourne False
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self.Config.SERVICE_PREFIX}reload {module_name}") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self.Config.SERVICE_PREFIX}reload {module_name}")
@@ -342,12 +390,14 @@ class Irc:
self.Base.db_record_module(fromuser, module_name) self.Base.db_record_module(fromuser, module_name)
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} chargé") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} chargé")
self.debug(self.loaded_classes) self.Base.logs.info(self.loaded_classes)
return True return True
except ModuleNotFoundError as moduleNotFound: except ModuleNotFoundError as moduleNotFound:
self.debug(f"MODULE_NOT_FOUND: {moduleNotFound}") self.Base.logs.error(f"MODULE_NOT_FOUND: {moduleNotFound}")
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.CONFIG_COLOR['rouge']}MODULE_NOT_FOUND{self.Config.CONFIG_COLOR['noire']} ]: {moduleNotFound}") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.CONFIG_COLOR['rouge']}MODULE_NOT_FOUND{self.Config.CONFIG_COLOR['noire']} ]: {moduleNotFound}")
except Exception as e:
self.Base.logs.error(f"Something went wrong with a module you want to load : {e}")
def insert_db_uid(self, uid:str, nickname:str, username:str, hostname:str, umodes:str, vhost:str, isWebirc: bool) -> None: def insert_db_uid(self, uid:str, nickname:str, username:str, hostname:str, umodes:str, vhost:str, isWebirc: bool) -> None:
@@ -397,10 +447,10 @@ class Irc:
if oldnickname in self.db_uid: if oldnickname in self.db_uid:
del self.db_uid[oldnickname] del self.db_uid[oldnickname]
else: else:
self.debug(f"L'ancien nickname {oldnickname} n'existe pas dans UID_DB") self.Base.logs.debug(f"L'ancien nickname {oldnickname} n'existe pas dans UID_DB")
response = False response = False
self.debug(f"{oldnickname} changed to {newnickname}") self.Base.logs.debug(f"{oldnickname} changed to {newnickname}")
return None return None
@@ -429,8 +479,6 @@ class Irc:
vhost = self.db_uid[uid]['vhost'] vhost = self.db_uid[uid]['vhost']
level = int(level) level = int(level)
self.db_admin[uid] = { self.db_admin[uid] = {
'nickname': nickname, 'nickname': nickname,
'username': username, 'username': username,
@@ -487,7 +535,7 @@ class Irc:
# Supprimer les doublons de la liste # Supprimer les doublons de la liste
self.db_chan = list(set(self.db_chan)) self.db_chan = list(set(self.db_chan))
self.debug(f"Le salon {channel} a été ajouté à la liste CHAN_DB") self.Base.logs.debug(f"Le salon {channel} a été ajouté à la liste CHAN_DB")
return response return response
@@ -498,13 +546,13 @@ class Irc:
if level > 4: if level > 4:
response = "Impossible d'ajouter un niveau > 4" response = "Impossible d'ajouter un niveau > 4"
self.debug(response) self.Base.logs.warning(response)
return response return response
# Verification si le user existe dans notre UID_DB # Verification si le user existe dans notre UID_DB
if not nickname in self.db_uid: if not nickname in self.db_uid:
response = f"{nickname} n'est pas connecté, impossible de l'enregistrer pour le moment" response = f"{nickname} n'est pas connecté, impossible de l'enregistrer pour le moment"
self.debug(response) self.Base.logs.warning(response)
return response return response
hostname = self.db_uid[nickname]['hostname'] hostname = self.db_uid[nickname]['hostname']
@@ -525,15 +573,15 @@ class Irc:
''', mes_donnees) ''', mes_donnees)
response = f"{nickname} ajouté en tant qu'administrateur de niveau {level}" response = f"{nickname} ajouté en tant qu'administrateur de niveau {level}"
self.send2socket(f':{self.Config.SERVICE_NICKNAME} NOTICE {nickname} : {response}') self.send2socket(f':{self.Config.SERVICE_NICKNAME} NOTICE {nickname} : {response}')
self.debug(response) self.Base.logs.info(response)
return response return response
else: else:
response = f'{nickname} Existe déjà dans les users enregistrés' response = f'{nickname} Existe déjà dans les users enregistrés'
self.send2socket(f':{self.Config.SERVICE_NICKNAME} NOTICE {nickname} : {response}') self.send2socket(f':{self.Config.SERVICE_NICKNAME} NOTICE {nickname} : {response}')
self.debug(response) self.Base.logs.info(response)
return response return response
def get_uid(self, uidornickname:str) -> str | None: def get_uid(self, uidornickname:str) -> Union[str, None]:
uid_recherche = uidornickname uid_recherche = uidornickname
response = None response = None
@@ -546,7 +594,7 @@ class Irc:
return response return response
def get_nickname(self, uidornickname:str) -> str | None: def get_nickname(self, uidornickname:str) -> Union[str, None]:
nickname_recherche = uidornickname nickname_recherche = uidornickname
@@ -586,11 +634,12 @@ class Irc:
def debug(self, debug_msg:str) -> None: def debug(self, debug_msg:str) -> None:
if self.Config.DEBUG == 1: # if self.Config.DEBUG == 1:
if type(debug_msg) == list: # if type(debug_msg) == list:
if debug_msg[0] != 'PING': # if debug_msg[0] != 'PING':
print(f"[{self.Base.get_datetime()}] - {debug_msg}") # print(f"[{self.Base.get_datetime()}] - {debug_msg}")
else: # else:
#
print(f"[{self.Base.get_datetime()}] - {debug_msg}") print(f"[{self.Base.get_datetime()}] - {debug_msg}")
return None return None
@@ -604,12 +653,27 @@ class Irc:
def cmd(self, data:list) -> None: def cmd(self, data:list) -> None:
try: try:
cmd = data
cmd_to_send:list[str] = data.copy()
cmd = data.copy()
cmd_to_debug = data.copy()
cmd_to_debug.pop(0)
if len(cmd) == 0 or len(cmd) == 1: if len(cmd) == 0 or len(cmd) == 1:
self.Base.logs.warning(f'Size ({str(len(cmd))}) - {cmd}')
return False return False
self.debug(cmd) # self.debug(cmd_to_debug)
if len(data) == 7:
if data[2] == 'PRIVMSG' and data[4] == ':auth':
data_copy = data.copy()
data_copy[6] = '**********'
self.Base.logs.debug(data_copy)
else:
self.Base.logs.debug(data)
else:
self.Base.logs.debug(data)
match cmd[0]: match cmd[0]:
@@ -651,8 +715,8 @@ class Irc:
# self.Base.create_thread(self.abuseipdb_scan, (cmd[2], )) # self.Base.create_thread(self.abuseipdb_scan, (cmd[2], ))
pass pass
# Possibilité de déclancher les bans a ce niveau. # Possibilité de déclancher les bans a ce niveau.
except IndexError: except IndexError as ie:
self.debug(f'cmd reputation: index error') self.Base.logs.error(f'{ie}')
case '320': case '320':
#:irc.deb.biz.st 320 PyDefender IRCParis07 :is in security-groups: known-users,webirc-users,tls-and-known-users,tls-users #:irc.deb.biz.st 320 PyDefender IRCParis07 :is in security-groups: known-users,webirc-users,tls-and-known-users,tls-users
@@ -671,17 +735,38 @@ class Irc:
hsid = str(cmd[0]).replace(':','') hsid = str(cmd[0]).replace(':','')
if hsid == self.HSID: if hsid == self.HSID:
if self.INIT == 1: if self.INIT == 1:
if self.Base.check_for_new_version():
version = f'{self.Base.DEFENDER_VERSION} >>> {self.Base.LATEST_DEFENDER_VERSION}'
else:
version = f'{self.Base.DEFENDER_VERSION}'
self.send2socket(f"MODE {self.Config.SERVICE_NICKNAME} +B") self.send2socket(f"MODE {self.Config.SERVICE_NICKNAME} +B")
self.send2socket(f"JOIN {self.Config.SERVICE_CHANLOG}") self.send2socket(f"JOIN {self.Config.SERVICE_CHANLOG}")
print(f"################### DEFENDER ###################") print(f"################### DEFENDER ###################")
print(f"# SERVICE CONNECTE ") print(f"# SERVICE CONNECTE ")
print(f"# SERVEUR : {self.Config.SERVEUR_IP} ") print(f"# SERVEUR : {self.Config.SERVEUR_IP} ")
print(f"# PORT : {self.Config.SERVEUR_PORT} ") print(f"# PORT : {self.Config.SERVEUR_PORT} ")
print(f"# SSL : {self.Config.SERVEUR_SSL} ")
print(f"# SSL VER : {self.SSL_VERSION} ")
print(f"# NICKNAME : {self.Config.SERVICE_NICKNAME} ") print(f"# NICKNAME : {self.Config.SERVICE_NICKNAME} ")
print(f"# CHANNEL : {self.Config.SERVICE_CHANLOG} ") print(f"# CHANNEL : {self.Config.SERVICE_CHANLOG} ")
print(f"# VERSION : {self.Config.DEFENDER_VERSION} ") print(f"# VERSION : {version} ")
print(f"################################################") 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.SSL_VERSION} ")
self.Base.logs.info(f"# NICKNAME : {self.Config.SERVICE_NICKNAME} ")
self.Base.logs.info(f"# CHANNEL : {self.Config.SERVICE_CHANLOG} ")
self.Base.logs.info(f"# VERSION : {version} ")
self.Base.logs.info(f"################################################")
if self.Base.check_for_new_version():
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} : New Version available {version}")
# Initialisation terminé aprés le premier PING # Initialisation terminé aprés le premier PING
self.INIT = 0 self.INIT = 0
# self.send2socket(f':{self.Config.SERVICE_ID} PING :{hsid}') # self.send2socket(f':{self.Config.SERVICE_ID} PING :{hsid}')
@@ -738,12 +823,24 @@ class Irc:
self.insert_db_uid(uid, nickname, username, hostname, umodes, vhost, isWebirc) self.insert_db_uid(uid, nickname, username, hostname, umodes, vhost, isWebirc)
for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd_to_send)
case 'PRIVMSG': case 'PRIVMSG':
try: try:
# Supprimer la premiere valeur # Supprimer la premiere valeur
cmd.pop(0) cmd.pop(0)
get_uid_or_nickname = str(cmd[0].replace(':','')) get_uid_or_nickname = str(cmd[0].replace(':',''))
if len(cmd) == 6:
if cmd[1] == 'PRIVMSG' and cmd[3] == ':auth':
cmd_copy = cmd.copy()
cmd_copy[5] = '**********'
self.Base.logs.debug(cmd_copy)
else:
self.Base.logs.info(cmd)
else:
self.Base.logs.info(f'{cmd}')
# user_trigger = get_user.split('!')[0] # user_trigger = get_user.split('!')[0]
user_trigger = self.get_nickname(get_uid_or_nickname) user_trigger = self.get_nickname(get_uid_or_nickname)
dnickname = self.Config.SERVICE_NICKNAME dnickname = self.Config.SERVICE_NICKNAME
@@ -757,7 +854,7 @@ class Irc:
arg = convert_to_string.split() arg = convert_to_string.split()
arg.remove(f':{self.Config.SERVICE_PREFIX}') arg.remove(f':{self.Config.SERVICE_PREFIX}')
if not arg[0].lower() in self.commands: if not arg[0].lower() in self.commands:
self.debug(f"This command {arg[0]} is not available") self.Base.logs.debug(f"This command {arg[0]} is not available")
return False return False
cmd_to_send = convert_to_string.replace(':','') cmd_to_send = convert_to_string.replace(':','')
@@ -777,7 +874,7 @@ class Irc:
# Réponse a un CTCP VERSION # Réponse a un CTCP VERSION
if arg[0] == '\x01VERSION\x01': if arg[0] == '\x01VERSION\x01':
self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01VERSION Service {self.Config.SERVICE_NICKNAME} V{self.Config.DEFENDER_VERSION}\x01') self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01VERSION Service {self.Config.SERVICE_NICKNAME} V{self.Base.DEFENDER_VERSION}\x01')
return False return False
# Réponse a un TIME # Réponse a un TIME
@@ -803,18 +900,19 @@ class Irc:
self._hcmds(user_trigger, arg) self._hcmds(user_trigger, arg)
except IndexError: except IndexError as io:
self.debug(f'cmd --> PRIVMSG --> List index out of range') self.Base.logs.error(f'{io}')
case _: case _:
pass pass
if cmd[2] != 'UID':
# Envoyer la commande aux classes dynamiquement chargées # Envoyer la commande aux classes dynamiquement chargées
for classe_name, classe_object in self.loaded_classes.items(): for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd) classe_object.cmd(cmd_to_send)
except IndexError as ie: except IndexError as ie:
self.debug(f"IRC CMD -> IndexError : {ie} - {cmd} - length {str(len(cmd))}") self.Base.logs.error(f"{ie} / {cmd} / length {str(len(cmd))}")
def _hcmds(self, user: str, cmd:list) -> None: def _hcmds(self, user: str, cmd:list) -> None:
@@ -846,8 +944,8 @@ class Irc:
current_command = cmd[0] current_command = cmd[0]
self.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR["rouge"]}{current_command}{self.Config.CONFIG_COLOR["noire"]} ] - Accès Refusé à {self.get_nickname(fromuser)}') self.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR["rouge"]}{current_command}{self.Config.CONFIG_COLOR["noire"]} ] - Accès Refusé à {self.get_nickname(fromuser)}')
self.send2socket(f':{dnickname} NOTICE {fromuser} : Accès Refusé') self.send2socket(f':{dnickname} NOTICE {fromuser} : Accès Refusé')
except IndexError: except IndexError as ie:
self.debug(f'_hcmd notallowed : Index Error') self.Base.logs.error(f'{ie}')
case 'deauth': case 'deauth':
@@ -872,6 +970,7 @@ class Irc:
uid_user = self.get_uid(user_to_log) uid_user = self.get_uid(user_to_log)
self.insert_db_admin(uid_user, user_from_db[1]) self.insert_db_admin(uid_user, user_from_db[1])
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR['verte']}{current_command}{self.Config.CONFIG_COLOR['noire']} ] - {self.get_nickname(fromuser)} est désormais connecté a {dnickname}") self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR['verte']}{current_command}{self.Config.CONFIG_COLOR['noire']} ] - {self.get_nickname(fromuser)} est désormais connecté a {dnickname}")
self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Connexion a {dnickname} réussie!")
else: else:
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR['rouge']}{current_command}{self.Config.CONFIG_COLOR['noire']} ] - {self.get_nickname(fromuser)} a tapé un mauvais mot de pass") self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR['rouge']}{current_command}{self.Config.CONFIG_COLOR['noire']} ] - {self.get_nickname(fromuser)} a tapé un mauvais mot de pass")
self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Mot de passe incorrecte") self.send2socket(f":{self.Config.SERVICE_NICKNAME} NOTICE {fromuser} :Mot de passe incorrecte")
@@ -888,13 +987,13 @@ class Irc:
response = self.create_defender_user(newnickname, newlevel, password) response = self.create_defender_user(newnickname, newlevel, password)
self.send2socket(f':{dnickname} NOTICE {fromuser} : {response}') self.send2socket(f':{dnickname} NOTICE {fromuser} : {response}')
self.debug(response) self.Base.logs.info(response)
except IndexError as ie: except IndexError as ie:
self.debug(f'_hcmd addaccess: {ie}') self.Base.logs.error(f'_hcmd addaccess: {ie}')
self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]') self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]')
except TypeError as te: except TypeError as te:
self.debug(f'_hcmd addaccess: out of index : {te}') self.Base.logs.error(f'_hcmd addaccess: out of index : {te}')
self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]') self.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} addaccess [nickname] [level] [password]')
case 'editaccess': case 'editaccess':
@@ -942,9 +1041,9 @@ class Irc:
self.send2socket(f":{dnickname} NOTICE {fromuser} : Impossible de modifier l'utilisateur {str(user_new_level)}") self.send2socket(f":{dnickname} NOTICE {fromuser} : Impossible de modifier l'utilisateur {str(user_new_level)}")
except TypeError as te: except TypeError as te:
self.debug(f"Type error : {te}") self.Base.logs.error(f"Type error : {te}")
except ValueError as ve: except ValueError as ve:
self.debug(f"Value Error : {ve}") self.Base.logs.error(f"Value Error : {ve}")
self.send2socket(f':{dnickname} NOTICE {fromuser} : .editaccess [USER] [NEWPASSWORD] [NEWLEVEL]') self.send2socket(f':{dnickname} NOTICE {fromuser} : .editaccess [USER] [NEWPASSWORD] [NEWLEVEL]')
case 'delaccess': case 'delaccess':
@@ -954,9 +1053,9 @@ class Irc:
if user_to_del != user_confirmation: if user_to_del != user_confirmation:
self.send2socket(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer') self.send2socket(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer')
self.Base.logs.warning(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer')
return None return None
print(len(cmd))
if len(cmd) < 3: if len(cmd) < 3:
self.send2socket(f':{dnickname} NOTICE {fromuser} : .delaccess [USER] [CONFIRMUSER]') self.send2socket(f':{dnickname} NOTICE {fromuser} : .delaccess [USER] [CONFIRMUSER]')
return None return None
@@ -975,6 +1074,7 @@ class Irc:
level_user_to_del = info_user[1] level_user_to_del = info_user[1]
if current_user_level <= level_user_to_del: if current_user_level <= level_user_to_del:
self.send2socket(f':{dnickname} NOTICE {fromuser} : You are not allowed to delete this access') self.send2socket(f':{dnickname} NOTICE {fromuser} : You are not allowed to delete this access')
self.Base.logs.warning(f':{dnickname} NOTICE {fromuser} : You are not allowed to delete this access')
return None return None
data_to_delete = {'user': user_to_del} data_to_delete = {'user': user_to_del}
@@ -984,6 +1084,7 @@ class Irc:
self.send2socket(f':{dnickname} NOTICE {fromuser} : User {user_to_del} has been deleted !') self.send2socket(f':{dnickname} NOTICE {fromuser} : User {user_to_del} has been deleted !')
else: else:
self.send2socket(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.") self.send2socket(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.")
self.Base.logs.warning(f":{dnickname} NOTICE {fromuser} : Impossible de supprimer l'utilisateur.")
case 'help': case 'help':
@@ -1022,11 +1123,12 @@ class Irc:
case 'unload': case 'unload':
# unload mod_dktmb # unload mod_dktmb
try:
module_name = str(cmd[1]).lower() # Le nom du module. exemple: mod_defender module_name = str(cmd[1]).lower() # Le nom du module. exemple: mod_defender
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender
if class_name in self.loaded_classes: if class_name in self.loaded_classes:
self.loaded_classes[class_name].unload()
for level, command in self.loaded_classes[class_name].commands_level.items(): for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands # Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]: for c in self.loaded_classes[class_name].commands_level[level]:
@@ -1039,14 +1141,18 @@ class Irc:
self.Base.db_delete_module(module_name) self.Base.db_delete_module(module_name)
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} supprimé") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} supprimé")
except:
self.Base.logs.error(f"Something went wrong with a module you want to load")
case 'reload': case 'reload':
# reload mod_dktmb # reload mod_dktmb
try:
module_name = str(cmd[1]).lower() # ==> mod_defender module_name = str(cmd[1]).lower() # ==> mod_defender
class_name = module_name.split('_')[1].capitalize() # ==> Defender class_name = module_name.split('_')[1].capitalize() # ==> Defender
if 'mods.' + module_name in sys.modules: if 'mods.' + module_name in sys.modules:
self.debug('Module Already Loaded ... reload the module ...') self.loaded_classes[class_name].unload()
self.Base.logs.info('Module Already Loaded ... reload the module ...')
the_module = sys.modules['mods.' + module_name] the_module = sys.modules['mods.' + module_name]
importlib.reload(the_module) importlib.reload(the_module)
@@ -1069,6 +1175,8 @@ class Irc:
return False return False
else: else:
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} n'est pas chargé !") self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} n'est pas chargé !")
except:
self.Base.logs.error(f"Something went wrong with a module you want to reload")
case 'quit': case 'quit':
try: try:
@@ -1083,12 +1191,12 @@ class Irc:
self.send2socket(f':{dnickname} NOTICE {fromuser} : Arrêt du service {dnickname}') self.send2socket(f':{dnickname} NOTICE {fromuser} : Arrêt du service {dnickname}')
self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}') self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}')
self.debug(f'Arrêt du server {dnickname}') self.Base.logs.info(f'Arrêt du server {dnickname}')
self.RESTART = 0 self.RESTART = 0
self.signal = False self.signal = False
except IndexError: except IndexError as ie:
self.debug('_hcmd die: out of index') self.Base.logs.error(f'{ie}')
self.send2socket(f"QUIT Good bye") self.send2socket(f"QUIT Good bye")
@@ -1101,16 +1209,19 @@ class Irc:
self.db_uid.clear() #Vider UID_DB self.db_uid.clear() #Vider UID_DB
self.db_chan = [] #Vider les salons self.db_chan = [] #Vider les salons
for class_name in self.loaded_classes:
self.loaded_classes[class_name].unload()
self.send2socket(f':{dnickname} NOTICE {fromuser} : Redémarrage du service {dnickname}') self.send2socket(f':{dnickname} NOTICE {fromuser} : Redémarrage du service {dnickname}')
self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}') self.send2socket(f':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}')
self.debug(f'Redémarrage du server {dnickname}') self.Base.logs.info(f'Redémarrage du server {dnickname}')
self.loaded_classes.clear() self.loaded_classes.clear()
self.RESTART = 1 # Set restart status to 1 saying that the service will restart self.RESTART = 1 # Set restart status to 1 saying that the service will restart
self.INIT = 1 # set init to 1 saying that the service will be re initiated self.INIT = 1 # set init to 1 saying that the service will be re initiated
case 'show_modules': case 'show_modules':
self.debug(self.loaded_classes) self.Base.logs.debug(self.loaded_classes)
results = self.Base.db_execute_query(f'SELECT module FROM {self.Base.DB_SCHEMA["modules"]}') results = self.Base.db_execute_query(f'SELECT module FROM {self.Base.DB_SCHEMA["modules"]}')
results = results.fetchall() results = results.fetchall()
@@ -1121,25 +1232,53 @@ class Irc:
for r in results: for r in results:
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Le module {r[0]} chargé") self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Le module {r[0]} chargé")
self.debug(r[0])
case 'show_timers': case 'show_timers':
if self.Base.running_timers: if self.Base.running_timers:
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :{self.Base.running_timers}") self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :{self.Base.running_timers}")
self.debug(self.Base.running_timers)
else: else:
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Aucun timers en cours d'execution") self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Aucun timers en cours d'execution")
case 'show_threads': case 'show_threads':
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :{self.Base.running_threads}")
running_thread_name:list = []
for thread in self.Base.running_threads:
running_thread_name.append(f"{thread.getName()} ({thread.is_alive()})")
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :{str(running_thread_name)}")
case 'uptime': case 'uptime':
uptime = self.get_defender_uptime() uptime = self.get_defender_uptime()
self.send2socket(f':{dnickname} NOTICE {fromuser} : {uptime}') self.send2socket(f':{dnickname} NOTICE {fromuser} : {uptime}')
case 'copyright': case 'copyright':
self.send2socket(f':{dnickname} NOTICE {fromuser} : # Defender V.{self.Config.DEFENDER_VERSION} Developped by adator® and dktmb® #') self.send2socket(f':{dnickname} NOTICE {fromuser} : # Defender V.{self.Base.DEFENDER_VERSION} Developped by adator® and dktmb® #')
case 'sentinel':
# .sentinel on
activation = str(cmd[1]).lower()
service_id = self.Config.SERVICE_ID
channel_to_dont_quit = [self.Config.SALON_JAIL, dchanlog]
if activation == 'on':
for chan in self.db_chan:
if not chan in channel_to_dont_quit:
self.send2socket(f":{service_id} JOIN {chan}")
if activation == 'off':
for chan in self.db_chan:
if not chan in channel_to_dont_quit:
self.send2socket(f":{service_id} PART {chan}")
case 'checkversion':
if self.Base.check_for_new_version():
self.send2socket(f':{dnickname} NOTICE {fromuser} : New Version available : {self.Base.DEFENDER_VERSION} >>> {self.Base.LATEST_DEFENDER_VERSION}')
self.send2socket(f':{dnickname} NOTICE {fromuser} : Please run (git pull origin main) in the current folder')
else:
self.send2socket(f':{dnickname} NOTICE {fromuser} : You have the latest version of defender')
pass
case _: case _:
pass pass

105
core/loadConf.py Normal file
View File

@@ -0,0 +1,105 @@
import json, os
from typing import Union
from dataclasses import dataclass, field
##########################################
# CONFIGURATION FILE #
##########################################
@dataclass
class ConfigDataModel:
SERVEUR_IP: str
SERVEUR_HOSTNAME: str # Le hostname du serveur IRC
SERVEUR_LINK: str # Host attendu par votre IRCd (ex. dans votre link block pour Unrealircd)
SERVEUR_PORT: int # Port du link
SERVEUR_PASSWORD: str # Mot de passe du link (Privilégiez argon2 sur Unrealircd)
SERVEUR_ID: str # SID (identification) du bot en tant que Services
SERVEUR_SSL: bool # Activer la connexion SSL
SERVICE_NAME: str # Le nom du service
SERVICE_NICKNAME: str # Nick du bot sur IRC
SERVICE_REALNAME: str # Realname du bot
SERVICE_USERNAME: str # Ident du bot
SERVICE_HOST: str # Host du bot
SERVICE_INFO: str # swhois du bot
SERVICE_CHANLOG: str # Salon des logs et autres messages issus du bot
SERVICE_SMODES: str # Mode du service
SERVICE_CMODES: str # Mode du salon (#ChanLog) que le bot appliquera à son entrée
SERVICE_UMODES: str # Mode que le bot pourra se donner à sa connexion au salon chanlog
SERVICE_PREFIX: str # Prefix pour envoyer les commandes au bot
SERVICE_ID: str = field(init=False) # L'identifiant du service
OWNER: str # Identifiant du compte admin
PASSWORD: str # Mot de passe du compte admin
SALON_JAIL: str # Salon pot de miel
SALON_JAIL_MODES: str # Mode du salon pot de miel
SALON_LIBERER: str # Le salon ou sera envoyé l'utilisateur clean
API_TIMEOUT: int # Timeout des api's
PORTS_TO_SCAN: list # Liste des ports a scanné pour une detection de proxy
WHITELISTED_IP: list # IP a ne pas scanner
GLINE_DURATION: str # La durée du gline
DEBUG_LEVEL: int # Le niveau des logs DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50
CONFIG_COLOR: dict
def __post_init__(self):
# Initialiser SERVICE_ID après la création de l'objet
self.SERVICE_ID:str = f"{self.SERVEUR_ID}AAAAAB"
class Config:
def __init__(self):
import_config = self.__load_json_configuration()
ConfigModel = ConfigDataModel(
SERVEUR_IP=import_config["SERVEUR_IP"],
SERVEUR_HOSTNAME=import_config["SERVEUR_HOSTNAME"],
SERVEUR_LINK=import_config["SERVEUR_LINK"],
SERVEUR_PORT=import_config["SERVEUR_PORT"],
SERVEUR_PASSWORD=import_config["SERVEUR_PASSWORD"],
SERVEUR_ID=import_config["SERVEUR_ID"],
SERVEUR_SSL=import_config["SERVEUR_SSL"],
SERVICE_NAME=import_config["SERVICE_NAME"],
SERVICE_NICKNAME=import_config["SERVICE_NICKNAME"],
SERVICE_REALNAME=import_config["SERVICE_REALNAME"],
SERVICE_USERNAME=import_config["SERVICE_USERNAME"],
SERVICE_HOST=import_config["SERVICE_HOST"],
SERVICE_INFO=import_config["SERVICE_INFO"],
SERVICE_CHANLOG=import_config["SERVICE_CHANLOG"],
SERVICE_SMODES=import_config["SERVICE_SMODES"],
SERVICE_CMODES=import_config["SERVICE_CMODES"],
SERVICE_UMODES=import_config["SERVICE_UMODES"],
SERVICE_PREFIX=import_config["SERVICE_PREFIX"],
OWNER=import_config["OWNER"],
PASSWORD=import_config["PASSWORD"],
SALON_JAIL=import_config["SALON_JAIL"],
SALON_JAIL_MODES=import_config["SALON_JAIL_MODES"],
SALON_LIBERER=import_config["SALON_LIBERER"],
API_TIMEOUT=import_config["API_TIMEOUT"],
PORTS_TO_SCAN=import_config["PORTS_TO_SCAN"],
WHITELISTED_IP=import_config["WHITELISTED_IP"],
GLINE_DURATION=import_config["GLINE_DURATION"],
DEBUG_LEVEL=import_config["DEBUG_LEVEL"],
CONFIG_COLOR=import_config["CONFIG_COLOR"]
)
self.ConfigModel = ConfigModel
return None
def __load_json_configuration(self):
conf_filename = f'core{os.sep}configuration.json'
with open(conf_filename, 'r') as configuration_data:
configuration:dict[str, Union[str, int, list, dict]] = json.load(configuration_data)
for key, value in configuration['CONFIG_COLOR'].items():
configuration['CONFIG_COLOR'][key] = value.encode('utf-8').decode('unicode_escape')
return configuration

File diff suppressed because it is too large Load Diff

View File

@@ -66,6 +66,10 @@ class Test():
self.core.db_execute_query(self.session, table_logs) self.core.db_execute_query(self.session, table_logs)
return None return None
def unload(self) -> None:
return None
def _hcmds(self, user:str, cmd: list) -> None: def _hcmds(self, user:str, cmd: list) -> None:
command = cmd[0].lower() command = cmd[0].lower()

3
version.json Normal file
View File

@@ -0,0 +1,3 @@
{
"version": "4.1.0"
}