23 Commits

Author SHA1 Message Date
adator85
884c5bf0cd . 2024-03-23 02:43:24 +01:00
adator85
7e24d7cf4c . 2024-03-23 01:50:55 +01:00
adator85
d16b73656f . 2024-03-21 21:31:24 +01:00
adator85
8acbb7187c . 2024-03-20 23:57:23 +01:00
adator85
51bea90e6f . 2024-03-20 23:53:46 +01:00
adator85
4cb54b5b2e . 2024-03-20 23:49:14 +01:00
adator85
310f732a5b . 2024-03-20 23:46:23 +01:00
adator85
018fd8d959 . 2024-03-20 23:45:44 +01:00
adator85
07fa518fcc . 2024-03-20 23:19:28 +01:00
adator85
37dcd23353 . 2024-03-20 21:39:42 +01:00
adator85
748e7bffc9 Correction du status 2024-03-20 21:16:10 +01:00
adator85
681e0da041 Mise en forme du code 2024-03-20 20:33:50 +01:00
adator85
667281ffb4 Ajout de quelques param de config 2024-03-20 20:12:51 +01:00
adator85
4b18675e8b . 2024-03-20 01:26:30 +01:00
adator85
f63aabfb7a . 2024-03-20 00:54:37 +01:00
adator85
b4c1df7f4a . 2024-03-19 23:37:58 +01:00
adator85
4c1a929867 Adding freeipapi scan 2024-03-19 23:34:21 +01:00
adator
0f1aa6f946 Merge pull request #7 from adator85/dev
Fix KeyError when a user change nickname
2024-02-20 01:12:32 +01:00
adator85
20684339d3 Fix KeyError when a user change nickname 2024-02-20 01:10:54 +01:00
adator
d53a3c58c9 Merge pull request #6 from adator85/dev
Corriger les commandes qui ce dupliquent lors du rechargement du mod
2024-02-02 23:24:13 +01:00
adator85
5c7f0e3ad0 Corriger les commandes qui ce dupliquent lors du rechargement du mod 2024-02-02 23:22:49 +01:00
adator
168f8db5ab Merge pull request #5 from adator85/dev
Bug - Correction de la commande .code
2024-02-02 22:54:28 +01:00
adator85
91a6218692 Bug - Correction de la commande .code 2024-02-02 22:52:06 +01:00
6 changed files with 583 additions and 153 deletions

View File

@@ -32,7 +32,7 @@ class Base:
self.db_create_first_admin() # Créer un nouvel admin si la base de données est vide
def get_unixtime(self)->int:
def get_unixtime(self) -> int:
"""
Cette fonction retourne un UNIXTIME de type 12365456
Return: Current time in seconds since the Epoch (int)
@@ -40,7 +40,7 @@ class Base:
unixtime = int( time.time() )
return unixtime
def get_datetime(self)->str:
def get_datetime(self) -> str:
"""
Retourne une date au format string (24-12-2023 20:50:59)
"""
@@ -137,7 +137,7 @@ class Base:
(:createdOn, :user, :password, :hostname, :vhost, :level)"""
, mes_donnees)
pass
return None
def create_timer(self, time_to_wait: float, func: object, func_args: tuple = ()) -> None:
@@ -153,9 +153,15 @@ class Base:
except AssertionError as ae:
self.__debug(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:
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:
# print(f"HeartBeat is running")
# return None
@@ -243,7 +249,7 @@ class Base:
self.running_sockets.remove(soc)
print(f"> Socket ==> closed {str(soc.fileno())}")
pass
return None
def db_init(self) -> tuple[Engine, Connection]:
@@ -367,7 +373,7 @@ class Base:
# Run Garbage Collector Timer
self.garbage_collector_timer()
self.garbage_collector_thread()
self.garbage_collector_sockets()
# self.garbage_collector_sockets()
return None
for key, value in self.periodic_func.items():

View File

@@ -1,4 +1,5 @@
import os
from typing import Literal, Dict, List
##########################################
# CONFIGURATION FILE : #
# Rename file to : configuration.py #
@@ -6,7 +7,7 @@ import os
class Config:
DEFENDER_VERSION = '1.1.0' # MAJOR.MINOR.BATCH
DEFENDER_VERSION = '3.3.2' # MAJOR.MINOR.BATCH
DEFENDER_DB_PATH = 'db' + os.sep # Séparateur en fonction de l'OS
DEFENDER_DB_NAME = 'defender' # Le nom de la base de données principale
SERVICE_NAME = 'defender' # Le nom du service
@@ -37,7 +38,11 @@ class Config:
SALON_JAIL_MODES = 'sS' # Mode du salon pot de miel
SALON_LIBERER = '#welcome' # Le salon ou sera envoyé l'utilisateur clean
API_TIMEOUT = 2 # Timeout des api's
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 = 0 # Afficher l'ensemble des messages du serveurs dans la console

View File

@@ -37,7 +37,7 @@ class Install:
print(f"===> Version of python : {python_version()} ==> OK")
return True
def checkDependencies(self) -> None:
"""### Verifie les dépendances si elles sont installées
- Test si les modules sont installés

View File

@@ -1,6 +1,6 @@
import ssl, re, importlib, sys, time, threading, socket
from datetime import datetime, timedelta
from typing import Union
from core.configuration import Config
from core.base import Base
@@ -27,7 +27,7 @@ class Irc:
self.commands_level = {
0: ['help', 'auth', 'copyright'],
1: ['load','reload','unload', 'deauth', 'uptime'],
2: ['show_sessions','show_modules', 'show_timers', 'show_threads'],
2: ['show_modules', 'show_timers', 'show_threads', 'sentinel'],
3: ['quit', 'restart','addaccess','editaccess', 'delaccess']
}
@@ -38,7 +38,7 @@ class Irc:
self.commands.append(command)
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 #
@@ -57,9 +57,9 @@ class Irc:
self.IrcSocket.connect(connexion_information)
# Créer un object ssl
ssl_context = self.__ssl_context()
ssl_connexion = ssl_context.wrap_socket(self.IrcSocket, server_hostname=self.Config.SERVEUR_HOSTNAME)
self.IrcSocket = ssl_connexion
# ssl_context = self.__ssl_context()
# ssl_connexion = ssl_context.wrap_socket(self.IrcSocket, server_hostname=self.Config.SERVEUR_HOSTNAME)
# self.IrcSocket = ssl_connexion
return None
@@ -78,50 +78,66 @@ class Irc:
self.load_existing_modules() # Charger les modules existant dans la base de données
while self.signal:
if self.RESTART == 1:
self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close()
try:
if self.RESTART == 1:
self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close()
while self.IrcSocket.fileno() != -1:
time.sleep(0.5)
self.debug("--> En attente de la fermeture du socket ...")
while self.IrcSocket.fileno() != -1:
time.sleep(0.5)
self.debug("--> En attente de la fermeture du socket ...")
self.__create_socket()
self.__link(self.IrcSocket)
self.load_existing_modules()
self.RESTART = 0
# 4072 max what the socket can grab
buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
# data = self.IrcSocket.recv(buffer_size).splitlines(True)
self.__create_socket()
self.__link(self.IrcSocket)
self.load_existing_modules()
self.RESTART = 0
# 4072 max what the socket can grab
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)
count_bytes = len(data_in_bytes)
data_in_bytes = self.IrcSocket.recv(buffer_size)
while count_bytes > 4070:
# If the received message is > 4070 then loop and add the value to the variable
new_data = self.IrcSocket.recv(buffer_size)
data_in_bytes += new_data
count_bytes = len(new_data)
# print("========================================================")
count_bytes = len(data_in_bytes)
data = data_in_bytes.splitlines()
while count_bytes > 4070:
# If the received message is > 4070 then loop and add the value to the variable
new_data = self.IrcSocket.recv(buffer_size)
data_in_bytes += new_data
count_bytes = len(new_data)
# print("========================================================")
# print(f"{str(buffer_size)} - {str(len(data_in_bytes))}")
data = data_in_bytes.splitlines()
# print(f"{str(buffer_size)} - {str(len(data_in_bytes))}")
if not data:
break
if not data:
break
self.send_response(data)
self.send_response(data)
if self.IrcSocket.fileno() == -1:
print('restarting the socket')
self.RESTART = 1
except ssl.SSLEOFError as soe:
self.debug(f"SSLEOFError __connect_to_irc: {soe} - {data}")
except ssl.SSLError as se:
self.debug(f"SSLError __connect_to_irc: {se} - {data}")
except OSError as oe:
self.debug(f"SSLError __connect_to_irc: {oe} - {data}")
except Exception as e:
self.debug(f"Exception __connect_to_irc: {e} - {data}")
self.IrcSocket.shutdown(socket.SHUT_RDWR)
self.IrcSocket.close()
self.debug("--> Fermeture de Defender ...")
except AssertionError as ae:
self.debug(f'Assertion error : {ae}')
except ValueError as ve:
self.debug(f'Value Error : {ve}')
except OSError as oe:
self.debug(f"OS Error : {oe}")
except ssl.SSLEOFError as soe:
self.debug(f"OS Error __connect_to_irc: {soe}")
except Exception as e:
self.debug(f"Exception: {e}")
def __link(self, writer:socket.socket) -> None:
"""Créer le link et envoyer les informations nécessaires pour la
@@ -130,7 +146,6 @@ class Irc:
Args:
writer (StreamWriter): permet l'envoi des informations au serveur.
"""
nickname = self.Config.SERVICE_NICKNAME
username = self.Config.SERVICE_USERNAME
realname = self.Config.SERVICE_REALNAME
@@ -151,8 +166,6 @@ class Irc:
unixtime = self.Base.get_unixtime()
# 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} 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'))
@@ -163,12 +176,10 @@ class Irc:
writer.send(f":{sid} SJOIN {unixtime} {chan} + :{service_id}\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.write(f"USER {nickname} {username} {username} {nickname} {username} :{username}\r\n".encode('utf-8'))
# writer.write(f"USER {username} {username} {username} :{username}\r\n".encode('utf-8'))
# writer.write(f"NICK {nickname}\r\n".encode('utf-8'))
def send2socket(self, send_message:str)->None:
return None
def send2socket(self, send_message:str) -> None:
"""Envoit les commandes à envoyer au serveur.
Args:
@@ -185,8 +196,12 @@ class Irc:
self.IrcSocket.send(f"{send_message}\r\n".encode(self.CHARSET[0],'replace'))
except AssertionError as ae:
self.debug(f"Assertion error : {ae}")
except ssl.SSLEOFError as soe:
self.debug(f"SSLEOFError send2socket: {soe} - {send_message}")
except ssl.SSLError as se:
self.debug(f"SSLError send2socket: {se} - {send_message}")
except OSError as oe:
self.debug(f"OS Error : {oe}")
self.debug(f"OSError send2socket: {oe} - {send_message}")
def send_response(self, responses:list[bytes]) -> None:
try:
@@ -207,6 +222,7 @@ class Irc:
##############################################
# FIN CONNEXION IRC #
##############################################
def load_existing_modules(self) -> None:
"""Charge les modules qui existe déja dans la base de données
@@ -219,7 +235,7 @@ class Irc:
return None
def get_defender_uptime(self)->str:
def get_defender_uptime(self) -> str:
"""Savoir depuis quand Defender est connecté
Returns:
@@ -228,7 +244,7 @@ class Irc:
current_datetime = datetime.now()
diff_date = current_datetime - self.defender_connexion_datetime
uptime = timedelta(days=diff_date.days, seconds=diff_date.seconds)
return uptime
def heartbeat(self, beat:float) -> None:
@@ -348,6 +364,8 @@ class Irc:
except ModuleNotFoundError as moduleNotFound:
self.debug(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}")
except Exception as e:
self.debug(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:
@@ -377,7 +395,7 @@ class Irc:
return None
def update_db_uid(self, uid:str, newnickname:str) -> None:
# Récupérer l'ancien nickname
oldnickname = self.db_uid[uid]['nickname']
@@ -389,7 +407,7 @@ class Irc:
'umodes': self.db_uid[uid]['umodes'],
'vhost': self.db_uid[uid]['vhost']
}
# Modification du nickname dans la ligne UID
self.db_uid[uid]['nickname'] = newnickname
@@ -401,7 +419,7 @@ class Irc:
response = False
self.debug(f"{oldnickname} changed to {newnickname}")
return None
def delete_db_uid(self, uid:str) -> None:
@@ -428,8 +446,6 @@ class Irc:
umodes = self.db_uid[uid]['umodes']
vhost = self.db_uid[uid]['vhost']
level = int(level)
self.db_admin[uid] = {
'nickname': nickname,
@@ -479,7 +495,7 @@ class Irc:
"""
if channel in self.db_chan:
return False
response = True
# Ajouter un nouveau salon
self.db_chan.append(channel)
@@ -533,7 +549,7 @@ class Irc:
self.debug(response)
return response
def get_uid(self, uidornickname:str) -> str | None:
def get_uid(self, uidornickname:str) -> Union[str, None]:
uid_recherche = uidornickname
response = None
@@ -546,8 +562,8 @@ class Irc:
return response
def get_nickname(self, uidornickname:str) -> str | None:
def get_nickname(self, uidornickname:str) -> Union[str, None]:
nickname_recherche = uidornickname
response = None
@@ -561,11 +577,11 @@ class Irc:
return response
def is_cmd_allowed(self,nickname:str, cmd:str) -> bool:
# Vérifier si le user est identifié et si il a les droits
is_command_allowed = False
uid = self.get_uid(nickname)
if uid in self.db_admin:
admin_level = self.db_admin[uid]['level']
@@ -607,10 +623,13 @@ class Irc:
cmd_to_send:list[str] = data.copy()
cmd = data.copy()
cmd_to_debug = data.copy()
cmd_to_debug.pop(0)
if len(cmd) == 0 or len(cmd) == 1:
return False
self.debug(cmd)
self.debug(cmd_to_debug)
match cmd[0]:
@@ -701,7 +720,7 @@ class Irc:
cmd.pop(0)
uid_who_quit = str(cmd[0]).replace(':', '')
self.delete_db_uid(uid_who_quit)
case 'PONG':
# ['@msgid=aTNJhp17kcPboF5diQqkUL;time=2023-12-28T20:35:58.411Z', ':irc.deb.biz.st', 'PONG', 'irc.deb.biz.st', ':Dev-PyDefender']
self.Base.execute_periodic_action()
@@ -739,6 +758,9 @@ class Irc:
self.insert_db_uid(uid, nickname, username, hostname, umodes, vhost, isWebirc)
for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd_to_send)
case 'PRIVMSG':
try:
# Supprimer la premiere valeur
@@ -780,13 +802,13 @@ class Irc:
if arg[0] == '\x01VERSION\x01':
self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01VERSION Service {self.Config.SERVICE_NICKNAME} V{self.Config.DEFENDER_VERSION}\x01')
return False
# Réponse a un TIME
if arg[0] == '\x01TIME\x01':
current_datetime = self.Base.get_datetime()
self.send2socket(f':{dnickname} NOTICE {user_trigger} :\x01TIME {current_datetime}\x01')
return False
# Réponse a un PING
if arg[0] == '\x01PING':
recieved_unixtime = int(arg[1].replace('\x01',''))
@@ -810,9 +832,10 @@ class Irc:
case _:
pass
# Envoyer la commande aux classes dynamiquement chargées
for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd_to_send)
if cmd[2] != 'UID':
# Envoyer la commande aux classes dynamiquement chargées
for classe_name, classe_object in self.loaded_classes.items():
classe_object.cmd(cmd_to_send)
except IndexError as ie:
self.debug(f"IRC CMD -> IndexError : {ie} - {cmd} - length {str(len(cmd))}")
@@ -868,7 +891,7 @@ class Irc:
query = f"SELECT id, level FROM {self.Base.DB_SCHEMA['admins']} WHERE user = :user AND password = :password"
result = self.Base.db_execute_query(query, mes_donnees)
user_from_db = result.fetchone()
if not user_from_db is None:
uid_user = self.get_uid(user_to_log)
self.insert_db_admin(uid_user, user_from_db[1])
@@ -1023,37 +1046,12 @@ class Irc:
case 'unload':
# unload mod_dktmb
module_name = str(cmd[1]).lower() # Le nom du module. exemple: mod_defender
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender
try:
module_name = str(cmd[1]).lower() # Le nom du module. exemple: mod_defender
class_name = module_name.split('_')[1].capitalize() # Nom de la class. exemple: Defender
if class_name in self.loaded_classes:
for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]:
self.commands.remove(c)
self.commands_level[level].remove(c)
del self.loaded_classes[class_name]
# Supprimer le module de la base de données
self.Base.db_delete_module(module_name)
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} supprimé")
case 'reload':
# reload mod_dktmb
module_name = str(cmd[1]).lower() # ==> mod_defender
class_name = module_name.split('_')[1].capitalize() # ==> Defender
if 'mods.' + module_name in sys.modules:
self.debug('Module Already Loaded ... reload the module ...')
the_module = sys.modules['mods.' + module_name]
importlib.reload(the_module)
# Supprimer la class déja instancier
if class_name in self.loaded_classes:
# Supprimer les commandes déclarer dans la classe
self.loaded_classes[class_name].unload()
for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]:
@@ -1062,14 +1060,46 @@ class Irc:
del self.loaded_classes[class_name]
my_class = getattr(the_module, class_name, None)
new_instance = my_class(self.ircObject)
self.loaded_classes[class_name] = new_instance
# Supprimer le module de la base de données
self.Base.db_delete_module(module_name)
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} rechargé")
return False
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} supprimé")
except:
self.debug(f"Something went wrong with a module you want to load")
case 'reload':
# reload mod_dktmb
try:
module_name = str(cmd[1]).lower() # ==> mod_defender
class_name = module_name.split('_')[1].capitalize() # ==> Defender
if 'mods.' + module_name in sys.modules:
self.loaded_classes[class_name].unload()
self.debug('Module Already Loaded ... reload the module ...')
the_module = sys.modules['mods.' + module_name]
importlib.reload(the_module)
# Supprimer la class déja instancier
if class_name in self.loaded_classes:
# Supprimer les commandes déclarer dans la classe
for level, command in self.loaded_classes[class_name].commands_level.items():
# Supprimer la commande de la variable commands
for c in self.loaded_classes[class_name].commands_level[level]:
self.commands.remove(c)
self.commands_level[level].remove(c)
del self.loaded_classes[class_name]
my_class = getattr(the_module, class_name, None)
new_instance = my_class(self.ircObject)
self.loaded_classes[class_name] = new_instance
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} rechargé")
return False
else:
self.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :Module {module_name} n'est pas chargé !")
except:
self.debug(f"Something went wrong with a module you want to reload")
case 'quit':
try:
@@ -1090,7 +1120,7 @@ class Irc:
except IndexError:
self.debug('_hcmd die: out of index')
self.send2socket(f"QUIT Good bye")
case 'restart':
@@ -1102,6 +1132,9 @@ class Irc:
self.db_uid.clear() #Vider UID_DB
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':{self.Config.SERVEUR_LINK} SQUIT {self.Config.SERVEUR_LINK} :{final_reason}')
self.debug(f'Redémarrage du server {dnickname}')
@@ -1133,7 +1166,12 @@ class Irc:
self.send2socket(f":{dnickname} PRIVMSG {dchanlog} :Aucun timers en cours d'execution")
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':
uptime = self.get_defender_uptime()
@@ -1142,5 +1180,21 @@ class Irc:
case 'copyright':
self.send2socket(f':{dnickname} NOTICE {fromuser} : # Defender V.{self.Config.DEFENDER_VERSION} Developped by adator® and dktmb® #')
case 'sentinel':
# .sentinel on
activation = str(cmd[1]).lower()
service_id = self.Config.SERVICE_ID
channel_to_dont_quit = [self.Config.SALON_JAIL, dchanlog]
if activation == 'on':
for chan in self.db_chan:
if not chan in channel_to_dont_quit:
self.send2socket(f":{service_id} JOIN {chan}")
if activation == 'off':
for chan in self.db_chan:
if not chan in channel_to_dont_quit:
self.send2socket(f":{service_id} PART {chan}")
case _:
pass

View File

@@ -1,5 +1,6 @@
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
# 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
# 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
# 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():
@@ -18,6 +22,20 @@ class Defender():
self.Irc = ircInstance # Ajouter l'object mod_irc 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.timeout = self.Config.API_TIMEOUT # API Timeout
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.debug(f'Module {self.__class__.__name__} loaded ...')
@@ -45,11 +63,28 @@ class Defender():
"""
for level, com in commands.items():
for c in commands[level]:
self.Irc.commands_level[level].append(c)
self.Irc.commands.append(c)
if not c in self.Irc.commands:
self.Irc.commands_level[level].append(c)
self.Irc.commands.append(c)
return None
def unload(self) -> None:
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 = 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:
"""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
@@ -95,6 +130,7 @@ class Defender():
self.flood_system = {} # Variable qui va contenir les users
self.reputation_first_connexion = {'ip': '', 'score': -1} # Contient les premieres informations de connexion
self.abuseipdb_key = '13c34603fee4d2941a2c443cc5c77fd750757ca2a2c1b304bd0f418aff80c24be12651d1a3cfe674' # Laisser vide si aucune clé
self.cloudfilt_key = 'r1gEtjtfgRQjtNBDMxsg' # Laisser vide si aucune clé
# Rejoindre les salons
self.join_saved_channels()
@@ -108,6 +144,8 @@ class Defender():
'local_scan': 0,
'psutil_scan': 0,
'abuseipdb_scan': 0,
'freeipapi_scan': 0,
'cloudfilt_scan': 0,
'flood': 0,
'flood_message': 5,
'flood_time': 1,
@@ -117,6 +155,14 @@ class Defender():
# Syncrhoniser la variable defConfig avec la configuration de la base de données.
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
def sync_db_configuration(self) -> None:
@@ -194,7 +240,7 @@ class Defender():
self.Irc.debug(f'DB_Def_config - new param updated : {param} {value}')
self.Irc.debug(self.defConfig)
def add_defender_channel(self, channel:str) -> bool:
"""Cette fonction ajoute les salons de join de Defender
@@ -348,11 +394,11 @@ class Defender():
uptime = current_datetime - connected_time
convert_to_minutes = uptime.seconds / 60
uptime_minutes = round(number=convert_to_minutes, ndigits=2)
uptime_minutes = round(number=convert_to_minutes, ndigits=0)
return uptime_minutes
def system_reputation(self, uid:str)->None:
def system_reputation(self, uid:str)-> None:
# Reputation security
# - Activation ou désactivation du système --> OK
# - Le user sera en mesure de changer la limite de la réputation --> OK
@@ -394,7 +440,7 @@ class Defender():
self.Irc.debug(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.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:
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.delete_db_reputation(uid)
@@ -425,6 +471,7 @@ class Defender():
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}")
if self.get_user_uptime_in_minutes(uid) >= reputation_timer and int(self.db_reputation[uid]['score']) <= int(reputation_seuil):
self.Irc.debug('-----'*20)
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']):
# return False
@@ -446,6 +493,16 @@ class Defender():
except AssertionError as ae:
self.Irc.debug(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.debug(f"thread_reputation_timer Error : {ve}")
def _execute_flood_action(self, action:str, channel:str) -> None:
"""DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING
@@ -532,6 +589,13 @@ class Defender():
return 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:
newSocket = ''
@@ -550,6 +614,8 @@ class Defender():
self.Irc.debug(f"Le port {str(port)} est fermé")
except AttributeError as ae:
self.Irc.debug(f"AttributeError : {ae}")
except socket.gaierror as err:
self.Irc.debug(f"Address Info Error: {err}")
finally:
# newSocket.shutdown(socket.SHUT_RDWR)
newSocket.close()
@@ -557,7 +623,37 @@ class Defender():
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.Irc.debug(f"thread_local_scan Error : {ve}")
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')
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
@@ -565,7 +661,26 @@ class Defender():
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.Irc.debug(f"thread_psutil_scan Error : {ve}")
def abuseipdb_scan(self, remote_ip:str) -> Union[dict[str, any], None]:
"""Analyse l'ip avec AbuseIpDB
Cette methode devra etre lancer toujours via un thread ou un timer.
Args:
@@ -575,6 +690,8 @@ class Defender():
dict[str, any] | None: les informations du provider
keys : 'score', 'country', 'isTor', 'totalReports'
"""
if remote_ip in self.Config.WHITELISTED_IP:
return None
if self.defConfig['abuseipdb_scan'] == 0:
return None
@@ -592,11 +709,14 @@ class Defender():
'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
decodedResponse = json.loads(response.text)
try:
if not 'data' in decodedResponse:
return None
result = {
'score': decodedResponse['data']['abuseConfidenceScore'],
'country': decodedResponse['data']['countryCode'],
@@ -609,13 +729,191 @@ class Defender():
color_red = self.Config.CONFIG_COLOR['rouge']
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()
return result
except KeyError as ke:
self.Irc.debug(f"AbuseIpDb KeyError : {ke}")
except requests.ReadTimeout as rt:
self.Irc.debug(f"AbuseIpDb Timeout : {rt}")
except requests.ConnectionError as ce:
self.Irc.debug(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.Irc.debug(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.Irc.debug(f'Too Many Requests - The rate limit for the API has been exceeded.')
return None
elif status_code != 200:
print("salut salut")
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.Irc.debug(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.Irc.debug(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.Irc.debug(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.Irc.debug(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.Irc.debug(f"Thread_cloudfilt_scan Error : {ve}")
def cmd(self, data:list) -> None:
@@ -634,14 +932,21 @@ class Defender():
self.reputation_first_connexion['score'] = cmd[3]
# self.Base.scan_ports(cmd[2])
if self.defConfig['local_scan'] == 1:
self.Base.create_thread(self.scan_ports, (cmd[2], ))
if self.defConfig['local_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
self.localscan_remote_ip.append(cmd[2])
if self.defConfig['psutil_scan'] == 1:
self.Base.create_thread(self.get_ports_connexion, (cmd[2], ))
if self.defConfig['psutil_scan'] == 1 and not cmd[2] in self.Config.WHITELISTED_IP:
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.
except IndexError:
self.Irc.debug(f'cmd reputation: index error')
@@ -725,33 +1030,42 @@ class Defender():
case 'SLOG':
# self.Base.scan_ports(cmd[7])
cmd.pop(0)
if self.defConfig['local_scan'] == 1:
self.Base.create_thread(self.scan_ports, (cmd[7], ))
if self.defConfig['local_scan'] == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
self.localscan_remote_ip.append(cmd[7])
if self.defConfig['psutil_scan'] == 1:
self.Base.create_thread(self.get_ports_connexion, (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:
self.Base.create_thread(self.abuseipdb_scan, (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':
# :0010BS24L NICK [NEWNICK] 1697917711
# Changement de nickname
cmd.pop(0)
uid = str(cmd[0]).replace(':','')
oldnick = self.db_reputation[uid]['nickname']
newnickname = cmd[2]
jail_salon = self.Config.SALON_JAIL
service_id = self.Config.SERVICE_ID
try:
cmd.pop(0)
uid = str(cmd[0]).replace(':','')
oldnick = self.db_reputation[uid]['nickname']
newnickname = cmd[2]
self.update_db_reputation(uid, newnickname)
jail_salon = self.Config.SALON_JAIL
service_id = self.Config.SERVICE_ID
if uid in self.db_reputation:
for chan in self.Irc.db_chan:
if chan != jail_salon:
self.Irc.send2socket(f":{service_id} MODE {chan} -b {oldnick}!*@*")
self.Irc.send2socket(f":{service_id} MODE {chan} +b {newnickname}!*@*")
self.update_db_reputation(uid, newnickname)
if uid in self.db_reputation:
for chan in self.Irc.db_chan:
if chan != jail_salon:
self.Irc.send2socket(f":{service_id} MODE {chan} -b {oldnick}!*@*")
self.Irc.send2socket(f":{service_id} MODE {chan} +b {newnickname}!*@*")
except KeyError as ke:
self.Irc.debug(f'cmd - NICK - KeyError: {ke}')
case 'QUIT':
# :001N1WD7L QUIT :Quit: free_znc_1
@@ -773,7 +1087,6 @@ class Defender():
command = str(cmd[0]).lower()
fromuser = user
# print(command)
dnickname = self.Config.SERVICE_NICKNAME # Defender nickname
dchanlog = self.Config.SERVICE_CHANLOG # Defender chan log
@@ -810,6 +1123,10 @@ class Defender():
release_code = cmd[1]
jailed_nickname = self.Irc.get_nickname(fromuser)
jailed_UID = self.Irc.get_uid(fromuser)
if not jailed_UID in self.db_reputation:
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : No code is requested ...")
return False
jailed_IP = self.db_reputation[jailed_UID]['ip']
jailed_salon = self.Config.SALON_JAIL
reputation_seuil = self.defConfig['reputation_seuil']
@@ -846,7 +1163,9 @@ class Defender():
except IndexError:
self.Irc.debug('_hcmd code: out of index')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]')
pass
except KeyError as ke:
self.Irc.debug(f'_hcmd code: KeyError {ke}')
# self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Right command : /msg {dnickname} code [code]')
pass
case 'reputation':
@@ -962,6 +1281,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 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 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
action = str(cmd[3]).lower() # => on / off
@@ -1009,14 +1330,49 @@ class Defender():
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 '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 _:
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 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:
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 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':
# .flood on/off
@@ -1076,16 +1432,21 @@ class Defender():
self.Irc.debug(f"{self.__class__.__name__} Value Error : {ve}")
case 'status':
color_green = self.Config.CONFIG_COLOR['verte']
color_red = self.Config.CONFIG_COLOR['rouge']
color_black = self.Config.CONFIG_COLOR['noire']
try:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Reputation ==> {self.defConfig["reputation"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [{color_green if self.defConfig["reputation"] == 1 else color_red}Reputation{color_black}] ==> {self.defConfig["reputation"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_seuil ==> {self.defConfig["reputation_seuil"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_ban_all_chan ==> {self.defConfig["reputation_ban_all_chan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : reputation_timer ==> {self.defConfig["reputation_timer"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : [Proxy_scan]')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : local_scan ==> {self.defConfig["local_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : psutil_scan ==> {self.defConfig["psutil_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : abuseipdb_scan ==> {self.defConfig["abuseipdb_scan"]}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : Flood ==> {self.defConfig["flood"]}')
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["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} : 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_time ==> {self.defConfig["flood_time"]}')

View File

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