mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-14 19:54:21 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7796d05206 | ||
|
|
3ba884216f | ||
|
|
5f2567f9e5 | ||
|
|
2ce19ee877 | ||
|
|
aaa1dd9a1a | ||
|
|
351fd6edaf | ||
|
|
a02f2f9a26 | ||
|
|
d0c17d69de | ||
|
|
d73adb6f0b | ||
|
|
eb9402dd8e | ||
|
|
b812e64992 | ||
|
|
35d5e7a2b5 | ||
|
|
21a825c92d | ||
|
|
9bd1f68df2 | ||
|
|
3fcfa0296d | ||
|
|
bcf972d08b | ||
|
|
1348ead6cd | ||
|
|
f6ebab4780 | ||
|
|
608ec57593 | ||
|
|
f392f2fb2f | ||
|
|
489e1e7b0a | ||
|
|
3d79270ca0 | ||
|
|
e60ada4260 | ||
|
|
ccb9f307b4 | ||
|
|
2fc8f2d346 | ||
|
|
e3ada04f2a | ||
|
|
6ba0551fee | ||
|
|
f44b08bf36 | ||
|
|
6142b4257f | ||
|
|
1a19e1613a | ||
|
|
ab15cce82b | ||
|
|
cdc15b7b47 | ||
|
|
01dcc90d63 | ||
|
|
31fe9f62ec | ||
|
|
f0853e3afb | ||
|
|
6dade09257 | ||
|
|
9533b010b2 | ||
|
|
824db73590 | ||
|
|
96bf4b6f80 | ||
|
|
922336363e |
13
README.md
13
README.md
@@ -25,16 +25,19 @@ Il permet aux opérateurs de gérer efficacement un canal, tout en offrant aux u
|
|||||||
|
|
||||||
Prérequis:
|
Prérequis:
|
||||||
- Système d'exploitation Linux (Windows non supporté)
|
- Système d'exploitation Linux (Windows non supporté)
|
||||||
- Droits d'administrateur (root) pour l'exécution du script
|
|
||||||
- Python version 3.10 ou supérieure
|
- Python version 3.10 ou supérieure
|
||||||
|
|
||||||
Bash:
|
Bash:
|
||||||
$ git clone https://github.com/adator85/IRC_DEFENDER_MODULES.git
|
$ git clone https://github.com/adator85/IRC_DEFENDER_MODULES.git
|
||||||
- Renommer le fichier exemple_configuration.json en configuration.json
|
- Renommer le fichier exemple_configuration.json en configuration.json
|
||||||
- Configurer le fichier configuration.json
|
- Configurer le fichier configuration.json
|
||||||
$ sudo python3 install.py
|
$ python3 main.py
|
||||||
|
|
||||||
Si votre configuration est bonne, votre service est censé etre connecté a votre réseau IRC
|
Si votre configuration est bonne, votre service est censé etre connecté a votre réseau IRC
|
||||||
|
Pour Les prochains lancement de defender vous devez utiliser la commande suivante:
|
||||||
|
|
||||||
|
Bash:
|
||||||
|
$ systemctl --user [start | stop | restart | status] defender
|
||||||
|
|
||||||
# Installation manuelle:
|
# Installation manuelle:
|
||||||
Bash:
|
Bash:
|
||||||
@@ -42,8 +45,10 @@ Si votre configuration est bonne, votre service est censé etre connecté a votr
|
|||||||
$ cd IRC_DEFENDER_MODULES
|
$ cd IRC_DEFENDER_MODULES
|
||||||
$ python3 -m venv .pyenv
|
$ python3 -m venv .pyenv
|
||||||
$ source .pyenv/bin/activate
|
$ source .pyenv/bin/activate
|
||||||
- Créer un service nommé "Defender.service" pour votre service et placer le dans "/etc/systemd/system/"
|
(pyenv)$ pip install sqlalchemy, psutil, requests, faker
|
||||||
$ sudo systemctl start Defender
|
- Créer un service nommé "defender.service" pour votre service et placer le dans "/PATH/TO/USER/.config/systemd/user/"
|
||||||
|
- Si le dossier n'existe pas il faut les créer
|
||||||
|
$ sudo systemctl --user start defender
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
|
|||||||
@@ -402,3 +402,97 @@ class Channel:
|
|||||||
self.log.debug(f'Search {name} -- result = {Channel}')
|
self.log.debug(f'Search {name} -- result = {Channel}')
|
||||||
|
|
||||||
return Channel
|
return Channel
|
||||||
|
|
||||||
|
class Clones:
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CloneModel:
|
||||||
|
alive: bool
|
||||||
|
nickname: str
|
||||||
|
username: str
|
||||||
|
|
||||||
|
UID_CLONE_DB: list[CloneModel] = []
|
||||||
|
|
||||||
|
def __init__(self, Base: Base) -> None:
|
||||||
|
self.log = Base.logs
|
||||||
|
|
||||||
|
def insert(self, newCloneObject: CloneModel) -> bool:
|
||||||
|
"""Create new Clone object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
newCloneObject (CloneModel): New CloneModel object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if inserted
|
||||||
|
"""
|
||||||
|
result = False
|
||||||
|
exist = False
|
||||||
|
|
||||||
|
for record in self.UID_CLONE_DB:
|
||||||
|
if record.nickname == newCloneObject.nickname:
|
||||||
|
# If the user exist then return False and do not go further
|
||||||
|
exist = True
|
||||||
|
self.log.debug(f'{record.nickname} already exist')
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not exist:
|
||||||
|
self.UID_CLONE_DB.append(newCloneObject)
|
||||||
|
result = True
|
||||||
|
self.log.debug(f'New Clone Object Created: ({newCloneObject})')
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
self.log.critical(f'The Clone Object was not inserted {newCloneObject}')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def delete(self, nickname: str) -> bool:
|
||||||
|
"""Delete the Clone Object starting from the nickname
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): nickname of the clone
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if deleted
|
||||||
|
"""
|
||||||
|
result = False
|
||||||
|
|
||||||
|
for record in self.UID_CLONE_DB:
|
||||||
|
if record.nickname == nickname:
|
||||||
|
# If the user exist then remove and return True and do not go further
|
||||||
|
self.UID_CLONE_DB.remove(record)
|
||||||
|
result = True
|
||||||
|
self.log.debug(f'The clone ({record.nickname}) has been deleted')
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
self.log.critical(f'The UID {nickname} was not deleted')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def exists(self, nickname: str) -> bool:
|
||||||
|
"""Check if the nickname exist
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): Nickname of the clone
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the nickname exist
|
||||||
|
"""
|
||||||
|
response = False
|
||||||
|
|
||||||
|
for cloneObject in self.UID_CLONE_DB:
|
||||||
|
if cloneObject.nickname == nickname:
|
||||||
|
response = True
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def kill(self, nickname:str) -> bool:
|
||||||
|
|
||||||
|
response = False
|
||||||
|
|
||||||
|
for cloneObject in self.UID_CLONE_DB:
|
||||||
|
if cloneObject.nickname == nickname:
|
||||||
|
cloneObject.alive = False # Kill the clone
|
||||||
|
response = True
|
||||||
|
|
||||||
|
return response
|
||||||
|
|||||||
17
core/base.py
17
core/base.py
@@ -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:
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
import socket, ssl, time
|
import socket, ssl, time
|
||||||
from ssl import SSLSocket
|
from ssl import SSLSocket
|
||||||
from core.loadConf import Config
|
from core.loadConf import Config
|
||||||
|
from core.Model import Clones
|
||||||
from core.base import Base
|
from core.base import Base
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
class Connection:
|
class Connection:
|
||||||
|
|
||||||
def __init__(self, server_port: int, nickname: str, username: str, channels:list[str], ssl:bool = False) -> None:
|
def __init__(self, server_port: int, nickname: str, username: str, channels:list[str], CloneObject: Clones, ssl:bool = False) -> None:
|
||||||
|
|
||||||
self.Config = Config().ConfigObject
|
self.Config = Config().ConfigObject
|
||||||
self.Base = Base(self.Config)
|
self.Base = Base(self.Config)
|
||||||
self.IrcSocket: Union[socket.socket, SSLSocket] = None
|
self.IrcSocket: Union[socket.socket, SSLSocket] = None
|
||||||
self.signal: bool = True
|
|
||||||
self.nickname = nickname
|
self.nickname = nickname
|
||||||
self.username = username
|
self.username = username
|
||||||
self.channels:list[str] = channels
|
self.channels:list[str] = channels
|
||||||
self.CHARSET = ['utf-8', 'iso-8859-1']
|
self.CHARSET = ['utf-8', 'iso-8859-1']
|
||||||
|
self.Clones = CloneObject
|
||||||
|
self.signal: bool = True
|
||||||
|
for clone in self.Clones.UID_CLONE_DB:
|
||||||
|
if clone.nickname == nickname:
|
||||||
|
self.currentCloneObject = clone
|
||||||
|
|
||||||
self.create_socket(self.Config.SERVEUR_IP, self.Config.SERVEUR_HOSTNAME, server_port, ssl)
|
self.create_socket(self.Config.SERVEUR_IP, self.Config.SERVEUR_HOSTNAME, server_port, ssl)
|
||||||
self.send_connection_information_to_server(self.IrcSocket)
|
self.send_connection_information_to_server(self.IrcSocket)
|
||||||
@@ -126,7 +132,6 @@ class Connection:
|
|||||||
break
|
break
|
||||||
|
|
||||||
self.parser(data)
|
self.parser(data)
|
||||||
|
|
||||||
except ssl.SSLEOFError as soe:
|
except ssl.SSLEOFError as soe:
|
||||||
self.Base.logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}")
|
self.Base.logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}")
|
||||||
self.signal = False
|
self.signal = False
|
||||||
@@ -156,6 +161,7 @@ class Connection:
|
|||||||
try:
|
try:
|
||||||
for data in cmd:
|
for data in cmd:
|
||||||
response = data.decode(self.CHARSET[0]).split()
|
response = data.decode(self.CHARSET[0]).split()
|
||||||
|
self.signal = self.currentCloneObject.alive
|
||||||
# print(response)
|
# print(response)
|
||||||
|
|
||||||
match response[0]:
|
match response[0]:
|
||||||
@@ -174,16 +180,28 @@ class Connection:
|
|||||||
self.send2socket(f"JOIN {channel}")
|
self.send2socket(f"JOIN {channel}")
|
||||||
return None
|
return None
|
||||||
case 'PRIVMSG':
|
case 'PRIVMSG':
|
||||||
|
self.Base.logs.debug(response)
|
||||||
|
self.Base.logs.debug(f'{self.currentCloneObject.nickname} - {self.currentCloneObject.alive}')
|
||||||
fullname = str(response[0]).replace(':', '')
|
fullname = str(response[0]).replace(':', '')
|
||||||
nickname = fullname.split('!')[0].replace(':','')
|
nickname = fullname.split('!')[0].replace(':','')
|
||||||
if nickname == self.Config.SERVICE_NICKNAME:
|
if nickname == self.Config.SERVICE_NICKNAME:
|
||||||
command = str(response[3]).replace(':','')
|
command = str(response[3]).replace(':','')
|
||||||
if command == 'KILL':
|
if command == 'KILL':
|
||||||
self.send2socket(f'QUIT :Thanks and goodbye')
|
self.send2socket(f'QUIT :Thanks and goodbye')
|
||||||
self.signal = False
|
self.signal = self.currentCloneObject.alive
|
||||||
if command == 'JOIN':
|
if command == 'JOIN':
|
||||||
channel_to_join = str(response[4])
|
channel_to_join = str(response[4])
|
||||||
self.send2socket(f"JOIN {channel_to_join}")
|
self.send2socket(f"JOIN {channel_to_join}")
|
||||||
|
if command == 'SAY':
|
||||||
|
clone_channel = str(response[4])
|
||||||
|
|
||||||
|
message = []
|
||||||
|
for i in range(5, len(response)):
|
||||||
|
message.append(response[i])
|
||||||
|
final_message = ' '.join(message)
|
||||||
|
|
||||||
|
self.send2socket(f"PRIVMSG {clone_channel} :{final_message}")
|
||||||
|
|
||||||
|
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
for data in cmd:
|
for data in cmd:
|
||||||
@@ -193,7 +211,6 @@ class Connection:
|
|||||||
response = data.decode(self.CHARSET[1],'replace').split()
|
response = data.decode(self.CHARSET[1],'replace').split()
|
||||||
except AssertionError as ae:
|
except AssertionError as ae:
|
||||||
self.Base.logs.error(f"Assertion error : {ae}")
|
self.Base.logs.error(f"Assertion error : {ae}")
|
||||||
pass
|
|
||||||
|
|
||||||
def __ssl_context(self) -> ssl.SSLContext:
|
def __ssl_context(self) -> ssl.SSLContext:
|
||||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||||
|
|||||||
@@ -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]
|
||||||
@@ -32,6 +32,12 @@ class Install:
|
|||||||
# 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():
|
||||||
|
|
||||||
@@ -45,6 +51,7 @@ class Install:
|
|||||||
|
|
||||||
def set_configuration(self):
|
def set_configuration(self):
|
||||||
|
|
||||||
|
self.skip_install = False
|
||||||
defender_install_folder = os.getcwd()
|
defender_install_folder = os.getcwd()
|
||||||
venv_folder = '.pyenv'
|
venv_folder = '.pyenv'
|
||||||
unix_user_home_directory = os.path.expanduser("~")
|
unix_user_home_directory = os.path.expanduser("~")
|
||||||
@@ -52,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(),
|
||||||
@@ -67,6 +76,24 @@ class Install:
|
|||||||
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
|
||||||
|
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:
|
||||||
|
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:
|
||||||
|
|
||||||
full_service_file_path = os.path.join(self.config.unix_systemd_folder, self.config.service_file_name)
|
full_service_file_path = os.path.join(self.config.unix_systemd_folder, self.config.service_file_name)
|
||||||
@@ -83,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)
|
||||||
|
|
||||||
@@ -113,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
|
||||||
|
|
||||||
@@ -123,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:
|
||||||
@@ -152,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é')
|
||||||
|
|
||||||
@@ -170,13 +198,10 @@ 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
|
||||||
|
|
||||||
# Check if user systemd is available (.config/systemd/user/)
|
contain = f'''[Unit]
|
||||||
if not os.path.exists(self.config.unix_systemd_folder):
|
|
||||||
self.run_subprocess(['mkdir', '-p', self.config.unix_systemd_folder])
|
|
||||||
|
|
||||||
contain = f'''[Unit]
|
|
||||||
Description=Defender IRC Service
|
Description=Defender IRC Service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@@ -186,20 +211,34 @@ 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/)
|
||||||
|
if not os.path.exists(self.config.unix_systemd_folder):
|
||||||
|
self.run_subprocess(['mkdir', '-p', self.config.unix_systemd_folder])
|
||||||
|
|
||||||
with open(full_service_file_path, 'w+') as servicefile:
|
with open(full_service_file_path, 'w+') as servicefile:
|
||||||
servicefile.write(contain)
|
servicefile.write(contain)
|
||||||
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)
|
||||||
|
|
||||||
|
else:
|
||||||
|
with open(full_service_file_path, 'w+') as servicefile:
|
||||||
|
servicefile.write(contain)
|
||||||
|
servicefile.close()
|
||||||
|
print(f'Service file generated with current configuration')
|
||||||
|
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)
|
||||||
|
|||||||
57
core/irc.py
57
core/irc.py
@@ -1,9 +1,9 @@
|
|||||||
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
|
from core.Model import User, Admin, Channel, Clones
|
||||||
from core.base import Base
|
from core.base import Base
|
||||||
|
|
||||||
class Irc:
|
class Irc:
|
||||||
@@ -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
|
||||||
@@ -30,7 +32,7 @@ class Irc:
|
|||||||
0: ['help', 'auth', 'copyright', 'uptime'],
|
0: ['help', 'auth', 'copyright', 'uptime'],
|
||||||
1: ['load','reload','unload', 'deauth', 'checkversion'],
|
1: ['load','reload','unload', 'deauth', 'checkversion'],
|
||||||
2: ['show_modules', 'show_timers', 'show_threads', 'show_channels', 'show_users', 'show_admins'],
|
2: ['show_modules', 'show_timers', 'show_threads', 'show_channels', 'show_users', 'show_admins'],
|
||||||
3: ['quit', 'restart','addaccess','editaccess', 'delaccess','umode']
|
3: ['quit', 'restart','addaccess','editaccess', 'delaccess']
|
||||||
}
|
}
|
||||||
|
|
||||||
# l'ensemble des commandes.
|
# l'ensemble des commandes.
|
||||||
@@ -43,6 +45,7 @@ class Irc:
|
|||||||
self.User = User(self.Base)
|
self.User = User(self.Base)
|
||||||
self.Admin = Admin(self.Base)
|
self.Admin = Admin(self.Base)
|
||||||
self.Channel = Channel(self.Base)
|
self.Channel = Channel(self.Base)
|
||||||
|
self.Clones = Clones(self.Base)
|
||||||
|
|
||||||
self.__create_table()
|
self.__create_table()
|
||||||
self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, ))
|
self.Base.create_thread(func=self.heartbeat, func_args=(self.beat, ))
|
||||||
@@ -199,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')
|
||||||
|
|
||||||
@@ -220,8 +226,8 @@ 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)
|
||||||
@@ -685,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} ")
|
||||||
@@ -774,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)
|
||||||
@@ -1341,15 +1350,5 @@ class Irc:
|
|||||||
(fromuser, )
|
(fromuser, )
|
||||||
)
|
)
|
||||||
|
|
||||||
case 'umode':
|
|
||||||
try:
|
|
||||||
# .umode nickname +mode
|
|
||||||
nickname = str(cmd[1])
|
|
||||||
umode = str(cmd[2])
|
|
||||||
|
|
||||||
self.send2socket(f':{dnickname} SVSMODE {nickname} {umode}')
|
|
||||||
except KeyError as ke:
|
|
||||||
self.Base.logs.error(ke)
|
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
pass
|
pass
|
||||||
|
|||||||
128
core/loadConf.py
128
core/loadConf.py
@@ -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:
|
||||||
|
|
||||||
|
|||||||
275
install.py
275
install.py
@@ -1,275 +0,0 @@
|
|||||||
from subprocess import check_call, run, CalledProcessError, PIPE
|
|
||||||
from platform import python_version, python_version_tuple, system
|
|
||||||
from sys import exit
|
|
||||||
import os, logging, shutil
|
|
||||||
|
|
||||||
try:
|
|
||||||
import pwd
|
|
||||||
except ModuleNotFoundError as err:
|
|
||||||
print(err)
|
|
||||||
|
|
||||||
class Install:
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
|
|
||||||
# Python required version
|
|
||||||
self.python_min_version = '3.10'
|
|
||||||
self.log_file = 'install.log'
|
|
||||||
self.ServiceName = 'Defender'
|
|
||||||
self.venv_name = '.pyenv'
|
|
||||||
self.venv_dependencies: list[str] = ['sqlalchemy','psutil','requests']
|
|
||||||
self.install_folder = os.getcwd()
|
|
||||||
self.osname = os.name
|
|
||||||
self.system_name = system()
|
|
||||||
self.cmd_linux_requirements: list[str] = ['apt', 'install', '-y', 'python3', 'python3-pip', 'python3-venv']
|
|
||||||
self.venv_pip_full_path = os.path.join(self.venv_name, f'bin{os.sep}pip')
|
|
||||||
self.venv_python_full_path = os.path.join(self.venv_name, f'bin{os.sep}python')
|
|
||||||
self.systemd_folder = '/etc/systemd/system/'
|
|
||||||
|
|
||||||
# Init log system
|
|
||||||
self.init_log_system()
|
|
||||||
|
|
||||||
# Exclude Windows OS
|
|
||||||
if self.osname == 'nt':
|
|
||||||
print('/!\\ Windows OS is not supported by this automatic installation /!\\')
|
|
||||||
self.Logs.critical('/!\\ Windows OS is not supported by this automatic install /!\\')
|
|
||||||
print(self.system_name)
|
|
||||||
exit(5)
|
|
||||||
|
|
||||||
if not self.is_root():
|
|
||||||
exit(5)
|
|
||||||
|
|
||||||
# Get the current user
|
|
||||||
self.system_username: str = input(f'What is the user ro run defender with ? [{os.getlogin()}] : ')
|
|
||||||
if str(self.system_username).strip() == '':
|
|
||||||
self.system_username = os.getlogin()
|
|
||||||
|
|
||||||
self.get_user_information(self.system_username)
|
|
||||||
|
|
||||||
self.Logs.debug(f'The user selected is: {self.system_username}')
|
|
||||||
self.Logs.debug(f'Operating system: {self.osname}')
|
|
||||||
|
|
||||||
# Install linux dependencies
|
|
||||||
self.install_linux_dependencies()
|
|
||||||
|
|
||||||
# Check python version
|
|
||||||
self.check_python_version()
|
|
||||||
|
|
||||||
# Create systemd service file
|
|
||||||
self.create_service_file()
|
|
||||||
|
|
||||||
# Check if Env Exist | install environment | Install python dependencies
|
|
||||||
self.check_venv()
|
|
||||||
|
|
||||||
# Create and start service
|
|
||||||
if self.osname != 'nt':
|
|
||||||
self.run_subprocess(['systemctl','daemon-reload'])
|
|
||||||
self.run_subprocess(['systemctl','start', self.ServiceName])
|
|
||||||
self.run_subprocess(['systemctl','status', self.ServiceName])
|
|
||||||
|
|
||||||
# Clean the Installation
|
|
||||||
self.clean_installation()
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def is_installed(self) -> bool:
|
|
||||||
|
|
||||||
is_installed = False
|
|
||||||
|
|
||||||
# Check logs folder
|
|
||||||
if os.path.exists('logs'):
|
|
||||||
is_installed = True
|
|
||||||
|
|
||||||
# Check db folder
|
|
||||||
if os.path.exists('db'):
|
|
||||||
is_installed = True
|
|
||||||
|
|
||||||
return is_installed
|
|
||||||
|
|
||||||
def is_root(self) -> bool:
|
|
||||||
|
|
||||||
if os.geteuid() != 0:
|
|
||||||
print('/!\\ user must run install.py as root /!\\')
|
|
||||||
self.Logs.critical('/!\\ user must run install.py as root /!\\')
|
|
||||||
return False
|
|
||||||
elif os.geteuid() == 0:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_user_information(self, system_user: str) -> None:
|
|
||||||
|
|
||||||
try:
|
|
||||||
username: tuple = pwd.getpwnam(system_user)
|
|
||||||
self.system_uid = username.pw_uid
|
|
||||||
self.system_gid = username.pw_gid
|
|
||||||
return None
|
|
||||||
|
|
||||||
except KeyError as ke:
|
|
||||||
self.Logs.critical(f"This user [{system_user}] doesn't exist: {ke}")
|
|
||||||
print(f"This user [{system_user}] doesn't exist: {ke}")
|
|
||||||
exit(5)
|
|
||||||
|
|
||||||
def init_log_system(self) -> None:
|
|
||||||
|
|
||||||
# Init logs object
|
|
||||||
self.Logs = logging
|
|
||||||
self.Logs.basicConfig(level=logging.DEBUG,
|
|
||||||
filename=self.log_file,
|
|
||||||
encoding='UTF-8',
|
|
||||||
format='%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(funcName)s - %(message)s')
|
|
||||||
|
|
||||||
self.Logs.debug('#################### STARTING INSTALLATION ####################')
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def clean_installation(self) -> None:
|
|
||||||
|
|
||||||
# Chown the Python Env to non user privilege
|
|
||||||
self.run_subprocess(['chown','-R', f'{self.system_username}:{self.system_username}',
|
|
||||||
f'{os.path.join(self.install_folder, self.venv_name)}'
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Chown the installation log file
|
|
||||||
self.run_subprocess(['chown','-R', f'{self.system_username}:{self.system_username}',
|
|
||||||
f'{os.path.join(self.install_folder, self.log_file)}'
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def run_subprocess(self, command:list) -> None:
|
|
||||||
|
|
||||||
try:
|
|
||||||
run_command = check_call(command)
|
|
||||||
self.Logs.debug(f'{command} - {run_command}')
|
|
||||||
print(f'{command} - {run_command}')
|
|
||||||
|
|
||||||
except CalledProcessError as e:
|
|
||||||
print(f"Command failed :{e.returncode}")
|
|
||||||
self.Logs.critical(f"Command failed :{e.returncode}")
|
|
||||||
exit(5)
|
|
||||||
|
|
||||||
def check_python_version(self) -> bool:
|
|
||||||
"""Test si la version de python est autorisée ou non
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True si la version de python est autorisé sinon False
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.Logs.debug(f'The current python version is: {python_version()}')
|
|
||||||
|
|
||||||
# Current system version
|
|
||||||
sys_major, sys_minor, sys_patch = python_version_tuple()
|
|
||||||
|
|
||||||
# min python version required
|
|
||||||
python_required_version = self.PYTHON_MIN_VERSION.split('.')
|
|
||||||
min_major, min_minor = tuple((python_required_version[0], python_required_version[1]))
|
|
||||||
|
|
||||||
if int(sys_major) < int(min_major):
|
|
||||||
print(f"## Your python version must be greather than or equal to {self.PYTHON_MIN_VERSION} ##")
|
|
||||||
self.Logs.critical(f'Your python version must be greather than or equal to {self.python_min_version}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
elif (int(sys_major) <= int(min_major)) and (int(sys_minor) < int(min_minor)):
|
|
||||||
print(f"## Your python version must be greather than or equal to {self.PYTHON_MIN_VERSION} ##")
|
|
||||||
self.Logs.critical(f'Your python version must be greather than or equal to {self.python_min_version}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
print(f"===> Version of python : {python_version()} ==> OK")
|
|
||||||
self.Logs.debug(f'Version of python : {python_version()} ==> OK')
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_packages(self, package_name) -> bool:
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Run a command in the virtual environment's Python to check if the package is installed
|
|
||||||
run([self.venv_python_full_path, '-c', f'import {package_name}'], check=True, stdout=PIPE, stderr=PIPE)
|
|
||||||
return True
|
|
||||||
except CalledProcessError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_venv(self) -> bool:
|
|
||||||
|
|
||||||
if os.path.exists(self.venv_name):
|
|
||||||
|
|
||||||
# Installer les dependances
|
|
||||||
self.install_dependencies()
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self.run_subprocess(['python3', '-m', 'venv', self.venv_name])
|
|
||||||
self.Logs.debug(f'Python Virtual env installed {self.venv_name}')
|
|
||||||
print(f'Python Virtual env installed {self.venv_name}')
|
|
||||||
|
|
||||||
self.install_dependencies()
|
|
||||||
return False
|
|
||||||
|
|
||||||
def create_service_file(self) -> None:
|
|
||||||
|
|
||||||
if self.systemd_folder is None:
|
|
||||||
# If Windows, do not install systemd
|
|
||||||
return None
|
|
||||||
|
|
||||||
if os.path.exists(f'{self.systemd_folder}{os.sep}{self.ServiceName}.service'):
|
|
||||||
print(f'/!\\ Service already created in the system /!\\')
|
|
||||||
self.Logs.warning('/!\\ Service already created in the system /!\\')
|
|
||||||
print(f'The service file will be regenerated')
|
|
||||||
self.Logs.warning('The service file will be regenerated')
|
|
||||||
|
|
||||||
|
|
||||||
contain = f'''[Unit]
|
|
||||||
Description={self.ServiceName} IRC Service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User={self.system_username}
|
|
||||||
ExecStart={os.path.join(self.install_folder, self.venv_python_full_path)} {os.path.join(self.install_folder, 'main.py')}
|
|
||||||
WorkingDirectory={self.install_folder}
|
|
||||||
SyslogIdentifier={self.ServiceName}
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
'''
|
|
||||||
|
|
||||||
with open(f'{self.ServiceName}.service.generated', 'w+') as servicefile:
|
|
||||||
servicefile.write(contain)
|
|
||||||
servicefile.close()
|
|
||||||
print('Service file generated with current configuration')
|
|
||||||
self.Logs.debug('Service file generated with current configuration')
|
|
||||||
|
|
||||||
source = f'{self.install_folder}{os.sep}{self.ServiceName}.service.generated'
|
|
||||||
self.run_subprocess(['chown','-R', f'{self.system_username}:{self.system_username}', source])
|
|
||||||
destination = f'{self.systemd_folder}'
|
|
||||||
shutil.copy(source, destination)
|
|
||||||
os.rename(f'{self.systemd_folder}{os.sep}{self.ServiceName}.service.generated', f'{self.systemd_folder}{os.sep}{self.ServiceName}.service')
|
|
||||||
print(f'Service file moved to systemd folder {self.systemd_folder}')
|
|
||||||
self.Logs.debug(f'Service file moved to systemd folder {self.systemd_folder}')
|
|
||||||
|
|
||||||
def install_linux_dependencies(self) -> None:
|
|
||||||
|
|
||||||
self.run_subprocess(self.cmd_linux_requirements)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def install_dependencies(self) -> None:
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.run_subprocess([self.venv_pip_full_path, 'cache', 'purge'])
|
|
||||||
self.run_subprocess([self.venv_python_full_path, '-m', 'pip', 'install', '--upgrade', 'pip'])
|
|
||||||
|
|
||||||
if self.check_packages('greenlet') is None:
|
|
||||||
self.run_subprocess(
|
|
||||||
[self.venv_pip_full_path, 'install', '--only-binary', ':all:', 'greenlet']
|
|
||||||
)
|
|
||||||
|
|
||||||
for module in self.venv_dependencies:
|
|
||||||
if not self.check_packages(module):
|
|
||||||
### Trying to install missing python packages ###
|
|
||||||
self.run_subprocess([self.venv_pip_full_path, 'install', module])
|
|
||||||
else:
|
|
||||||
self.Logs.debug(f'{module} already installed')
|
|
||||||
print(f"==> {module} already installed")
|
|
||||||
|
|
||||||
except CalledProcessError as cpe:
|
|
||||||
self.Logs.critical(f'{cpe}')
|
|
||||||
|
|
||||||
Install()
|
|
||||||
@@ -9,7 +9,6 @@ class Clone():
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ModConfModel:
|
class ModConfModel:
|
||||||
clone_count: int
|
|
||||||
clone_nicknames: list[str]
|
clone_nicknames: list[str]
|
||||||
|
|
||||||
def __init__(self, ircInstance:Irc) -> None:
|
def __init__(self, ircInstance:Irc) -> None:
|
||||||
@@ -35,9 +34,11 @@ class Clone():
|
|||||||
# Add Channel object to the module (Mandatory)
|
# Add Channel object to the module (Mandatory)
|
||||||
self.Channel = ircInstance.Channel
|
self.Channel = ircInstance.Channel
|
||||||
|
|
||||||
|
self.Clone = ircInstance.Clones
|
||||||
|
|
||||||
# Créer les nouvelles commandes du module
|
# Créer les nouvelles commandes du module
|
||||||
self.commands_level = {
|
self.commands_level = {
|
||||||
1: ['clone_connect', 'clone_join', 'clone_kill', 'clone_list']
|
1: ['clone']
|
||||||
}
|
}
|
||||||
|
|
||||||
# Init the module (Mandatory)
|
# Init the module (Mandatory)
|
||||||
@@ -97,15 +98,13 @@ class Clone():
|
|||||||
"""### Load Module Configuration
|
"""### Load Module Configuration
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Variable qui va contenir les options de configuration du module Defender
|
|
||||||
# Variable qui va contenir les options de configuration du module Defender
|
# Variable qui va contenir les options de configuration du module Defender
|
||||||
self.ModConfig = self.ModConfModel(
|
self.ModConfig = self.ModConfModel(
|
||||||
clone_count=0,
|
|
||||||
clone_nicknames=[]
|
clone_nicknames=[]
|
||||||
)
|
)
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -123,22 +122,23 @@ class Clone():
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def thread_create_clones(self, nickname: str, username: str, channels:list, server_port:int, ssl:bool) -> None:
|
def thread_create_clones(self, nickname: str, username: str, channels: list, server_port: int, ssl: bool) -> None:
|
||||||
|
|
||||||
Connection(server_port=server_port, nickname=nickname, username=username, channels=channels, ssl=ssl)
|
Connection(server_port=server_port, nickname=nickname, username=username, channels=channels, CloneObject=self.Clone, ssl=ssl)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def thread_join_channels(self, channel_name: str, wait: float, clone_name:str = None):
|
def thread_join_channels(self, channel_name: str, wait: float, clone_name:str = None):
|
||||||
|
|
||||||
if clone_name is None:
|
if clone_name is None:
|
||||||
for clone in self.ModConfig.clone_nicknames:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone} :JOIN {channel_name}')
|
self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone.nickname} :JOIN {channel_name}')
|
||||||
time.sleep(wait)
|
time.sleep(wait)
|
||||||
else:
|
else:
|
||||||
for clone in self.ModConfig.clone_nicknames:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
if clone_name == clone:
|
if clone_name == clone.nickname:
|
||||||
self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone} :JOIN {channel_name}')
|
self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} PRIVMSG {clone.nickname} :JOIN {channel_name}')
|
||||||
|
time.sleep(wait)
|
||||||
|
|
||||||
def generate_names(self) -> tuple[str, str]:
|
def generate_names(self) -> tuple[str, str]:
|
||||||
try:
|
try:
|
||||||
@@ -146,13 +146,25 @@ class Clone():
|
|||||||
nickname = fake.first_name()
|
nickname = fake.first_name()
|
||||||
username = fake.last_name()
|
username = fake.last_name()
|
||||||
|
|
||||||
if not nickname in self.ModConfig.clone_nicknames:
|
if self.Clone.exists(nickname=nickname):
|
||||||
self.ModConfig.clone_nicknames.append(nickname)
|
|
||||||
else:
|
|
||||||
caracteres = '0123456789'
|
caracteres = '0123456789'
|
||||||
randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
||||||
nickname = nickname + str(randomize)
|
nickname = nickname + str(randomize)
|
||||||
self.ModConfig.clone_nicknames.append(nickname)
|
self.Clone.insert(
|
||||||
|
self.Clone.CloneModel(alive=True, nickname=nickname, username=username)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.Clone.insert(
|
||||||
|
self.Clone.CloneModel(alive=True, nickname=nickname, username=username)
|
||||||
|
)
|
||||||
|
|
||||||
|
# if not nickname in self.ModConfig.clone_nicknames:
|
||||||
|
# self.ModConfig.clone_nicknames.append(nickname)
|
||||||
|
# else:
|
||||||
|
# caracteres = '0123456789'
|
||||||
|
# randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
||||||
|
# nickname = nickname + str(randomize)
|
||||||
|
# self.ModConfig.clone_nicknames.append(nickname)
|
||||||
|
|
||||||
return (nickname, username)
|
return (nickname, username)
|
||||||
|
|
||||||
@@ -183,60 +195,110 @@ class Clone():
|
|||||||
|
|
||||||
match command:
|
match command:
|
||||||
|
|
||||||
case 'clone_connect':
|
case 'clone':
|
||||||
# clone_connect 25
|
option = str(cmd[1]).lower()
|
||||||
try:
|
|
||||||
number_of_clones = int(cmd[1])
|
|
||||||
for i in range(number_of_clones):
|
|
||||||
nickname, username = self.generate_names()
|
|
||||||
self.Base.create_thread(
|
|
||||||
self.thread_create_clones,
|
|
||||||
(nickname, username, [], 6697, True)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{str(number_of_clones)} clones joined the network')
|
if len(command) == 1:
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list')
|
||||||
|
|
||||||
except Exception as err:
|
match option:
|
||||||
self.Logs.error(f'{err}')
|
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone_connect [number of clone you want to connect]')
|
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} clone_kill 6')
|
|
||||||
|
|
||||||
case 'clone_kill':
|
case 'connect':
|
||||||
try:
|
try:
|
||||||
clone_name = str(cmd[1])
|
number_of_clones = int(cmd[2])
|
||||||
|
for i in range(number_of_clones):
|
||||||
|
nickname, username = self.generate_names()
|
||||||
|
self.Base.create_thread(
|
||||||
|
self.thread_create_clones,
|
||||||
|
(nickname, username, [], 6697, True)
|
||||||
|
)
|
||||||
|
|
||||||
if clone_name.lower() == 'all':
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{str(number_of_clones)} clones joined the network')
|
||||||
for clone in self.ModConfig.clone_nicknames:
|
except Exception as err:
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {clone} :KILL')
|
self.Logs.error(f'{err}')
|
||||||
self.ModConfig.clone_nicknames.remove(clone)
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect [number of clone you want to connect]')
|
||||||
else:
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} clone connect 6')
|
||||||
for clone in self.ModConfig.clone_nicknames:
|
|
||||||
if clone_name == clone:
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {clone} :KILL')
|
|
||||||
self.ModConfig.clone_nicknames.remove(clone)
|
|
||||||
|
|
||||||
except Exception as err:
|
case 'kill':
|
||||||
self.Logs.error(f'{err}')
|
try:
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone_kill all')
|
# clone kill [all | nickname]
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone_kill [clone_name]')
|
clone_name = str(cmd[2])
|
||||||
|
clone_to_kill: list[str] = []
|
||||||
|
|
||||||
case 'clone_join':
|
if clone_name.lower() == 'all':
|
||||||
try:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
# clone_join nickname #channel
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {clone.nickname} :KILL')
|
||||||
clone_name = str(cmd[1])
|
clone_to_kill.append(clone.nickname)
|
||||||
clone_channel_to_join = cmd[2]
|
clone.alive = False
|
||||||
|
|
||||||
if clone_name.lower() == 'all':
|
for clone_nickname in clone_to_kill:
|
||||||
self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 4))
|
self.Clone.delete(clone_nickname)
|
||||||
else:
|
|
||||||
self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 4, clone_name))
|
|
||||||
|
|
||||||
except Exception as err:
|
del clone_to_kill
|
||||||
self.Logs.error(f'{err}')
|
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone_join all #channel')
|
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone_join clone_nickname #channel')
|
|
||||||
|
|
||||||
case 'clone_list':
|
else:
|
||||||
|
if self.Clone.exists(clone_name):
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :KILL')
|
||||||
|
self.Clone.kill(clone_name)
|
||||||
|
self.Clone.delete(clone_name)
|
||||||
|
|
||||||
for clone_name in self.ModConfig.clone_nicknames:
|
except Exception as err:
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :>> {clone_name}')
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill all')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill clone_nickname')
|
||||||
|
|
||||||
|
case 'join':
|
||||||
|
try:
|
||||||
|
# clone join [all | nickname] #channel
|
||||||
|
clone_name = str(cmd[2])
|
||||||
|
clone_channel_to_join = str(cmd[3])
|
||||||
|
|
||||||
|
if clone_name.lower() == 'all':
|
||||||
|
self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2))
|
||||||
|
else:
|
||||||
|
self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2, clone_name))
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join all #channel')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join clone_nickname #channel')
|
||||||
|
|
||||||
|
case 'list':
|
||||||
|
try:
|
||||||
|
for clone_name in self.Clone.UID_CLONE_DB:
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :>> {clone_name.nickname} | {clone_name.username}')
|
||||||
|
pass
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'{err}')
|
||||||
|
|
||||||
|
case 'say':
|
||||||
|
try:
|
||||||
|
# clone say clone_nickname #channel message
|
||||||
|
clone_name = str(cmd[2])
|
||||||
|
clone_channel = str(cmd[3]) if self.Base.Is_Channel(str(cmd[3])) else None
|
||||||
|
|
||||||
|
message = []
|
||||||
|
for i in range(4, len(cmd)):
|
||||||
|
message.append(cmd[i])
|
||||||
|
final_message = ' '.join(message)
|
||||||
|
|
||||||
|
if clone_channel is None or not self.Clone.exists(clone_name):
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message')
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self.Clone.exists(clone_name):
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :SAY {clone_channel} {final_message}')
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message')
|
||||||
|
|
||||||
|
case _:
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel [message]')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list')
|
||||||
|
|||||||
@@ -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']
|
2: ['owner', 'deowner', 'op', 'deop', 'halfop', 'dehalfop', 'voice', 'devoice', 'opall', '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,54 @@ 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)
|
||||||
|
set_mode = 'v'
|
||||||
|
mode:str = ''
|
||||||
|
users:str = ''
|
||||||
|
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||||
|
|
||||||
|
self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}")
|
||||||
|
for uid in uids_split:
|
||||||
|
for i in range(0, len(uid)):
|
||||||
|
mode += set_mode
|
||||||
|
users += f'{self.User.get_nickname(self.Base.clean_uid(uid[i]))} '
|
||||||
|
if i == len(uid) - 1:
|
||||||
|
self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}")
|
||||||
|
mode = ''
|
||||||
|
users = ''
|
||||||
|
|
||||||
|
case 'opall':
|
||||||
|
chan_info = self.Channel.get_Channel(fromchannel)
|
||||||
|
set_mode = 'o'
|
||||||
|
mode:str = ''
|
||||||
|
users:str = ''
|
||||||
|
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||||
|
|
||||||
|
self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{set_mode} {dnickname}")
|
||||||
|
for uid in uids_split:
|
||||||
|
for i in range(0, len(uid)):
|
||||||
|
mode += set_mode
|
||||||
|
users += f'{self.User.get_nickname(self.Base.clean_uid(uid[i]))} '
|
||||||
|
if i == len(uid) - 1:
|
||||||
|
self.Irc.send2socket(f":{service_id} MODE {fromchannel} +{mode} {users}")
|
||||||
|
mode = ''
|
||||||
|
users = ''
|
||||||
|
|
||||||
case 'op':
|
case 'op':
|
||||||
# /mode #channel +o user
|
# /mode #channel +o user
|
||||||
# .op #channel user
|
# .op #channel user
|
||||||
@@ -481,3 +529,13 @@ class Command():
|
|||||||
|
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(f'{ie}')
|
self.Logs.error(f'{ie}')
|
||||||
|
|
||||||
|
case 'umode':
|
||||||
|
try:
|
||||||
|
# .umode nickname +mode
|
||||||
|
nickname = str(cmd[1])
|
||||||
|
umode = str(cmd[2])
|
||||||
|
|
||||||
|
self.send2socket(f':{dnickname} SVSMODE {nickname} {umode}')
|
||||||
|
except KeyError as ke:
|
||||||
|
self.Base.logs.error(ke)
|
||||||
@@ -48,7 +48,7 @@ class Votekick():
|
|||||||
|
|
||||||
# Créer les nouvelles commandes du module
|
# Créer les nouvelles commandes du module
|
||||||
self.commands_level = {
|
self.commands_level = {
|
||||||
0: ['vote_for', 'vote_against'],
|
0: ['vote'],
|
||||||
1: ['activate', 'deactivate', 'submit', 'vote_stat', 'vote_verdict', 'vote_cancel']
|
1: ['activate', 'deactivate', 'submit', 'vote_stat', 'vote_verdict', 'vote_cancel']
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +60,8 @@ class Votekick():
|
|||||||
|
|
||||||
def __init_module(self) -> None:
|
def __init_module(self) -> None:
|
||||||
|
|
||||||
|
self.Admin = self.Irc.Admin
|
||||||
|
|
||||||
self.__set_commands(self.commands_level)
|
self.__set_commands(self.commands_level)
|
||||||
self.__create_tables()
|
self.__create_tables()
|
||||||
self.join_saved_channels()
|
self.join_saved_channels()
|
||||||
@@ -192,7 +194,9 @@ class Votekick():
|
|||||||
|
|
||||||
def join_saved_channels(self) -> None:
|
def join_saved_channels(self) -> None:
|
||||||
|
|
||||||
result = self.Base.db_execute_query("SELECT id, channel FROM votekick_channel")
|
param = {'module_name': self.module_name}
|
||||||
|
result = self.Base.db_execute_query(f"SELECT id, channel_name FROM {self.Config.table_channel} WHERE module_name = :module_name", param)
|
||||||
|
|
||||||
channels = result.fetchall()
|
channels = result.fetchall()
|
||||||
unixtime = self.Base.get_unixtime()
|
unixtime = self.Base.get_unixtime()
|
||||||
|
|
||||||
@@ -218,15 +222,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):
|
||||||
@@ -255,186 +262,213 @@ class Votekick():
|
|||||||
fromchannel = channel
|
fromchannel = channel
|
||||||
|
|
||||||
match command:
|
match command:
|
||||||
|
case 'vote':
|
||||||
|
option = str(cmd[1]).lower()
|
||||||
|
match option:
|
||||||
|
|
||||||
case 'vote_cancel':
|
case 'activate':
|
||||||
try:
|
try:
|
||||||
if channel is None:
|
# vote activate #channel
|
||||||
self.Logs.error(f"The channel is not known, defender can't cancel the vote")
|
if self.Admin.get_Admin(fromuser) is None:
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :You need to specify the channel => /msg {dnickname} vote_cancel #channel')
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command')
|
||||||
|
return None
|
||||||
|
|
||||||
for vote in self.VOTE_CHANNEL_DB:
|
sentchannel = str(cmd[2]).lower() if self.Base.Is_Channel(str(cmd[2]).lower()) else None
|
||||||
if vote.channel_name == channel:
|
if sentchannel is None:
|
||||||
self.init_vote_system(channel)
|
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Vote system re-initiated')
|
|
||||||
|
|
||||||
except IndexError as ke:
|
self.insert_vote_channel(
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} vote_cancel #channel')
|
self.VoteChannelModel(
|
||||||
self.Logs.error(f'Index Error: {ke}')
|
channel_name=sentchannel,
|
||||||
|
target_user='',
|
||||||
|
voter_users=[],
|
||||||
|
vote_for=0,
|
||||||
|
vote_against=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
case 'vote_for':
|
self.Base.db_query_channel('add', self.module_name, sentchannel)
|
||||||
try:
|
|
||||||
# vote_for
|
|
||||||
channel = fromchannel
|
|
||||||
for chan in self.VOTE_CHANNEL_DB:
|
|
||||||
if chan.channel_name == channel:
|
|
||||||
if fromuser in chan.voter_users:
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :You already submitted a vote')
|
|
||||||
else:
|
|
||||||
chan.vote_for += 1
|
|
||||||
chan.voter_users.append(fromuser)
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Vote recorded, thank you')
|
|
||||||
|
|
||||||
except KeyError as ke:
|
self.Irc.send2socket(f":{dnickname} JOIN {sentchannel}")
|
||||||
self.Logs.error(f'Key Error: {ke}')
|
self.Irc.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}")
|
||||||
except IndexError as ie:
|
self.Irc.send2socket(f":{dnickname} PRIVMSG {sentchannel} :You can now use !submit <nickname> to decide if he will stay or not on this channel ")
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} vote_cancel #channel')
|
except Exception as err:
|
||||||
self.Logs.error(f'Index Error: {ie}')
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option} #channel')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option} #welcome')
|
||||||
|
|
||||||
case 'vote_against':
|
case 'deactivate':
|
||||||
try:
|
try:
|
||||||
# vote_against
|
# vote deactivate #channel
|
||||||
channel = fromchannel
|
if self.Admin.get_Admin(fromuser) is None:
|
||||||
for chan in self.VOTE_CHANNEL_DB:
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command')
|
||||||
if chan.channel_name == channel:
|
return None
|
||||||
if fromuser in chan.voter_users:
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :You already submitted a vote')
|
|
||||||
else:
|
|
||||||
chan.vote_against += 1
|
|
||||||
chan.voter_users.append(fromuser)
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Vote recorded, thank you')
|
|
||||||
|
|
||||||
except KeyError as ke:
|
sentchannel = str(cmd[2]).lower() if self.Base.Is_Channel(str(cmd[2]).lower()) else None
|
||||||
self.Logs.error(f'Key Error: {ke}')
|
if sentchannel is None:
|
||||||
|
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
||||||
|
|
||||||
case 'vote_stat':
|
self.Irc.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}")
|
||||||
try:
|
self.Irc.send2socket(f":{dnickname} PART {sentchannel}")
|
||||||
# channel = str(fullcmd[2]).lower()
|
|
||||||
for chan in self.VOTE_CHANNEL_DB:
|
|
||||||
if chan.channel_name == channel:
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Channel: {chan.channel_name} | Target: {self.User.get_nickname(chan.target_user)} | For: {chan.vote_for} | Against: {chan.vote_against} | Number of voters: {str(len(chan.voter_users))}')
|
|
||||||
|
|
||||||
except KeyError as ke:
|
for chan in self.VOTE_CHANNEL_DB:
|
||||||
self.Logs.error(f'Key Error: {ke}')
|
if chan.channel_name == sentchannel:
|
||||||
|
self.VOTE_CHANNEL_DB.remove(chan)
|
||||||
|
self.Base.db_query_channel('del', self.module_name, chan.channel_name)
|
||||||
|
|
||||||
case 'vote_verdict':
|
self.Logs.debug(f"The Channel {sentchannel} has been deactivated from the vote system")
|
||||||
try:
|
except Exception as err:
|
||||||
# channel = str(fullcmd[2]).lower()
|
self.Logs.error(f'{err}')
|
||||||
for chan in self.VOTE_CHANNEL_DB:
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option} #channel')
|
||||||
if chan.channel_name == channel:
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option} #welcome')
|
||||||
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} 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')
|
|
||||||
|
|
||||||
# Init the system
|
case '+':
|
||||||
if self.init_vote_system(channel):
|
try:
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :System vote re initiated')
|
# vote +
|
||||||
|
channel = fromchannel
|
||||||
|
for chan in self.VOTE_CHANNEL_DB:
|
||||||
|
if chan.channel_name == channel:
|
||||||
|
if fromuser in chan.voter_users:
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :You already submitted a vote')
|
||||||
|
else:
|
||||||
|
chan.vote_for += 1
|
||||||
|
chan.voter_users.append(fromuser)
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Vote recorded, thank you')
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
except KeyError as ke:
|
case '-':
|
||||||
self.Logs.error(f'Key Error: {ke}')
|
try:
|
||||||
|
# vote -
|
||||||
|
channel = fromchannel
|
||||||
|
for chan in self.VOTE_CHANNEL_DB:
|
||||||
|
if chan.channel_name == channel:
|
||||||
|
if fromuser in chan.voter_users:
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :You already submitted a vote')
|
||||||
|
else:
|
||||||
|
chan.vote_against += 1
|
||||||
|
chan.voter_users.append(fromuser)
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Vote recorded, thank you')
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
case 'submit':
|
case 'cancel':
|
||||||
# submit nickname
|
try:
|
||||||
try:
|
# vote cancel
|
||||||
nickname_submitted = cmd[1]
|
if self.Admin.get_Admin(fromuser) is None:
|
||||||
# channel = str(fullcmd[2]).lower()
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command')
|
||||||
uid_submitted = self.User.get_uid(nickname_submitted)
|
return None
|
||||||
user_submitted = self.User.get_User(nickname_submitted)
|
|
||||||
|
|
||||||
# check if there is an ongoing vote
|
if channel is None:
|
||||||
if self.is_vote_ongoing(channel):
|
self.Logs.error(f"The channel is not known, defender can't cancel the vote")
|
||||||
for vote in self.VOTE_CHANNEL_DB:
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :You need to specify the channel => /msg {dnickname} vote_cancel #channel')
|
||||||
if vote.channel_name == channel:
|
|
||||||
ongoing_user = self.User.get_nickname(vote.target_user)
|
|
||||||
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :There is an ongoing vote on {ongoing_user}')
|
for vote in self.VOTE_CHANNEL_DB:
|
||||||
return False
|
if vote.channel_name == channel:
|
||||||
|
self.init_vote_system(channel)
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Vote system re-initiated')
|
||||||
|
|
||||||
# check if the user exist
|
except Exception as err:
|
||||||
if user_submitted is None:
|
self.Logs.error(f'{err}')
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This nickname <{nickname_submitted}> do not exist')
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option}')
|
||||||
return False
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
uid_cleaned = self.Base.clean_uid(uid_submitted)
|
case 'status':
|
||||||
ChannelInfo = self.Channel.get_Channel(channel)
|
try:
|
||||||
if ChannelInfo is None:
|
# vote status
|
||||||
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :This channel [{channel}] do not exist in the Channel Object')
|
for chan in self.VOTE_CHANNEL_DB:
|
||||||
return False
|
if chan.channel_name == channel:
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :Channel: {chan.channel_name} | Target: {self.User.get_nickname(chan.target_user)} | For: {chan.vote_for} | Against: {chan.vote_against} | Number of voters: {str(len(chan.voter_users))}')
|
||||||
|
|
||||||
clean_uids_in_channel: list = []
|
except Exception as err:
|
||||||
for uid in ChannelInfo.uids:
|
self.Logs.error(f'{err}')
|
||||||
clean_uids_in_channel.append(self.Base.clean_uid(uid))
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
if not uid_cleaned in clean_uids_in_channel:
|
case 'submit':
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This nickname <{nickname_submitted}> is not available in this channel')
|
try:
|
||||||
return False
|
# vote submit nickname
|
||||||
|
if self.Admin.get_Admin(fromuser) is None:
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command')
|
||||||
|
return None
|
||||||
|
|
||||||
# check if Ircop or Service or Bot
|
nickname_submitted = cmd[2]
|
||||||
pattern = fr'[o|B|S]'
|
uid_submitted = self.User.get_uid(nickname_submitted)
|
||||||
operator_user = re.findall(pattern, user_submitted.umodes)
|
user_submitted = self.User.get_User(nickname_submitted)
|
||||||
if operator_user:
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :You cant vote for this user ! he/she is protected')
|
|
||||||
return False
|
|
||||||
|
|
||||||
for chan in self.VOTE_CHANNEL_DB:
|
# check if there is an ongoing vote
|
||||||
if chan.channel_name == channel:
|
if self.is_vote_ongoing(channel):
|
||||||
chan.target_user = self.User.get_uid(nickname_submitted)
|
for vote in self.VOTE_CHANNEL_DB:
|
||||||
|
if vote.channel_name == channel:
|
||||||
|
ongoing_user = self.User.get_nickname(vote.target_user)
|
||||||
|
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :{nickname_submitted} has been targeted for a vote')
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :There is an ongoing vote on {ongoing_user}')
|
||||||
|
return False
|
||||||
|
|
||||||
self.Base.create_timer(60, self.timer_vote_verdict, (channel, ))
|
# check if the user exist
|
||||||
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This vote will end after 60 secondes')
|
if user_submitted is None:
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This nickname <{nickname_submitted}> do not exist')
|
||||||
|
return False
|
||||||
|
|
||||||
except KeyError as ke:
|
uid_cleaned = self.Base.clean_uid(uid_submitted)
|
||||||
self.Logs.error(f'Key Error: {ke}')
|
ChannelInfo = self.Channel.get_Channel(channel)
|
||||||
except TypeError as te:
|
if ChannelInfo is None:
|
||||||
self.Logs.error(te)
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :This channel [{channel}] do not exist in the Channel Object')
|
||||||
|
return False
|
||||||
|
|
||||||
case 'activate':
|
clean_uids_in_channel: list = []
|
||||||
try:
|
for uid in ChannelInfo.uids:
|
||||||
# activate #channel
|
clean_uids_in_channel.append(self.Base.clean_uid(uid))
|
||||||
sentchannel = str(cmd[1]).lower() if self.Base.Is_Channel(str(cmd[1]).lower()) else None
|
|
||||||
if sentchannel is None:
|
|
||||||
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The correct command is {self.Config.SERVICE_PREFIX}ACTIVATE #CHANNEL")
|
|
||||||
|
|
||||||
self.insert_vote_channel(
|
if not uid_cleaned in clean_uids_in_channel:
|
||||||
self.VoteChannelModel(
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This nickname <{nickname_submitted}> is not available in this channel')
|
||||||
channel_name=sentchannel,
|
return False
|
||||||
target_user='',
|
|
||||||
voter_users=[],
|
|
||||||
vote_for=0,
|
|
||||||
vote_against=0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.Base.db_query_channel('add', self.module_name, sentchannel)
|
# check if Ircop or Service or Bot
|
||||||
|
pattern = fr'[o|B|S]'
|
||||||
|
operator_user = re.findall(pattern, user_submitted.umodes)
|
||||||
|
if operator_user:
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :You cant vote for this user ! he/she is protected')
|
||||||
|
return False
|
||||||
|
|
||||||
self.Irc.send2socket(f":{dnickname} JOIN {sentchannel}")
|
for chan in self.VOTE_CHANNEL_DB:
|
||||||
self.Irc.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}")
|
if chan.channel_name == channel:
|
||||||
self.Irc.send2socket(f":{dnickname} PRIVMSG {sentchannel} :You can now use !submit <nickname> to decide if he will stay or not on this channel ")
|
chan.target_user = self.User.get_uid(nickname_submitted)
|
||||||
|
|
||||||
except KeyError as ke:
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :{nickname_submitted} has been targeted for a vote')
|
||||||
self.Logs.error(f"Key Error : {ke}")
|
|
||||||
|
|
||||||
case 'deactivate':
|
self.Base.create_timer(60, self.timer_vote_verdict, (channel, ))
|
||||||
try:
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :This vote will end after 60 secondes')
|
||||||
# deactivate #channel
|
|
||||||
sentchannel = str(cmd[1]).lower() if self.Base.Is_Channel(str(cmd[1]).lower()) else None
|
|
||||||
if sentchannel is None:
|
|
||||||
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} :The correct command is {self.Config.SERVICE_PREFIX}DEACTIVATE #CHANNEL")
|
|
||||||
|
|
||||||
self.Irc.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}")
|
except Exception as err:
|
||||||
self.Irc.send2socket(f":{dnickname} PART {sentchannel}")
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option} nickname')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option} adator')
|
||||||
|
|
||||||
for chan in self.VOTE_CHANNEL_DB:
|
case 'verdict':
|
||||||
if chan.channel_name == sentchannel:
|
try:
|
||||||
self.VOTE_CHANNEL_DB.remove(chan)
|
# vote verdict
|
||||||
self.Base.db_query_channel('del', self.module_name, chan.channel_name)
|
if self.Admin.get_Admin(fromuser) is None:
|
||||||
# self.db_delete_vote_channel(chan.channel_name)
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Your are not allowed to execute this command')
|
||||||
|
return None
|
||||||
|
|
||||||
self.Logs.debug(f"The Channel {sentchannel} has been deactivated from the vote system")
|
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} :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} :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')
|
||||||
|
|
||||||
except KeyError as ke:
|
# Init the system
|
||||||
self.Logs.error(f"Key Error : {ke}")
|
if self.init_vote_system(channel):
|
||||||
|
self.Irc.send2socket(f':{dnickname} PRIVMSG {channel} :System vote re initiated')
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'{err}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} {command} {option}')
|
||||||
|
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"version": "5.1.0"
|
"version": "5.1.5"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user