Merge pull request #26 from adator85/dev

Dev
This commit is contained in:
adator
2024-09-01 14:59:38 +02:00
committed by GitHub
7 changed files with 203 additions and 74 deletions

View File

@@ -9,9 +9,9 @@ from core.loadConf import ConfigDataModel
class Base: class Base:
CORE_DB_PATH = 'core' + os.sep + 'db' + os.sep # Le dossier bases de données core # 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 # 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 # PYTHON_MIN_VERSION = '3.10' # Version min de python
def __init__(self, Config: ConfigDataModel) -> None: def __init__(self, Config: ConfigDataModel) -> None:
@@ -26,6 +26,7 @@ class Base:
self.lock = threading.RLock() # Création du lock 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.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 self.__create_db() # Initialisation de la base de données
@@ -200,7 +201,7 @@ class Base:
else: else:
return False 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 """Enregistre les modules dans la base de données
Args: Args:
@@ -210,7 +211,7 @@ class Base:
if not self.db_isModuleExist(module_name): if not self.db_isModuleExist(module_name):
self.logs.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.Config.table_module} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)" 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) self.db_execute_query(insert_cmd_query, mes_donnees)
else: else:
self.logs.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")
@@ -532,6 +533,7 @@ class Base:
full_path_db = self.Config.db_path + self.Config.db_name full_path_db = self.Config.db_path + self.Config.db_name
if not os.path.exists(db_directory): if not os.path.exists(db_directory):
self.install = True
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)
@@ -600,6 +602,11 @@ class Base:
self.db_execute_query(table_core_channel) self.db_execute_query(table_core_channel)
self.db_execute_query(table_core_config) 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 return None
def db_execute_query(self, query:str, params:dict = {}) -> CursorResult: def db_execute_query(self, query:str, params:dict = {}) -> CursorResult:

View File

@@ -1,6 +1,4 @@
from importlib.util import find_spec
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path
from subprocess import check_call, run, CalledProcessError, PIPE from subprocess import check_call, run, CalledProcessError, PIPE
from platform import python_version, python_version_tuple from platform import python_version, python_version_tuple
from sys import exit from sys import exit
@@ -10,9 +8,11 @@ class Install:
@dataclass @dataclass
class CoreConfig: class CoreConfig:
install_log_file: str
unix_systemd_folder: str unix_systemd_folder: str
service_file_name: str service_file_name: str
service_cmd_executable: list service_cmd_executable: list
service_cmd_daemon_reload: list
defender_main_executable: str defender_main_executable: str
python_min_version: str python_min_version: str
python_current_version_tuple: tuple[str, str, str] python_current_version_tuple: tuple[str, str, str]
@@ -27,14 +27,17 @@ class Install:
def __init__(self) -> None: def __init__(self) -> None:
self.set_configuration() self.set_configuration()
if self.skip_install:
return None
if not self.check_python_version(): if not self.check_python_version():
# Tester si c'est la bonne version de python # Tester si c'est la bonne version de python
exit("Python Version Error") exit("Python Version Error")
else: else:
if self.skip_install:
return None
print(f'Configuration loaded : {self.config}')
# Sinon tester les dependances python et les installer avec pip # Sinon tester les dependances python et les installer avec pip
if self.do_install(): if self.do_install():
@@ -56,9 +59,11 @@ class Install:
defender_main_executable = os.path.join(defender_install_folder, 'main.py') defender_main_executable = os.path.join(defender_install_folder, 'main.py')
self.config = self.CoreConfig( self.config = self.CoreConfig(
install_log_file='install.log',
unix_systemd_folder=unix_systemd_folder, unix_systemd_folder=unix_systemd_folder,
service_file_name='defender.service', service_file_name='defender.service',
service_cmd_executable=['systemctl', '--user', 'start', 'defender'], service_cmd_executable=['systemctl', '--user', 'start', 'defender'],
service_cmd_daemon_reload=['systemctl', '--user', 'daemon-reload'],
defender_main_executable=defender_main_executable, defender_main_executable=defender_main_executable,
python_min_version='3.10', python_min_version='3.10',
python_current_version_tuple=python_version_tuple(), python_current_version_tuple=python_version_tuple(),
@@ -70,12 +75,24 @@ class Install:
venv_pip_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}pip', 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' venv_python_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}python'
) )
# Exclude Windows OS # Exclude Windows OS
if os.name == 'nt': if os.name == 'nt':
#print('/!\\ Skip installation /!\\') #print('/!\\ Skip installation /!\\')
self.skip_install = True self.skip_install = True
else:
if self.is_root():
self.skip_install = True
def is_root(self) -> bool:
if os.geteuid() != 0:
print('User without privileges ==> PASS')
return False
elif os.geteuid() == 0:
print('/!\\ Do not use root to install Defender /!\\')
exit("Do not use root to install Defender")
return True
def do_install(self) -> bool: def do_install(self) -> bool:
@@ -93,12 +110,12 @@ class Install:
def run_subprocess(self, command:list) -> None: def run_subprocess(self, command:list) -> None:
print(command) print(f'> {command}')
try: try:
check_call(command) check_call(command)
print("La commande s'est terminée avec succès.") print("The command completed successfully.")
except CalledProcessError as e: except CalledProcessError as e:
print(f"La commande a échoué avec le code de retour :{e.returncode}") print(f"The command failed with the return code: {e.returncode}")
print(f"Try to install dependencies ...") print(f"Try to install dependencies ...")
exit(5) exit(5)
@@ -123,7 +140,7 @@ class Install:
print(f"## Your python version must be greather than or equal to {self.config.python_current_version} ##") print(f"## Your python version must be greather than or equal to {self.config.python_current_version} ##")
return False return False
print(f"===> Version of python : {self.config.python_current_version} ==> OK") print(f"> Version of python : {self.config.python_current_version} ==> OK")
return True return True
@@ -133,7 +150,8 @@ class Install:
# Run a command in the virtual environment's Python to check if the package is installed # Run a command in the virtual environment's Python to check if the package is installed
run([self.config.venv_python_executable, '-c', f'import {package_name}'], check=True, stdout=PIPE, stderr=PIPE) run([self.config.venv_python_executable, '-c', f'import {package_name}'], check=True, stdout=PIPE, stderr=PIPE)
return True return True
except CalledProcessError: except CalledProcessError as cpe:
print(cpe)
return False return False
def install_dependencies(self) -> None: def install_dependencies(self) -> None:
@@ -162,7 +180,7 @@ class Install:
print("===> Verifier si pip est a jour") print("===> Verifier si pip est a jour")
self.run_subprocess([self.config.venv_python_executable, '-m', 'pip', 'install', '--upgrade', 'pip']) self.run_subprocess([self.config.venv_python_executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
if find_spec('greenlet') is None: if not self.check_package('greenlet'):
self.run_subprocess([self.config.venv_pip_executable, 'install', '--only-binary', ':all:', 'greenlet']) self.run_subprocess([self.config.venv_pip_executable, 'install', '--only-binary', ':all:', 'greenlet'])
print('====> Module Greenlet installé') print('====> Module Greenlet installé')
@@ -180,6 +198,7 @@ class Install:
if os.path.exists(full_service_file_path): if os.path.exists(full_service_file_path):
print(f'/!\\ Service file already exist /!\\') print(f'/!\\ Service file already exist /!\\')
self.run_subprocess(self.config.service_cmd_executable)
return None return None
contain = f'''[Unit] contain = f'''[Unit]
@@ -192,7 +211,7 @@ SyslogIdentifier=Defender
Restart=on-failure Restart=on-failure
[Install] [Install]
WantedBy=multi-user.target WantedBy=default.target
''' '''
# Check if user systemd is available (.config/systemd/user/) # Check if user systemd is available (.config/systemd/user/)
if not os.path.exists(self.config.unix_systemd_folder): if not os.path.exists(self.config.unix_systemd_folder):
@@ -203,6 +222,7 @@ WantedBy=multi-user.target
servicefile.close() servicefile.close()
print(f'Service file generated with current configuration') print(f'Service file generated with current configuration')
print(f'Running Defender IRC Service ...') print(f'Running Defender IRC Service ...')
self.run_subprocess(self.config.service_cmd_daemon_reload)
self.run_subprocess(self.config.service_cmd_executable) self.run_subprocess(self.config.service_cmd_executable)
else: else:
@@ -211,13 +231,14 @@ WantedBy=multi-user.target
servicefile.close() servicefile.close()
print(f'Service file generated with current configuration') print(f'Service file generated with current configuration')
print(f'Running Defender IRC Service ...') print(f'Running Defender IRC Service ...')
self.run_subprocess(self.config.service_cmd_daemon_reload)
self.run_subprocess(self.config.service_cmd_executable) self.run_subprocess(self.config.service_cmd_executable)
def print_final_message(self) -> None: def print_final_message(self) -> None:
print(f"#"*24) print(f"#"*24)
print("Installation complete ...") print("Installation complete ...")
print("You must change environment using the command below") print("If the configuration is correct, then you must see your service connected to your irc server")
print(f"source {self.config.defender_install_folder}{os.sep}{self.config.venv_folder}{os.sep}bin{os.sep}activate") print(f"If any issue, you can see the log file for debug {self.config.defender_install_folder}{os.sep}logs{os.sep}defender.log")
print(f"#"*24) print(f"#"*24)
exit(1) exit(1)

View File

@@ -1,7 +1,7 @@
import ssl, re, importlib, sys, time, threading, socket import ssl, re, importlib, sys, time, threading, socket
from ssl import SSLSocket from ssl import SSLSocket
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Union from typing import Union, Literal
from core.loadConf import Config from core.loadConf import Config
from core.Model import User, Admin, Channel, Clones from core.Model import User, Admin, Channel, Clones
from core.base import Base 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.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
"""0: utf-8 | 1: iso-8859-1"""
self.SSL_VERSION = None # Version SSL self.SSL_VERSION = None # Version SSL
self.Config = Config().ConfigObject self.Config = Config().ConfigObject
@@ -200,19 +202,22 @@ class Irc:
version = self.Config.current_version version = self.Config.current_version
unixtime = self.Base.get_unixtime() unixtime = self.Base.get_unixtime()
charset = self.CHARSET[0]
# Envoyer un message d'identification # Envoyer un message d'identification
writer.send(f":{sid} PASS :{password}\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('utf-8')) 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('utf-8')) # 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('utf-8')) 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('utf-8')) writer.send(f":{sid} PROTOCTL SID={sid}\r\n".encode(charset))
writer.send(f":{sid} SERVER {link} 1 :{info}\r\n".encode('utf-8')) writer.send(f":{sid} SERVER {link} 1 :{info}\r\n".encode(charset))
writer.send(f":{sid} {nickname} :Reserved for services\r\n".encode('utf-8')) 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('utf-8')) 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('utf-8')) writer.send(f":{sid} SJOIN {unixtime} {chan} + :{service_id}\r\n".encode(charset))
writer.send(f":{sid} MODE {chan} +{cmodes}\r\n".encode('utf-8')) writer.send(f":{sid} TKL + Q * {nickname} {host} 0 {unixtime} :Reserved for services\r\n".encode(charset))
writer.send(f":{sid} SAMODE {chan} +{umodes} {nickname}\r\n".encode('utf-8'))
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') self.Base.logs.debug('Link information sent to the server')
@@ -221,9 +226,9 @@ class Irc:
self.Base.logs.critical(f'{ae}') self.Base.logs.critical(f'{ae}')
def __join_saved_channels(self) -> None: def __join_saved_channels(self) -> None:
"""## Joining saved channels"""
core_table = 'core_channel' core_table = self.Config.table_channel
query = f'''SELECT distinct channel_name FROM {core_table}''' query = f'''SELECT distinct channel_name FROM {core_table}'''
exec_query = self.Base.db_execute_query(query) exec_query = self.Base.db_execute_query(query)
result_query = exec_query.fetchall() result_query = exec_query.fetchall()
@@ -686,7 +691,10 @@ class Irc:
else: else:
version = f'{current_version}' 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"################### DEFENDER ###################")
print(f"# SERVICE CONNECTE ") print(f"# SERVICE CONNECTE ")
print(f"# SERVEUR : {self.Config.SERVEUR_IP} ") print(f"# SERVEUR : {self.Config.SERVEUR_IP} ")
@@ -775,8 +783,8 @@ class Irc:
for i in range(start_boucle, len(cmd)): for i in range(start_boucle, len(cmd)):
parsed_UID = str(cmd[i]) parsed_UID = str(cmd[i])
# pattern = fr'[:|@|%|\+|~|\*]*' # pattern = fr'[:|@|%|\+|~|\*]*'
pattern = fr':' # pattern = fr':'
parsed_UID = re.sub(pattern, '', parsed_UID) # parsed_UID = re.sub(pattern, '', parsed_UID)
clean_uid = self.Base.clean_uid(parsed_UID) clean_uid = self.Base.clean_uid(parsed_UID)
if len(clean_uid) == 9: if len(clean_uid) == 9:
list_users.append(parsed_UID) list_users.append(parsed_UID)

View File

@@ -1,6 +1,6 @@
import json, sys import json, sys
from os import sep from os import sep
from typing import Union from typing import Union, Literal
from dataclasses import dataclass, field from dataclasses import dataclass, field
########################################## ##########################################
@@ -11,58 +11,128 @@ from dataclasses import dataclass, field
class ConfigDataModel: class ConfigDataModel:
SERVEUR_IP: str SERVEUR_IP: str
SERVEUR_HOSTNAME: str # Le hostname du serveur IRC """Server public IP (could be 127.0.0.1 localhost)"""
SERVEUR_LINK: str # Host attendu par votre IRCd (ex. dans votre link block pour Unrealircd)
SERVEUR_PORT: int # Port du link
SERVEUR_PASSWORD: str # Mot de passe du link (Privilégiez argon2 sur Unrealircd)
SERVEUR_ID: str # SID (identification) du bot en tant que Services
SERVEUR_SSL: bool # Activer la connexion SSL
SERVICE_NAME: str # Le nom du service SERVEUR_HOSTNAME: str
SERVICE_NICKNAME: str # Nick du bot sur IRC """IRC Server Hostname (your.hostname.extension)"""
SERVICE_REALNAME: str # Realname du bot
SERVICE_USERNAME: str # Ident du bot
SERVICE_HOST: str # Host du bot
SERVICE_INFO: str # swhois du bot
SERVICE_CHANLOG: str # Salon des logs et autres messages issus du bot
SERVICE_SMODES: str # Mode du service
SERVICE_CMODES: str # Mode du salon (#ChanLog) que le bot appliquera à son entrée
SERVICE_UMODES: str # Mode que le bot pourra se donner à sa connexion au salon chanlog
SERVICE_PREFIX: str # Prefix pour envoyer les commandes au bot
SERVICE_ID: str = field(init=False) # L'identifiant du service
OWNER: str # Identifiant du compte admin SERVEUR_LINK: str
PASSWORD: str # Mot de passe du compte admin """The link hostname (should be the same as your unrealircd link block)"""
SALON_JAIL: str # Salon pot de miel SERVEUR_PORT: int
SALON_JAIL_MODES: str # Mode du salon pot de miel """Server port as configured in your unrealircd link block"""
SALON_LIBERER: str # Le salon ou sera envoyé l'utilisateur clean
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 SERVEUR_ID: str
WHITELISTED_IP: list # IP a ne pas scanner """Service identification could be Z01 should be unique"""
GLINE_DURATION: str # La durée du gline
DEBUG_LEVEL: int # Le niveau des logs DEBUG 10 | INFO 20 | WARNING 30 | ERROR 40 | CRITICAL 50 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] CONFIG_COLOR: dict[str, str]
table_admin: str table_admin: str
"""Admin table"""
table_commande: str table_commande: str
"""Core command table"""
table_log: str table_log: str
"""Core log table"""
table_module: str table_module: str
"""Core module table"""
table_config: str table_config: str
"""Core configuration table"""
table_channel: str table_channel: str
"""Core channel table"""
current_version: str current_version: str
"""Current version of Defender"""
latest_version: str latest_version: str
"""The Latest version fetched from github"""
db_name: str db_name: str
"""The database name"""
db_path: str db_path: str
"""The database path"""
def __post_init__(self): def __post_init__(self):
# Initialiser SERVICE_ID après la création de l'objet # Initialiser SERVICE_ID après la création de l'objet
self.SERVICE_ID:str = f"{self.SERVEUR_ID}AAAAAB" self.SERVICE_ID:str = f"{self.SERVEUR_ID}AAAAAB"
"""The service ID which is SERVEUR_ID and AAAAAB"""
class Config: class Config:

View File

@@ -35,7 +35,7 @@ class Command():
# Create module commands (Mandatory) # Create module commands (Mandatory)
self.commands_level = { self.commands_level = {
1: ['join', 'part'], 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 # Init the module
@@ -97,7 +97,7 @@ class Command():
""" """
try: try:
# Build the default configuration model (Mandatory) # Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel(param_exemple1='param value 1', param_exemple2=1) self.ModConfig = self.ModConfModel()
# Sync the configuration with core configuration (Mandatory) # Sync the configuration with core configuration (Mandatory)
self.Base.db_sync_core_config(self.module_name, self.ModConfig) self.Base.db_sync_core_config(self.module_name, self.ModConfig)
@@ -172,6 +172,26 @@ class Command():
match 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': case 'op':
# /mode #channel +o user # /mode #channel +o user
# .op #channel user # .op #channel user

View File

@@ -218,15 +218,18 @@ class Votekick():
dnickname = self.Config.SERVICE_NICKNAME dnickname = self.Config.SERVICE_NICKNAME
if not self.is_vote_ongoing(channel):
return None
for chan in self.VOTE_CHANNEL_DB: for chan in self.VOTE_CHANNEL_DB:
if chan.channel_name == channel: if chan.channel_name == channel:
target_user = self.User.get_nickname(chan.target_user) target_user = self.User.get_nickname(chan.target_user)
if chan.vote_for > chan.vote_against: 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.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)) self.Channel.delete_user_from_channel(channel, self.User.get_uid(target_user))
elif chan.vote_for <= chan.vote_against: 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 # Init the system
if self.init_vote_system(channel): if self.init_vote_system(channel):
@@ -323,10 +326,10 @@ class Votekick():
if chan.channel_name == channel: if chan.channel_name == channel:
target_user = self.User.get_nickname(chan.target_user) target_user = self.User.get_nickname(chan.target_user)
if chan.vote_for > chan.vote_against: 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.Irc.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
elif chan.vote_for <= chan.vote_against: 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 # Init the system
if self.init_vote_system(channel): if self.init_vote_system(channel):

View File

@@ -1,3 +1,3 @@
{ {
"version": "5.1.0" "version": "5.1.5"
} }