mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 19:24:23 +00:00
v5.1.5
This commit is contained in:
17
core/base.py
17
core/base.py
@@ -9,9 +9,9 @@ from core.loadConf import ConfigDataModel
|
||||
|
||||
class Base:
|
||||
|
||||
CORE_DB_PATH = 'core' + os.sep + 'db' + os.sep # Le dossier bases de données core
|
||||
MODS_DB_PATH = 'mods' + os.sep + 'db' + os.sep # Le dossier bases de données des modules
|
||||
PYTHON_MIN_VERSION = '3.10' # Version min de python
|
||||
# CORE_DB_PATH = 'core' + os.sep + 'db' + os.sep # Le dossier bases de données core
|
||||
# MODS_DB_PATH = 'mods' + os.sep + 'db' + os.sep # Le dossier bases de données des modules
|
||||
# PYTHON_MIN_VERSION = '3.10' # Version min de python
|
||||
|
||||
def __init__(self, Config: ConfigDataModel) -> None:
|
||||
|
||||
@@ -26,6 +26,7 @@ class Base:
|
||||
|
||||
self.lock = threading.RLock() # Création du lock
|
||||
|
||||
self.install: bool = False # Initialisation de la variable d'installation
|
||||
self.engine, self.cursor = self.db_init() # Initialisation de la connexion a la base de données
|
||||
self.__create_db() # Initialisation de la base de données
|
||||
|
||||
@@ -200,7 +201,7 @@ class Base:
|
||||
else:
|
||||
return False
|
||||
|
||||
def db_record_module(self, user_cmd:str, module_name:str) -> None:
|
||||
def db_record_module(self, user_cmd:str, module_name:str, isdefault:int = 0) -> None:
|
||||
"""Enregistre les modules dans la base de données
|
||||
|
||||
Args:
|
||||
@@ -210,7 +211,7 @@ class Base:
|
||||
if not self.db_isModuleExist(module_name):
|
||||
self.logs.debug(f"Le module {module_name} n'existe pas alors ont le créer")
|
||||
insert_cmd_query = f"INSERT INTO {self.Config.table_module} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)"
|
||||
mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'module_name': module_name, 'isdefault': 0}
|
||||
mes_donnees = {'datetime': self.get_datetime(), 'user': user_cmd, 'module_name': module_name, 'isdefault': isdefault}
|
||||
self.db_execute_query(insert_cmd_query, mes_donnees)
|
||||
else:
|
||||
self.logs.debug(f"Le module {module_name} existe déja dans la base de données")
|
||||
@@ -532,6 +533,7 @@ class Base:
|
||||
full_path_db = self.Config.db_path + self.Config.db_name
|
||||
|
||||
if not os.path.exists(db_directory):
|
||||
self.install = True
|
||||
os.makedirs(db_directory)
|
||||
|
||||
engine = create_engine(f'sqlite:///{full_path_db}.db', echo=False)
|
||||
@@ -600,6 +602,11 @@ class Base:
|
||||
self.db_execute_query(table_core_channel)
|
||||
self.db_execute_query(table_core_config)
|
||||
|
||||
if self.install:
|
||||
self.db_record_module('sys', 'mod_command', 1)
|
||||
self.db_record_module('sys', 'mod_defender', 1)
|
||||
self.install = False
|
||||
|
||||
return None
|
||||
|
||||
def db_execute_query(self, query:str, params:dict = {}) -> CursorResult:
|
||||
|
||||
@@ -70,12 +70,23 @@ class Install:
|
||||
venv_pip_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}pip',
|
||||
venv_python_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}python'
|
||||
)
|
||||
|
||||
|
||||
# Exclude Windows OS
|
||||
if os.name == 'nt':
|
||||
#print('/!\\ Skip installation /!\\')
|
||||
self.skip_install = True
|
||||
else:
|
||||
if self.is_root():
|
||||
self.skip_install = True
|
||||
|
||||
def is_root(self) -> bool:
|
||||
|
||||
if os.geteuid() != 0:
|
||||
return False
|
||||
elif os.geteuid() == 0:
|
||||
print('/!\\ Do not use root to install Defender /!\\')
|
||||
self.Logs.critical('/!\\ Do not use root to install Defender /!\\')
|
||||
return True
|
||||
|
||||
def do_install(self) -> bool:
|
||||
|
||||
@@ -192,7 +203,7 @@ SyslogIdentifier=Defender
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=default.target
|
||||
'''
|
||||
# Check if user systemd is available (.config/systemd/user/)
|
||||
if not os.path.exists(self.config.unix_systemd_folder):
|
||||
|
||||
44
core/irc.py
44
core/irc.py
@@ -1,7 +1,7 @@
|
||||
import ssl, re, importlib, sys, time, threading, socket
|
||||
from ssl import SSLSocket
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Union
|
||||
from typing import Union, Literal
|
||||
from core.loadConf import Config
|
||||
from core.Model import User, Admin, Channel, Clones
|
||||
from core.base import Base
|
||||
@@ -21,6 +21,8 @@ class Irc:
|
||||
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.CHARSET = ['utf-8', 'iso-8859-1'] # Charset utiliser pour décoder/encoder les messages
|
||||
"""0: utf-8 | 1: iso-8859-1"""
|
||||
|
||||
self.SSL_VERSION = None # Version SSL
|
||||
|
||||
self.Config = Config().ConfigObject
|
||||
@@ -200,19 +202,22 @@ class Irc:
|
||||
|
||||
version = self.Config.current_version
|
||||
unixtime = self.Base.get_unixtime()
|
||||
charset = self.CHARSET[0]
|
||||
|
||||
# Envoyer un message d'identification
|
||||
writer.send(f":{sid} PASS :{password}\r\n".encode('utf-8'))
|
||||
writer.send(f":{sid} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK 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 SID={sid}\r\n".encode('utf-8'))
|
||||
writer.send(f":{sid} SERVER {link} 1 :{info}\r\n".encode('utf-8'))
|
||||
writer.send(f":{sid} {nickname} :Reserved for services\r\n".encode('utf-8'))
|
||||
writer.send(f":{sid} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * * :{realname}\r\n".encode('utf-8'))
|
||||
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":{sid} SAMODE {chan} +{umodes} {nickname}\r\n".encode('utf-8'))
|
||||
writer.send(f":{sid} PASS :{password}\r\n".encode(charset))
|
||||
writer.send(f":{sid} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS\r\n".encode(charset))
|
||||
# writer.send(f":{sid} PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT MLOCK SID MTAGS\r\n".encode(charset))
|
||||
writer.send(f":{sid} PROTOCTL EAUTH={link},,,{service_name}-v{version}\r\n".encode(charset))
|
||||
writer.send(f":{sid} PROTOCTL SID={sid}\r\n".encode(charset))
|
||||
writer.send(f":{sid} SERVER {link} 1 :{info}\r\n".encode(charset))
|
||||
writer.send(f":{sid} {nickname} :Reserved for services\r\n".encode(charset))
|
||||
writer.send(f":{sid} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * * :{realname}\r\n".encode(charset))
|
||||
writer.send(f":{sid} SJOIN {unixtime} {chan} + :{service_id}\r\n".encode(charset))
|
||||
writer.send(f":{sid} TKL + Q * {nickname} {host} 0 {unixtime} :Reserved for services\r\n".encode(charset))
|
||||
|
||||
writer.send(f":{service_id} MODE {chan} +{cmodes}\r\n".encode(charset))
|
||||
writer.send(f":{service_id} MODE {chan} +{umodes} {service_id}\r\n".encode(charset))
|
||||
|
||||
self.Base.logs.debug('Link information sent to the server')
|
||||
|
||||
@@ -221,9 +226,9 @@ class Irc:
|
||||
self.Base.logs.critical(f'{ae}')
|
||||
|
||||
def __join_saved_channels(self) -> None:
|
||||
|
||||
core_table = 'core_channel'
|
||||
|
||||
"""## Joining saved channels"""
|
||||
core_table = self.Config.table_channel
|
||||
|
||||
query = f'''SELECT distinct channel_name FROM {core_table}'''
|
||||
exec_query = self.Base.db_execute_query(query)
|
||||
result_query = exec_query.fetchall()
|
||||
@@ -686,7 +691,10 @@ class Irc:
|
||||
else:
|
||||
version = f'{current_version}'
|
||||
|
||||
self.send2socket(f"JOIN {self.Config.SERVICE_CHANLOG}")
|
||||
# self.send2socket(f":{self.Config.SERVICE_NICKNAME} SVSJOIN {self.Config.SERVICE_NICKNAME} {self.Config.SERVICE_CHANLOG}")
|
||||
# self.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.SERVICE_CHANLOG} +o {self.Config.SERVICE_NICKNAME}")
|
||||
# self.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.SERVICE_CHANLOG} +{self.Config.SERVICE_CMODES}")
|
||||
|
||||
print(f"################### DEFENDER ###################")
|
||||
print(f"# SERVICE CONNECTE ")
|
||||
print(f"# SERVEUR : {self.Config.SERVEUR_IP} ")
|
||||
@@ -775,8 +783,8 @@ class Irc:
|
||||
for i in range(start_boucle, len(cmd)):
|
||||
parsed_UID = str(cmd[i])
|
||||
# pattern = fr'[:|@|%|\+|~|\*]*'
|
||||
pattern = fr':'
|
||||
parsed_UID = re.sub(pattern, '', parsed_UID)
|
||||
# pattern = fr':'
|
||||
# parsed_UID = re.sub(pattern, '', parsed_UID)
|
||||
clean_uid = self.Base.clean_uid(parsed_UID)
|
||||
if len(clean_uid) == 9:
|
||||
list_users.append(parsed_UID)
|
||||
|
||||
128
core/loadConf.py
128
core/loadConf.py
@@ -1,6 +1,6 @@
|
||||
import json, sys
|
||||
from os import sep
|
||||
from typing import Union
|
||||
from typing import Union, Literal
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
##########################################
|
||||
@@ -11,58 +11,128 @@ from dataclasses import dataclass, field
|
||||
class ConfigDataModel:
|
||||
|
||||
SERVEUR_IP: str
|
||||
SERVEUR_HOSTNAME: str # Le hostname du serveur IRC
|
||||
SERVEUR_LINK: str # Host attendu par votre IRCd (ex. dans votre link block pour Unrealircd)
|
||||
SERVEUR_PORT: int # Port du link
|
||||
SERVEUR_PASSWORD: str # Mot de passe du link (Privilégiez argon2 sur Unrealircd)
|
||||
SERVEUR_ID: str # SID (identification) du bot en tant que Services
|
||||
SERVEUR_SSL: bool # Activer la connexion SSL
|
||||
"""Server public IP (could be 127.0.0.1 localhost)"""
|
||||
|
||||
SERVICE_NAME: str # Le nom du service
|
||||
SERVICE_NICKNAME: str # Nick du bot sur IRC
|
||||
SERVICE_REALNAME: str # Realname du bot
|
||||
SERVICE_USERNAME: str # Ident du bot
|
||||
SERVICE_HOST: str # Host du bot
|
||||
SERVICE_INFO: str # swhois du bot
|
||||
SERVICE_CHANLOG: str # Salon des logs et autres messages issus du bot
|
||||
SERVICE_SMODES: str # Mode du service
|
||||
SERVICE_CMODES: str # Mode du salon (#ChanLog) que le bot appliquera à son entrée
|
||||
SERVICE_UMODES: str # Mode que le bot pourra se donner à sa connexion au salon chanlog
|
||||
SERVICE_PREFIX: str # Prefix pour envoyer les commandes au bot
|
||||
SERVICE_ID: str = field(init=False) # L'identifiant du service
|
||||
SERVEUR_HOSTNAME: str
|
||||
"""IRC Server Hostname (your.hostname.extension)"""
|
||||
|
||||
OWNER: str # Identifiant du compte admin
|
||||
PASSWORD: str # Mot de passe du compte admin
|
||||
SERVEUR_LINK: str
|
||||
"""The link hostname (should be the same as your unrealircd link block)"""
|
||||
|
||||
SALON_JAIL: str # Salon pot de miel
|
||||
SALON_JAIL_MODES: str # Mode du salon pot de miel
|
||||
SALON_LIBERER: str # Le salon ou sera envoyé l'utilisateur clean
|
||||
SERVEUR_PORT: int
|
||||
"""Server port as configured in your unrealircd link block"""
|
||||
|
||||
API_TIMEOUT: int # Timeout des api's
|
||||
SERVEUR_PASSWORD: str
|
||||
"""Your link password"""
|
||||
|
||||
PORTS_TO_SCAN: list # Liste des ports a scanné pour une detection de proxy
|
||||
WHITELISTED_IP: list # IP a ne pas scanner
|
||||
GLINE_DURATION: str # La durée du gline
|
||||
SERVEUR_ID: str
|
||||
"""Service identification could be Z01 should be unique"""
|
||||
|
||||
DEBUG_LEVEL: int # Le niveau des logs DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50
|
||||
SERVEUR_SSL: bool
|
||||
"""Activate SSL connexion"""
|
||||
|
||||
SERVICE_NAME: str
|
||||
"""Service name (Ex. Defender)"""
|
||||
|
||||
SERVICE_NICKNAME: str
|
||||
"""Nickname of the service (Ex. Defender)"""
|
||||
|
||||
SERVICE_REALNAME: str
|
||||
"""Realname of the service"""
|
||||
|
||||
SERVICE_USERNAME: str
|
||||
"""Username of the service"""
|
||||
|
||||
SERVICE_HOST: str
|
||||
"""The service hostname"""
|
||||
|
||||
SERVICE_INFO: str
|
||||
"""Swhois of the service"""
|
||||
|
||||
SERVICE_CHANLOG: str
|
||||
"""The channel used by the service (ex. #services)"""
|
||||
|
||||
SERVICE_SMODES: str
|
||||
"""The service mode (ex. +ioqBS)"""
|
||||
|
||||
SERVICE_CMODES: str
|
||||
"""The mode of the log channel (ex. ntsO)"""
|
||||
|
||||
SERVICE_UMODES: str
|
||||
"""The mode of the service when joining chanlog (ex. o, the service will be operator in the chanlog)"""
|
||||
|
||||
SERVICE_PREFIX: str
|
||||
"""The default prefix to communicate with the service"""
|
||||
|
||||
SERVICE_ID: str = field(init=False)
|
||||
"""The service unique ID"""
|
||||
|
||||
OWNER: str
|
||||
"""The nickname of the admin of the service"""
|
||||
|
||||
PASSWORD: str
|
||||
"""The password of the admin of the service"""
|
||||
|
||||
SALON_JAIL: str
|
||||
"""The JAIL channel (ex. #jail)"""
|
||||
|
||||
SALON_JAIL_MODES: str
|
||||
"""The jail channel modes (ex. sS)"""
|
||||
|
||||
SALON_LIBERER: str
|
||||
"""Channel where the nickname will be released"""
|
||||
|
||||
API_TIMEOUT: int
|
||||
"""Default api timeout in second"""
|
||||
|
||||
PORTS_TO_SCAN: list
|
||||
"""List of ports to scan available for proxy_scan in the mod_defender module"""
|
||||
|
||||
WHITELISTED_IP: list
|
||||
"""List of remote IP to don't scan"""
|
||||
|
||||
GLINE_DURATION: str
|
||||
"""Gline duration"""
|
||||
|
||||
DEBUG_LEVEL:Literal[10, 20, 30, 40, 50] # Le niveau des logs DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50
|
||||
"""Logs level: DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50"""
|
||||
|
||||
CONFIG_COLOR: dict[str, str]
|
||||
|
||||
table_admin: str
|
||||
"""Admin table"""
|
||||
|
||||
table_commande: str
|
||||
"""Core command table"""
|
||||
|
||||
table_log: str
|
||||
"""Core log table"""
|
||||
|
||||
table_module: str
|
||||
"""Core module table"""
|
||||
|
||||
table_config: str
|
||||
"""Core configuration table"""
|
||||
|
||||
table_channel: str
|
||||
"""Core channel table"""
|
||||
|
||||
current_version: str
|
||||
"""Current version of Defender"""
|
||||
|
||||
latest_version: str
|
||||
"""The Latest version fetched from github"""
|
||||
|
||||
db_name: str
|
||||
"""The database name"""
|
||||
|
||||
db_path: str
|
||||
"""The database path"""
|
||||
|
||||
def __post_init__(self):
|
||||
# Initialiser SERVICE_ID après la création de l'objet
|
||||
self.SERVICE_ID:str = f"{self.SERVEUR_ID}AAAAAB"
|
||||
"""The service ID which is SERVEUR_ID and AAAAAB"""
|
||||
|
||||
class Config:
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class Command():
|
||||
# Create module commands (Mandatory)
|
||||
self.commands_level = {
|
||||
1: ['join', 'part'],
|
||||
2: ['owner', 'deowner', 'op', 'deop', 'halfop', 'dehalfop', 'voice', 'devoice', 'ban', 'unban','kick', 'kickban', 'umode']
|
||||
2: ['owner', 'deowner', 'op', 'deop', 'halfop', 'dehalfop', 'voice', 'devoice', 'deopall', 'devoiceall', 'voiceall', 'ban', 'unban','kick', 'kickban', 'umode']
|
||||
}
|
||||
|
||||
# Init the module
|
||||
@@ -172,6 +172,26 @@ class Command():
|
||||
|
||||
match command:
|
||||
|
||||
case 'deopall':
|
||||
try:
|
||||
self.Irc.send2socket(f":{service_id} SVSMODE {fromchannel} -o")
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OP: {str(e)}')
|
||||
|
||||
case 'devoiceall':
|
||||
try:
|
||||
self.Irc.send2socket(f":{service_id} SVSMODE {fromchannel} -v")
|
||||
|
||||
except IndexError as e:
|
||||
self.Logs.warning(f'_hcmd OP: {str(e)}')
|
||||
|
||||
case 'voiceall':
|
||||
chan_info = self.Channel.get_Channel(fromchannel)
|
||||
for uid in chan_info.uids:
|
||||
self.Irc.send2socket(f":{service_id} MODE {fromchannel} +v {self.User.get_nickname(self.Base.clean_uid(uid))}")
|
||||
|
||||
|
||||
case 'op':
|
||||
# /mode #channel +o user
|
||||
# .op #channel user
|
||||
|
||||
@@ -218,15 +218,18 @@ class Votekick():
|
||||
|
||||
dnickname = self.Config.SERVICE_NICKNAME
|
||||
|
||||
if not self.is_vote_ongoing(channel):
|
||||
return None
|
||||
|
||||
for chan in self.VOTE_CHANNEL_DB:
|
||||
if chan.channel_name == channel:
|
||||
target_user = self.User.get_nickname(chan.target_user)
|
||||
if chan.vote_for > chan.vote_against:
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :The user {self.Config.CONFIG_COLOR["gras"]}{target_user}{self.Config.CONFIG_COLOR["nogc"]} will be kicked from this channel')
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :User {self.Config.CONFIG_COLOR["gras"]}{target_user}{self.Config.CONFIG_COLOR["nogc"]} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll be kicked from the channel')
|
||||
self.Irc.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||
self.Channel.delete_user_from_channel(channel, self.User.get_uid(target_user))
|
||||
elif chan.vote_for <= chan.vote_against:
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This user [{target_user}] will stay on this channel')
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :User {self.Config.CONFIG_COLOR["gras"]}{target_user}{self.Config.CONFIG_COLOR["nogc"]} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll remain in the channel')
|
||||
|
||||
# Init the system
|
||||
if self.init_vote_system(channel):
|
||||
@@ -323,10 +326,10 @@ class Votekick():
|
||||
if chan.channel_name == channel:
|
||||
target_user = self.User.get_nickname(chan.target_user)
|
||||
if chan.vote_for > chan.vote_against:
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :The user {self.Config.CONFIG_COLOR["gras"]}{target_user}{self.Config.CONFIG_COLOR["nogc"]} will be kicked from this channel')
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :User {self.Config.CONFIG_COLOR["gras"]}{target_user}{self.Config.CONFIG_COLOR["nogc"]} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll be kicked from the channel')
|
||||
self.Irc.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||
elif chan.vote_for <= chan.vote_against:
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This user will stay on this channel')
|
||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :User {self.Config.CONFIG_COLOR["gras"]}{target_user}{self.Config.CONFIG_COLOR["nogc"]} has {chan.vote_against} votes against and {chan.vote_for} votes for. For this reason, it\'ll remain in the channel')
|
||||
|
||||
# Init the system
|
||||
if self.init_vote_system(channel):
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "5.1.0"
|
||||
"version": "5.1.5"
|
||||
}
|
||||
Reference in New Issue
Block a user