Merge pull request #8 from adator85/main

align main to dev
This commit is contained in:
adator
2024-08-03 17:04:26 +02:00
committed by GitHub
8 changed files with 827 additions and 297 deletions

View File

@@ -1,8 +1,9 @@
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.configuration import Config
from core.sys_configuration import SysConfig
class Base: class Base:
@@ -19,6 +20,10 @@ class Base:
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.SysConfig = SysConfig() # Importer les information pour le systeme
self.init_log_system() # Demarrer le systeme de log
self.get_latest_defender_version()
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,6 +37,26 @@ 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_latest_defender_version(self) -> None:
try:
#token = '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'
token = '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'
json_url = f'https://github.com/adator85/IRC_DEFENDER_MODULES/blob/e27a027ae99a6c11171635b2a120803e8682aac6/version.json'
headers = {
'Authorization': f'token {token}',
'Accept': 'application/vnd.github.v3.raw' # Indique à GitHub que nous voulons le contenu brut du fichier
}
response = requests.get(json_url)
response.raise_for_status() # Vérifie si la requête a réussi
json_response:dict = response.json()
self.SysConfig.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 get_unixtime(self) -> int: def get_unixtime(self) -> int:
""" """
Cette fonction retourne un UNIXTIME de type 12365456 Cette fonction retourne un UNIXTIME de type 12365456
@@ -62,12 +87,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 +149,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 +186,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 +197,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 +219,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.SysConfig.DEFENDER_DB_PATH
full_path_db = self.Config.DEFENDER_DB_PATH + self.Config.DEFENDER_DB_NAME full_path_db = self.SysConfig.DEFENDER_DB_PATH + self.SysConfig.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 +371,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 +404,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 +430,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 +442,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

@@ -1,4 +1,3 @@
import os
########################################## ##########################################
# CONFIGURATION FILE : # # CONFIGURATION FILE : #
# Rename file to : configuration.py # # Rename file to : configuration.py #
@@ -6,18 +5,15 @@ import os
class Config: class Config:
DEFENDER_VERSION = '3.2.2' # MAJOR.MINOR.BATCH SERVEUR_IP = '0.0.0.0' # IP ou host du serveur à rejoindre
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_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_LINK = 'your link' # Host attendu par votre IRCd (ex. dans votre link block pour Unrealircd)
SERVEUR_PORT = 6666 # Port du link SERVEUR_PORT = 6666 # Port du link
SERVEUR_PASSWORD = 'your link password' # Mot de passe du link (Privilégiez argon2 sur Unrealircd) 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 SERVEUR_ID = '002' # SID (identification) du bot en tant que Services
SERVEUR_SSL = True # Activer / Desactiver la connexion SSL
SERVICE_NAME = 'defender' # Le nom du service
SERVICE_NICKNAME = 'BotName' # Nick du bot sur IRC SERVICE_NICKNAME = 'BotName' # Nick du bot sur IRC
SERVICE_REALNAME = 'BotRealname' # Realname du bot SERVICE_REALNAME = 'BotRealname' # Realname du bot
SERVICE_USERNAME = 'BotIdent' # Ident du bot SERVICE_USERNAME = 'BotIdent' # Ident du bot
@@ -37,9 +33,13 @@ class Config:
SALON_JAIL_MODES = 'sS' # Mode du 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 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 API_TIMEOUT = 2 # Timeout des api's
DEBUG = 0 # Afficher l'ensemble des messages du serveurs dans la console PORTS_TO_SCAN = [3028, 8080, 1080, 1085, 4145, 9050] # Liste des ports a scanné pour une detection de proxy
WHITELISTED_IP = ['127.0.0.1'] # IP a ne pas scanner
GLINE_DURATION = '1d' # La durée du gline
DEBUG_LEVEL = 10 # Le niveau des logs DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50
CONFIG_COLOR = { CONFIG_COLOR = {
'blanche': '\x0300', # Couleur blanche 'blanche': '\x0300', # Couleur blanche

View File

@@ -1,7 +1,9 @@
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.configuration import Config
from core.sys_configuration import SysConfig
from core.base import Base from core.base import Base
class Irc: class Irc:
@@ -16,12 +18,15 @@ 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()
self.SysConfig = SysConfig()
# Liste des commandes internes du bot # Liste des commandes internes du bot
self.commands_level = { self.commands_level = {
@@ -38,7 +43,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 +53,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 +103,25 @@ 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 ...')
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 +129,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 +166,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 +183,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.SysConfig.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,9 +198,11 @@ 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')) return None
except AttributeError as ae:
self.Base.logs.critical(f'{ae}')
def send2socket(self, send_message:str) -> None: def send2socket(self, send_message:str) -> None:
"""Envoit les commandes à envoyer au serveur. """Envoit les commandes à envoyer au serveur.
@@ -175,18 +211,25 @@ class Irc:
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 +237,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 +247,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
@@ -252,7 +298,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 +308,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 +332,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 +346,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 +355,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,14 +387,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: except Exception as e:
self.debug(f"Something went wrong with a module you want to load") 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:
@@ -399,10 +444,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
@@ -431,8 +476,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,
@@ -489,7 +532,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
@@ -500,13 +543,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']
@@ -527,15 +570,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
@@ -548,7 +591,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
@@ -606,13 +649,27 @@ class Irc:
def cmd(self, data:list) -> None: def cmd(self, data:list) -> None:
try: try:
cmd_to_send:list[str] = data.copy() cmd_to_send:list[str] = data.copy()
cmd = 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]:
@@ -654,8 +711,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
@@ -680,11 +737,24 @@ class Irc:
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 : {self.SysConfig.DEFENDER_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 : {self.SysConfig.DEFENDER_VERSION} ")
self.Base.logs.info(f"################################################")
# 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}')
@@ -750,6 +820,15 @@ class Irc:
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
@@ -783,7 +862,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.SysConfig.DEFENDER_VERSION}\x01')
return False return False
# Réponse a un TIME # Réponse a un TIME
@@ -809,8 +888,8 @@ 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
@@ -821,7 +900,7 @@ class Irc:
classe_object.cmd(cmd_to_send) 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:
@@ -853,8 +932,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':
@@ -879,6 +958,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")
@@ -895,13 +975,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':
@@ -949,9 +1029,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':
@@ -961,9 +1041,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
@@ -982,6 +1062,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}
@@ -991,6 +1072,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':
@@ -1034,7 +1116,7 @@ class Irc:
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]:
@@ -1048,7 +1130,7 @@ class Irc:
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: except:
self.debug(f"Something went wrong with a module you want to load") 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
@@ -1057,7 +1139,8 @@ class Irc:
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)
@@ -1081,7 +1164,7 @@ class Irc:
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: except:
self.debug(f"Something went wrong with a module you want to reload") self.Base.logs.error(f"Something went wrong with a module you want to reload")
case 'quit': case 'quit':
try: try:
@@ -1096,12 +1179,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")
@@ -1114,16 +1197,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()
@@ -1134,25 +1220,28 @@ 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.SysConfig.DEFENDER_VERSION} Developped by adator® and dktmb® #')
case 'sentinel': case 'sentinel':
# .sentinel on # .sentinel on

22
core/sys_configuration.py Normal file
View File

@@ -0,0 +1,22 @@
import os, json
####################################################################################################
# DO NOT TOUCH THIS FILE #
####################################################################################################
class SysConfig:
DEFENDER_VERSION = '4.0.0' # MAJOR.MINOR.BATCH
LATEST_DEFENDER_VERSION = '0.0.0' # 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) -> None:
version_filename = f'.{os.sep}version.json'
with open(version_filename, 'r') as version_data:
self.global_configuration:dict[str, str] = json.load(version_data)
self.DEFENDER_VERSION = self.global_configuration["version"]
return None

View File

@@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import re, socket, psutil, requests, json from typing import Union
import re, socket, psutil, requests, json, time
from core.irc import Irc from core.irc import Irc
# Le module crée devra réspecter quelques conditions # Le module crée devra réspecter quelques conditions
@@ -9,7 +10,10 @@ from core.irc import Irc
# 2 . Récuperer la configuration dans une variable # 2 . Récuperer la configuration dans une variable
# 3 . Définir et enregistrer les nouvelles commandes # 3 . Définir et enregistrer les nouvelles commandes
# 4 . Créer vos tables, en utilisant toujours le nom des votre classe en minuscule ==> defender_votre-table # 4 . Créer vos tables, en utilisant toujours le nom des votre classe en minuscule ==> defender_votre-table
# 3. une methode _hcmds(self, user:str, cmd: list) devra toujours etre crée. # 3. Methode suivantes:
# cmd(self, data:list)
# _hcmds(self, user:str, cmd: list)
# unload(self)
class Defender(): class Defender():
@@ -18,8 +22,22 @@ class Defender():
self.Irc = ircInstance # Ajouter l'object mod_irc a la classe ( Obligatoire ) self.Irc = ircInstance # Ajouter l'object mod_irc a la classe ( Obligatoire )
self.Config = ircInstance.Config # Ajouter la configuration a la classe ( Obligatoire ) self.Config = ircInstance.Config # Ajouter la configuration a la classe ( Obligatoire )
self.Base = ircInstance.Base # Ajouter l'objet Base au module ( Obligatoire ) self.Base = ircInstance.Base # Ajouter l'objet Base au module ( Obligatoire )
self.timeout = self.Config.API_TIMEOUT # API Timeout
self.Irc.debug(f'Module {self.__class__.__name__} loaded ...') self.freeipapi_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec freeipapi
self.cloudfilt_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec cloudfilt
self.abuseipdb_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec abuseipdb
self.psutil_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec psutil_scan
self.localscan_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec local_scan
self.abuseipdb_isRunning:bool = True
self.freeipapi_isRunning:bool = True
self.cloudfilt_isRunning:bool = True
self.psutil_isRunning:bool = True
self.localscan_isRunning:bool = True
self.reputationTimer_isRunning:bool = True
self.Irc.Base.logs.info(f'Module {self.__class__.__name__} loaded ...')
# Créer les nouvelles commandes du module # Créer les nouvelles commandes du module
self.commands_level = { self.commands_level = {
@@ -39,9 +57,6 @@ class Defender():
Args: Args:
commands (list): Liste des commandes du module commands (list): Liste des commandes du module
Returns:
None: Aucun retour attendu
""" """
for level, com in commands.items(): for level, com in commands.items():
for c in commands[level]: for c in commands[level]:
@@ -51,6 +66,24 @@ class Defender():
return None return None
def unload(self) -> None:
"""Cette methode sera executée a chaque désactivation ou
rechargement de module
"""
self.abuseipdb_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec abuseipdb
self.freeipapi_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec freeipapi
self.cloudfilt_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec cloudfilt
self.psutil_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec psutil_scan
self.localscan_remote_ip:list = [] # Liste qui va contenir les adresses ip a scanner avec local_scan
self.abuseipdb_isRunning:bool = False
self.freeipapi_isRunning:bool = False
self.cloudfilt_isRunning:bool = False
self.psutil_isRunning:bool = False
self.localscan_isRunning:bool = False
self.reputationTimer_isRunning:bool = False
return None
def __create_tables(self) -> None: def __create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas. """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 Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
@@ -95,7 +128,10 @@ class Defender():
self.db_reputation = {} # Definir la variable qui contiendra la liste des user concerné par la réputation self.db_reputation = {} # Definir la variable qui contiendra la liste des user concerné par la réputation
self.flood_system = {} # Variable qui va contenir les users self.flood_system = {} # Variable qui va contenir les users
self.reputation_first_connexion = {'ip': '', 'score': -1} # Contient les premieres informations de connexion self.reputation_first_connexion = {'ip': '', 'score': -1} # Contient les premieres informations de connexion
# 13c34603fee4d2941a2c443cc5c77fd750757ca2a2c1b304bd0f418aff80c24be12651d1a3cfe674
self.abuseipdb_key = '13c34603fee4d2941a2c443cc5c77fd750757ca2a2c1b304bd0f418aff80c24be12651d1a3cfe674' # Laisser vide si aucune clé self.abuseipdb_key = '13c34603fee4d2941a2c443cc5c77fd750757ca2a2c1b304bd0f418aff80c24be12651d1a3cfe674' # Laisser vide si aucune clé
# r1gEtjtfgRQjtNBDMxsg
self.cloudfilt_key = 'r1gEtjtfgRQjtNBDMxsg' # Laisser vide si aucune clé
# Rejoindre les salons # Rejoindre les salons
self.join_saved_channels() self.join_saved_channels()
@@ -109,6 +145,8 @@ class Defender():
'local_scan': 0, 'local_scan': 0,
'psutil_scan': 0, 'psutil_scan': 0,
'abuseipdb_scan': 0, 'abuseipdb_scan': 0,
'freeipapi_scan': 0,
'cloudfilt_scan': 0,
'flood': 0, 'flood': 0,
'flood_message': 5, 'flood_message': 5,
'flood_time': 1, 'flood_time': 1,
@@ -118,6 +156,14 @@ class Defender():
# Syncrhoniser la variable defConfig avec la configuration de la base de données. # Syncrhoniser la variable defConfig avec la configuration de la base de données.
self.sync_db_configuration() self.sync_db_configuration()
# Démarrer les threads pour démarrer les api
self.Base.create_thread(func=self.thread_freeipapi_scan)
self.Base.create_thread(func=self.thread_cloudfilt_scan)
self.Base.create_thread(func=self.thread_abuseipdb_scan)
self.Base.create_thread(func=self.thread_local_scan)
self.Base.create_thread(func=self.thread_psutil_scan)
self.Base.create_thread(func=self.thread_reputation_timer)
return True return True
def sync_db_configuration(self) -> None: def sync_db_configuration(self) -> None:
@@ -135,7 +181,7 @@ class Defender():
insert = self.Base.db_execute_query('INSERT INTO def_config (datetime, parameter, value) VALUES (:datetime, :parameter, :value)', mes_donnees) insert = self.Base.db_execute_query('INSERT INTO def_config (datetime, parameter, value) VALUES (:datetime, :parameter, :value)', mes_donnees)
insert_rows = insert.rowcount insert_rows = insert.rowcount
if insert_rows > 0: if insert_rows > 0:
self.Irc.debug(f'Row affected into def_config : {insert_rows}') self.Irc.Base.logs.debug(f'Row affected into def_config : {insert_rows}')
# Inserer une nouvelle configuration # Inserer une nouvelle configuration
for param, value in self.defConfig.items(): for param, value in self.defConfig.items():
@@ -149,7 +195,7 @@ class Defender():
insert = self.Base.db_execute_query('INSERT INTO def_config (datetime, parameter, value) VALUES (:datetime, :parameter, :value)', mes_donnees) insert = self.Base.db_execute_query('INSERT INTO def_config (datetime, parameter, value) VALUES (:datetime, :parameter, :value)', mes_donnees)
insert_rows = insert.rowcount insert_rows = insert.rowcount
if insert_rows > 0: if insert_rows > 0:
self.Irc.debug(f'DB_Def_config - new param included : {insert_rows}') self.Irc.Base.logs.debug(f'DB_Def_config - new param included : {insert_rows}')
# Supprimer un parameter si il n'existe plus dans la variable global # Supprimer un parameter si il n'existe plus dans la variable global
query = "SELECT parameter FROM def_config" query = "SELECT parameter FROM def_config"
@@ -162,7 +208,7 @@ class Defender():
delete = self.Base.db_execute_query('DELETE FROM def_config WHERE parameter = :parameter', mes_donnees) delete = self.Base.db_execute_query('DELETE FROM def_config WHERE parameter = :parameter', mes_donnees)
row_affected = delete.rowcount row_affected = delete.rowcount
if row_affected > 0: if row_affected > 0:
self.Irc.debug(f'DB_Def_config - param [{dbparam[0]}] has been deleted') self.Irc.Base.logs.debug(f'DB_Def_config - param [{dbparam[0]}] has been deleted')
# Synchroniser la base de données avec la variable global # Synchroniser la base de données avec la variable global
query = "SELECT parameter, value FROM def_config" query = "SELECT parameter, value FROM def_config"
@@ -172,13 +218,13 @@ class Defender():
for param, value in result: for param, value in result:
self.defConfig[param] = self.Base.int_if_possible(value) self.defConfig[param] = self.Base.int_if_possible(value)
self.Irc.debug(self.defConfig) self.Irc.Base.logs.debug(self.defConfig)
return None return None
def update_db_configuration(self, param:str, value:str) -> None: def update_db_configuration(self, param:str, value:str) -> None:
if not param in self.defConfig: if not param in self.defConfig:
self.Irc.debug(f"Le parametre {param} n'existe pas dans la variable global") self.Irc.Base.logs.error(f"Le parametre {param} n'existe pas dans la variable global")
return None return None
mes_donnees = {'parameter': param} mes_donnees = {'parameter': param}
@@ -192,9 +238,9 @@ class Defender():
updated_rows = update.rowcount updated_rows = update.rowcount
if updated_rows > 0: if updated_rows > 0:
self.defConfig[param] = self.Base.int_if_possible(value) self.defConfig[param] = self.Base.int_if_possible(value)
self.Irc.debug(f'DB_Def_config - new param updated : {param} {value}') self.Irc.Base.logs.debug(f'DB_Def_config - new param updated : {param} {value}')
self.Irc.debug(self.defConfig) self.Irc.Base.logs.debug(self.defConfig)
def add_defender_channel(self, channel:str) -> bool: def add_defender_channel(self, channel:str) -> bool:
"""Cette fonction ajoute les salons de join de Defender """Cette fonction ajoute les salons de join de Defender
@@ -261,7 +307,7 @@ class Defender():
secret_code = self.Base.get_random(8) secret_code = self.Base.get_random(8)
if not uid in self.Irc.db_uid: if not uid in self.Irc.db_uid:
self.Irc.debug(f'Etrange UID {uid}') self.Irc.Base.logs.error(f'Etrange UID {uid}')
return None return None
if uid in self.db_reputation: if uid in self.db_reputation:
@@ -269,7 +315,7 @@ class Defender():
self.db_reputation[uid]['updated_datetime'] = currentDateTime self.db_reputation[uid]['updated_datetime'] = currentDateTime
self.db_reputation[uid]['secret_code'] = secret_code self.db_reputation[uid]['secret_code'] = secret_code
else: else:
self.Irc.debug(f"L'UID {uid} n'existe pas dans REPUTATION_DB") self.Irc.Base.logs.error(f"L'UID {uid} n'existe pas dans REPUTATION_DB")
return None return None
@@ -284,7 +330,7 @@ class Defender():
if uid in self.db_reputation: if uid in self.db_reputation:
# Si le nickname existe dans le dictionnaire alors le supprimer # Si le nickname existe dans le dictionnaire alors le supprimer
del self.db_reputation[uid] del self.db_reputation[uid]
self.Irc.debug(f"Le UID {uid} a été supprimé du REPUTATION_DB") self.Irc.Base.logs.debug(f"Le UID {uid} a été supprimé du REPUTATION_DB")
def insert_db_trusted(self, uid: str, nickname:str) -> None: def insert_db_trusted(self, uid: str, nickname:str) -> None:
@@ -393,21 +439,22 @@ class Defender():
self.Irc.send2socket(f":{service_id} MODE {chan} +b {jailed_nickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} +b {jailed_nickname}!*@*")
self.Irc.send2socket(f":{service_id} KICK {chan} {jailed_nickname}") self.Irc.send2socket(f":{service_id} KICK {chan} {jailed_nickname}")
self.Irc.debug(f"system_reputation : {jailed_nickname} à été capturé par le système de réputation") self.Irc.Base.logs.info(f"system_reputation : {jailed_nickname} à été capturé par le système de réputation")
# self.Irc.create_ping_timer(int(self.defConfig['reputation_timer']) * 60, 'Defender', 'system_reputation_timer') # self.Irc.create_ping_timer(int(self.defConfig['reputation_timer']) * 60, 'Defender', 'system_reputation_timer')
self.Base.create_timer(int(self.defConfig['reputation_timer']) * 60, self.system_reputation_timer) # self.Base.create_timer(int(self.defConfig['reputation_timer']) * 60, self.system_reputation_timer)
else: else:
self.Irc.debug(f"system_reputation : {jailed_nickname} à été supprimé du système de réputation car connecté via WebIrc ou il est dans la 'Trusted list'") self.Irc.Base.logs.info(f"system_reputation : {jailed_nickname} à été supprimé du système de réputation car connecté via WebIrc ou il est dans la 'Trusted list'")
self.delete_db_reputation(uid) self.delete_db_reputation(uid)
except IndexError as e: except IndexError as e:
self.Irc.debug(f"system_reputation : {str(e)}") self.Irc.Base.logs.error(f"system_reputation : {str(e)}")
def system_reputation_timer(self) -> None: def system_reputation_timer(self) -> None:
try: try:
reputation_flag = int(self.defConfig['reputation']) reputation_flag = int(self.defConfig['reputation'])
reputation_timer = int(self.defConfig['reputation_timer']) reputation_timer = int(self.defConfig['reputation_timer'])
reputation_seuil = self.defConfig['reputation_seuil'] reputation_seuil = self.defConfig['reputation_seuil']
ban_all_chan = self.Base.int_if_possible(self.defConfig['reputation_ban_all_chan'])
service_id = self.Config.SERVICE_ID service_id = self.Config.SERVICE_ID
dchanlog = self.Config.SERVICE_CHANLOG dchanlog = self.Config.SERVICE_CHANLOG
color_red = self.Config.CONFIG_COLOR['rouge'] color_red = self.Config.CONFIG_COLOR['rouge']
@@ -419,25 +466,25 @@ class Defender():
elif reputation_timer == 0: elif reputation_timer == 0:
return None return None
# self.Irc.debug(self.db_reputation)
uid_to_clean = [] uid_to_clean = []
for uid in self.db_reputation: for uid in self.db_reputation:
if not self.db_reputation[uid]['isWebirc']: # Si il ne vient pas de WebIRC if not self.db_reputation[uid]['isWebirc']: # Si il ne vient pas de WebIRC
self.Irc.debug(f"Nickname: {self.db_reputation[uid]['nickname']} | uptime: {self.get_user_uptime_in_minutes(uid)} | reputation time: {reputation_timer}") # self.Irc.debug(f"Nickname: {self.db_reputation[uid]['nickname']} | uptime: {self.get_user_uptime_in_minutes(uid)} | reputation time: {reputation_timer}")
if self.get_user_uptime_in_minutes(uid) >= reputation_timer and int(self.db_reputation[uid]['score']) <= int(reputation_seuil): if self.get_user_uptime_in_minutes(uid) >= reputation_timer and int(self.db_reputation[uid]['score']) <= int(reputation_seuil):
self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} :[{color_red} REPUTATION {color_black}] : Action sur {self.db_reputation[uid]['nickname']} aprés {str(reputation_timer)} minutes d'inactivité") self.Irc.send2socket(f":{service_id} PRIVMSG {dchanlog} :[{color_red} REPUTATION {color_black}] : Action sur {self.db_reputation[uid]['nickname']} aprés {str(reputation_timer)} minutes d'inactivité")
# if not system_reputation_timer_action(cglobal['reputation_timer_action'], uid, self.db_reputation[uid]['nickname']): # if not system_reputation_timer_action(cglobal['reputation_timer_action'], uid, self.db_reputation[uid]['nickname']):
# return False # return False
self.Irc.send2socket(f":{service_id} KILL {self.db_reputation[uid]['nickname']} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code ") self.Irc.send2socket(f":{service_id} KILL {self.db_reputation[uid]['nickname']} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code ")
self.Irc.debug(f"Action sur {self.db_reputation[uid]['nickname']} aprés {str(reputation_timer)} minutes d'inactivité") self.Irc.Base.logs.info(f"Nickname: {self.db_reputation[uid]['nickname']} KILLED after {str(reputation_timer)} minutes of inactivity")
uid_to_clean.append(uid) uid_to_clean.append(uid)
for uid in uid_to_clean: for uid in uid_to_clean:
# Suppression des éléments dans {UID_DB} et {REPUTATION_DB} # Suppression des éléments dans {UID_DB} et {REPUTATION_DB}
for chan in self.Irc.db_chan: for chan in self.Irc.db_chan:
if chan != salon_jail: if chan != salon_jail and ban_all_chan == 1:
self.Irc.send2socket(f":{service_id} MODE {chan} -b {self.db_reputation[uid]['nickname']}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} -b {self.db_reputation[uid]['nickname']}!*@*")
# Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}. # Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}.
@@ -445,7 +492,17 @@ class Defender():
self.delete_db_reputation(uid) self.delete_db_reputation(uid)
except AssertionError as ae: except AssertionError as ae:
self.Irc.debug(f'Assertion Error -> {ae}') self.Irc.Base.logs.error(f'Assertion Error -> {ae}')
def thread_reputation_timer(self) -> None:
try:
while self.reputationTimer_isRunning:
self.system_reputation_timer()
time.sleep(5)
return None
except ValueError as ve:
self.Irc.Base.logs.error(f"thread_reputation_timer Error : {ve}")
def _execute_flood_action(self, action:str, channel:str) -> None: def _execute_flood_action(self, action:str, channel:str) -> None:
"""DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING """DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING
@@ -505,10 +562,10 @@ class Defender():
get_diff_secondes = unixtime - self.flood_system[get_detected_uid]['first_msg_time'] get_diff_secondes = unixtime - self.flood_system[get_detected_uid]['first_msg_time']
elif self.flood_system[get_detected_uid]['nbr_msg'] > flood_message: elif self.flood_system[get_detected_uid]['nbr_msg'] > flood_message:
self.Irc.debug('system de flood detecté') self.Irc.Base.logs.info('system de flood detecté')
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} : {color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)') self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} : {color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)')
self.Irc.send2socket(f":{service_id} MODE {channel} +m") self.Irc.send2socket(f":{service_id} MODE {channel} +m")
self.Irc.debug(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}') self.Irc.Base.logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}')
self.flood_system[get_detected_uid]['nbr_msg'] = 0 self.flood_system[get_detected_uid]['nbr_msg'] = 0
self.flood_system[get_detected_uid]['first_msg_time'] = unixtime self.flood_system[get_detected_uid]['first_msg_time'] = unixtime
@@ -533,10 +590,17 @@ class Defender():
return None return None
def scan_ports(self, remote_ip: str) -> None: def scan_ports(self, remote_ip: str) -> None:
"""local_scan
Args:
remote_ip (str): _description_
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
for port in self.Config.PORTS_TO_SCAN: for port in self.Config.PORTS_TO_SCAN:
newSocket = '' newSocket = ''
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
newSocket.settimeout(0.5) newSocket.settimeout(0.5)
try: try:
connection = (remote_ip, self.Base.int_if_possible(port)) connection = (remote_ip, self.Base.int_if_possible(port))
@@ -548,25 +612,76 @@ class Defender():
newSocket.shutdown(socket.SHUT_RDWR) newSocket.shutdown(socket.SHUT_RDWR)
newSocket.close() newSocket.close()
except (socket.timeout, ConnectionRefusedError): except (socket.timeout, ConnectionRefusedError):
self.Irc.debug(f"Le port {str(port)} est fermé") self.Base.logs.info(f"Le port {remote_ip}:{str(port)} est fermé")
except AttributeError as ae: except AttributeError as ae:
self.Irc.debug(f"AttributeError : {ae}") self.Base.logs.warning(f"AttributeError ({remote_ip}): {ae}")
except socket.gaierror as err:
self.Base.logs.warning(f"Address Info Error ({remote_ip}): {err}")
finally: finally:
# newSocket.shutdown(socket.SHUT_RDWR) # newSocket.shutdown(socket.SHUT_RDWR)
newSocket.close() newSocket.close()
self.Irc.debug('=======> Fermeture de la socket') self.Base.logs.info('=======> Fermeture de la socket')
pass pass
def thread_local_scan(self) -> None:
try:
while self.localscan_isRunning:
list_to_remove:list = []
for ip in self.localscan_remote_ip:
self.scan_ports(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.localscan_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Base.logs.warning(f"thread_local_scan Error : {ve}")
def get_ports_connexion(self, remote_ip: str) -> list[int]: def get_ports_connexion(self, remote_ip: str) -> list[int]:
"""psutil_scan
Args:
remote_ip (str): _description_
Returns:
list[int]: _description_
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
connections = psutil.net_connections(kind='inet') connections = psutil.net_connections(kind='inet')
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip] matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
self.Irc.debug(f"Connexion of {remote_ip} using ports : {str(matching_ports)}") self.Base.logs.info(f"Connexion of {remote_ip} using ports : {str(matching_ports)}")
return matching_ports return matching_ports
def abuseipdb_scan(self, remote_ip:str) -> dict[str, any] | None: def thread_psutil_scan(self) -> None:
try:
while self.psutil_isRunning:
list_to_remove:list = []
for ip in self.psutil_remote_ip:
self.get_ports_connexion(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.psutil_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Base.logs.warning(f"thread_psutil_scan Error : {ve}")
def abuseipdb_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec AbuseIpDB """Analyse l'ip avec AbuseIpDB
Cette methode devra etre lancer toujours via un thread ou un timer. Cette methode devra etre lancer toujours via un thread ou un timer.
Args: Args:
@@ -576,6 +691,8 @@ class Defender():
dict[str, any] | None: les informations du provider dict[str, any] | None: les informations du provider
keys : 'score', 'country', 'isTor', 'totalReports' keys : 'score', 'country', 'isTor', 'totalReports'
""" """
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['abuseipdb_scan'] == 0: if self.defConfig['abuseipdb_scan'] == 0:
return None return None
@@ -593,11 +710,14 @@ class Defender():
'Key': self.abuseipdb_key 'Key': self.abuseipdb_key
} }
response = requests.request(method='GET', url=url, headers=headers, params=querystring) response = requests.request(method='GET', url=url, headers=headers, params=querystring, timeout=self.timeout)
# Formatted output # Formatted output
decodedResponse = json.loads(response.text) decodedResponse = json.loads(response.text)
try: try:
if not 'data' in decodedResponse:
return None
result = { result = {
'score': decodedResponse['data']['abuseConfidenceScore'], 'score': decodedResponse['data']['abuseConfidenceScore'],
'country': decodedResponse['data']['countryCode'], 'country': decodedResponse['data']['countryCode'],
@@ -610,13 +730,191 @@ class Defender():
color_red = self.Config.CONFIG_COLOR['rouge'] color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire'] color_black = self.Config.CONFIG_COLOR['noire']
self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}ABUSEIPDB_SCAN{color_black} ] : Connexion de {remote_ip} Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}") self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}ABUSEIPDB_SCAN{color_black} ] : Connexion de {remote_ip} ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}")
if result['isTor']:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
elif result['score'] >= 95:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
response.close() response.close()
return result return result
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f"AbuseIpDb KeyError : {ke}") self.Base.logs.error(f"AbuseIpDb KeyError : {ke}")
except requests.ReadTimeout as rt:
self.Base.logs.error(f"AbuseIpDb Timeout : {rt}")
except requests.ConnectionError as ce:
self.Base.logs.error(f"AbuseIpDb Connection Error : {ce}")
def thread_abuseipdb_scan(self) -> None:
try:
while self.abuseipdb_isRunning:
list_to_remove:list = []
for ip in self.abuseipdb_remote_ip:
self.abuseipdb_scan(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.abuseipdb_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Base.logs.error(f"thread_abuseipdb_scan Error : {ve}")
def freeipapi_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec Freeipapi
Cette methode devra etre lancer toujours via un thread ou un timer.
Args:
remote_ip (_type_): l'ip a analyser
Returns:
dict[str, any] | None: les informations du provider
keys : 'countryCode', 'isProxy'
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['freeipapi_scan'] == 0:
return None
service_id = self.Config.SERVICE_ID
service_chanlog = self.Config.SERVICE_CHANLOG
color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire']
url = f'https://freeipapi.com/api/json/{remote_ip}'
headers = {
'Accept': 'application/json',
}
response = requests.request(method='GET', url=url, headers=headers, timeout=self.timeout)
# Formatted output
decodedResponse = json.loads(response.text)
try:
status_code = response.status_code
if status_code == 429:
self.Base.logs.warning(f'Too Many Requests - The rate limit for the API has been exceeded.')
return None
elif status_code != 200:
self.Base.logs.warning(f'status code = {str(status_code)}')
return None
result = {
'countryCode': decodedResponse['countryCode'] if 'countryCode' in decodedResponse else None,
'isProxy': decodedResponse['isProxy'] if 'isProxy' in decodedResponse else None
}
self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}FREEIPAPI_SCAN{color_black} ] : Connexion de {remote_ip} ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}")
if result['isProxy']:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
response.close()
return result
except KeyError as ke:
self.Base.logs.error(f"FREEIPAPI_SCAN KeyError : {ke}")
def thread_freeipapi_scan(self) -> None:
try:
while self.freeipapi_isRunning:
list_to_remove:list = []
for ip in self.freeipapi_remote_ip:
self.freeipapi_scan(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.freeipapi_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Base.logs.error(f"thread_freeipapi_scan Error : {ve}")
def cloudfilt_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec cloudfilt
Cette methode devra etre lancer toujours via un thread ou un timer.
Args:
remote_ip (_type_): l'ip a analyser
Returns:
dict[str, any] | None: les informations du provider
keys : 'countryCode', 'isProxy'
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['cloudfilt_scan'] == 0:
return None
if self.cloudfilt_key == '':
return None
service_id = self.Config.SERVICE_ID
service_chanlog = self.Config.SERVICE_CHANLOG
color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire']
url = f"https://developers18334.cloudfilt.com/"
data = {
'ip': remote_ip,
'key': self.cloudfilt_key
}
response = requests.post(url=url, data=data)
# Formatted output
decodedResponse = json.loads(response.text)
try:
status_code = response.status_code
if status_code != 200:
self.Base.logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
return None
result = {
'countryiso': decodedResponse['countryiso'] if 'countryiso' in decodedResponse else None,
'listed': decodedResponse['listed'] if 'listed' in decodedResponse else None,
'listed_by': decodedResponse['listed_by'] if 'listed_by' in decodedResponse else None,
'host': decodedResponse['host'] if 'host' in decodedResponse else None
}
self.Irc.send2socket(f":{service_id} PRIVMSG {service_chanlog} :[ {color_red}CLOUDFILT_SCAN{color_black} ] : Connexion de {str(remote_ip)} ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}")
if result['listed']:
self.Irc.send2socket(f":{service_id} GLINE +*@{remote_ip} {self.Config.GLINE_DURATION} You connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
response.close()
return result
except KeyError as ke:
self.Base.logs.error(f"CLOUDFILT_SCAN KeyError : {ke}")
return None
def thread_cloudfilt_scan(self) -> None:
try:
while self.cloudfilt_isRunning:
list_to_remove:list = []
for ip in self.cloudfilt_remote_ip:
self.cloudfilt_scan(ip)
list_to_remove.append(ip)
time.sleep(1)
for ip_to_remove in list_to_remove:
self.cloudfilt_remote_ip.remove(ip_to_remove)
time.sleep(1)
return None
except ValueError as ve:
self.Base.logs.error(f"Thread_cloudfilt_scan Error : {ve}")
def cmd(self, data:list) -> None: def cmd(self, data:list) -> None:
@@ -634,18 +932,28 @@ class Defender():
self.reputation_first_connexion['ip'] = cmd[2] self.reputation_first_connexion['ip'] = cmd[2]
self.reputation_first_connexion['score'] = cmd[3] self.reputation_first_connexion['score'] = cmd[3]
if not self.Base.is_valid_ip(cmd[2]):
return None
# self.Base.scan_ports(cmd[2]) # self.Base.scan_ports(cmd[2])
if self.defConfig['local_scan'] == 1: if self.defConfig['local_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.scan_ports, (cmd[2], )) self.localscan_remote_ip.append(cmd[2])
if self.defConfig['psutil_scan'] == 1: if self.defConfig['psutil_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.get_ports_connexion, (cmd[2], )) self.psutil_remote_ip.append(cmd[2])
if self.defConfig['abuseipdb_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.abuseipdb_remote_ip.append(cmd[2])
if self.defConfig['freeipapi_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.freeipapi_remote_ip.append(cmd[2])
if self.defConfig['cloudfilt_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.cloudfilt_remote_ip.append(cmd[2])
if self.defConfig['abuseipdb_scan'] == 1:
self.Base.create_thread(self.abuseipdb_scan, (cmd[2], ))
# Possibilité de déclancher les bans a ce niveau. # Possibilité de déclancher les bans a ce niveau.
except IndexError: except IndexError:
self.Irc.debug(f'cmd reputation: index error') self.Irc.Base.logs.error(f'cmd reputation: index error')
match cmd[2]: match cmd[2]:
@@ -698,7 +1006,7 @@ class Defender():
if uid in self.db_reputation: if uid in self.db_reputation:
if reputation_flag == 1 and int(client_score) <= int(reputation_seuil): if reputation_flag == 1 and int(client_score) <= int(reputation_seuil):
self.system_reputation(uid) self.system_reputation(uid)
self.Irc.debug('Démarrer le systeme de reputation') self.Base.logs.info('Démarrer le systeme de reputation')
case 'SJOIN': case 'SJOIN':
# ['@msgid=F9B7JeHL5pj9nN57cJ5pEr;time=2023-12-28T20:47:24.305Z', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL'] # ['@msgid=F9B7JeHL5pj9nN57cJ5pEr;time=2023-12-28T20:47:24.305Z', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL']
@@ -719,21 +1027,31 @@ class Defender():
self.Irc.send2socket(f":{service_id} MODE {parsed_chan} +b {self.db_reputation[parsed_UID]['nickname']}!*@*") self.Irc.send2socket(f":{service_id} MODE {parsed_chan} +b {self.db_reputation[parsed_UID]['nickname']}!*@*")
self.Irc.send2socket(f":{service_id} KICK {parsed_chan} {self.db_reputation[parsed_UID]['nickname']}") self.Irc.send2socket(f":{service_id} KICK {parsed_chan} {self.db_reputation[parsed_UID]['nickname']}")
self.Irc.debug(f'SJOIN parsed_uid : {parsed_UID}') self.Base.logs.debug(f'SJOIN parsed_uid : {parsed_UID}')
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f"key error SJOIN : {ke}") self.Base.logs.error(f"key error SJOIN : {ke}")
case 'SLOG': case 'SLOG':
# self.Base.scan_ports(cmd[7]) # self.Base.scan_ports(cmd[7])
cmd.pop(0) cmd.pop(0)
if self.defConfig['local_scan'] == 1:
self.Base.create_thread(self.scan_ports, (cmd[7], ))
if self.defConfig['psutil_scan'] == 1: if not self.Base.is_valid_ip(cmd[7]):
self.Base.create_thread(self.get_ports_connexion, (cmd[7], )) return None
if self.defConfig['abuseipdb_scan'] == 1: if self.defConfig['local_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.Base.create_thread(self.abuseipdb_scan, (cmd[7], )) self.localscan_remote_ip.append(cmd[7])
if self.defConfig['psutil_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.psutil_remote_ip.append(cmd[7])
if self.defConfig['abuseipdb_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.abuseipdb_remote_ip.append(cmd[7])
if self.defConfig['freeipapi_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.freeipapi_remote_ip.append(cmd[7])
if self.defConfig['cloudfilt_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.cloudfilt_remote_ip.append(cmd[7])
case 'NICK': case 'NICK':
# :0010BS24L NICK [NEWNICK] 1697917711 # :0010BS24L NICK [NEWNICK] 1697917711
@@ -755,11 +1073,12 @@ class Defender():
self.Irc.send2socket(f":{service_id} MODE {chan} -b {oldnick}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} -b {oldnick}!*@*")
self.Irc.send2socket(f":{service_id} MODE {chan} +b {newnickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} +b {newnickname}!*@*")
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f'cmd - NICK - KeyError: {ke}') self.Base.logs.error(f'cmd - NICK - KeyError: {ke}')
case 'QUIT': case 'QUIT':
# :001N1WD7L QUIT :Quit: free_znc_1 # :001N1WD7L QUIT :Quit: free_znc_1
cmd.pop(0) cmd.pop(0)
ban_all_chan = self.Base.int_if_possible(self.defConfig['reputation_ban_all_chan'])
user_id = str(cmd[0]).replace(':','') user_id = str(cmd[0]).replace(':','')
final_UID = user_id final_UID = user_id
@@ -769,7 +1088,7 @@ class Defender():
if final_UID in self.db_reputation: if final_UID in self.db_reputation:
final_nickname = self.db_reputation[user_id]['nickname'] final_nickname = self.db_reputation[user_id]['nickname']
for chan in self.Irc.db_chan: for chan in self.Irc.db_chan:
if chan != jail_salon: if chan != jail_salon and ban_all_chan == 1:
self.Irc.send2socket(f":{service_id} MODE {chan} -b {final_nickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} -b {final_nickname}!*@*")
self.delete_db_reputation(final_UID) self.delete_db_reputation(final_UID)
@@ -796,9 +1115,9 @@ class Defender():
# self.Base.create_timer(timer_sent, self.Base.garbage_collector_sockets) # self.Base.create_timer(timer_sent, self.Base.garbage_collector_sockets)
except TypeError as te: except TypeError as te:
self.Irc.debug(f"Type Error -> {te}") self.Base.logs.error(f"Type Error -> {te}")
except ValueError as ve: except ValueError as ve:
self.Irc.debug(f"Value Error -> {ve}") self.Base.logs.error(f"Value Error -> {ve}")
case 'show_reputation': case 'show_reputation':
@@ -822,12 +1141,11 @@ class Defender():
reputation_seuil = self.defConfig['reputation_seuil'] reputation_seuil = self.defConfig['reputation_seuil']
welcome_salon = self.Config.SALON_LIBERER welcome_salon = self.Config.SALON_LIBERER
self.Irc.debug(f"IP de {jailed_nickname} : {jailed_IP}") self.Base.logs.debug(f"IP de {jailed_nickname} : {jailed_IP}")
link = self.Config.SERVEUR_LINK link = self.Config.SERVEUR_LINK
color_green = self.Config.CONFIG_COLOR['verte'] color_green = self.Config.CONFIG_COLOR['verte']
color_black = self.Config.CONFIG_COLOR['noire'] color_black = self.Config.CONFIG_COLOR['noire']
if jailed_UID in self.db_reputation: if jailed_UID in self.db_reputation:
if release_code == self.db_reputation[jailed_UID]['secret_code']: if release_code == self.db_reputation[jailed_UID]['secret_code']:
self.Irc.send2socket(f':{dnickname} PRIVMSG {jailed_salon} : Bon mot de passe. Allez du vent !') self.Irc.send2socket(f':{dnickname} PRIVMSG {jailed_salon} : Bon mot de passe. Allez du vent !')
@@ -838,7 +1156,7 @@ class Defender():
self.Irc.send2socket(f":{service_id} MODE {chan} -b {jailed_nickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {chan} -b {jailed_nickname}!*@*")
del self.db_reputation[jailed_UID] del self.db_reputation[jailed_UID]
self.Irc.debug(f'{jailed_UID} - {jailed_nickname} removed from REPUTATION_DB') self.Base.logs.debug(f'{jailed_UID} - {jailed_nickname} removed from REPUTATION_DB')
self.Irc.send2socket(f":{service_id} SAPART {jailed_nickname} {jailed_salon}") self.Irc.send2socket(f":{service_id} SAPART {jailed_nickname} {jailed_salon}")
self.Irc.send2socket(f":{service_id} SAJOIN {jailed_nickname} {welcome_salon}") self.Irc.send2socket(f":{service_id} SAJOIN {jailed_nickname} {welcome_salon}")
self.Irc.send2socket(f":{link} REPUTATION {jailed_IP} {int(reputation_seuil) + 1}") self.Irc.send2socket(f":{link} REPUTATION {jailed_IP} {int(reputation_seuil) + 1}")
@@ -851,14 +1169,13 @@ class Defender():
self.Irc.send2socket(f":{dnickname} PRIVMSG {jailed_salon} : Ce n'est pas à toi de taper le mot de passe !") self.Irc.send2socket(f":{dnickname} PRIVMSG {jailed_salon} : Ce n'est pas à toi de taper le mot de passe !")
except IndexError: except IndexError:
self.Irc.debug('_hcmd code: out of index') self.Base.logs.error('_hcmd code: out of index')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]')
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f'_hcmd code: KeyError {ke}') self.Base.logs.error(f'_hcmd code: KeyError {ke}')
# self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]') # self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]')
pass pass
case 'reputation': case 'reputation':
# .reputation [on/off] --> activate or deactivate reputation system # .reputation [on/off] --> activate or deactivate reputation system
# .reputation set banallchan [on/off] --> activate or deactivate ban in all channel # .reputation set banallchan [on/off] --> activate or deactivate ban in all channel
@@ -919,7 +1236,6 @@ class Defender():
self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR["verte"]}BAN ON ALL CHANS{self.Config.CONFIG_COLOR["noire"]} ] : Activated by {fromuser}') self.Irc.send2socket(f':{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR["verte"]}BAN ON ALL CHANS{self.Config.CONFIG_COLOR["noire"]} ] : Activated by {fromuser}')
elif get_value == 'off': elif get_value == 'off':
print(get_value)
if self.defConfig[key] == 0: if self.defConfig[key] == 0:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR['rouge']}BAN ON ALL CHANS{self.Config.CONFIG_COLOR['noire']} ] : Already deactivated") self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {self.Config.CONFIG_COLOR['rouge']}BAN ON ALL CHANS{self.Config.CONFIG_COLOR['noire']} ] : Already deactivated")
return False return False
@@ -944,15 +1260,16 @@ class Defender():
case _: case _:
pass pass
except IndexError: except IndexError as ie:
self.Irc.debug('_hcmd reputation: out of index') self.Base.logs.warning(f'{ie}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set banallchan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set banallchan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set limit [1234]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set limit [1234]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set timer [1234]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set timer [1234]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set action [kill|None]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} reputation set action [kill|None]')
except ValueError: except ValueError as ve:
self.Base.logs.warning(f'{ie}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : La valeur devrait etre un entier >= 0') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : La valeur devrait etre un entier >= 0')
case 'proxy_scan': case 'proxy_scan':
@@ -972,6 +1289,8 @@ class Defender():
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]')
option = str(cmd[2]).lower() # => local_scan, psutil_scan, abuseipdb_scan option = str(cmd[2]).lower() # => local_scan, psutil_scan, abuseipdb_scan
action = str(cmd[3]).lower() # => on / off action = str(cmd[3]).lower() # => on / off
@@ -1019,14 +1338,49 @@ class Defender():
self.update_db_configuration(option, 0) self.update_db_configuration(option, 0)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}") self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}")
case 'freeipapi_scan':
if action == 'on':
if self.defConfig[option] == 1:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated")
return None
self.update_db_configuration(option, 1)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}")
elif action == 'off':
if self.defConfig[option] == 0:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated")
return None
self.update_db_configuration(option, 0)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}")
case 'cloudfilt_scan':
if action == 'on':
if self.defConfig[option] == 1:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated")
return None
self.update_db_configuration(option, 1)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}")
elif action == 'off':
if self.defConfig[option] == 0:
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Already Deactivated")
return None
self.update_db_configuration(option, 0)
self.Irc.send2socket(f":{dnickname} PRIVMSG {dchanlog} :[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}")
case _: case _:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]')
else: else:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set local_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set psutil_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set abuseipdb_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set freeipapi_scan [ON/OFF]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} proxy_scan set cloudfilt_scan [ON/OFF]')
case 'flood': case 'flood':
# .flood on/off # .flood on/off
@@ -1083,7 +1437,7 @@ class Defender():
pass pass
except ValueError as ve: except ValueError as ve:
self.Irc.debug(f"{self.__class__.__name__} Value Error : {ve}") self.Base.logs.error(f"{self.__class__.__name__} Value Error : {ve}")
case 'status': case 'status':
color_green = self.Config.CONFIG_COLOR['verte'] color_green = self.Config.CONFIG_COLOR['verte']
@@ -1098,13 +1452,15 @@ class Defender():
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["local_scan"] == 1 else color_red}local_scan{color_black} ==> {self.defConfig["local_scan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["local_scan"] == 1 else color_red}local_scan{color_black} ==> {self.defConfig["local_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["psutil_scan"] == 1 else color_red}psutil_scan{color_black} ==> {self.defConfig["psutil_scan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["psutil_scan"] == 1 else color_red}psutil_scan{color_black} ==> {self.defConfig["psutil_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["abuseipdb_scan"] == 1 else color_red}abuseipdb_scan{color_black} ==> {self.defConfig["abuseipdb_scan"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["abuseipdb_scan"] == 1 else color_red}abuseipdb_scan{color_black} ==> {self.defConfig["abuseipdb_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["freeipapi_scan"] == 1 else color_red}freeipapi_scan{color_black} ==> {self.defConfig["freeipapi_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {color_green if self.defConfig["cloudfilt_scan"] == 1 else color_red}cloudfilt_scan{color_black} ==> {self.defConfig["cloudfilt_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.defConfig["flood"] == 1 else color_red}Flood{color_black}] ==> {self.defConfig["flood"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.defConfig["flood"] == 1 else color_red}Flood{color_black}] ==> {self.defConfig["flood"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_action ==> Coming soon') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_action ==> Coming soon')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_message ==> {self.defConfig["flood_message"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_message ==> {self.defConfig["flood_message"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_time ==> {self.defConfig["flood_time"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_time ==> {self.defConfig["flood_time"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_timer ==> {self.defConfig["flood_timer"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : flood_timer ==> {self.defConfig["flood_timer"]}')
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f"Key Error : {ke}") self.Base.logs.error(f"Key Error : {ke}")
case 'join': case 'join':
@@ -1113,8 +1469,8 @@ class Defender():
self.Irc.send2socket(f':{service_id} JOIN {channel}') self.Irc.send2socket(f':{service_id} JOIN {channel}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {dnickname} JOINED {channel}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {dnickname} JOINED {channel}')
self.add_defender_channel(channel) self.add_defender_channel(channel)
except IndexError: except IndexError as ie:
self.Irc.debug('_hcmd join: out of index') self.Base.logs.error(f'{ie}')
case 'part': case 'part':
@@ -1127,8 +1483,8 @@ class Defender():
self.Irc.send2socket(f':{service_id} PART {channel}') self.Irc.send2socket(f':{service_id} PART {channel}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {dnickname} LEFT {channel}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : {dnickname} LEFT {channel}')
self.delete_defender_channel(channel) self.delete_defender_channel(channel)
except IndexError: except IndexError as ie:
self.Irc.debug('_hcmd part: out of index') self.Base.logs.error(f'{ie}')
case 'op' | 'o': case 'op' | 'o':
# /mode #channel +o user # /mode #channel +o user
@@ -1140,7 +1496,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} +o {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} +o {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd OP: {str(e)}') self.Base.logs.warning(f'_hcmd OP: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} op [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} op [#SALON] [NICKNAME]')
case 'deop' | 'do': case 'deop' | 'do':
@@ -1151,7 +1507,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} -o {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} -o {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd DEOP: {str(e)}') self.Base.logs.warning(f'_hcmd DEOP: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deop [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deop [#SALON] [NICKNAME]')
case 'owner' | 'q': case 'owner' | 'q':
@@ -1162,7 +1518,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} +q {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} +q {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd OWNER: {str(e)}') self.Base.logs.warning(f'_hcmd OWNER: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} owner [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} owner [#SALON] [NICKNAME]')
case 'deowner' | 'dq': case 'deowner' | 'dq':
@@ -1173,7 +1529,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} -q {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} -q {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd DEOWNER: {str(e)}') self.Base.logs.warning(f'_hcmd DEOWNER: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} deowner [#SALON] [NICKNAME]')
case 'halfop' | 'h': case 'halfop' | 'h':
@@ -1184,7 +1540,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} +h {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} +h {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd halfop: {str(e)}') self.Base.logs.warning(f'_hcmd halfop: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} halfop [#SALON] [NICKNAME]')
case 'dehalfop' | 'dh': case 'dehalfop' | 'dh':
@@ -1195,7 +1551,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} -h {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} -h {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd DEHALFOP: {str(e)}') self.Base.logs.warning(f'_hcmd DEHALFOP: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} dehalfop [#SALON] [NICKNAME]')
case 'voice' | 'v': case 'voice' | 'v':
@@ -1206,7 +1562,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} +v {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} +v {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd VOICE: {str(e)}') self.Base.logs.warning(f'_hcmd VOICE: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} voice [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} voice [#SALON] [NICKNAME]')
case 'devoice' | 'dv': case 'devoice' | 'dv':
@@ -1217,7 +1573,7 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} -v {nickname}") self.Irc.send2socket(f":{service_id} MODE {channel} -v {nickname}")
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd DEVOICE: {str(e)}') self.Base.logs.warning(f'_hcmd DEVOICE: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} devoice [#SALON] [NICKNAME]')
case 'ban' | 'b': case 'ban' | 'b':
@@ -1227,9 +1583,9 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} +b {nickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {channel} +b {nickname}!*@*")
self.Irc.debug(f'{fromuser} has banned {nickname} from {channel}') self.Base.logs.debug(f'{fromuser} has banned {nickname} from {channel}')
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd BAN: {str(e)}') self.Base.logs.warning(f'_hcmd BAN: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} ban [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} ban [#SALON] [NICKNAME]')
case 'unban' | 'ub': case 'unban' | 'ub':
@@ -1239,9 +1595,9 @@ class Defender():
nickname = cmd[2] nickname = cmd[2]
self.Irc.send2socket(f":{service_id} MODE {channel} -b {nickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {channel} -b {nickname}!*@*")
self.Irc.debug(f'{fromuser} has unbanned {nickname} from {channel}') self.Base.logs.debug(f'{fromuser} has unbanned {nickname} from {channel}')
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd UNBAN: {str(e)}') self.Base.logs.warning(f'_hcmd UNBAN: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} unban [#SALON] [NICKNAME]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} unban [#SALON] [NICKNAME]')
case 'kick' | 'k': case 'kick' | 'k':
@@ -1257,9 +1613,9 @@ class Defender():
final_reason = ' '.join(reason) final_reason = ' '.join(reason)
self.Irc.send2socket(f":{service_id} KICK {channel} {nickname} {final_reason}") self.Irc.send2socket(f":{service_id} KICK {channel} {nickname} {final_reason}")
self.Irc.debug(f'{fromuser} has kicked {nickname} from {channel} : {final_reason}') self.Base.logs.debug(f'{fromuser} has kicked {nickname} from {channel} : {final_reason}')
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd KICK: {str(e)}') self.Base.logs.warning(f'_hcmd KICK: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} kick [#SALON] [NICKNAME] [REASON]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} kick [#SALON] [NICKNAME] [REASON]')
case 'kickban' | 'kb': case 'kickban' | 'kb':
@@ -1276,9 +1632,9 @@ class Defender():
self.Irc.send2socket(f":{service_id} KICK {channel} {nickname} {final_reason}") self.Irc.send2socket(f":{service_id} KICK {channel} {nickname} {final_reason}")
self.Irc.send2socket(f":{service_id} MODE {channel} +b {nickname}!*@*") self.Irc.send2socket(f":{service_id} MODE {channel} +b {nickname}!*@*")
self.Irc.debug(f'{fromuser} has kicked and banned {nickname} from {channel} : {final_reason}') self.Base.logs.debug(f'{fromuser} has kicked and banned {nickname} from {channel} : {final_reason}')
except IndexError as e: except IndexError as e:
self.Irc.debug(f'_hcmd KICKBAN: {str(e)}') self.Base.logs.warning(f'_hcmd KICKBAN: {str(e)}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} kickban [#SALON] [NICKNAME] [REASON]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} kickban [#SALON] [NICKNAME] [REASON]')
case 'info': case 'info':
@@ -1304,7 +1660,7 @@ class Defender():
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : MODES : {self.Irc.db_uid[uid_query]["umodes"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : MODES : {self.Irc.db_uid[uid_query]["umodes"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : CONNECTION TIME : {self.Irc.db_uid[uid_query]["datetime"]}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : CONNECTION TIME : {self.Irc.db_uid[uid_query]["datetime"]}')
except KeyError as ke: except KeyError as ke:
self.Irc.debug(f"Key error info user : {ke}") self.Base.logs.warning(f"Key error info user : {ke}")
case 'show_users': case 'show_users':
for uid, infousers in self.Irc.db_uid.items(): for uid, infousers in self.Irc.db_uid.items():

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.0.0"
}