mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 19:24:23 +00:00
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,3 +11,5 @@ configuration_inspircd.json
|
|||||||
configuration_unreal6.json
|
configuration_unreal6.json
|
||||||
*.log
|
*.log
|
||||||
test.py
|
test.py
|
||||||
|
users.txt
|
||||||
|
modules.txt
|
||||||
65
Makefile
Normal file
65
Makefile
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
OS := $(shell uname -s)
|
||||||
|
CURRENT_USER := $(shell whoami)
|
||||||
|
PYTHON_VERSION := $(shell python3 -V)
|
||||||
|
HOME_DIR := $(shell echo $$HOME)
|
||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
install:
|
||||||
|
ifeq ($(wildcard config/configuration.yaml),)
|
||||||
|
$(error You must provide the Configuration file: config/configuration.yaml)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
$(info Installation for os : $(OS))
|
||||||
|
$(info Python version: $(PYTHON_VERSION))
|
||||||
|
$(info Home directory: $(HOME_DIR))
|
||||||
|
|
||||||
|
@python3 core/install.py --check-version
|
||||||
|
@if [ $$? -eq 0 ]; then \
|
||||||
|
echo "Python Version OK! Well done :)"; \
|
||||||
|
else \
|
||||||
|
echo "Error: Script failed with exit code $$?"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
$(info Creating the systemd user folder...)
|
||||||
|
mkdir -p $(HOME_DIR)/.config/systemd/user
|
||||||
|
|
||||||
|
$(info Creating Python Virtual Environment...)
|
||||||
|
python3 -m venv .pyenv
|
||||||
|
@. .pyenv/bin/activate && \
|
||||||
|
python -m pip install --upgrade pip && \
|
||||||
|
pip cache purge && \
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
@. .pyenv/bin/activate && python core/install.py --install
|
||||||
|
loginctl enable-linger $(CURRENT_USER)
|
||||||
|
@sleep 2
|
||||||
|
@export echo $DBUS_SESSION_BUS_ADDRESS && \
|
||||||
|
systemctl --user daemon-reload && \
|
||||||
|
systemctl --user start defender
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
@export echo $DBUS_SESSION_BUS_ADDRESS && \
|
||||||
|
systemctl --user stop defender
|
||||||
|
$(info Defender has been stopped...)
|
||||||
|
@if [ -e .pyenv ]; then \
|
||||||
|
rm -rf .pyenv; \
|
||||||
|
echo "Virtual Env has been removed!"; \
|
||||||
|
fi
|
||||||
|
@if [ -e $(HOME_DIR)/.config/systemd/user/defender.service ]; then \
|
||||||
|
rm $(HOME_DIR)/.config/systemd/user/defender.service; \
|
||||||
|
echo "Systemd file has been removed!"; \
|
||||||
|
fi
|
||||||
|
@export echo $DBUS_SESSION_BUS_ADDRESS && systemctl --user daemon-reload && echo "Systemd Daemon reloaded!"
|
||||||
|
endif
|
||||||
|
|
||||||
|
update:
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
$(info Starting update from the main repository...)
|
||||||
|
@. .pyenv/bin/activate && python core/install.py --git-update
|
||||||
|
$(info Update done!)
|
||||||
|
endif
|
||||||
139
README.md
139
README.md
@@ -34,10 +34,11 @@ Il permet aux opérateurs de gérer efficacement un canal, tout en offrant aux u
|
|||||||
- Python version 3.10 ou supérieure
|
- Python version 3.10 ou supérieure
|
||||||
```bash
|
```bash
|
||||||
# Bash
|
# Bash
|
||||||
$ git clone https://github.com/adator85/IRC_DEFENDER_MODULES.git
|
$ git clone https://github.com/adator85/DEFENDER.git defender
|
||||||
|
$ cd defender/
|
||||||
# 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
|
||||||
$ python3 main.py
|
$ make install
|
||||||
```
|
```
|
||||||
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:
|
Pour Les prochains lancement de defender vous devez utiliser la commande suivante:
|
||||||
@@ -49,11 +50,11 @@ Pour Les prochains lancement de defender vous devez utiliser la commande suivant
|
|||||||
# Installation manuelle:
|
# Installation manuelle:
|
||||||
```bash
|
```bash
|
||||||
# Bash
|
# Bash
|
||||||
$ git clone https://github.com/adator85/IRC_DEFENDER_MODULES.git
|
$ git clone https://github.com/adator85/DEFENDER.git defender
|
||||||
$ cd IRC_DEFENDER_MODULES
|
$ cd defender/
|
||||||
$ python3 -m venv .pyenv
|
$ python3 -m venv .pyenv
|
||||||
$ source .pyenv/bin/activate
|
$ source .pyenv/bin/activate
|
||||||
(pyenv)$ pip install sqlalchemy, psutil, requests, faker, unrealircd_rpc_py, pyyaml
|
(pyenv)$ pip install -r requirements.txt
|
||||||
|
|
||||||
# Créer un service nommé "defender.service"
|
# Créer un service nommé "defender.service"
|
||||||
# pour votre service et placer le dans "/PATH/TO/USER/.config/systemd/user/"
|
# pour votre service et placer le dans "/PATH/TO/USER/.config/systemd/user/"
|
||||||
@@ -104,87 +105,91 @@ Pour Les prochains lancement de defender vous devez utiliser la commande suivant
|
|||||||
GLINE_DURATION: Durée de bannissement temporaire d'un utilisateur en minutes. (default : "30")
|
GLINE_DURATION: Durée de bannissement temporaire d'un utilisateur en minutes. (default : "30")
|
||||||
|
|
||||||
DEBUG (Debug)
|
DEBUG (Debug)
|
||||||
DEBUG_LEVEL: Niveau de verbosité des messages de debug (plus grand est le nombre, plus il y a d'informations). (default : 20) Pour une production
|
DEBUG_LEVEL: Niveau de verbosité des messages de debug (plus petit est le nombre, plus il y a d'informations). (default : 20) Pour une production
|
||||||
|
DEBUG_HARD: Généralement utiliser pour les developpeurs.
|
||||||
|
|
||||||
```
|
```
|
||||||
Modification de la configuration
|
Modification de la configuration
|
||||||
|
|
||||||
Vous devez modifier le fichier configuration.json en remplaçant les valeurs par défaut avec vos propres informations. Assurez-vous de bien lire la description de chaque paramètre pour une configuration optimale du service.
|
Vous devez modifier le fichier configuration.yaml en remplaçant les valeurs par défaut avec vos propres informations. Assurez-vous de bien lire la description de chaque paramètre pour une configuration optimale du service.
|
||||||
|
|
||||||
## Exemple de configuration de base
|
## Exemple de configuration de base
|
||||||
```json
|
```yaml
|
||||||
{
|
configuration:
|
||||||
"SERVEUR_IP": "IP.DE.TON.SERVER",
|
SERVEUR_IP: "YOUR.SERVER.IP"
|
||||||
"SERVEUR_HOSTNAME": "HOST.DE.TON.SERVER",
|
SERVEUR_HOSTNAME: "YOUR.SERVER.HOST"
|
||||||
"SERVEUR_LINK": "LINK.DE.TON.SERVER",
|
SERVEUR_LINK: "LINK.DE.TON.SERVER"
|
||||||
"SERVEUR_PORT": 6901,
|
SERVEUR_PORT: 7002
|
||||||
"SERVEUR_PASSWORD": "MOT_DE_PASS_DE_TON_LINK",
|
SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD"
|
||||||
"SERVEUR_ID": "10Z",
|
SERVEUR_ID: "006"
|
||||||
"SERVEUR_SSL": true,
|
SERVEUR_SSL: true
|
||||||
|
|
||||||
"SERVICE_NAME": "defender",
|
SERVICE_NAME: "defender"
|
||||||
"SERVICE_NICKNAME": "PyDefender",
|
SERVICE_NICKNAME: "PyDefender"
|
||||||
"SERVICE_REALNAME": "Python Defender Security",
|
SERVICE_REALNAME: "Python Defender Security"
|
||||||
"SERVICE_USERNAME": "PyDefender",
|
SERVICE_USERNAME: "PyDefender"
|
||||||
"SERVICE_HOST": "HOST.DE.TON.DEFENDER",
|
SERVICE_HOST: "HOST.DE.TON.DEFENDER"
|
||||||
|
SERVICE_INFO: "Network IRC Service"
|
||||||
|
SERVICE_CHANLOG: "#services"
|
||||||
|
SERVICE_SMODES: "+ioqBS"
|
||||||
|
SERVICE_CMODES: "ntsOP"
|
||||||
|
SERVICE_UMODES: "o"
|
||||||
|
SERVICE_PREFIX: "!"
|
||||||
|
|
||||||
"OWNER": "TON_NICK_NAME",
|
OWNER: "TON_NICK_NAME"
|
||||||
"PASSWORD": "TON_PASSWORD"
|
PASSWORD: "TON_PASSWORD"
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Exemple complet de configuration
|
## Exemple complet de configuration
|
||||||
```json
|
```yaml
|
||||||
{
|
configuration:
|
||||||
"SERVEUR_IP": "YOUR.SERVER.IP",
|
SERVEUR_IP: "YOUR.SERVER.IP"
|
||||||
"SERVEUR_HOSTNAME": "YOUR.SERVER.HOST",
|
SERVEUR_HOSTNAME: "YOUR.SERVER.HOST"
|
||||||
"SERVEUR_LINK": "LINK.DE.TON.SERVER",
|
SERVEUR_LINK: "LINK.DE.TON.SERVER"
|
||||||
"SERVEUR_PORT": 6901,
|
SERVEUR_PORT: 7002
|
||||||
"SERVEUR_PASSWORD": "YOUR_LINK_PASSWORD",
|
SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD"
|
||||||
"SERVEUR_ID": "10Z",
|
SERVEUR_ID: "006"
|
||||||
"SERVEUR_SSL": true,
|
SERVEUR_SSL: true
|
||||||
|
|
||||||
"SERVICE_NAME": "defender",
|
SERVICE_NAME: "defender"
|
||||||
"SERVICE_NICKNAME": "PyDefender",
|
SERVICE_NICKNAME: "PyDefender"
|
||||||
"SERVICE_REALNAME": "Python Defender Security",
|
SERVICE_REALNAME: "Python Defender Security"
|
||||||
"SERVICE_USERNAME": "PyDefender",
|
SERVICE_USERNAME: "PyDefender"
|
||||||
"SERVICE_HOST": "HOST.DE.TON.DEFENDER",
|
SERVICE_HOST: "HOST.DE.TON.DEFENDER"
|
||||||
"SERVICE_INFO": "Network IRC Service",
|
SERVICE_INFO: "Network IRC Service"
|
||||||
"SERVICE_CHANLOG": "#services",
|
SERVICE_CHANLOG: "#services"
|
||||||
"SERVICE_SMODES": "+ioqBS",
|
SERVICE_SMODES: "+ioqBS"
|
||||||
"SERVICE_CMODES": "ntsOP",
|
SERVICE_CMODES: "ntsOP"
|
||||||
"SERVICE_UMODES": "o",
|
SERVICE_UMODES: "o"
|
||||||
"SERVICE_PREFIX": "!",
|
SERVICE_PREFIX: "!"
|
||||||
|
|
||||||
"OWNER": "TON_NICK_NAME",
|
OWNER: "TON_NICK_NAME"
|
||||||
"PASSWORD": "TON_PASSWORD",
|
PASSWORD: "TON_PASSWORD"
|
||||||
|
|
||||||
"JSONRPC_URL": "https://your.domaine.com:8600/api",
|
JSONRPC_URL: "https://your.domaine.com:8600/api"
|
||||||
"JSONRPC_PATH_TO_SOCKET_FILE": "/PATH/TO/YOUR/IRCD/data/rpc.socket",
|
JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket"
|
||||||
"JSONRPC_METHOD": "socket",
|
JSONRPC_METHOD: "unixsocket"
|
||||||
"JSONRPC_USER": "YOUR_RPC_USER",
|
JSONRPC_USER: "YOUR_RPC_USER"
|
||||||
"JSONRPC_PASSWORD": "YOUR_RPC_PASSWORD",
|
JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD"
|
||||||
|
|
||||||
"SALON_JAIL": "#jail",
|
SALON_JAIL: "#jail"
|
||||||
"SALON_JAIL_MODES": "sS",
|
SALON_JAIL_MODES: "sS"
|
||||||
"SALON_LIBERER": "#welcome",
|
SALON_LIBERER: "#welcome"
|
||||||
|
|
||||||
"CLONE_CHANNEL": "#clones",
|
CLONE_CHANNEL: "#clones"
|
||||||
"CLONE_CMODES": "+nts",
|
CLONE_CMODES: "+nts"
|
||||||
"CLONE_LOG_HOST_EXEMPT": ["HOST.TO.SKIP"],
|
CLONE_LOG_HOST_EXEMPT: ["HOST.TO.SKIP"]
|
||||||
"CLONE_CHANNEL_PASSWORD": "YOUR_CHANNEL_PASSWORD",
|
CLONE_CHANNEL_PASSWORD: "YOUR_CHANNEL_PASSWORD"
|
||||||
|
|
||||||
"API_TIMEOUT": 2,
|
API_TIMEOUT: 2
|
||||||
|
|
||||||
"PORTS_TO_SCAN": [3028, 8080, 1080, 1085, 4145, 9050],
|
PORTS_TO_SCAN: [3028 8080 1080 1085 4145 9050]
|
||||||
"WHITELISTED_IP": ["127.0.0.1"],
|
WHITELISTED_IP: ["127.0.0.1"]
|
||||||
"GLINE_DURATION": "30",
|
GLINE_DURATION: "30"
|
||||||
|
|
||||||
"DEBUG_LEVEL": 20
|
DEBUG_LEVEL: 20
|
||||||
|
DEBUG_HARD: true
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# \\!/ Attention \\!/
|
# \\!/ Attention \\!/
|
||||||
@@ -192,7 +197,7 @@ Le mot de passe de l'administrateur et le mot de passe du service doivent être
|
|||||||
Ne partagez pas vos informations de connexion au serveur IRC avec des tiers.
|
Ne partagez pas vos informations de connexion au serveur IRC avec des tiers.
|
||||||
a votre premiere connexion vous devez tapez
|
a votre premiere connexion vous devez tapez
|
||||||
```
|
```
|
||||||
/msg [NomDuService] auth [nickname] [password]
|
/msg [NomDuService] firstauth [nickname] [password]
|
||||||
-- Une fois identifié tapez la commande suivante
|
-- Une fois identifié tapez la commande suivante
|
||||||
/msg [NomDuService] editaccess [nickname] [Nouveau-Password] 5
|
/msg [NomDuService] editaccess [nickname] [Nouveau-Password] 5
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ configuration:
|
|||||||
SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD"
|
SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD"
|
||||||
SERVEUR_ID: "006"
|
SERVEUR_ID: "006"
|
||||||
SERVEUR_SSL: true
|
SERVEUR_SSL: true
|
||||||
|
SERVEUR_PROTOCOL: "unreal6" # unreal6 or inspircd
|
||||||
|
|
||||||
SERVICE_NAME: "defender"
|
SERVICE_NAME: "defender"
|
||||||
SERVICE_NICKNAME: "PyDefender"
|
SERVICE_NICKNAME: "PyDefender"
|
||||||
@@ -24,7 +25,7 @@ configuration:
|
|||||||
|
|
||||||
JSONRPC_URL: "https://your.domaine.com:8600/api"
|
JSONRPC_URL: "https://your.domaine.com:8600/api"
|
||||||
JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket"
|
JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket"
|
||||||
JSONRPC_METHOD: "socket"
|
JSONRPC_METHOD: "unixsocket"
|
||||||
JSONRPC_USER: "YOUR_RPC_USER"
|
JSONRPC_USER: "YOUR_RPC_USER"
|
||||||
JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD"
|
JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD"
|
||||||
|
|
||||||
@@ -39,8 +40,8 @@ configuration:
|
|||||||
|
|
||||||
API_TIMEOUT: 2
|
API_TIMEOUT: 2
|
||||||
|
|
||||||
PORTS_TO_SCAN: [3028 8080 1080 1085 4145 9050]
|
PORTS_TO_SCAN: [3028, 8080, 1080, 1085, 4145, 9050]
|
||||||
WHITELISTED_IP: ["127.0.0.1"]
|
WHITELISTED_IP: ["127.0.0.1", "192.168.1.1"]
|
||||||
GLINE_DURATION: "30"
|
GLINE_DURATION: "30"
|
||||||
|
|
||||||
DEBUG_LEVEL: 20
|
DEBUG_LEVEL: 20
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
__version__ = '6.3'
|
||||||
198
core/base.py
198
core/base.py
@@ -1,18 +1,15 @@
|
|||||||
import importlib
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import ast
|
import ast
|
||||||
import requests
|
import requests
|
||||||
from pathlib import Path
|
|
||||||
from types import ModuleType
|
|
||||||
from dataclasses import fields
|
from dataclasses import fields
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Callable, Iterable, Optional, TYPE_CHECKING
|
||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
from sqlalchemy import create_engine, Engine, Connection, CursorResult
|
from sqlalchemy import create_engine, Engine, Connection, CursorResult
|
||||||
from sqlalchemy.sql import text
|
from sqlalchemy.sql import text
|
||||||
@@ -30,7 +27,8 @@ class Base:
|
|||||||
self.Utils = loader.Utils
|
self.Utils = loader.Utils
|
||||||
self.logs = loader.Logs
|
self.logs = loader.Logs
|
||||||
|
|
||||||
self.check_for_new_version(True) # Verifier si une nouvelle version est disponible
|
# Check if new Defender version is available
|
||||||
|
self.check_for_new_version(True)
|
||||||
|
|
||||||
# Liste des timers en cours
|
# Liste des timers en cours
|
||||||
self.running_timers: list[threading.Timer] = self.Settings.RUNNING_TIMERS
|
self.running_timers: list[threading.Timer] = self.Settings.RUNNING_TIMERS
|
||||||
@@ -38,18 +36,26 @@ class Base:
|
|||||||
# Liste des threads en cours
|
# Liste des threads en cours
|
||||||
self.running_threads: list[threading.Thread] = self.Settings.RUNNING_THREADS
|
self.running_threads: list[threading.Thread] = self.Settings.RUNNING_THREADS
|
||||||
|
|
||||||
|
# List of all async tasks
|
||||||
|
self.running_asynctasks: list[asyncio.Task] = self.Settings.RUNNING_ASYNCTASKS
|
||||||
|
|
||||||
# Les sockets ouvert
|
# Les sockets ouvert
|
||||||
self.running_sockets: list[socket.socket] = self.Settings.RUNNING_SOCKETS
|
self.running_sockets: list[socket.socket] = self.Settings.RUNNING_SOCKETS
|
||||||
|
|
||||||
# Liste des fonctions en attentes
|
# Liste des fonctions en attentes
|
||||||
self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC
|
self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC
|
||||||
|
|
||||||
# Création du lock
|
# Init install variable
|
||||||
self.lock = self.Settings.LOCK
|
self.install: bool = False
|
||||||
|
|
||||||
self.install: bool = False # Initialisation de la variable d'installation
|
# Init database connection
|
||||||
self.engine, self.cursor = self.db_init() # Initialisation de la connexion a la base de données
|
self.engine, self.cursor = self.db_init()
|
||||||
self.__create_db() # Initialisation de la base de données
|
|
||||||
|
# Create the database
|
||||||
|
# self.__create_db()
|
||||||
|
|
||||||
|
async def init(self) -> None:
|
||||||
|
await self.__create_db()
|
||||||
|
|
||||||
def __set_current_defender_version(self) -> None:
|
def __set_current_defender_version(self) -> None:
|
||||||
"""This will put the current version of Defender
|
"""This will put the current version of Defender
|
||||||
@@ -136,7 +142,7 @@ class Base:
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.logs.error(f'General Error: {err}')
|
self.logs.error(f'General Error: {err}')
|
||||||
|
|
||||||
def create_log(self, log_message: str) -> None:
|
async def create_log(self, log_message: str) -> None:
|
||||||
"""Enregiste les logs
|
"""Enregiste les logs
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -147,11 +153,11 @@ class Base:
|
|||||||
"""
|
"""
|
||||||
sql_insert = f"INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)"
|
sql_insert = f"INSERT INTO {self.Config.TABLE_LOG} (datetime, server_msg) VALUES (:datetime, :server_msg)"
|
||||||
mes_donnees = {'datetime': str(self.Utils.get_sdatetime()),'server_msg': f'{log_message}'}
|
mes_donnees = {'datetime': str(self.Utils.get_sdatetime()),'server_msg': f'{log_message}'}
|
||||||
self.db_execute_query(sql_insert, mes_donnees)
|
await self.db_execute_query(sql_insert, mes_donnees)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def log_cmd(self, user_cmd: str, cmd: str) -> None:
|
async def log_cmd(self, user_cmd: str, cmd: str) -> None:
|
||||||
"""Enregistre les commandes envoyées par les utilisateurs
|
"""Enregistre les commandes envoyées par les utilisateurs
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -167,11 +173,11 @@ class Base:
|
|||||||
|
|
||||||
insert_cmd_query = f"INSERT INTO {self.Config.TABLE_COMMAND} (datetime, user, commande) VALUES (:datetime, :user, :commande)"
|
insert_cmd_query = f"INSERT INTO {self.Config.TABLE_COMMAND} (datetime, user, commande) VALUES (:datetime, :user, :commande)"
|
||||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'commande': cmd}
|
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': user_cmd, 'commande': cmd}
|
||||||
self.db_execute_query(insert_cmd_query, mes_donnees)
|
await self.db_execute_query(insert_cmd_query, mes_donnees)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool:
|
async def db_sync_core_config(self, module_name: str, dataclassObj: object) -> bool:
|
||||||
"""Sync module local parameters with the database
|
"""Sync module local parameters with the database
|
||||||
if new module then local param will be stored in the database
|
if new module then local param will be stored in the database
|
||||||
if old module then db param will be moved to the local dataclassObj
|
if old module then db param will be moved to the local dataclassObj
|
||||||
@@ -198,7 +204,7 @@ class Base:
|
|||||||
param_to_search = {'module_name': module_name, 'param_key': param_key}
|
param_to_search = {'module_name': module_name, 'param_key': param_key}
|
||||||
|
|
||||||
search_query = f'''SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key'''
|
search_query = f'''SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key'''
|
||||||
excecute_search_query = self.db_execute_query(search_query, param_to_search)
|
excecute_search_query = await self.db_execute_query(search_query, param_to_search)
|
||||||
result_search_query = excecute_search_query.fetchone()
|
result_search_query = excecute_search_query.fetchone()
|
||||||
|
|
||||||
if result_search_query is None:
|
if result_search_query is None:
|
||||||
@@ -210,7 +216,7 @@ class Base:
|
|||||||
insert_query = f'''INSERT INTO {core_table} (datetime, module_name, param_key, param_value)
|
insert_query = f'''INSERT INTO {core_table} (datetime, module_name, param_key, param_value)
|
||||||
VALUES (:datetime, :module_name, :param_key, :param_value)
|
VALUES (:datetime, :module_name, :param_key, :param_value)
|
||||||
'''
|
'''
|
||||||
execution = self.db_execute_query(insert_query, param_to_insert)
|
execution = await self.db_execute_query(insert_query, param_to_insert)
|
||||||
|
|
||||||
if execution.rowcount > 0:
|
if execution.rowcount > 0:
|
||||||
self.logs.debug(f'New parameter added to the database: {param_key} --> {param_value}')
|
self.logs.debug(f'New parameter added to the database: {param_key} --> {param_value}')
|
||||||
@@ -218,14 +224,14 @@ class Base:
|
|||||||
# Delete from DB unused parameter
|
# Delete from DB unused parameter
|
||||||
query_select = f"SELECT module_name, param_key, param_value FROM {core_table} WHERE module_name = :module_name"
|
query_select = f"SELECT module_name, param_key, param_value FROM {core_table} WHERE module_name = :module_name"
|
||||||
parameter = {'module_name': module_name}
|
parameter = {'module_name': module_name}
|
||||||
execute_query_select = self.db_execute_query(query_select, parameter)
|
execute_query_select = await self.db_execute_query(query_select, parameter)
|
||||||
result_query_select = execute_query_select.fetchall()
|
result_query_select = execute_query_select.fetchall()
|
||||||
|
|
||||||
for result in result_query_select:
|
for result in result_query_select:
|
||||||
db_mod_name, db_param_key, db_param_value = result
|
db_mod_name, db_param_key, db_param_value = result
|
||||||
if not hasattr(dataclassObj, db_param_key):
|
if not hasattr(dataclassObj, db_param_key):
|
||||||
mes_donnees = {'param_key': db_param_key, 'module_name': db_mod_name}
|
mes_donnees = {'param_key': db_param_key, 'module_name': db_mod_name}
|
||||||
execute_delete = self.db_execute_query(f'DELETE FROM {core_table} WHERE module_name = :module_name and param_key = :param_key', mes_donnees)
|
execute_delete = await self.db_execute_query(f'DELETE FROM {core_table} WHERE module_name = :module_name and param_key = :param_key', mes_donnees)
|
||||||
row_affected = execute_delete.rowcount
|
row_affected = execute_delete.rowcount
|
||||||
if row_affected > 0:
|
if row_affected > 0:
|
||||||
self.logs.debug(f'A parameter has been deleted from the database: {db_param_key} --> {db_param_value} | Mod: {db_mod_name}')
|
self.logs.debug(f'A parameter has been deleted from the database: {db_param_key} --> {db_param_value} | Mod: {db_mod_name}')
|
||||||
@@ -233,7 +239,7 @@ class Base:
|
|||||||
# Sync local variable with Database
|
# Sync local variable with Database
|
||||||
query = f"SELECT param_key, param_value FROM {core_table} WHERE module_name = :module_name"
|
query = f"SELECT param_key, param_value FROM {core_table} WHERE module_name = :module_name"
|
||||||
parameter = {'module_name': module_name}
|
parameter = {'module_name': module_name}
|
||||||
response = self.db_execute_query(query, parameter)
|
response = await self.db_execute_query(query, parameter)
|
||||||
result = response.fetchall()
|
result = response.fetchall()
|
||||||
|
|
||||||
for param, value in result:
|
for param, value in result:
|
||||||
@@ -250,43 +256,43 @@ class Base:
|
|||||||
self.logs.error(err)
|
self.logs.error(err)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_update_core_config(self, module_name:str, dataclassObj: object, param_key:str, param_value: str) -> bool:
|
async def db_update_core_config(self, module_name:str, dataclass_obj: object, param_key:str, param_value: str) -> bool:
|
||||||
|
|
||||||
core_table = self.Config.TABLE_CONFIG
|
core_table = self.Config.TABLE_CONFIG
|
||||||
# Check if the param exist
|
# Check if the param exist
|
||||||
if not hasattr(dataclassObj, param_key):
|
if not hasattr(dataclass_obj, param_key):
|
||||||
self.logs.error(f"Le parametre {param_key} n'existe pas dans la variable global")
|
self.logs.error(f"Le parametre {param_key} n'existe pas dans la variable global")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
mes_donnees = {'module_name': module_name, 'param_key': param_key, 'param_value': param_value}
|
mes_donnees = {'module_name': module_name, 'param_key': param_key, 'param_value': param_value}
|
||||||
search_param_query = f"SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key"
|
search_param_query = f"SELECT id FROM {core_table} WHERE module_name = :module_name AND param_key = :param_key"
|
||||||
result = self.db_execute_query(search_param_query, mes_donnees)
|
result = await self.db_execute_query(search_param_query, mes_donnees)
|
||||||
isParamExist = result.fetchone()
|
is_param_exist = result.fetchone()
|
||||||
|
|
||||||
if not isParamExist is None:
|
if not is_param_exist is None:
|
||||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(),
|
mes_donnees = {'datetime': self.Utils.get_sdatetime(),
|
||||||
'module_name': module_name,
|
'module_name': module_name,
|
||||||
'param_key': param_key,
|
'param_key': param_key,
|
||||||
'param_value': param_value
|
'param_value': param_value
|
||||||
}
|
}
|
||||||
query = f'''UPDATE {core_table} SET datetime = :datetime, param_value = :param_value WHERE module_name = :module_name AND param_key = :param_key'''
|
query = f'''UPDATE {core_table} SET datetime = :datetime, param_value = :param_value WHERE module_name = :module_name AND param_key = :param_key'''
|
||||||
update = self.db_execute_query(query, mes_donnees)
|
update = await self.db_execute_query(query, mes_donnees)
|
||||||
updated_rows = update.rowcount
|
updated_rows = update.rowcount
|
||||||
if updated_rows > 0:
|
if updated_rows > 0:
|
||||||
setattr(dataclassObj, param_key, self.int_if_possible(param_value))
|
setattr(dataclass_obj, param_key, self.int_if_possible(param_value))
|
||||||
self.logs.debug(f'Parameter updated : {param_key} - {param_value} | Module: {module_name}')
|
self.logs.debug(f'Parameter updated : {param_key} - {param_value} | Module: {module_name}')
|
||||||
else:
|
else:
|
||||||
self.logs.error(f'Parameter NOT updated : {param_key} - {param_value} | Module: {module_name}')
|
self.logs.error(f'Parameter NOT updated : {param_key} - {param_value} | Module: {module_name}')
|
||||||
else:
|
else:
|
||||||
self.logs.error(f'Parameter and Module do not exist: Param ({param_key}) - Value ({param_value}) | Module ({module_name})')
|
self.logs.error(f'Parameter and Module do not exist: Param ({param_key}) - Value ({param_value}) | Module ({module_name})')
|
||||||
|
|
||||||
self.logs.debug(dataclassObj)
|
self.logs.debug(dataclass_obj)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def db_create_first_admin(self) -> None:
|
async def db_create_first_admin(self) -> None:
|
||||||
|
|
||||||
user = self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}")
|
user = await self.db_execute_query(f"SELECT id FROM {self.Config.TABLE_ADMIN}")
|
||||||
if not user.fetchall():
|
if not user.fetchall():
|
||||||
admin = self.Config.OWNER
|
admin = self.Config.OWNER
|
||||||
password = self.Utils.hash_password(self.Config.PASSWORD)
|
password = self.Utils.hash_password(self.Config.PASSWORD)
|
||||||
@@ -299,7 +305,7 @@ class Base:
|
|||||||
'language': 'EN',
|
'language': 'EN',
|
||||||
'level': 5
|
'level': 5
|
||||||
}
|
}
|
||||||
self.db_execute_query(f"""
|
await self.db_execute_query(f"""
|
||||||
INSERT INTO {self.Config.TABLE_ADMIN}
|
INSERT INTO {self.Config.TABLE_ADMIN}
|
||||||
(createdOn, user, password, hostname, vhost, language, level)
|
(createdOn, user, password, hostname, vhost, language, level)
|
||||||
VALUES
|
VALUES
|
||||||
@@ -334,6 +340,9 @@ class Base:
|
|||||||
run_once (bool, optional): If you want to ensure that this method/function run once. Defaults to False.
|
run_once (bool, optional): If you want to ensure that this method/function run once. Defaults to False.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
# Clean unused threads first
|
||||||
|
self.garbage_collector_thread()
|
||||||
|
|
||||||
func_name = func.__name__
|
func_name = func.__name__
|
||||||
|
|
||||||
if run_once:
|
if run_once:
|
||||||
@@ -347,8 +356,49 @@ class Base:
|
|||||||
self.running_threads.append(th)
|
self.running_threads.append(th)
|
||||||
self.logs.debug(f"-- Thread ID : {str(th.ident)} | Thread name : {th.name} | Running Threads : {len(threading.enumerate())}")
|
self.logs.debug(f"-- Thread ID : {str(th.ident)} | Thread name : {th.name} | Running Threads : {len(threading.enumerate())}")
|
||||||
|
|
||||||
except AssertionError as ae:
|
except Exception as err:
|
||||||
self.logs.error(f'{ae}')
|
self.logs.error(err, exc_info=True)
|
||||||
|
|
||||||
|
def create_asynctask(self, func: Any, *, async_name: str = None, run_once: bool = False) -> asyncio.Task:
|
||||||
|
"""Create a new asynchrone and store it into running_asynctasks variable
|
||||||
|
|
||||||
|
Args:
|
||||||
|
func (Callable): The function you want to call in asynchrone way
|
||||||
|
async_name (str, optional): The task name. Defaults to None.
|
||||||
|
run_once (bool, optional): If true the task will be run once. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
asyncio.Task: The Task
|
||||||
|
"""
|
||||||
|
name = func.__name__ if async_name is None else async_name
|
||||||
|
|
||||||
|
if run_once:
|
||||||
|
for task in asyncio.all_tasks():
|
||||||
|
if task.get_name().lower() == async_name.lower():
|
||||||
|
return None
|
||||||
|
|
||||||
|
task = asyncio.create_task(func, name=name)
|
||||||
|
task.add_done_callback(self.asynctask_done)
|
||||||
|
self.running_asynctasks.append(task)
|
||||||
|
|
||||||
|
self.logs.debug(f"++ New asynchrone task created as: {task.get_name()}")
|
||||||
|
return task
|
||||||
|
|
||||||
|
def asynctask_done(self, task: asyncio.Task):
|
||||||
|
"""Log task when done
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task (asyncio.Task): The Asyncio Task callback
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if task.exception():
|
||||||
|
self.logs.error(f"[ASYNCIO] Task {task.get_name()} failed with exception: {task.exception()}")
|
||||||
|
else:
|
||||||
|
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} completed successfully.")
|
||||||
|
except asyncio.CancelledError as ce:
|
||||||
|
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with cancelled error.")
|
||||||
|
except asyncio.InvalidStateError as ie:
|
||||||
|
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with invalid state error.")
|
||||||
|
|
||||||
def is_thread_alive(self, thread_name: str) -> bool:
|
def is_thread_alive(self, thread_name: str) -> bool:
|
||||||
"""Check if the thread is still running! using the is_alive method of Threads.
|
"""Check if the thread is still running! using the is_alive method of Threads.
|
||||||
@@ -393,7 +443,7 @@ class Base:
|
|||||||
Returns:
|
Returns:
|
||||||
int: Number of threads
|
int: Number of threads
|
||||||
"""
|
"""
|
||||||
with self.lock:
|
with self.Settings.LOCK:
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
for thr in self.running_threads:
|
for thr in self.running_threads:
|
||||||
@@ -425,11 +475,11 @@ class Base:
|
|||||||
if thread.name != 'heartbeat':
|
if thread.name != 'heartbeat':
|
||||||
if not thread.is_alive():
|
if not thread.is_alive():
|
||||||
self.running_threads.remove(thread)
|
self.running_threads.remove(thread)
|
||||||
self.logs.info(f"-- Thread {str(thread.name)} {str(thread.native_id)} removed")
|
self.logs.debug(f"-- Thread {str(thread.name)} {str(thread.native_id)} has been removed!")
|
||||||
|
|
||||||
# print(threading.enumerate())
|
# print(threading.enumerate())
|
||||||
except AssertionError as ae:
|
except Exception as err:
|
||||||
self.logs.error(f'Assertion Error -> {ae}')
|
self.logs.error(err, exc_info=True)
|
||||||
|
|
||||||
def garbage_collector_sockets(self) -> None:
|
def garbage_collector_sockets(self) -> None:
|
||||||
|
|
||||||
@@ -442,16 +492,35 @@ class Base:
|
|||||||
self.running_sockets.remove(soc)
|
self.running_sockets.remove(soc)
|
||||||
self.logs.debug(f"-- Socket ==> closed {str(soc.fileno())}")
|
self.logs.debug(f"-- Socket ==> closed {str(soc.fileno())}")
|
||||||
|
|
||||||
def shutdown(self) -> None:
|
async def shutdown(self) -> None:
|
||||||
"""Methode qui va préparer l'arrêt complêt du service
|
"""Methode qui va préparer l'arrêt complêt du service
|
||||||
"""
|
"""
|
||||||
|
# Stop RpcServer if running
|
||||||
|
await self.Loader.RpcServer.stop_server()
|
||||||
|
|
||||||
|
# unload modules.
|
||||||
|
self.logs.debug(f"=======> Unloading all modules!")
|
||||||
|
for module in self.Loader.ModuleUtils.model_get_loaded_modules().copy():
|
||||||
|
await self.Loader.ModuleUtils.unload_one_module(module.module_name)
|
||||||
|
|
||||||
|
self.logs.debug(f"=======> Closing all Coroutines!")
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(asyncio.gather(*self.running_asynctasks), timeout=5)
|
||||||
|
except asyncio.exceptions.TimeoutError as te:
|
||||||
|
self.logs.debug(f"Asyncio Timeout reached! {te}")
|
||||||
|
for task in self.running_asynctasks:
|
||||||
|
task.cancel()
|
||||||
|
except asyncio.exceptions.CancelledError as cerr:
|
||||||
|
self.logs.debug(f"Asyncio CancelledError reached! {cerr}")
|
||||||
|
|
||||||
|
|
||||||
# Nettoyage des timers
|
# Nettoyage des timers
|
||||||
self.logs.debug(f"=======> Checking for Timers to stop")
|
self.logs.debug(f"=======> Checking for Timers to stop")
|
||||||
for timer in self.running_timers:
|
for timer in self.running_timers:
|
||||||
while timer.is_alive():
|
while timer.is_alive():
|
||||||
self.logs.debug(f"> waiting for {timer.name} to close")
|
self.logs.debug(f"> waiting for {timer.name} to close")
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
time.sleep(0.2)
|
await asyncio.sleep(0.2)
|
||||||
self.running_timers.remove(timer)
|
self.running_timers.remove(timer)
|
||||||
self.logs.debug(f"> Cancelling {timer.name} {timer.native_id}")
|
self.logs.debug(f"> Cancelling {timer.name} {timer.native_id}")
|
||||||
|
|
||||||
@@ -472,6 +541,8 @@ class Base:
|
|||||||
self.running_sockets.remove(soc)
|
self.running_sockets.remove(soc)
|
||||||
self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}")
|
self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}")
|
||||||
|
|
||||||
|
self.db_close()
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def db_init(self) -> tuple[Engine, Connection]:
|
def db_init(self) -> tuple[Engine, Connection]:
|
||||||
@@ -485,10 +556,10 @@ class Base:
|
|||||||
|
|
||||||
engine = create_engine(f'sqlite:///{full_path_db}.db', echo=False)
|
engine = create_engine(f'sqlite:///{full_path_db}.db', echo=False)
|
||||||
cursor = engine.connect()
|
cursor = engine.connect()
|
||||||
self.logs.info("-- database connexion has been initiated")
|
self.logs.info("-- Database connexion has been initiated")
|
||||||
return engine, cursor
|
return engine, cursor
|
||||||
|
|
||||||
def __create_db(self) -> None:
|
async def __create_db(self) -> None:
|
||||||
|
|
||||||
table_core_log = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_LOG} (
|
table_core_log = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_LOG} (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@@ -539,6 +610,7 @@ class Base:
|
|||||||
vhost TEXT,
|
vhost TEXT,
|
||||||
password TEXT,
|
password TEXT,
|
||||||
fingerprint TEXT,
|
fingerprint TEXT,
|
||||||
|
language TEXT,
|
||||||
level INTEGER
|
level INTEGER
|
||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
@@ -557,27 +629,27 @@ class Base:
|
|||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.db_execute_query(table_core_log)
|
await self.db_execute_query(table_core_log)
|
||||||
self.db_execute_query(table_core_log_command)
|
await self.db_execute_query(table_core_log_command)
|
||||||
self.db_execute_query(table_core_module)
|
await self.db_execute_query(table_core_module)
|
||||||
self.db_execute_query(table_core_admin)
|
await self.db_execute_query(table_core_admin)
|
||||||
self.db_execute_query(table_core_client)
|
await self.db_execute_query(table_core_client)
|
||||||
self.db_execute_query(table_core_channel)
|
await self.db_execute_query(table_core_channel)
|
||||||
self.db_execute_query(table_core_config)
|
await self.db_execute_query(table_core_config)
|
||||||
|
|
||||||
# Patch database
|
# Patch database
|
||||||
self.db_patch(self.Config.TABLE_ADMIN, "language", "TEXT")
|
await self.db_patch(self.Config.TABLE_ADMIN, "language", "TEXT")
|
||||||
|
|
||||||
if self.install:
|
if self.install:
|
||||||
self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True)
|
await self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True)
|
||||||
self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
|
await self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
|
||||||
self.install = False
|
self.install = False
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def db_execute_query(self, query:str, params:dict = {}) -> CursorResult:
|
async def db_execute_query(self, query:str, params:dict = {}) -> CursorResult:
|
||||||
|
|
||||||
with self.lock:
|
async with self.Loader.Settings.AILOCK:
|
||||||
insert_query = text(query)
|
insert_query = text(query)
|
||||||
if not params:
|
if not params:
|
||||||
response = self.cursor.execute(insert_query)
|
response = self.cursor.execute(insert_query)
|
||||||
@@ -588,8 +660,8 @@ class Base:
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def db_is_column_exist(self, table_name: str, column_name: str) -> bool:
|
async def db_is_column_exist(self, table_name: str, column_name: str) -> bool:
|
||||||
q = self.db_execute_query(f"PRAGMA table_info({table_name})")
|
q = await self.db_execute_query(f"PRAGMA table_info({table_name})")
|
||||||
existing_columns = [col[1] for col in q.fetchall()]
|
existing_columns = [col[1] for col in q.fetchall()]
|
||||||
|
|
||||||
if column_name in existing_columns:
|
if column_name in existing_columns:
|
||||||
@@ -597,12 +669,12 @@ class Base:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool:
|
async def db_patch(self, table_name: str, column_name: str, column_type: str) -> bool:
|
||||||
if not self.db_is_column_exist(table_name, column_name):
|
if not await self.db_is_column_exist(table_name, column_name):
|
||||||
patch = f"ALTER TABLE {self.Config.TABLE_ADMIN} ADD COLUMN {column_name} {column_type}"
|
patch = f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}"
|
||||||
update_row = f"UPDATE {self.Config.TABLE_ADMIN} SET language = 'EN' WHERE language is null"
|
update_row = f"UPDATE {table_name} SET language = 'EN' WHERE language is null"
|
||||||
self.db_execute_query(patch)
|
await self.db_execute_query(patch)
|
||||||
self.db_execute_query(update_row)
|
await self.db_execute_query(update_row)
|
||||||
self.logs.debug(f"The patch has been applied")
|
self.logs.debug(f"The patch has been applied")
|
||||||
self.logs.debug(f"Table name: {table_name}, Column name: {column_name}, Column type: {column_type}")
|
self.logs.debug(f"Table name: {table_name}, Column name: {column_name}, Column type: {column_type}")
|
||||||
return True
|
return True
|
||||||
@@ -610,9 +682,9 @@ class Base:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def db_close(self) -> None:
|
def db_close(self) -> None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.cursor.close()
|
self.cursor.close()
|
||||||
|
self.logs.debug("Database engine closed!")
|
||||||
except AttributeError as ae:
|
except AttributeError as ae:
|
||||||
self.logs.error(f"Attribute Error : {ae}")
|
self.logs.error(f"Attribute Error : {ae}")
|
||||||
|
|
||||||
|
|||||||
84
core/classes/interfaces/imodule.py
Normal file
84
core/classes/interfaces/imodule.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import TYPE_CHECKING, Optional, Union
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class IModule(ABC):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
@dataclass
|
||||||
|
class ModConfModel:
|
||||||
|
"""The Model containing the module parameters
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, uplink: 'Loader') -> None:
|
||||||
|
|
||||||
|
# import the context
|
||||||
|
self.ctx = uplink
|
||||||
|
|
||||||
|
# Module name (Mandatory)
|
||||||
|
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
||||||
|
|
||||||
|
# Log the module
|
||||||
|
self.ctx.Logs.debug(f'Loading Module {self.module_name} ...')
|
||||||
|
|
||||||
|
async def sync_db(self) -> None:
|
||||||
|
# Sync the configuration with core configuration (Mandatory)
|
||||||
|
await self.ctx.Base.db_sync_core_config(self.module_name, self.mod_config)
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def update_configuration(self, param_key: str, param_value: Union[str, int]) -> None:
|
||||||
|
"""Update the local and core configuration
|
||||||
|
|
||||||
|
Args:
|
||||||
|
param_key (str): The parameter key
|
||||||
|
param_value (str): The parameter value
|
||||||
|
"""
|
||||||
|
await self.ctx.Base.db_update_core_config(self.module_name, self.mod_config, param_key, param_value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def mod_config(self) -> ModConfModel:
|
||||||
|
"""
|
||||||
|
The module configuration model
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def create_tables(self) -> None:
|
||||||
|
"""Method that will create the database if it does not exist.
|
||||||
|
A single Session for this class will be created, which will be used within this class/module.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None: No return is expected
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def load(self) -> None:
|
||||||
|
"""This method is executed when the module is loaded or reloaded.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def unload(self) -> None:
|
||||||
|
"""This method is executed when the module is unloaded or reloaded.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def cmd(self, data: list) -> None:
|
||||||
|
"""When recieving server messages.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (list): The recieved message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def hcmds(self, user: str, channel: Optional[str], cmd: list[str], fullcmd: Optional[list[str]] = None) -> None:
|
||||||
|
"""These are the commands recieved from a client
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (str): The client
|
||||||
|
channel (str|None): The channel if available
|
||||||
|
cmd (list): The user command sent
|
||||||
|
fullcmd (list, optional): The full server message. Defaults to [].
|
||||||
|
"""
|
||||||
@@ -3,13 +3,27 @@ from typing import Optional, TYPE_CHECKING
|
|||||||
from core.classes.protocols.command_handler import CommandHandler
|
from core.classes.protocols.command_handler import CommandHandler
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.definition import MClient, MSasl
|
from core.definition import MClient, MSasl, MUser, MChannel
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
class IProtocol(ABC):
|
class IProtocol(ABC):
|
||||||
|
|
||||||
Handler: Optional[CommandHandler] = None
|
Handler: Optional[CommandHandler] = None
|
||||||
|
|
||||||
|
def __init__(self, context: 'Loader'):
|
||||||
|
self.name: Optional[str] = None
|
||||||
|
self.protocol_version: int = -1
|
||||||
|
self.known_protocol: set[str] = set()
|
||||||
|
self._ctx = context
|
||||||
|
self.Handler = CommandHandler(context)
|
||||||
|
self.init_protocol()
|
||||||
|
self._ctx.Logs.info(f"[PROTOCOL] Protocol [{self.__class__.__name__}] loaded!")
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def init_protocol(self):
|
||||||
|
"""Init protocol
|
||||||
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]:
|
def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]:
|
||||||
"""Get the position of known commands
|
"""Get the position of known commands
|
||||||
@@ -28,7 +42,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send2socket(self, message: str, print_log: bool = True) -> None:
|
async def send2socket(self, message: str, print_log: bool = True) -> None:
|
||||||
"""Envoit les commandes à envoyer au serveur.
|
"""Envoit les commandes à envoyer au serveur.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -37,7 +51,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None):
|
async def send_priv_msg(self, nick_from: str, msg: str, channel: str = None, nick_to: str = None):
|
||||||
"""Sending PRIVMSG to a channel or to a nickname by batches
|
"""Sending PRIVMSG to a channel or to a nickname by batches
|
||||||
could be either channel or nickname not both together
|
could be either channel or nickname not both together
|
||||||
Args:
|
Args:
|
||||||
@@ -48,7 +62,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None:
|
async def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None:
|
||||||
"""Sending NOTICE by batches
|
"""Sending NOTICE by batches
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -58,13 +72,13 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_link(self) -> None:
|
async def send_link(self) -> None:
|
||||||
"""Créer le link et envoyer les informations nécessaires pour la
|
"""Créer le link et envoyer les informations nécessaires pour la
|
||||||
connexion au serveur.
|
connexion au serveur.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
async def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||||
"""Send a gline command to the server
|
"""Send a gline command to the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -77,7 +91,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_set_nick(self, newnickname: str) -> None:
|
async def send_set_nick(self, newnickname: str) -> None:
|
||||||
"""Change nickname of the server
|
"""Change nickname of the server
|
||||||
\n This method will also update the User object
|
\n This method will also update the User object
|
||||||
Args:
|
Args:
|
||||||
@@ -85,7 +99,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None:
|
async def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None:
|
||||||
"""Set a mode to channel or to a nickname or for a user in a channel
|
"""Set a mode to channel or to a nickname or for a user in a channel
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -96,7 +110,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
async def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -106,7 +120,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_ungline(self, nickname:str, hostname: str) -> None:
|
async def send_ungline(self, nickname:str, hostname: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -115,7 +129,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
async def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -128,7 +142,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_unkline(self, nickname:str, hostname: str) -> None:
|
async def send_unkline(self, nickname:str, hostname: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -137,7 +151,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_sjoin(self, channel: str) -> None:
|
async def send_sjoin(self, channel: str) -> None:
|
||||||
"""Server will join a channel with pre defined umodes
|
"""Server will join a channel with pre defined umodes
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -145,7 +159,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None:
|
async def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -154,7 +168,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None:
|
async def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -163,7 +177,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None:
|
async def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -173,7 +187,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None:
|
async def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -183,7 +197,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_svsmode(self, nickname: str, user_mode: str) -> None:
|
async def send_svsmode(self, nickname: str, user_mode: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -192,7 +206,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_svs2mode(self, nickname: str, user_mode: str) -> None:
|
async def send_svs2mode(self, nickname: str, user_mode: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -201,7 +215,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_svslogin(self, client_uid: str, user_account: str) -> None:
|
async def send_svslogin(self, client_uid: str, user_account: str) -> None:
|
||||||
"""Log a client into his account.
|
"""Log a client into his account.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -210,7 +224,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_svslogout(self, client_obj: 'MClient') -> None:
|
async def send_svslogout(self, client_obj: 'MClient') -> None:
|
||||||
"""Logout a client from his account
|
"""Logout a client from his account
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -218,7 +232,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None:
|
async def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None:
|
||||||
"""Send quit message
|
"""Send quit message
|
||||||
- Delete uid from User object
|
- Delete uid from User object
|
||||||
- Delete uid from Reputation object
|
- Delete uid from Reputation object
|
||||||
@@ -230,7 +244,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None:
|
async def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None:
|
||||||
"""Send UID to the server
|
"""Send UID to the server
|
||||||
- Insert User to User Object
|
- Insert User to User Object
|
||||||
Args:
|
Args:
|
||||||
@@ -246,7 +260,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None:
|
async def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None:
|
||||||
"""Joining a channel
|
"""Joining a channel
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -257,7 +271,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None:
|
async def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None:
|
||||||
"""Part from a channel
|
"""Part from a channel
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -267,7 +281,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_mode_chan(self, channel_name: str, channel_mode: str) -> None:
|
async def send_mode_chan(self, channel_name: str, channel_mode: str) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -276,7 +290,7 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send_raw(self, raw_command: str) -> None:
|
async def send_raw(self, raw_command: str) -> None:
|
||||||
"""Send raw message to the server
|
"""Send raw message to the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -288,56 +302,51 @@ class IProtocol(ABC):
|
|||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def parse_uid(self, serverMsg: list[str]) -> dict[str, str]:
|
def parse_uid(self, server_msg: list[str]) -> Optional['MUser']:
|
||||||
"""Parse UID and return dictionary.
|
"""Parse UID and return dictionary.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): The UID IRCD message
|
server_msg (list[str]): The UID IRCD message
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, str]: The response as dictionary.
|
Optional[MUser]: The MUser object or None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def parse_quit(self, serverMsg: list[str]) -> dict[str, str]:
|
def parse_quit(self, server_msg: list[str]) -> tuple[Optional['MUser'], str]:
|
||||||
"""Parse quit and return dictionary.
|
"""Parse quit and return dictionary.
|
||||||
>>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit']
|
>>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit']
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): The server message to parse
|
server_msg (list[str]): The server message to parse
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, str]: The response as dictionary.
|
tuple[MUser, str]: The User Who Quit Object and the reason.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def parse_nick(self, serverMsg: list[str]) -> dict[str, str]:
|
def parse_nick(self, server_msg: list[str]) -> tuple[Optional['MUser'], str, str]:
|
||||||
"""Parse nick changes and return dictionary.
|
"""Parse nick changes and return dictionary.
|
||||||
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
|
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): The server message to parse
|
server_msg (list[str]): The server message to parse
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, str]: The response as dictionary.
|
tuple(MUser, newnickname(str), timestamp(str)): Tuple of the response.
|
||||||
|
|
||||||
|
>>> MUser, newnickname, timestamp
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def parse_privmsg(self, serverMsg: list[str]) -> dict[str, str]:
|
def parse_privmsg(self, server_msg: list[str]) -> tuple[Optional['MUser'], Optional['MUser'], Optional['MChannel'], str]:
|
||||||
"""Parse PRIVMSG message.
|
"""Parse PRIVMSG message.
|
||||||
>>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message']
|
>>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message']
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): The server message to parse
|
server_msg (list[str]): The server message to parse
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict[str, str]: The response as dictionary.
|
tuple[MUser(Sender), MUser(Reciever), MChannel, str]: Sender user model, reciever user model, Channel model, messgae.
|
||||||
```python
|
|
||||||
response = {
|
|
||||||
"uid": '97KAAAAAE',
|
|
||||||
"channel": '#welcome',
|
|
||||||
"message": 'This is my public message'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
@@ -345,181 +354,181 @@ class IProtocol(ABC):
|
|||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_svs2mode(self, serverMsg: list[str]) -> None:
|
async def on_svs2mode(self, server_msg: list[str]) -> None:
|
||||||
"""Handle svs2mode coming from a server
|
"""Handle svs2mode coming from a server
|
||||||
>>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r']
|
>>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r']
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_mode(self, serverMsg: list[str]) -> None:
|
async def on_mode(self, server_msg: list[str]) -> None:
|
||||||
"""Handle mode coming from a server
|
"""Handle mode coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_umode2(self, serverMsg: list[str]) -> None:
|
async def on_umode2(self, server_msg: list[str]) -> None:
|
||||||
"""Handle umode2 coming from a server
|
"""Handle umode2 coming from a server
|
||||||
>>> [':adator_', 'UMODE2', '-i']
|
>>> [':adator_', 'UMODE2', '-i']
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_quit(self, serverMsg: list[str]) -> None:
|
async def on_quit(self, server_msg: list[str]) -> None:
|
||||||
"""Handle quit coming from a server
|
"""Handle quit coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_squit(self, serverMsg: list[str]) -> None:
|
async def on_squit(self, server_msg: list[str]) -> None:
|
||||||
"""Handle squit coming from a server
|
"""Handle squit coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_protoctl(self, serverMsg: list[str]) -> None:
|
async def on_protoctl(self, server_msg: list[str]) -> None:
|
||||||
"""Handle protoctl coming from a server
|
"""Handle protoctl coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_nick(self, serverMsg: list[str]) -> None:
|
async def on_nick(self, server_msg: list[str]) -> None:
|
||||||
"""Handle nick coming from a server
|
"""Handle nick coming from a server
|
||||||
new nickname
|
new nickname
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_sjoin(self, serverMsg: list[str]) -> None:
|
async def on_sjoin(self, server_msg: list[str]) -> None:
|
||||||
"""Handle sjoin coming from a server
|
"""Handle sjoin coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_part(self, serverMsg: list[str]) -> None:
|
async def on_part(self, server_msg: list[str]) -> None:
|
||||||
"""Handle part coming from a server
|
"""Handle part coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_eos(self, serverMsg: list[str]) -> None:
|
async def on_eos(self, server_msg: list[str]) -> None:
|
||||||
"""Handle EOS coming from a server
|
"""Handle EOS coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_reputation(self, serverMsg: list[str]) -> None:
|
async def on_reputation(self, server_msg: list[str]) -> None:
|
||||||
"""Handle REPUTATION coming from a server
|
"""Handle REPUTATION coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_uid(self, serverMsg: list[str]) -> None:
|
async def on_uid(self, server_msg: list[str]) -> None:
|
||||||
"""Handle uid message coming from the server
|
"""Handle uid message coming from the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_privmsg(self, serverMsg: list[str]) -> None:
|
async def on_privmsg(self, server_msg: list[str]) -> None:
|
||||||
"""Handle PRIVMSG message coming from the server
|
"""Handle PRIVMSG message coming from the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_server_ping(self, serverMsg: list[str]) -> None:
|
async def on_server_ping(self, server_msg: list[str]) -> None:
|
||||||
"""Send a PONG message to the server
|
"""Send a PONG message to the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): List of str coming from the server
|
server_msg (list[str]): List of str coming from the server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_server(self, serverMsg: list[str]) -> None:
|
async def on_server(self, server_msg: list[str]) -> None:
|
||||||
"""_summary_
|
"""_summary_
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): _description_
|
server_msg (list[str]): _description_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_version(self, serverMsg: list[str]) -> None:
|
async def on_version(self, server_msg: list[str]) -> None:
|
||||||
"""Sending Server Version to the server
|
"""Sending Server Version to the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): List of str coming from the server
|
server_msg (list[str]): List of str coming from the server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_time(self, serverMsg: list[str]) -> None:
|
async def on_time(self, server_msg: list[str]) -> None:
|
||||||
"""Sending TIME answer to a requestor
|
"""Sending TIME answer to a requestor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): List of str coming from the server
|
server_msg (list[str]): List of str coming from the server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_ping(self, serverMsg: list[str]) -> None:
|
async def on_ping(self, server_msg: list[str]) -> None:
|
||||||
"""Sending a PING answer to requestor
|
"""Sending a PING answer to requestor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): List of str coming from the server
|
server_msg (list[str]): List of str coming from the server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_version_msg(self, serverMsg: list[str]) -> None:
|
async def on_version_msg(self, server_msg: list[str]) -> None:
|
||||||
"""Handle version coming from the server
|
"""Handle version coming from the server
|
||||||
\n ex. /version Defender
|
\n ex. /version Defender
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original message from the server
|
server_msg (list[str]): Original message from the server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_smod(self, serverMsg: list[str]) -> None:
|
async def on_smod(self, server_msg: list[str]) -> None:
|
||||||
"""Handle SMOD message coming from the server
|
"""Handle SMOD message coming from the server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_sasl(self, serverMsg: list[str]) -> Optional['MSasl']:
|
async def on_sasl(self, server_msg: list[str]) -> Optional['MSasl']:
|
||||||
"""Handle SASL coming from a server
|
"""Handle SASL coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
server_msg (list[str]): Original server message
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool:
|
async def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool:
|
||||||
"""Finalize sasl authentication
|
"""Finalize sasl authentication
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -530,18 +539,27 @@ class IProtocol(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_md(self, serverMsg: list[str]) -> None:
|
async def on_md(self, server_msg: list[str]) -> None:
|
||||||
"""Handle MD responses
|
"""Handle MD responses
|
||||||
[':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...']
|
[':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...']
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): The server reply
|
server_msg (list[str]): The server reply
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_kick(self, serverMsg: list[str]) -> None:
|
async def on_kick(self, server_msg: list[str]) -> None:
|
||||||
"""When a user is kicked out from a channel
|
"""When a user is kicked out from a channel
|
||||||
|
|
||||||
Eg. ['@unrealircd.org...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User']
|
Eg. ['@unrealircd.org...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User']
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): The server message
|
server_msg (list[str]): The server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def on_sethost(self, server_msg: list[str]) -> None:
|
||||||
|
"""On SETHOST command
|
||||||
|
>>> [':001DN7305', 'SETHOST', ':netadmin.example.org']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
server_msg (list[str]): _description_
|
||||||
"""
|
"""
|
||||||
34
core/classes/interfaces/irpc_endpoint.py
Normal file
34
core/classes/interfaces/irpc_endpoint.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import starlette.status as http_status_code
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class IRPC:
|
||||||
|
|
||||||
|
def __init__(self, loader: 'Loader'):
|
||||||
|
self.ctx = loader
|
||||||
|
self.http_status_code = http_status_code
|
||||||
|
self.response_model = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 123
|
||||||
|
}
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.response_model = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 123
|
||||||
|
}
|
||||||
|
|
||||||
|
def create_error_response(self, error_code: JSONRPCErrorCode, details: dict = None) -> dict[str, str]:
|
||||||
|
"""Create a JSON-RPC error!"""
|
||||||
|
response = {
|
||||||
|
"code": error_code.value,
|
||||||
|
"message": error_code.description(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if details:
|
||||||
|
response["data"] = details
|
||||||
|
|
||||||
|
return response
|
||||||
@@ -93,17 +93,10 @@ class Admin:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if the admin has been deleted
|
bool: True if the admin has been deleted
|
||||||
"""
|
"""
|
||||||
|
admin_obj = self.get_admin(uidornickname)
|
||||||
for record in self.UID_ADMIN_DB:
|
if admin_obj:
|
||||||
if record.uid == uidornickname:
|
self.UID_ADMIN_DB.remove(admin_obj)
|
||||||
# If the admin exist, delete and do not go further
|
self.Logs.debug(f'UID ({admin_obj.uid}) has been deleted')
|
||||||
self.UID_ADMIN_DB.remove(record)
|
|
||||||
self.Logs.debug(f'UID ({record.uid}) has been deleted')
|
|
||||||
return True
|
|
||||||
if record.nickname.lower() == uidornickname.lower():
|
|
||||||
# If the admin exist, delete and do not go further
|
|
||||||
self.UID_ADMIN_DB.remove(record)
|
|
||||||
self.Logs.debug(f'nickname ({record.nickname}) has been deleted')
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.Logs.debug(f'The UID {uidornickname} was not deleted')
|
self.Logs.debug(f'The UID {uidornickname} was not deleted')
|
||||||
@@ -180,7 +173,7 @@ class Admin:
|
|||||||
|
|
||||||
return admin.language
|
return admin.language
|
||||||
|
|
||||||
def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool:
|
async def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool:
|
||||||
"""Check the fingerprint
|
"""Check the fingerprint
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -190,9 +183,12 @@ class Admin:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if found
|
bool: True if found
|
||||||
"""
|
"""
|
||||||
|
if fp is None:
|
||||||
|
return False
|
||||||
|
|
||||||
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp"
|
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp"
|
||||||
data = {'fp': fp}
|
data = {'fp': fp}
|
||||||
exe = self.Base.db_execute_query(query, data)
|
exe = await self.Base.db_execute_query(query, data)
|
||||||
result = exe.fetchone()
|
result = exe.fetchone()
|
||||||
if result:
|
if result:
|
||||||
account = result[0]
|
account = result[0]
|
||||||
@@ -203,11 +199,12 @@ class Admin:
|
|||||||
admin_obj = self.Definition.MAdmin(**user_obj.to_dict(), account=account, level=level, language=language)
|
admin_obj = self.Definition.MAdmin(**user_obj.to_dict(), account=account, level=level, language=language)
|
||||||
if self.insert(admin_obj):
|
if self.insert(admin_obj):
|
||||||
self.Setting.current_admin = admin_obj
|
self.Setting.current_admin = admin_obj
|
||||||
|
self.Logs.debug(f"[Fingerprint login] {user_obj.nickname} ({admin_obj.account}) has been logged in successfully!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_is_admin_exist(self, admin_nickname: str) -> bool:
|
async def db_is_admin_exist(self, admin_nickname: str) -> bool:
|
||||||
"""Verify if the admin exist in the database!
|
"""Verify if the admin exist in the database!
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -219,7 +216,7 @@ class Admin:
|
|||||||
|
|
||||||
mes_donnees = {'admin': admin_nickname}
|
mes_donnees = {'admin': admin_nickname}
|
||||||
query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user = :admin"
|
query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user = :admin"
|
||||||
r = self.Base.db_execute_query(query_search_user, mes_donnees)
|
r = await self.Base.db_execute_query(query_search_user, mes_donnees)
|
||||||
exist_user = r.fetchone()
|
exist_user = r.fetchone()
|
||||||
if exist_user:
|
if exist_user:
|
||||||
return True
|
return True
|
||||||
@@ -17,9 +17,7 @@ class Channel:
|
|||||||
Args:
|
Args:
|
||||||
loader (Loader): The Loader Instance
|
loader (Loader): The Loader Instance
|
||||||
"""
|
"""
|
||||||
self.Logs = loader.Logs
|
self._ctx = loader
|
||||||
self.Base = loader.Base
|
|
||||||
self.Utils = loader.Utils
|
|
||||||
|
|
||||||
def insert(self, new_channel: 'MChannel') -> bool:
|
def insert(self, new_channel: 'MChannel') -> bool:
|
||||||
"""This method will insert a new channel and if the channel exist it will update the user list (uids)
|
"""This method will insert a new channel and if the channel exist it will update the user list (uids)
|
||||||
@@ -34,14 +32,14 @@ class Channel:
|
|||||||
exist = False
|
exist = False
|
||||||
|
|
||||||
if not self.is_valid_channel(new_channel.name):
|
if not self.is_valid_channel(new_channel.name):
|
||||||
self.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #")
|
self._ctx.Logs.error(f"The channel {new_channel.name} is not valid, channel must start with #")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for record in self.UID_CHANNEL_DB:
|
for record in self.UID_CHANNEL_DB:
|
||||||
if record.name.lower() == new_channel.name.lower():
|
if record.name.lower() == new_channel.name.lower():
|
||||||
# If the channel exist, update the user list and do not go further
|
# If the channel exist, update the user list and do not go further
|
||||||
exist = True
|
exist = True
|
||||||
# self.Logs.debug(f'{record.name} already exist')
|
# self._ctx.Logs.debug(f'{record.name} already exist')
|
||||||
|
|
||||||
for user in new_channel.uids:
|
for user in new_channel.uids:
|
||||||
record.uids.append(user)
|
record.uids.append(user)
|
||||||
@@ -49,7 +47,7 @@ class Channel:
|
|||||||
# Supprimer les doublons
|
# Supprimer les doublons
|
||||||
del_duplicates = list(set(record.uids))
|
del_duplicates = list(set(record.uids))
|
||||||
record.uids = del_duplicates
|
record.uids = del_duplicates
|
||||||
# self.Logs.debug(f'Updating a new UID to the channel {record}')
|
# self._ctx.Logs.debug(f'Updating a new UID to the channel {record}')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if not exist:
|
if not exist:
|
||||||
@@ -57,10 +55,10 @@ class Channel:
|
|||||||
new_channel.name = new_channel.name.lower()
|
new_channel.name = new_channel.name.lower()
|
||||||
self.UID_CHANNEL_DB.append(new_channel)
|
self.UID_CHANNEL_DB.append(new_channel)
|
||||||
result = True
|
result = True
|
||||||
# self.Logs.debug(f'New Channel Created: ({new_channel})')
|
# self._ctx.Logs.debug(f'New Channel Created: ({new_channel})')
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
self.Logs.critical(f'The Channel Object was not inserted {new_channel}')
|
self._ctx.Logs.critical(f'The Channel Object was not inserted {new_channel}')
|
||||||
|
|
||||||
self.clean_channel()
|
self.clean_channel()
|
||||||
|
|
||||||
@@ -103,7 +101,7 @@ class Channel:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
for userid in chan_obj.uids:
|
for userid in chan_obj.uids:
|
||||||
if self.Utils.clean_uid(userid) == self.Utils.clean_uid(uid):
|
if self._ctx.Utils.clean_uid(userid) == self._ctx.Utils.clean_uid(uid):
|
||||||
chan_obj.uids.remove(userid)
|
chan_obj.uids.remove(userid)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
@@ -111,7 +109,7 @@ class Channel:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
self.Logs.error(f'{ve}')
|
self._ctx.Logs.error(f'{ve}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def delete_user_from_all_channel(self, uid:str) -> bool:
|
def delete_user_from_all_channel(self, uid:str) -> bool:
|
||||||
@@ -128,7 +126,7 @@ class Channel:
|
|||||||
|
|
||||||
for record in self.UID_CHANNEL_DB:
|
for record in self.UID_CHANNEL_DB:
|
||||||
for user_id in record.uids:
|
for user_id in record.uids:
|
||||||
if self.Utils.clean_uid(user_id) == self.Utils.clean_uid(uid):
|
if self._ctx.Utils.clean_uid(user_id) == self._ctx.Utils.clean_uid(uid):
|
||||||
record.uids.remove(user_id)
|
record.uids.remove(user_id)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
@@ -136,7 +134,7 @@ class Channel:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
self.Logs.error(f'{ve}')
|
self._ctx.Logs.error(f'{ve}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add_user_to_a_channel(self, channel_name: str, uid: str) -> bool:
|
def add_user_to_a_channel(self, channel_name: str, uid: str) -> bool:
|
||||||
@@ -154,7 +152,7 @@ class Channel:
|
|||||||
|
|
||||||
if chan_obj is None:
|
if chan_obj is None:
|
||||||
# Create a new channel if the channel don't exist
|
# Create a new channel if the channel don't exist
|
||||||
self.Logs.debug(f"New channel will be created ({channel_name} - {uid})")
|
self._ctx.Logs.debug(f"New channel will be created ({channel_name} - {uid})")
|
||||||
return self.insert(MChannel(channel_name, uids=[uid]))
|
return self.insert(MChannel(channel_name, uids=[uid]))
|
||||||
|
|
||||||
chan_obj.uids.append(uid)
|
chan_obj.uids.append(uid)
|
||||||
@@ -163,7 +161,7 @@ class Channel:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self._ctx.Logs.error(f'{err}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_user_present_in_channel(self, channel_name: str, uid: str) -> bool:
|
def is_user_present_in_channel(self, channel_name: str, uid: str) -> bool:
|
||||||
@@ -180,9 +178,9 @@ class Channel:
|
|||||||
if chan is None:
|
if chan is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
clean_uid = self.Utils.clean_uid(uid=uid)
|
clean_uid = self._ctx.Utils.clean_uid(uid=uid)
|
||||||
for chan_uid in chan.uids:
|
for chan_uid in chan.uids:
|
||||||
if self.Utils.clean_uid(chan_uid) == clean_uid:
|
if self._ctx.Utils.clean_uid(chan_uid) == clean_uid:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -197,7 +195,7 @@ class Channel:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self._ctx.Logs.error(f'{err}')
|
||||||
|
|
||||||
def get_channel(self, channel_name: str) -> Optional['MChannel']:
|
def get_channel(self, channel_name: str) -> Optional['MChannel']:
|
||||||
"""Get the channel object
|
"""Get the channel object
|
||||||
@@ -237,13 +235,13 @@ class Channel:
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
except TypeError as te:
|
except TypeError as te:
|
||||||
self.Logs.error(f'TypeError: [{channel_to_check}] - {te}')
|
self._ctx.Logs.error(f'TypeError: [{channel_to_check}] - {te}')
|
||||||
return False
|
return False
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'Error Not defined: {err}')
|
self._ctx.Logs.error(f'Error Not defined: {err}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool:
|
async def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool:
|
||||||
"""You can add a channel or delete a channel.
|
"""You can add a channel or delete a channel.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -256,39 +254,49 @@ class Channel:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
channel_name = channel_name.lower() if self.is_valid_channel(channel_name) else None
|
channel_name = channel_name.lower() if self.is_valid_channel(channel_name) else None
|
||||||
core_table = self.Base.Config.TABLE_CHANNEL
|
core_table = self._ctx.Base.Config.TABLE_CHANNEL
|
||||||
|
|
||||||
if not channel_name:
|
if not channel_name:
|
||||||
self.Logs.warning(f'The channel [{channel_name}] is not correct')
|
self._ctx.Logs.warning(f'The channel [{channel_name}] is not correct')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
match action:
|
match action:
|
||||||
|
|
||||||
case 'add':
|
case 'add':
|
||||||
mes_donnees = {'module_name': module_name, 'channel_name': channel_name}
|
mes_donnees = {'module_name': module_name, 'channel_name': channel_name}
|
||||||
response = self.Base.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees)
|
response = await self._ctx.Base.db_execute_query(f"SELECT id FROM {core_table} WHERE module_name = :module_name AND channel_name = :channel_name", mes_donnees)
|
||||||
is_channel_exist = response.fetchone()
|
is_channel_exist = response.fetchone()
|
||||||
|
|
||||||
if is_channel_exist is None:
|
if is_channel_exist is None:
|
||||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name}
|
mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name}
|
||||||
insert = self.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees)
|
insert = await self._ctx.Base.db_execute_query(f"INSERT INTO {core_table} (datetime, channel_name, module_name) VALUES (:datetime, :channel_name, :module_name)", mes_donnees)
|
||||||
if insert.rowcount:
|
if insert.rowcount:
|
||||||
self.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}')
|
self._ctx.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}')
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
case 'del':
|
case 'del':
|
||||||
mes_donnes = {'channel_name': channel_name, 'module_name': module_name}
|
mes_donnes = {'channel_name': channel_name, 'module_name': module_name}
|
||||||
response = self.Base.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes)
|
response = await self._ctx.Base.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes)
|
||||||
|
|
||||||
if response.rowcount > 0:
|
if response.rowcount > 0:
|
||||||
self.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}')
|
self._ctx.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}')
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(err)
|
self._ctx.Logs.error(err)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def db_join_saved_channels(self) -> None:
|
||||||
|
"""## Joining saved channels"""
|
||||||
|
exec_query = await self._ctx.Base.db_execute_query(f'SELECT distinct channel_name FROM {self._ctx.Config.TABLE_CHANNEL}')
|
||||||
|
result_query = exec_query.fetchall()
|
||||||
|
|
||||||
|
if result_query:
|
||||||
|
for chan_name in result_query:
|
||||||
|
chan = chan_name[0]
|
||||||
|
await self._ctx.Irc.Protocol.send_sjoin(channel=chan)
|
||||||
@@ -201,7 +201,7 @@ class Client:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def db_is_account_exist(self, account: str) -> bool:
|
async def db_is_account_exist(self, account: str) -> bool:
|
||||||
"""Check if the account exist in the database
|
"""Check if the account exist in the database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -213,7 +213,7 @@ class Client:
|
|||||||
|
|
||||||
table_client = self.Base.Config.TABLE_CLIENT
|
table_client = self.Base.Config.TABLE_CLIENT
|
||||||
account_to_check = {'account': account.lower()}
|
account_to_check = {'account': account.lower()}
|
||||||
account_to_check_query = self.Base.db_execute_query(f"""
|
account_to_check_query = await self.Base.db_execute_query(f"""
|
||||||
SELECT id FROM {table_client} WHERE LOWER(account) = :account
|
SELECT id FROM {table_client} WHERE LOWER(account) = :account
|
||||||
""", account_to_check)
|
""", account_to_check)
|
||||||
|
|
||||||
@@ -5,79 +5,84 @@ from typing import TYPE_CHECKING
|
|||||||
import socket
|
import socket
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.loader import Loader
|
||||||
|
|
||||||
# Modules impacted by rehashing!
|
# Modules impacted by rehashing!
|
||||||
REHASH_MODULES = [
|
REHASH_MODULES = [
|
||||||
'core.definition',
|
'core.definition',
|
||||||
'core.utils',
|
'core.utils',
|
||||||
'core.classes.config',
|
'core.classes.modules.config',
|
||||||
'core.base',
|
'core.base',
|
||||||
'core.classes.commands',
|
'core.classes.modules.commands',
|
||||||
'core.classes.protocols.interface',
|
'core.classes.modules.rpc.rpc_channel',
|
||||||
|
'core.classes.modules.rpc.rpc_command',
|
||||||
|
'core.classes.modules.rpc.rpc_user',
|
||||||
|
'core.classes.modules.rpc.rpc',
|
||||||
|
'core.classes.interfaces.iprotocol',
|
||||||
|
'core.classes.interfaces.imodule',
|
||||||
|
'core.classes.protocols.command_handler',
|
||||||
'core.classes.protocols.factory',
|
'core.classes.protocols.factory',
|
||||||
'core.classes.protocols.unreal6',
|
'core.classes.protocols.unreal6',
|
||||||
'core.classes.protocols.inspircd'
|
'core.classes.protocols.inspircd'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -> None:
|
async def restart_service(uplink: 'Loader', reason: str = "Restarting with no reason!") -> None:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
uplink (Irc): The Irc instance
|
uplink (Irc): The Irc instance
|
||||||
reason (str): The reason of the restart.
|
reason (str): The reason of the restart.
|
||||||
"""
|
"""
|
||||||
# reload modules.
|
# unload modules.
|
||||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||||
uplink.ModuleUtils.unload_one_module(uplink, module.module_name)
|
await uplink.ModuleUtils.unload_one_module(module.module_name)
|
||||||
|
|
||||||
|
uplink.Base.garbage_collector_thread()
|
||||||
|
|
||||||
|
uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!')
|
||||||
|
await uplink.Irc.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason)
|
||||||
|
uplink.Logs.debug('Restarting Defender ...')
|
||||||
|
|
||||||
|
for mod in REHASH_MODULES:
|
||||||
|
importlib.reload(sys.modules[mod])
|
||||||
|
|
||||||
|
# Reload configuration
|
||||||
|
uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model
|
||||||
|
uplink.Base = uplink.BaseModule.Base(uplink)
|
||||||
|
|
||||||
uplink.ModuleUtils.model_clear() # Clear loaded modules.
|
uplink.ModuleUtils.model_clear() # Clear loaded modules.
|
||||||
uplink.User.UID_DB.clear() # Clear User Object
|
uplink.User.UID_DB.clear() # Clear User Object
|
||||||
uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object
|
uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object
|
||||||
uplink.Client.CLIENT_DB.clear() # Clear Client object
|
uplink.Client.CLIENT_DB.clear() # Clear Client object
|
||||||
uplink.Base.garbage_collector_thread()
|
uplink.Irc.Protocol.Handler.DB_IRCDCOMMS.clear()
|
||||||
|
|
||||||
uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!')
|
# Reload Service modules
|
||||||
uplink.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason)
|
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||||
uplink.Logs.debug('Restarting Defender ...')
|
await uplink.ModuleUtils.reload_one_module(module.module_name, uplink.Settings.current_admin)
|
||||||
uplink.IrcSocket.shutdown(socket.SHUT_RDWR)
|
|
||||||
uplink.IrcSocket.close()
|
|
||||||
|
|
||||||
while uplink.IrcSocket.fileno() != -1:
|
uplink.Irc.signal = True
|
||||||
time.sleep(0.5)
|
await uplink.Irc.run()
|
||||||
uplink.Logs.warning('-- Waiting for socket to close ...')
|
|
||||||
|
|
||||||
# Reload configuration
|
|
||||||
uplink.Loader.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model
|
|
||||||
uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
|
|
||||||
|
|
||||||
for mod in REHASH_MODULES:
|
|
||||||
importlib.reload(sys.modules[mod])
|
|
||||||
|
|
||||||
uplink.Protocol = uplink.Loader.PFactory.get()
|
|
||||||
uplink.Protocol.register_command()
|
|
||||||
|
|
||||||
uplink.init_service_user()
|
|
||||||
uplink.Utils.create_socket(uplink)
|
|
||||||
uplink.Protocol.send_link()
|
|
||||||
uplink.Config.DEFENDER_RESTART = 0
|
uplink.Config.DEFENDER_RESTART = 0
|
||||||
|
|
||||||
def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
async def rehash_service(uplink: 'Loader', nickname: str) -> None:
|
||||||
need_a_restart = ["SERVEUR_ID"]
|
need_a_restart = ["SERVEUR_ID"]
|
||||||
uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS)
|
uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS)
|
||||||
|
|
||||||
|
await uplink.RpcServer.stop_server()
|
||||||
|
|
||||||
restart_flag = False
|
restart_flag = False
|
||||||
config_model_bakcup = uplink.Config
|
config_model_bakcup = uplink.Config
|
||||||
mods = REHASH_MODULES
|
mods = REHASH_MODULES
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
importlib.reload(sys.modules[mod])
|
importlib.reload(sys.modules[mod])
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
nick_from=uplink.Config.SERVICE_NICKNAME,
|
||||||
msg=f'[REHASH] Module [{mod}] reloaded',
|
msg=f'[REHASH] Module [{mod}] reloaded',
|
||||||
channel=uplink.Config.SERVICE_CHANLOG
|
channel=uplink.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
uplink.Utils = sys.modules['core.utils']
|
uplink.Utils = sys.modules['core.utils']
|
||||||
uplink.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).configuration_model
|
uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model
|
||||||
uplink.Config.HSID = config_model_bakcup.HSID
|
uplink.Config.HSID = config_model_bakcup.HSID
|
||||||
uplink.Config.DEFENDER_INIT = config_model_bakcup.DEFENDER_INIT
|
uplink.Config.DEFENDER_INIT = config_model_bakcup.DEFENDER_INIT
|
||||||
uplink.Config.DEFENDER_RESTART = config_model_bakcup.DEFENDER_RESTART
|
uplink.Config.DEFENDER_RESTART = config_model_bakcup.DEFENDER_RESTART
|
||||||
@@ -90,7 +95,7 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
|||||||
|
|
||||||
for key, value in conf_bkp_dict.items():
|
for key, value in conf_bkp_dict.items():
|
||||||
if config_dict[key] != value and key != 'COLORS':
|
if config_dict[key] != value and key != 'COLORS':
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
nick_from=uplink.Config.SERVICE_NICKNAME,
|
||||||
msg=f'[{key}]: {value} ==> {config_dict[key]}',
|
msg=f'[{key}]: {value} ==> {config_dict[key]}',
|
||||||
channel=uplink.Config.SERVICE_CHANLOG
|
channel=uplink.Config.SERVICE_CHANLOG
|
||||||
@@ -99,25 +104,28 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
|||||||
restart_flag = True
|
restart_flag = True
|
||||||
|
|
||||||
if config_model_bakcup.SERVICE_NICKNAME != uplink.Config.SERVICE_NICKNAME:
|
if config_model_bakcup.SERVICE_NICKNAME != uplink.Config.SERVICE_NICKNAME:
|
||||||
uplink.Protocol.send_set_nick(uplink.Config.SERVICE_NICKNAME)
|
await uplink.Irc.Protocol.send_set_nick(uplink.Config.SERVICE_NICKNAME)
|
||||||
|
|
||||||
if restart_flag:
|
if restart_flag:
|
||||||
uplink.Config.SERVEUR_ID = config_model_bakcup.SERVEUR_ID
|
uplink.Config.SERVEUR_ID = config_model_bakcup.SERVEUR_ID
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
nick_from=uplink.Config.SERVICE_NICKNAME,
|
||||||
channel=uplink.Config.SERVICE_CHANLOG,
|
channel=uplink.Config.SERVICE_CHANLOG,
|
||||||
msg='You need to restart defender !')
|
msg='You need to restart defender !')
|
||||||
|
|
||||||
# Reload Main Commands Module
|
# Reload Main Commands Module
|
||||||
uplink.Commands = uplink.Loader.CommandModule.Command(uplink.Loader)
|
uplink.Commands = uplink.CommandModule.Command(uplink)
|
||||||
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
|
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
|
||||||
|
|
||||||
uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
|
uplink.Base = uplink.BaseModule.Base(uplink)
|
||||||
uplink.Protocol = uplink.Loader.PFactory.get()
|
uplink.Irc.Protocol = uplink.PFactory.get()
|
||||||
uplink.Protocol.register_command()
|
uplink.Irc.Protocol.register_command()
|
||||||
|
|
||||||
|
uplink.RpcServer = uplink.RpcServerModule.JSonRpcServer(uplink)
|
||||||
|
uplink.Base.create_asynctask(uplink.RpcServer.start_server())
|
||||||
|
|
||||||
# Reload Service modules
|
# Reload Service modules
|
||||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||||
uplink.ModuleUtils.reload_one_module(uplink, module.module_name, nickname)
|
await uplink.ModuleUtils.reload_one_module(module.module_name, nickname)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
1
core/classes/modules/rpc/__init__.py
Normal file
1
core/classes/modules/rpc/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
__version__ = '1.0.0'
|
||||||
139
core/classes/modules/rpc/rpc.py
Normal file
139
core/classes/modules/rpc/rpc.py
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import uvicorn
|
||||||
|
import core.classes.modules.rpc.rpc_errors as rpcerr
|
||||||
|
import starlette.status as http_status_code
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.routing import Route
|
||||||
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
from core.classes.modules.rpc.rpc_user import RPCUser
|
||||||
|
from core.classes.modules.rpc.rpc_channel import RPCChannel
|
||||||
|
from core.classes.modules.rpc.rpc_command import RPCCommand
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class JSonRpcServer:
|
||||||
|
|
||||||
|
def __init__(self, context: 'Loader', *, hostname: str = 'localhost', port: int = 5000):
|
||||||
|
self._ctx = context
|
||||||
|
self.live: bool = False
|
||||||
|
self.host = hostname
|
||||||
|
self.port = port
|
||||||
|
self.routes: list[Route] = []
|
||||||
|
self.server: Optional[uvicorn.Server] = None
|
||||||
|
|
||||||
|
self.methods: dict = {
|
||||||
|
'user.list': RPCUser(context).user_list,
|
||||||
|
'user.get': RPCUser(context).user_get,
|
||||||
|
'channel.list': RPCChannel(context).channel_list,
|
||||||
|
'command.list': RPCCommand(context).command_list,
|
||||||
|
'command.get.by.name': RPCCommand(context).command_get_by_name,
|
||||||
|
'command.get.by.module': RPCCommand(context).command_get_by_module
|
||||||
|
}
|
||||||
|
|
||||||
|
async def start_server(self):
|
||||||
|
|
||||||
|
if not self.live:
|
||||||
|
self.routes = [Route('/api', self.request_handler, methods=['POST'])]
|
||||||
|
self.app_jsonrpc = Starlette(debug=False, routes=self.routes)
|
||||||
|
config = uvicorn.Config(self.app_jsonrpc, host=self.host, port=self.port, log_level=self._ctx.Config.DEBUG_LEVEL)
|
||||||
|
self.server = uvicorn.Server(config)
|
||||||
|
self.live = True
|
||||||
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
|
self._ctx.Config.SERVICE_NICKNAME,
|
||||||
|
"[DEFENDER JSONRPC SERVER] RPC Server started!",
|
||||||
|
self._ctx.Config.SERVICE_CHANLOG
|
||||||
|
)
|
||||||
|
await self.server.serve()
|
||||||
|
self._ctx.Logs.debug("Server is going to shutdown!")
|
||||||
|
else:
|
||||||
|
self._ctx.Logs.debug("Server already running")
|
||||||
|
|
||||||
|
async def stop_server(self):
|
||||||
|
|
||||||
|
if self.server:
|
||||||
|
self.server.should_exit = True
|
||||||
|
await self.server.shutdown()
|
||||||
|
self.live = False
|
||||||
|
self._ctx.Logs.debug("JSON-RPC Server off!")
|
||||||
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
|
self._ctx.Config.SERVICE_NICKNAME,
|
||||||
|
"[DEFENDER JSONRPC SERVER] RPC Server Stopped!",
|
||||||
|
self._ctx.Config.SERVICE_CHANLOG
|
||||||
|
)
|
||||||
|
|
||||||
|
async def request_handler(self, request: Request) -> JSONResponse:
|
||||||
|
|
||||||
|
request_data: dict = await request.json()
|
||||||
|
method = request_data.get("method", None)
|
||||||
|
params: dict[str, Any] = request_data.get("params", {})
|
||||||
|
|
||||||
|
auth: JSONResponse = self.authenticate(request.headers, request_data)
|
||||||
|
if not json.loads(auth.body).get('result', False):
|
||||||
|
return auth
|
||||||
|
|
||||||
|
response_data = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request_data.get('id', 123)
|
||||||
|
}
|
||||||
|
|
||||||
|
response_data['method'] = method
|
||||||
|
rip = request.client.host
|
||||||
|
rport = request.client.port
|
||||||
|
http_code = http_status_code.HTTP_200_OK
|
||||||
|
|
||||||
|
if method in self.methods:
|
||||||
|
r: JSONResponse = self.methods[method](**params)
|
||||||
|
resp = json.loads(r.body)
|
||||||
|
resp['id'] = request_data.get('id', 123)
|
||||||
|
return JSONResponse(resp, r.status_code)
|
||||||
|
|
||||||
|
response_data['error'] = rpcerr.create_error_response(rpcerr.JSONRPCErrorCode.METHOD_NOT_FOUND)
|
||||||
|
self._ctx.Logs.debug(f'[RPC ERROR] {method} recieved from {rip}:{rport}')
|
||||||
|
http_code = http_status_code.HTTP_404_NOT_FOUND
|
||||||
|
return JSONResponse(response_data, http_code)
|
||||||
|
|
||||||
|
def authenticate(self, headers: dict, body: dict) -> JSONResponse:
|
||||||
|
ok_auth = {
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': body.get('id', 123),
|
||||||
|
'result': True
|
||||||
|
}
|
||||||
|
|
||||||
|
logs = self._ctx.Logs
|
||||||
|
auth: str = headers.get('Authorization', '')
|
||||||
|
if not auth:
|
||||||
|
return self.send_auth_error(body)
|
||||||
|
|
||||||
|
# Authorization header format: Basic base64(username:password)
|
||||||
|
auth_type, auth_string = auth.split(' ', 1)
|
||||||
|
if auth_type.lower() != 'basic':
|
||||||
|
return self.send_auth_error(body)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Decode the base64-encoded username:password
|
||||||
|
decoded_credentials = base64.b64decode(auth_string).decode('utf-8')
|
||||||
|
username, password = decoded_credentials.split(":", 1)
|
||||||
|
|
||||||
|
# Check the username and password.
|
||||||
|
for rpcuser in self._ctx.Config.RPC_USERS:
|
||||||
|
if rpcuser.get('USERNAME', None) == username and rpcuser.get('PASSWORD', None) == password:
|
||||||
|
return JSONResponse(ok_auth)
|
||||||
|
|
||||||
|
return self.send_auth_error(body)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logs.error(e)
|
||||||
|
return self.send_auth_error(body)
|
||||||
|
|
||||||
|
def send_auth_error(self, request_data: dict) -> JSONResponse:
|
||||||
|
|
||||||
|
response_data = {
|
||||||
|
'jsonrpc': '2.0',
|
||||||
|
'id': request_data.get('id', 123),
|
||||||
|
'error': rpcerr.create_error_response(rpcerr.JSONRPCErrorCode.AUTHENTICATION_ERROR)
|
||||||
|
}
|
||||||
|
return JSONResponse(response_data, http_status_code.HTTP_403_FORBIDDEN)
|
||||||
17
core/classes/modules/rpc/rpc_channel.py
Normal file
17
core/classes/modules/rpc/rpc_channel.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
from core.classes.interfaces.irpc_endpoint import IRPC
|
||||||
|
from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class RPCChannel(IRPC):
|
||||||
|
def __init__(self, loader: 'Loader'):
|
||||||
|
super().__init__(loader)
|
||||||
|
|
||||||
|
def channel_list(self, **kwargs) -> JSONResponse:
|
||||||
|
self.reset()
|
||||||
|
self.response_model['result'] = [chan.to_dict() for chan in self.ctx.Channel.UID_CHANNEL_DB]
|
||||||
|
return JSONResponse(self.response_model)
|
||||||
44
core/classes/modules/rpc/rpc_command.py
Normal file
44
core/classes/modules/rpc/rpc_command.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
from core.classes.interfaces.irpc_endpoint import IRPC
|
||||||
|
from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class RPCCommand(IRPC):
|
||||||
|
def __init__(self, loader: 'Loader'):
|
||||||
|
super().__init__(loader)
|
||||||
|
|
||||||
|
def command_list(self, **kwargs) -> JSONResponse:
|
||||||
|
self.reset()
|
||||||
|
self.response_model['result'] = [command.to_dict() for command in self.ctx.Commands.DB_COMMANDS]
|
||||||
|
return JSONResponse(self.response_model)
|
||||||
|
|
||||||
|
def command_get_by_module(self, **kwargs) -> JSONResponse:
|
||||||
|
self.reset()
|
||||||
|
module_name: str = kwargs.get('module_name', '')
|
||||||
|
|
||||||
|
if not module_name:
|
||||||
|
self.response_model['error'] = self.create_error_response(JSONRPCErrorCode.INVALID_PARAMS, {'module_name': 'The param to use is module_name'})
|
||||||
|
return JSONResponse(self.response_model, self.http_status_code.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
self.response_model['result'] = [command.to_dict() for command in self.ctx.Commands.DB_COMMANDS if command.module_name.lower() == module_name.lower()]
|
||||||
|
return JSONResponse(self.response_model)
|
||||||
|
|
||||||
|
def command_get_by_name(self, **kwargs) -> JSONResponse:
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
command_name: str = kwargs.get('command_name', '')
|
||||||
|
if not command_name:
|
||||||
|
self.response_model['error'] = self.create_error_response(JSONRPCErrorCode.INVALID_PARAMS, {'command_name': f'The param to use is command_name'})
|
||||||
|
return JSONResponse(self.response_model, self.http_status_code.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
command_to_return: list[dict] = []
|
||||||
|
for command in self.ctx.Commands.DB_COMMANDS:
|
||||||
|
if command.command_name.lower() == command_name.lower():
|
||||||
|
command_to_return.append(command.to_dict())
|
||||||
|
|
||||||
|
self.response_model['result'] = command_to_return
|
||||||
|
|
||||||
|
return JSONResponse(self.response_model)
|
||||||
43
core/classes/modules/rpc/rpc_errors.py
Normal file
43
core/classes/modules/rpc/rpc_errors.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
class JSONRPCErrorCode(Enum):
|
||||||
|
PARSE_ERROR = -32700 # Syntax error in the request (malformed JSON)
|
||||||
|
INVALID_REQUEST = -32600 # Invalid Request (incorrect structure or missing fields)
|
||||||
|
METHOD_NOT_FOUND = -32601 # Method not found (the requested method does not exist)
|
||||||
|
INVALID_PARAMS = -32602 # Invalid Params (the parameters provided are incorrect)
|
||||||
|
INTERNAL_ERROR = -32603 # Internal Error (an internal server error occurred)
|
||||||
|
|
||||||
|
# Custom application-specific errors (beyond standard JSON-RPC codes)
|
||||||
|
CUSTOM_ERROR = 1001 # Custom application-defined error (e.g., user not found)
|
||||||
|
AUTHENTICATION_ERROR = 1002 # Authentication failure (e.g., invalid credentials)
|
||||||
|
PERMISSION_ERROR = 1003 # Permission error (e.g., user does not have access to this method)
|
||||||
|
RESOURCE_NOT_FOUND = 1004 # Resource not found (e.g., the requested resource does not exist)
|
||||||
|
DUPLICATE_REQUEST = 1005 # Duplicate request (e.g., a similar request has already been processed)
|
||||||
|
|
||||||
|
def description(self):
|
||||||
|
"""Returns a description associated with each error code"""
|
||||||
|
descriptions = {
|
||||||
|
JSONRPCErrorCode.PARSE_ERROR: "The JSON request is malformed.",
|
||||||
|
JSONRPCErrorCode.INVALID_REQUEST: "The request is invalid (missing or incorrect fields).",
|
||||||
|
JSONRPCErrorCode.METHOD_NOT_FOUND: "The requested method could not be found.",
|
||||||
|
JSONRPCErrorCode.INVALID_PARAMS: "The parameters provided are invalid.",
|
||||||
|
JSONRPCErrorCode.INTERNAL_ERROR: "An internal error occurred on the server.",
|
||||||
|
JSONRPCErrorCode.CUSTOM_ERROR: "A custom error defined by the application.",
|
||||||
|
JSONRPCErrorCode.AUTHENTICATION_ERROR: "User authentication failed.",
|
||||||
|
JSONRPCErrorCode.PERMISSION_ERROR: "User does not have permission to access this method.",
|
||||||
|
JSONRPCErrorCode.RESOURCE_NOT_FOUND: "The requested resource could not be found.",
|
||||||
|
JSONRPCErrorCode.DUPLICATE_REQUEST: "The request is a duplicate or is already being processed.",
|
||||||
|
}
|
||||||
|
return descriptions.get(self, "Unknown error")
|
||||||
|
|
||||||
|
def create_error_response(error_code: JSONRPCErrorCode, details: dict = None) -> dict[str, str]:
|
||||||
|
"""Create a JSON-RPC error!"""
|
||||||
|
response = {
|
||||||
|
"code": error_code.value,
|
||||||
|
"message": error_code.description(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if details:
|
||||||
|
response["data"] = details
|
||||||
|
|
||||||
|
return response
|
||||||
45
core/classes/modules/rpc/rpc_user.py
Normal file
45
core/classes/modules/rpc/rpc_user.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
from core.classes.interfaces.irpc_endpoint import IRPC
|
||||||
|
from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
from core.definition import MUser
|
||||||
|
|
||||||
|
class RPCUser(IRPC):
|
||||||
|
def __init__(self, loader: 'Loader'):
|
||||||
|
super().__init__(loader)
|
||||||
|
|
||||||
|
def user_list(self, **kwargs) -> JSONResponse:
|
||||||
|
self.reset()
|
||||||
|
users = self.ctx.User.UID_DB.copy()
|
||||||
|
copy_users: list['MUser'] = []
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
copy_user = user.copy()
|
||||||
|
copy_user.connexion_datetime = copy_user.connexion_datetime.strftime('%d-%m-%Y')
|
||||||
|
copy_users.append(copy_user)
|
||||||
|
|
||||||
|
self.response_model['result'] = [user.to_dict() for user in copy_users]
|
||||||
|
|
||||||
|
return JSONResponse(self.response_model)
|
||||||
|
|
||||||
|
def user_get(self, **kwargs) -> JSONResponse:
|
||||||
|
self.reset()
|
||||||
|
uidornickname = kwargs.get('uid_or_nickname', '')
|
||||||
|
|
||||||
|
if not uidornickname:
|
||||||
|
self.response_model['error'] = self.create_error_response(JSONRPCErrorCode.INVALID_PARAMS, {'uid_or_nickname': 'The param to use is uid_or_nickname'})
|
||||||
|
return JSONResponse(self.response_model, self.http_status_code.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
user = self.ctx.User.get_user(uidornickname)
|
||||||
|
if user:
|
||||||
|
user_copy = user.copy()
|
||||||
|
user_copy.connexion_datetime = user_copy.connexion_datetime.strftime('%d-%m-%Y')
|
||||||
|
self.response_model['result'] = user_copy.to_dict()
|
||||||
|
return JSONResponse(self.response_model)
|
||||||
|
|
||||||
|
self.response_model['result'] = 'User not found!'
|
||||||
|
return JSONResponse(self.response_model, self.http_status_code.HTTP_204_NO_CONTENT)
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
"""This class should never be reloaded.
|
"""This class should never be reloaded.
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
from logging import Logger
|
from logging import Logger
|
||||||
from threading import Timer, Thread, RLock
|
from threading import Timer, Thread, RLock
|
||||||
|
from asyncio.locks import Lock
|
||||||
from socket import socket
|
from socket import socket
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
from core.definition import MSModule, MAdmin
|
from core.definition import MSModule, MAdmin
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.classes.user import User
|
from core.classes.modules.user import User
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
"""This Class will never be reloaded.
|
"""This Class will never be reloaded.
|
||||||
@@ -17,9 +19,11 @@ class Settings:
|
|||||||
|
|
||||||
RUNNING_TIMERS: list[Timer] = []
|
RUNNING_TIMERS: list[Timer] = []
|
||||||
RUNNING_THREADS: list[Thread] = []
|
RUNNING_THREADS: list[Thread] = []
|
||||||
|
RUNNING_ASYNCTASKS: list[asyncio.Task] = []
|
||||||
RUNNING_SOCKETS: list[socket] = []
|
RUNNING_SOCKETS: list[socket] = []
|
||||||
PERIODIC_FUNC: dict[str, Any] = {}
|
PERIODIC_FUNC: dict[str, Any] = {}
|
||||||
LOCK: RLock = RLock()
|
LOCK: RLock = RLock()
|
||||||
|
AILOCK: Lock = Lock()
|
||||||
|
|
||||||
CONSOLE: bool = False
|
CONSOLE: bool = False
|
||||||
|
|
||||||
@@ -1,33 +1,32 @@
|
|||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
from .unreal6 import Unrealircd6
|
from .unreal6 import Unrealircd6
|
||||||
from .inspircd import Inspircd
|
from .inspircd import Inspircd
|
||||||
from .interface import IProtocol
|
from ..interfaces.iprotocol import IProtocol
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.loader import Loader
|
||||||
|
|
||||||
class ProtocolFactorty:
|
class ProtocolFactorty:
|
||||||
|
|
||||||
def __init__(self, uplink: 'Irc'):
|
def __init__(self, context: 'Loader'):
|
||||||
"""ProtocolFactory init.
|
"""ProtocolFactory init.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
uplink (Irc): The Irc object
|
context (Loader): The Context object
|
||||||
"""
|
"""
|
||||||
self.__Config = uplink.Config
|
self.__ctx = context
|
||||||
self.__uplink = uplink
|
|
||||||
|
|
||||||
def get(self) -> Optional[IProtocol]:
|
def get(self) -> Optional[IProtocol]:
|
||||||
|
|
||||||
protocol = self.__Config.SERVEUR_PROTOCOL
|
protocol = self.__ctx.Config.SERVEUR_PROTOCOL
|
||||||
|
|
||||||
match protocol:
|
match protocol:
|
||||||
case 'unreal6':
|
case 'unreal6':
|
||||||
self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
|
self.__ctx.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
|
||||||
return Unrealircd6(self.__uplink)
|
return Unrealircd6(self.__ctx)
|
||||||
case 'inspircd':
|
case 'inspircd':
|
||||||
self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
|
self.__ctx.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
|
||||||
return Inspircd(self.__uplink)
|
return Inspircd(self.__ctx)
|
||||||
case _:
|
case _:
|
||||||
self.__uplink.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)")
|
self.__ctx.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)")
|
||||||
raise Exception("Unknown protocol!")
|
raise Exception("Unknown protocol!")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from json import dumps
|
from json import dumps
|
||||||
from dataclasses import dataclass, field, asdict, fields
|
from dataclasses import dataclass, field, asdict, fields, replace
|
||||||
from typing import Literal, Any, Optional
|
from typing import Literal, Any, Optional
|
||||||
from os import sep
|
from os import sep
|
||||||
|
from core.classes.interfaces.imodule import IModule
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MainModel:
|
class MainModel:
|
||||||
@@ -15,6 +16,10 @@ class MainModel:
|
|||||||
"""Return the object of a dataclass a json str."""
|
"""Return the object of a dataclass a json str."""
|
||||||
return dumps(self.to_dict())
|
return dumps(self.to_dict())
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
"""Return the object of a dataclass a json str."""
|
||||||
|
return replace(self)
|
||||||
|
|
||||||
def get_attributes(self) -> list[str]:
|
def get_attributes(self) -> list[str]:
|
||||||
"""Return a list of attributes name"""
|
"""Return a list of attributes name"""
|
||||||
return [f.name for f in fields(self)]
|
return [f.name for f in fields(self)]
|
||||||
@@ -205,6 +210,9 @@ class MConfig(MainModel):
|
|||||||
PASSWORD: str = "password"
|
PASSWORD: str = "password"
|
||||||
"""The password of the admin of the service"""
|
"""The password of the admin of the service"""
|
||||||
|
|
||||||
|
RPC_USERS: list[dict] = field(default_factory=list)
|
||||||
|
"""The Defender rpc users"""
|
||||||
|
|
||||||
JSONRPC_URL: str = None
|
JSONRPC_URL: str = None
|
||||||
"""The RPC url, if local https://127.0.0.1:PORT/api should be fine"""
|
"""The RPC url, if local https://127.0.0.1:PORT/api should be fine"""
|
||||||
|
|
||||||
@@ -347,7 +355,15 @@ class MCommand(MainModel):
|
|||||||
class MModule(MainModel):
|
class MModule(MainModel):
|
||||||
module_name: str = None
|
module_name: str = None
|
||||||
class_name: str = None
|
class_name: str = None
|
||||||
class_instance: Optional[Any] = None
|
class_instance: Optional[IModule] = None
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DefenderModuleHeader(MainModel):
|
||||||
|
name: str = ''
|
||||||
|
version: str = ''
|
||||||
|
description: str = ''
|
||||||
|
author: str = ''
|
||||||
|
core_version: str = ''
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MSModule:
|
class MSModule:
|
||||||
|
|||||||
150
core/install.py
Normal file
150
core/install.py
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from subprocess import check_call, CalledProcessError, check_output
|
||||||
|
from pathlib import Path
|
||||||
|
from platform import python_version_tuple
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Python Installation Code")
|
||||||
|
parser.add_argument('--check-version', action='store_true', help='Check if the python version is ok!')
|
||||||
|
parser.add_argument('--install', action='store_true', help='Run the installation')
|
||||||
|
parser.add_argument('--git-update', action='store_true', help='Update from git (main repository)')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
PYTHON_REQUIRED_VERSION = (3, 10, 0)
|
||||||
|
PYTHON_SYSTEM_VERSION = tuple(map(int, python_version_tuple()))
|
||||||
|
ROOT_PATH = os.getcwd()
|
||||||
|
PYENV = Path(ROOT_PATH).joinpath('.pyenv/bin/python') if os.name != 'nt' else Path(ROOT_PATH).joinpath('.pyenv/Scripts/python.exe')
|
||||||
|
PIPENV = Path(f'{ROOT_PATH}/.pyenv/bin/pip') if os.name != 'nt' else Path(f'{ROOT_PATH}/.pyenv/Scripts/pip.exe')
|
||||||
|
USER_HOME_DIRECTORY = Path.home()
|
||||||
|
SYSTEMD_PATH = Path(USER_HOME_DIRECTORY).joinpath('.config', 'systemd', 'user')
|
||||||
|
PY_EXEC = 'defender.py'
|
||||||
|
SERVICE_FILE_NAME = 'defender.service'
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Package:
|
||||||
|
name: str = None
|
||||||
|
version: str = None
|
||||||
|
|
||||||
|
def __load_required_package_versions() -> list[Package]:
|
||||||
|
"""This will create Package model with package names and required version
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
DB_PACKAGES: list[Package] = []
|
||||||
|
version_filename = Path(ROOT_PATH).joinpath('version.json') # f'.{os.sep}version.json'
|
||||||
|
with open(version_filename, 'r') as version_data:
|
||||||
|
package_info:dict[str, str] = json.load(version_data)
|
||||||
|
|
||||||
|
for name, version in package_info.items():
|
||||||
|
if name == 'version':
|
||||||
|
continue
|
||||||
|
DB_PACKAGES.append(
|
||||||
|
Package(name=name, version=version)
|
||||||
|
)
|
||||||
|
|
||||||
|
return DB_PACKAGES
|
||||||
|
|
||||||
|
except FileNotFoundError as fe:
|
||||||
|
print(f"File not found: {fe}")
|
||||||
|
except Exception as err:
|
||||||
|
print(f"General Error: {err}")
|
||||||
|
|
||||||
|
def update_packages() -> None:
|
||||||
|
try:
|
||||||
|
newVersion = False
|
||||||
|
db_packages = __load_required_package_versions()
|
||||||
|
print(ROOT_PATH)
|
||||||
|
if sys.prefix not in PYENV.__str__():
|
||||||
|
print(f"You are probably running a new installation or you are not using your virtual env {PYENV}")
|
||||||
|
return newVersion
|
||||||
|
|
||||||
|
print(f"> Checking for dependencies versions ==> WAIT")
|
||||||
|
for package in db_packages:
|
||||||
|
newVersion = False
|
||||||
|
_required_version = package.version
|
||||||
|
_installed_version: str = None
|
||||||
|
output = check_output([PIPENV, 'show', package.name])
|
||||||
|
for line in output.decode().splitlines():
|
||||||
|
if line.startswith('Version:'):
|
||||||
|
_installed_version = line.split(':')[1].strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
required_version = tuple(map(int, _required_version.split('.')))
|
||||||
|
installed_version = tuple(map(int, _installed_version.split('.')))
|
||||||
|
|
||||||
|
if required_version > installed_version:
|
||||||
|
print(f'> New version of {package.name} is available {installed_version} ==> {required_version}')
|
||||||
|
newVersion = True
|
||||||
|
|
||||||
|
if newVersion:
|
||||||
|
check_call([PIPENV, 'install', '--upgrade', package.name])
|
||||||
|
|
||||||
|
print(f"> Dependencies versions ==> OK")
|
||||||
|
return newVersion
|
||||||
|
|
||||||
|
except CalledProcessError:
|
||||||
|
print(f"[!] Package {package.name} not installed [!]")
|
||||||
|
except Exception as err:
|
||||||
|
print(f"UpdatePackage Error: {err}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def run_git_update() -> None:
|
||||||
|
check_call(['git', 'pull', 'origin', 'main'])
|
||||||
|
|
||||||
|
def check_python_requirement():
|
||||||
|
if PYTHON_SYSTEM_VERSION < PYTHON_REQUIRED_VERSION:
|
||||||
|
raise RuntimeError(f"Your Python Version is not meeting the requirement, System Version: {PYTHON_SYSTEM_VERSION} < Required Version {PYTHON_REQUIRED_VERSION}")
|
||||||
|
|
||||||
|
def create_service_file():
|
||||||
|
|
||||||
|
pyenv = PYENV
|
||||||
|
systemd_path = SYSTEMD_PATH
|
||||||
|
py_exec = PY_EXEC
|
||||||
|
service_file_name = SERVICE_FILE_NAME
|
||||||
|
|
||||||
|
if not Path(systemd_path).exists():
|
||||||
|
print("[!] Folder not available")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
contain = f'''[Unit]
|
||||||
|
Description=Defender IRC Service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart={pyenv} {py_exec}
|
||||||
|
WorkingDirectory={ROOT_PATH}
|
||||||
|
SyslogIdentifier=Defender
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
'''
|
||||||
|
with open(Path(systemd_path).joinpath(service_file_name), "w") as file:
|
||||||
|
file.write(contain)
|
||||||
|
print('Service file generated with current configuration')
|
||||||
|
print('Running IRC Service ...')
|
||||||
|
|
||||||
|
print(f"#"*24)
|
||||||
|
print("Installation complete ...")
|
||||||
|
print("If the configuration is correct, then you must see your service connected to your irc server")
|
||||||
|
print(f"If any issue, you can see the log file for debug {ROOT_PATH}{os.sep}logs{os.sep}defender.log")
|
||||||
|
print(f"#"*24)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if args.check_version:
|
||||||
|
check_python_requirement()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.install:
|
||||||
|
create_service_file()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if args.git_update:
|
||||||
|
run_git_update()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
import os
|
|
||||||
import json
|
|
||||||
from sys import exit, prefix
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from subprocess import check_call, run, CalledProcessError, PIPE, check_output
|
|
||||||
from platform import python_version, python_version_tuple
|
|
||||||
|
|
||||||
class Install:
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CoreConfig:
|
|
||||||
install_log_file: str
|
|
||||||
unix_systemd_folder: str
|
|
||||||
service_file_name: str
|
|
||||||
service_cmd_executable: list
|
|
||||||
service_cmd_daemon_reload: list
|
|
||||||
defender_main_executable: str
|
|
||||||
python_min_version: str
|
|
||||||
python_current_version_tuple: tuple[int, int, int]
|
|
||||||
python_current_version: tuple[int, int, int]
|
|
||||||
defender_install_folder: str
|
|
||||||
venv_folder: str
|
|
||||||
venv_cmd_installation: list
|
|
||||||
venv_cmd_requirements: list[str]
|
|
||||||
venv_pip_executable: str
|
|
||||||
venv_python_executable: str
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Package:
|
|
||||||
name: str = None
|
|
||||||
version: str = None
|
|
||||||
|
|
||||||
DB_PACKAGES: list[Package] = []
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
|
|
||||||
self.set_configuration()
|
|
||||||
|
|
||||||
if self.skip_install:
|
|
||||||
self.install_dependencies()
|
|
||||||
self.check_packages_version()
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.check_packages_version()
|
|
||||||
|
|
||||||
# Sinon tester les dependances python et les installer avec pip
|
|
||||||
if self.do_install():
|
|
||||||
|
|
||||||
self.install_dependencies()
|
|
||||||
|
|
||||||
self.create_service_file()
|
|
||||||
|
|
||||||
self.print_final_message()
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def set_configuration(self):
|
|
||||||
|
|
||||||
self.skip_install = False
|
|
||||||
defender_install_folder = os.getcwd()
|
|
||||||
venv_folder = '.pyenv'
|
|
||||||
unix_user_home_directory = os.path.expanduser("~")
|
|
||||||
unix_systemd_folder = os.path.join(unix_user_home_directory, '.config', 'systemd', 'user')
|
|
||||||
defender_main_executable = os.path.join(defender_install_folder, 'defender.py')
|
|
||||||
|
|
||||||
self.config = self.CoreConfig(
|
|
||||||
install_log_file='install.log',
|
|
||||||
unix_systemd_folder=unix_systemd_folder,
|
|
||||||
service_file_name='defender.service',
|
|
||||||
service_cmd_executable=['systemctl', '--user', 'start', 'defender'],
|
|
||||||
service_cmd_daemon_reload=['systemctl', '--user', 'daemon-reload'],
|
|
||||||
defender_main_executable=defender_main_executable,
|
|
||||||
python_min_version=(3, 10, 0),
|
|
||||||
python_current_version_tuple=tuple(map(int, python_version_tuple())),
|
|
||||||
python_current_version=python_version(),
|
|
||||||
defender_install_folder=defender_install_folder,
|
|
||||||
venv_folder=venv_folder,
|
|
||||||
venv_cmd_installation=['python3', '-m', 'venv', venv_folder],
|
|
||||||
venv_cmd_requirements=['sqlalchemy','psutil','requests','faker','pyyaml','unrealircd_rpc_py'],
|
|
||||||
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'
|
|
||||||
)
|
|
||||||
|
|
||||||
if not self.check_python_version():
|
|
||||||
# If the Python version is not good then Exit
|
|
||||||
exit("[!] Python version error [!]")
|
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(self.config.defender_install_folder, 'config', 'configuration.yaml')):
|
|
||||||
# If configuration file do not exist
|
|
||||||
exit("[!] Configuration file (core/configuration.yaml) doesn't exist! please create it [!]")
|
|
||||||
|
|
||||||
# Exclude Windows OS from the installation
|
|
||||||
if os.name == 'nt':
|
|
||||||
# If windows, modify pip and python virtual environment executable
|
|
||||||
self.config.venv_pip_executable = f'{os.path.join(defender_install_folder, venv_folder, "Scripts")}{os.sep}pip.exe'
|
|
||||||
self.config.venv_python_executable = f'{os.path.join(defender_install_folder, venv_folder, "Scripts")}{os.sep}python.exe'
|
|
||||||
self.skip_install = True
|
|
||||||
return False
|
|
||||||
|
|
||||||
if self.is_root():
|
|
||||||
exit(f'[!] I highly not recommend running Defender as root [!]')
|
|
||||||
self.skip_install = True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_root(self) -> bool:
|
|
||||||
|
|
||||||
if os.geteuid() != 0:
|
|
||||||
print('> User without privileges ==> OK')
|
|
||||||
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:
|
|
||||||
|
|
||||||
full_service_file_path = os.path.join(self.config.unix_systemd_folder, self.config.service_file_name)
|
|
||||||
|
|
||||||
if not os.path.exists(full_service_file_path):
|
|
||||||
print(f'[!] Service file does not exist [!]')
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Check if virtual env exist
|
|
||||||
if not os.path.exists(f'{os.path.join(self.config.defender_install_folder, self.config.venv_folder)}'):
|
|
||||||
self.run_subprocess(self.config.venv_cmd_installation)
|
|
||||||
print(f'[!] Virtual env does not exist run the install [!]')
|
|
||||||
return True
|
|
||||||
|
|
||||||
def run_subprocess(self, command:list) -> None:
|
|
||||||
|
|
||||||
print(f'> {command}')
|
|
||||||
try:
|
|
||||||
check_call(command)
|
|
||||||
print("The command completed successfully.")
|
|
||||||
except CalledProcessError as e:
|
|
||||||
print(f"The command failed with the return code: {e.returncode}")
|
|
||||||
print(f"Try to install dependencies ...")
|
|
||||||
exit(5)
|
|
||||||
|
|
||||||
def get_packages_version_from_json(self) -> None:
|
|
||||||
"""This will create Package model with package names and required version
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
|
|
||||||
version_filename = f'.{os.sep}version.json'
|
|
||||||
with open(version_filename, 'r') as version_data:
|
|
||||||
package_info:dict[str, str] = json.load(version_data)
|
|
||||||
|
|
||||||
for name, version in package_info.items():
|
|
||||||
if name == 'version':
|
|
||||||
continue
|
|
||||||
|
|
||||||
self.DB_PACKAGES.append(
|
|
||||||
self.Package(name=name, version=version)
|
|
||||||
)
|
|
||||||
|
|
||||||
return None
|
|
||||||
except FileNotFoundError as fe:
|
|
||||||
print(f"File not found: {fe}")
|
|
||||||
except Exception as err:
|
|
||||||
print(f"General Error: {err}")
|
|
||||||
|
|
||||||
def check_packages_version(self) -> bool:
|
|
||||||
|
|
||||||
try:
|
|
||||||
newVersion = False
|
|
||||||
self.get_packages_version_from_json()
|
|
||||||
|
|
||||||
if not self.config.venv_folder in prefix:
|
|
||||||
print(f"You are probably running a new installation or you are not using your virtual env {self.config.venv_folder}")
|
|
||||||
return newVersion
|
|
||||||
|
|
||||||
print(f"> Checking for dependencies versions ==> WAIT")
|
|
||||||
for package in self.DB_PACKAGES:
|
|
||||||
newVersion = False
|
|
||||||
_required_version = package.version
|
|
||||||
_installed_version: str = None
|
|
||||||
|
|
||||||
output = check_output([self.config.venv_pip_executable, 'show', package.name])
|
|
||||||
for line in output.decode().splitlines():
|
|
||||||
if line.startswith('Version:'):
|
|
||||||
_installed_version = line.split(':')[1].strip()
|
|
||||||
break
|
|
||||||
|
|
||||||
required_version = tuple(map(int, _required_version.split('.')))
|
|
||||||
installed_version = tuple(map(int, _installed_version.split('.')))
|
|
||||||
|
|
||||||
if required_version > installed_version:
|
|
||||||
print(f'> New version of {package.name} is available {installed_version} ==> {required_version}')
|
|
||||||
newVersion = True
|
|
||||||
|
|
||||||
if newVersion:
|
|
||||||
self.run_subprocess([self.config.venv_pip_executable, 'install', '--upgrade', package.name])
|
|
||||||
|
|
||||||
print(f"> Dependencies versions ==> OK")
|
|
||||||
return newVersion
|
|
||||||
|
|
||||||
except CalledProcessError:
|
|
||||||
print(f"[!] Package {package.name} not installed [!]")
|
|
||||||
except Exception as err:
|
|
||||||
print(f"General Error: {err}")
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
if self.config.python_current_version_tuple < self.config.python_min_version:
|
|
||||||
print(f"## Your python version must be greather than or equal to {self.config.python_min_version} ##")
|
|
||||||
return False
|
|
||||||
|
|
||||||
print(f"> Version of python : {self.config.python_current_version} ==> OK")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_package(self, package_name) -> bool:
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 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)
|
|
||||||
return True
|
|
||||||
except CalledProcessError as cpe:
|
|
||||||
print(cpe)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def install_dependencies(self) -> None:
|
|
||||||
"""### Verifie les dépendances si elles sont installées
|
|
||||||
- Test si les modules sont installés
|
|
||||||
- Met a jour pip
|
|
||||||
- Install les modules manquants
|
|
||||||
"""
|
|
||||||
do_install = False
|
|
||||||
|
|
||||||
# Check if virtual env exist
|
|
||||||
if not os.path.exists(f'{os.path.join(self.config.defender_install_folder, self.config.venv_folder)}'):
|
|
||||||
self.run_subprocess(self.config.venv_cmd_installation)
|
|
||||||
do_install = True
|
|
||||||
|
|
||||||
for module in self.config.venv_cmd_requirements:
|
|
||||||
module = module.replace('pyyaml', 'yaml')
|
|
||||||
if not self.check_package(module):
|
|
||||||
do_install = True
|
|
||||||
|
|
||||||
if not do_install:
|
|
||||||
return None
|
|
||||||
|
|
||||||
print("===> Clean pip cache")
|
|
||||||
self.run_subprocess([self.config.venv_pip_executable, 'cache', 'purge'])
|
|
||||||
|
|
||||||
print("===> Check if pip is up to date")
|
|
||||||
self.run_subprocess([self.config.venv_python_executable, '-m', 'pip', 'install', '--upgrade', 'pip'])
|
|
||||||
|
|
||||||
if not self.check_package('greenlet'):
|
|
||||||
self.run_subprocess([self.config.venv_pip_executable, 'install', '--only-binary', ':all:', 'greenlet'])
|
|
||||||
print('====> Greenlet installed')
|
|
||||||
|
|
||||||
for module in self.config.venv_cmd_requirements:
|
|
||||||
if not self.check_package(module):
|
|
||||||
print("### Trying to install missing python packages ###")
|
|
||||||
self.run_subprocess([self.config.venv_pip_executable, 'install', module])
|
|
||||||
print(f"====> Module {module} installed!")
|
|
||||||
else:
|
|
||||||
print(f"==> {module} already installed")
|
|
||||||
|
|
||||||
def create_service_file(self) -> None:
|
|
||||||
|
|
||||||
full_service_file_path = os.path.join(self.config.unix_systemd_folder, self.config.service_file_name)
|
|
||||||
|
|
||||||
if os.path.exists(full_service_file_path):
|
|
||||||
print(f'[!] Service file already exist [!]')
|
|
||||||
self.run_subprocess(self.config.service_cmd_executable)
|
|
||||||
return None
|
|
||||||
|
|
||||||
contain = f'''[Unit]
|
|
||||||
Description=Defender IRC Service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
ExecStart={self.config.venv_python_executable} {self.config.defender_main_executable}
|
|
||||||
WorkingDirectory={self.config.defender_install_folder}
|
|
||||||
SyslogIdentifier=Defender
|
|
||||||
Restart=on-failure
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
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:
|
|
||||||
servicefile.write(contain)
|
|
||||||
servicefile.close()
|
|
||||||
print('Service file generated with current configuration')
|
|
||||||
print('Running 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('Service file generated with current configuration')
|
|
||||||
print('Running IRC Service ...')
|
|
||||||
self.run_subprocess(self.config.service_cmd_daemon_reload)
|
|
||||||
self.run_subprocess(self.config.service_cmd_executable)
|
|
||||||
|
|
||||||
def print_final_message(self) -> None:
|
|
||||||
|
|
||||||
print(f"#"*24)
|
|
||||||
print("Installation complete ...")
|
|
||||||
print("If the configuration is correct, then you must see your service connected to your irc server")
|
|
||||||
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)
|
|
||||||
exit(1)
|
|
||||||
930
core/irc.py
930
core/irc.py
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,16 @@ traduction:
|
|||||||
# Message help
|
# Message help
|
||||||
- orig: "Access denied!"
|
- orig: "Access denied!"
|
||||||
trad: "Accès refusé."
|
trad: "Accès refusé."
|
||||||
|
- orig: "Wrong password!"
|
||||||
|
trad: "Mot de passe incorrect!"
|
||||||
- orig: "%s - %sLoaded%s by %s on %s"
|
- orig: "%s - %sLoaded%s by %s on %s"
|
||||||
trad: "%s - %sChargé%s par %s le %s"
|
trad: "%s - %sChargé%s par %s le %s"
|
||||||
|
- orig: "Module %s loaded!"
|
||||||
|
trad: "Module %s chargé!"
|
||||||
|
- orig: "cmd method is not available in the module (%s)"
|
||||||
|
trad: "La méthode cmd n'est pas disponible dans le module (%s)"
|
||||||
|
- orig: "[%sMODULE ERROR%s] Module %s is facing issues! %s"
|
||||||
|
trad: "[%sMODULE ERREUR%s] Le module %s a rencontré une erreur! %s"
|
||||||
- orig: "%s - %sNot Loaded%s"
|
- orig: "%s - %sNot Loaded%s"
|
||||||
trad: "%s - %sNon chargé%s"
|
trad: "%s - %sNon chargé%s"
|
||||||
- orig: "Successfuly connected to %s"
|
- orig: "Successfuly connected to %s"
|
||||||
|
|||||||
@@ -1,18 +1,28 @@
|
|||||||
from logging import Logger
|
from logging import Logger
|
||||||
from core.classes.settings import global_settings
|
from core.classes.modules.settings import global_settings
|
||||||
from core.classes import translation, user, admin, client, channel, reputation, settings, sasl
|
from core.classes.modules import translation, user, admin, client, channel, reputation, settings, sasl
|
||||||
import core.logs as logs
|
import core.logs as logs
|
||||||
import core.definition as df
|
import core.definition as df
|
||||||
import core.utils as utils
|
import core.utils as utils
|
||||||
import core.base as base_mod
|
import core.base as base_mod
|
||||||
import core.module as module_mod
|
import core.module as module_mod
|
||||||
import core.classes.commands as commands_mod
|
import core.classes.modules.commands as commands_mod
|
||||||
import core.classes.config as conf_mod
|
import core.classes.modules.config as conf_mod
|
||||||
|
import core.classes.modules.rpc.rpc as rpc_mod
|
||||||
import core.irc as irc
|
import core.irc as irc
|
||||||
import core.classes.protocols.factory as factory
|
import core.classes.protocols.factory as factory
|
||||||
|
|
||||||
class Loader:
|
class Loader:
|
||||||
|
|
||||||
|
_instance = None
|
||||||
|
|
||||||
|
def __new__(cls, *agrs):
|
||||||
|
|
||||||
|
if cls._instance is None:
|
||||||
|
cls._instance = super().__new__(cls)
|
||||||
|
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Load Main Modules
|
# Load Main Modules
|
||||||
@@ -26,6 +36,8 @@ class Loader:
|
|||||||
|
|
||||||
self.LoggingModule: logs = logs
|
self.LoggingModule: logs = logs
|
||||||
|
|
||||||
|
self.RpcServerModule: rpc_mod = rpc_mod
|
||||||
|
|
||||||
self.Utils: utils = utils
|
self.Utils: utils = utils
|
||||||
|
|
||||||
# Load Classes
|
# Load Classes
|
||||||
@@ -67,6 +79,11 @@ class Loader:
|
|||||||
|
|
||||||
self.Irc: irc.Irc = irc.Irc(self)
|
self.Irc: irc.Irc = irc.Irc(self)
|
||||||
|
|
||||||
self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc)
|
self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self)
|
||||||
|
|
||||||
|
self.RpcServer: rpc_mod.JSonRpcServer = rpc_mod.JSonRpcServer(self)
|
||||||
|
|
||||||
self.Logs.debug(self.Utils.tr("Loader %s success", __name__))
|
self.Logs.debug(self.Utils.tr("Loader %s success", __name__))
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
await self.Base.init()
|
||||||
|
|||||||
288
core/module.py
288
core/module.py
@@ -1,27 +1,26 @@
|
|||||||
'''
|
'''
|
||||||
This is the main operational file to handle modules
|
This is the main operational file to handle modules
|
||||||
'''
|
'''
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
import sys
|
||||||
import importlib
|
import importlib
|
||||||
|
from pathlib import Path
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
from core.definition import MModule
|
from core.definition import DefenderModuleHeader, MModule
|
||||||
|
from core.utils import tr
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.loader import Loader
|
from core.loader import Loader
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
|
from core.classes.interfaces.imodule import IModule
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
|
|
||||||
DB_MODULES: list[MModule] = []
|
DB_MODULES: list[MModule] = []
|
||||||
|
DB_MODULE_HEADERS: list[DefenderModuleHeader] = []
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader') -> None:
|
def __init__(self, loader: 'Loader') -> None:
|
||||||
self.__Loader = loader
|
self._ctx = loader
|
||||||
self.__Base = loader.Base
|
|
||||||
self.__Logs = loader.Logs
|
|
||||||
self.__Utils = loader.Utils
|
|
||||||
self.__Config = loader.Config
|
|
||||||
|
|
||||||
def get_all_available_modules(self) -> list[str]:
|
def get_all_available_modules(self) -> list[str]:
|
||||||
"""Get list of all main modules
|
"""Get list of all main modules
|
||||||
@@ -31,71 +30,126 @@ class Module:
|
|||||||
list[str]: List of all module names.
|
list[str]: List of all module names.
|
||||||
"""
|
"""
|
||||||
base_path = Path('mods')
|
base_path = Path('mods')
|
||||||
return [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')]
|
modules_available = [file.name.replace('.py', '') for file in base_path.rglob('mod_*.py')]
|
||||||
|
self._ctx.Logs.debug(f"Modules available: {modules_available}")
|
||||||
|
return modules_available
|
||||||
|
|
||||||
def get_module_information(self, module_name: str) -> tuple[str, str, str]:
|
def get_module_information(self, module_name: str) -> tuple[Optional[str], Optional[str], Optional[str]]:
|
||||||
# module_name : mod_defender
|
# module_name : mod_defender
|
||||||
if not module_name.lower().startswith('mod_'):
|
if not module_name.lower().startswith('mod_'):
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
module_name = module_name.lower()
|
module_name = module_name.lower() # --> mod_defender
|
||||||
module_folder = module_name.split('_')[1].lower() # --> defender
|
module_folder = module_name.split('_')[1].lower() # --> defender
|
||||||
class_name = module_name.split('_')[1].capitalize() # --> Defender
|
class_name = module_name.split('_')[1].capitalize() # --> Defender
|
||||||
|
self._ctx.Logs.debug(f"Module information Folder: {module_folder}, Name: {module_name}, Class: {class_name}")
|
||||||
return module_folder, module_name, class_name
|
return module_folder, module_name, class_name
|
||||||
|
|
||||||
def load_one_module(self, uplink: 'Irc', module_name: str, nickname: str, is_default: bool = False) -> bool:
|
def get_module_header(self, module_name: str) -> Optional[DefenderModuleHeader]:
|
||||||
|
|
||||||
|
for mod_h in self.DB_MODULE_HEADERS:
|
||||||
|
if module_name.lower() == mod_h.name.lower():
|
||||||
|
self._ctx.Logs.debug(f"Module Header found: {mod_h}")
|
||||||
|
return mod_h
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_module_header(self, module_header: dict[str, str]) -> bool:
|
||||||
|
"""Create a new module header into DB_MODULE_HEADERS
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module_header (dict[str, str]): The module header
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the module header has been created.
|
||||||
|
"""
|
||||||
|
mod_header = DefenderModuleHeader(**module_header)
|
||||||
|
if self.get_module_header(mod_header.name) is None:
|
||||||
|
self._ctx.Logs.debug(f"[MOD_HEADER] The module header has been created! ({mod_header.name} v{mod_header.version})")
|
||||||
|
self.DB_MODULE_HEADERS.append(mod_header)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_module_header(self, module_name: str) -> bool:
|
||||||
|
mod_header = self.get_module_header(module_name)
|
||||||
|
if mod_header is not None:
|
||||||
|
self._ctx.Logs.debug(f"[MOD_HEADER] The module header has been deleted ({mod_header.name} v{mod_header.version})")
|
||||||
|
self.DB_MODULE_HEADERS.remove(mod_header)
|
||||||
|
return True
|
||||||
|
|
||||||
|
self._ctx.Logs.debug(f"[MOD_HEADER ERROR] Impossible to remove the module header ({module_name})")
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def load_one_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool:
|
||||||
|
|
||||||
module_folder, module_name, class_name = self.get_module_information(module_name)
|
module_folder, module_name, class_name = self.get_module_information(module_name)
|
||||||
|
|
||||||
if module_folder is None or module_name is None or class_name is None:
|
if module_folder is None or module_name is None or class_name is None:
|
||||||
self.__Logs.error(f"There is an error with the module name! {module_folder}, {module_name}, {class_name}")
|
self._ctx.Logs.error(f"There is an error with the module name! {module_folder}, {module_name}, {class_name}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self.is_module_exist_in_sys_module(module_name):
|
if self.is_module_exist_in_sys_module(module_name):
|
||||||
self.__Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!")
|
self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] already loaded!")
|
||||||
if self.model_is_module_exist(module_name):
|
if self.model_is_module_exist(module_name):
|
||||||
# Si le module existe dans la variable globale retourne False
|
# Si le module existe dans la variable globale retourne False
|
||||||
self.__Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!")
|
self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] exist in the local variable!")
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self.__Config.SERVICE_PREFIX}reload {module_name}",
|
msg=f"Le module {module_name} est déja chargé ! si vous souhaiter le recharge tapez {self._ctx.Config.SERVICE_PREFIX}reload {module_name}",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.reload_one_module(uplink, module_name, nickname)
|
return self.reload_one_module(module_name, nickname)
|
||||||
|
|
||||||
# Charger le module
|
# Charger le module
|
||||||
|
try:
|
||||||
loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}')
|
loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}')
|
||||||
my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe
|
my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe
|
||||||
create_instance_of_the_class = my_class(uplink) # Créer une nouvelle instance de la classe
|
create_instance_of_the_class: 'IModule' = my_class(self._ctx) # Créer une nouvelle instance de la classe
|
||||||
|
await create_instance_of_the_class.load() if self._ctx.Utils.is_coroutinefunction(create_instance_of_the_class.load) else create_instance_of_the_class.load()
|
||||||
|
self.create_module_header(create_instance_of_the_class.MOD_HEADER)
|
||||||
|
except AttributeError as attr:
|
||||||
|
red = self._ctx.Config.COLORS.red
|
||||||
|
nogc = self._ctx.Config.COLORS.red
|
||||||
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
|
msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr),
|
||||||
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
|
)
|
||||||
|
self._ctx.Logs.error(msg=attr, exc_info=True)
|
||||||
|
return False
|
||||||
|
|
||||||
if not hasattr(create_instance_of_the_class, 'cmd'):
|
if not hasattr(create_instance_of_the_class, 'cmd'):
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"Module {module_name} ne contient pas de méthode cmd",
|
msg=tr("cmd method is not available in the module (%s)", module_name),
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.__Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available")
|
self._ctx.Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available")
|
||||||
self.db_delete_module(module_name)
|
await self.db_delete_module(module_name)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Charger la nouvelle class dans la variable globale
|
# Charger la nouvelle class dans la variable globale
|
||||||
if self.model_insert_module(MModule(module_name, class_name, create_instance_of_the_class)):
|
if self.model_insert_module(MModule(module_name, class_name, create_instance_of_the_class)):
|
||||||
# Enregistrer le module dans la base de données
|
# Enregistrer le module dans la base de données
|
||||||
self.db_register_module(module_name, nickname, is_default)
|
await self.db_register_module(module_name, nickname, is_default)
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"Module {module_name} chargé",
|
msg=tr("Module %s loaded!", module_name),
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
|
|
||||||
self.__Logs.debug(f"Module {class_name} has been loaded")
|
self._ctx.Logs.debug(f"Module {class_name} has been loaded")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def load_all_modules(self) -> bool:
|
def load_all_modules(self) -> bool:
|
||||||
...
|
...
|
||||||
|
|
||||||
def reload_one_module(self, uplink: 'Irc', module_name: str, nickname: str) -> bool:
|
async def reload_one_module(self, module_name: str, nickname: str) -> bool:
|
||||||
"""Reloading one module and insert it into the model as well as the database
|
"""Reloading one module and insert it into the model as well as the database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -107,20 +161,21 @@ class Module:
|
|||||||
bool: True if the module has been reloaded
|
bool: True if the module has been reloaded
|
||||||
"""
|
"""
|
||||||
module_folder, module_name, class_name = self.get_module_information(module_name)
|
module_folder, module_name, class_name = self.get_module_information(module_name)
|
||||||
red = self.__Config.COLORS.red
|
red = self._ctx.Config.COLORS.red
|
||||||
nogc = self.__Config.COLORS.nogc
|
nogc = self._ctx.Config.COLORS.nogc
|
||||||
try:
|
try:
|
||||||
if self.is_module_exist_in_sys_module(module_name):
|
if self.is_module_exist_in_sys_module(module_name):
|
||||||
module_model = self.model_get_module(module_name)
|
module_model = self.model_get_module(module_name)
|
||||||
if module_model:
|
if module_model:
|
||||||
module_model.class_instance.unload()
|
self.delete_module_header(module_model.class_instance.MOD_HEADER['name'])
|
||||||
|
await module_model.class_instance.unload() if self._ctx.Utils.is_coroutinefunction(module_model.class_instance.unload) else module_model.class_instance.unload()
|
||||||
else:
|
else:
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}",
|
msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] hasn't been reloaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.__Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self.__Config.SERVICE_PREFIX}load {module_name}")
|
self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] not found! Please use {self._ctx.Config.SERVICE_PREFIX}load {module_name}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# reload module dependencies
|
# reload module dependencies
|
||||||
@@ -129,36 +184,38 @@ class Module:
|
|||||||
the_module = sys.modules[f'mods.{module_folder}.{module_name}']
|
the_module = sys.modules[f'mods.{module_folder}.{module_name}']
|
||||||
importlib.reload(the_module)
|
importlib.reload(the_module)
|
||||||
my_class = getattr(the_module, class_name, None)
|
my_class = getattr(the_module, class_name, None)
|
||||||
new_instance = my_class(uplink)
|
new_instance: 'IModule' = my_class(self._ctx)
|
||||||
|
await new_instance.load() if self._ctx.Utils.is_coroutinefunction(new_instance.load) else new_instance.load()
|
||||||
|
self.create_module_header(new_instance.MOD_HEADER)
|
||||||
module_model.class_instance = new_instance
|
module_model.class_instance = new_instance
|
||||||
|
|
||||||
# Créer le module dans la base de données
|
# Créer le module dans la base de données
|
||||||
self.db_register_module(module_name, nickname)
|
await self.db_register_module(module_name, nickname)
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"Module [{module_folder}.{module_name}] has been reloaded!",
|
msg=f"Module [{module_folder}.{module_name}] has been reloaded!",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.__Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!")
|
self._ctx.Logs.debug(f"Module [{module_folder}.{module_name}] reloaded!")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
# Module is not loaded! Nothing to reload
|
# Module is not loaded! Nothing to reload
|
||||||
self.__Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}")
|
self._ctx.Logs.debug(f"[RELOAD MODULE ERROR] [{module_folder}.{module_name}] is not loaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}")
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self.__Config.SERVICE_PREFIX}load {module_name}",
|
msg=f"[ {red}RELOAD MODULE ERROR{nogc} ] Module [{module_folder}.{module_name}] is not loaded! You must use {self._ctx.Config.SERVICE_PREFIX}load {module_name}",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except (TypeError, AttributeError, KeyError, Exception) as err:
|
except (TypeError, AttributeError, KeyError, Exception) as err:
|
||||||
self.__Logs.error(f"[RELOAD MODULE ERROR]: {err}")
|
self._ctx.Logs.error(f"[RELOAD MODULE ERROR]: {err}", exc_info=True)
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[RELOAD MODULE ERROR]: {err}",
|
msg=f"[RELOAD MODULE ERROR]: {err}",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.db_delete_module(module_name)
|
await self.db_delete_module(module_name)
|
||||||
|
|
||||||
def reload_all_modules(self) -> bool:
|
def reload_all_modules(self) -> bool:
|
||||||
...
|
...
|
||||||
@@ -184,38 +241,41 @@ class Module:
|
|||||||
try:
|
try:
|
||||||
if 'mod_' not in name and 'schemas' not in name:
|
if 'mod_' not in name and 'schemas' not in name:
|
||||||
importlib.reload(module)
|
importlib.reload(module)
|
||||||
self.__Logs.debug(f'[LOAD_MODULE] Module {module} success')
|
self._ctx.Logs.debug(f'[LOAD_MODULE] Module {module} success')
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.__Logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}')
|
self._ctx.Logs.error(f'[LOAD_MODULE] Module {module} failed [!] - {err}')
|
||||||
|
|
||||||
def unload_one_module(self, uplink: 'Irc', module_name: str, keep_in_db: bool = True) -> bool:
|
async def unload_one_module(self, module_name: str, keep_in_db: bool = True) -> bool:
|
||||||
"""Unload a module
|
"""Unload a module
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mod_name (str): Module name ex mod_defender
|
uplink (Irc): The Irc instance
|
||||||
|
module_name (str): Module name ex mod_defender
|
||||||
|
keep_in_db (bool): Keep in database
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if success
|
bool: True if success
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Le nom du module. exemple: mod_defender
|
# Le nom du module. exemple: mod_defender
|
||||||
red = self.__Config.COLORS.red
|
red = self._ctx.Config.COLORS.red
|
||||||
nogc = self.__Config.COLORS.nogc
|
nogc = self._ctx.Config.COLORS.nogc
|
||||||
module_folder, module_name, class_name = self.get_module_information(module_name)
|
module_folder, module_name, class_name = self.get_module_information(module_name)
|
||||||
module = self.model_get_module(module_name)
|
module = self.model_get_module(module_name)
|
||||||
if module is None:
|
if module is None:
|
||||||
self.__Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!")
|
self._ctx.Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!")
|
||||||
self.db_delete_module(module_name)
|
await self.db_delete_module(module_name)
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[ {red}UNLOAD MODULE ERROR{nogc} ] This module {module_name} is not loaded!",
|
msg=f"[ {red}UNLOAD MODULE ERROR{nogc} ] This module {module_name} is not loaded!",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if module:
|
if module:
|
||||||
module.class_instance.unload()
|
self.delete_module_header(module.class_instance.MOD_HEADER['name'])
|
||||||
|
await module.class_instance.unload() if self._ctx.Utils.is_coroutinefunction(module.class_instance.unload) else module.class_instance.unload()
|
||||||
self.DB_MODULES.remove(module)
|
self.DB_MODULES.remove(module)
|
||||||
|
|
||||||
# Delete from the sys.modules.
|
# Delete from the sys.modules.
|
||||||
@@ -223,25 +283,25 @@ class Module:
|
|||||||
del sys.modules[f"mods.{module_folder}.{module_name}"]
|
del sys.modules[f"mods.{module_folder}.{module_name}"]
|
||||||
|
|
||||||
if sys.modules.get(f'mods.{module_folder}.{module_name}'):
|
if sys.modules.get(f'mods.{module_folder}.{module_name}'):
|
||||||
self.__Logs.debug(f"Module mods.{module_folder}.{module_name} still in the sys.modules")
|
self._ctx.Logs.debug(f"Module mods.{module_folder}.{module_name} still in the sys.modules")
|
||||||
|
|
||||||
# Supprimer le module de la base de données
|
# Supprimer le module de la base de données
|
||||||
if not keep_in_db:
|
if not keep_in_db:
|
||||||
self.db_delete_module(module_name)
|
await self.db_delete_module(module_name)
|
||||||
|
|
||||||
uplink.Protocol.send_priv_msg(
|
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[ UNLOAD MODULE INFO ] Module {module_name} has been unloaded!",
|
msg=f"[ UNLOAD MODULE INFO ] Module {module_name} has been unloaded!",
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.__Logs.debug(f"[ UNLOAD MODULE ] {module_name} has been unloaded!")
|
self._ctx.Logs.debug(f"[ UNLOAD MODULE ] {module_name} has been unloaded!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.__Logs.debug(f"[UNLOAD MODULE]: Module {module_name} not found in DB_MODULES variable!")
|
self._ctx.Logs.debug(f"[UNLOAD MODULE]: Module {module_name} not found in DB_MODULES variable!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.__Logs.error(f"General Error: {err}")
|
self._ctx.Logs.error(f"General Error: {err}", exc_info=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def unload_all_modules(self) -> bool:
|
def unload_all_modules(self) -> bool:
|
||||||
@@ -258,7 +318,9 @@ class Module:
|
|||||||
"""
|
"""
|
||||||
module_folder, module_name, class_name = self.get_module_information(module_name)
|
module_folder, module_name, class_name = self.get_module_information(module_name)
|
||||||
if "mods." + module_folder + "." + module_name in sys.modules:
|
if "mods." + module_folder + "." + module_name in sys.modules:
|
||||||
|
self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) found in sys.modules")
|
||||||
return True
|
return True
|
||||||
|
self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@@ -275,10 +337,10 @@ class Module:
|
|||||||
"""
|
"""
|
||||||
for module in self.DB_MODULES:
|
for module in self.DB_MODULES:
|
||||||
if module.module_name.lower() == module_name.lower():
|
if module.module_name.lower() == module_name.lower():
|
||||||
self.__Logs.debug(f"[MODEL MODULE GET] The module {module_name} has been found in the model DB_MODULES")
|
self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} has been found in the model DB_MODULES")
|
||||||
return module
|
return module
|
||||||
|
|
||||||
self.__Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES")
|
self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def model_get_loaded_modules(self) -> list[MModule]:
|
def model_get_loaded_modules(self) -> list[MModule]:
|
||||||
@@ -288,7 +350,7 @@ class Module:
|
|||||||
Returns:
|
Returns:
|
||||||
list[MModule]: A list of module model object
|
list[MModule]: A list of module model object
|
||||||
"""
|
"""
|
||||||
# self.__Logs.debug(f"[MODEL MODULE LOADED MODULES] {len(self.DB_MODULES)} modules found!")
|
# self._ctx.Logs.debug(f"[MODEL MODULE LOADED MODULES] {len(self.DB_MODULES)} modules found!")
|
||||||
return self.DB_MODULES
|
return self.DB_MODULES
|
||||||
|
|
||||||
def model_insert_module(self, module_model: MModule) -> bool:
|
def model_insert_module(self, module_model: MModule) -> bool:
|
||||||
@@ -303,17 +365,17 @@ class Module:
|
|||||||
module = self.model_get_module(module_model.module_name)
|
module = self.model_get_module(module_model.module_name)
|
||||||
if module is None:
|
if module is None:
|
||||||
self.DB_MODULES.append(module_model)
|
self.DB_MODULES.append(module_model)
|
||||||
self.__Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} has been inserted in the local variable model DB_MODULES")
|
self._ctx.Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} has been inserted in the local variable model DB_MODULES")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.__Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} already exist in the local variable model DB_MODULES")
|
self._ctx.Logs.debug(f"[MODEL MODULE INSERT] The module {module_model.module_name} already exist in the local variable model DB_MODULES")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def model_clear(self) -> None:
|
def model_clear(self) -> None:
|
||||||
"""Clear DB_MODULES list!
|
"""Clear DB_MODULES list!
|
||||||
"""
|
"""
|
||||||
self.DB_MODULES.clear()
|
self.DB_MODULES.clear()
|
||||||
self.__Logs.debug("[MODEL MODULE CLEAR] The local variable model DB_MODULES has been cleared")
|
self._ctx.Logs.debug("[MODEL MODULE CLEAR] The local variable model DB_MODULES has been cleared")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def model_is_module_exist(self, module_name: str) -> bool:
|
def model_is_module_exist(self, module_name: str) -> bool:
|
||||||
@@ -326,30 +388,30 @@ class Module:
|
|||||||
bool: True if the module_name exist
|
bool: True if the module_name exist
|
||||||
"""
|
"""
|
||||||
if self.model_get_module(module_name):
|
if self.model_get_module(module_name):
|
||||||
self.__Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} exist in the local model DB_MODULES!")
|
self._ctx.Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} exist in the local model DB_MODULES!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.__Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} is not available in the local model DB_MODULES!")
|
self._ctx.Logs.debug(f"[MODEL MODULE EXIST] The module {module_name} is not available in the local model DB_MODULES!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
'''
|
'''
|
||||||
OPERATION DEDICATED TO DATABASE MANAGEMENT
|
OPERATION DEDICATED TO DATABASE MANAGEMENT
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def db_load_all_existing_modules(self, uplink: 'Irc') -> bool:
|
async def db_load_all_existing_modules(self) -> bool:
|
||||||
"""Charge les modules qui existe déja dans la base de données
|
"""Charge les modules qui existe déja dans la base de données
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
None: Aucun retour requis, elle charge puis c'est tout
|
None: Aucun retour requis, elle charge puis c'est tout
|
||||||
"""
|
"""
|
||||||
self.__Logs.debug("[DB LOAD MODULE] Loading modules from the database!")
|
self._ctx.Logs.debug("[DB LOAD MODULE] Loading modules from the database!")
|
||||||
result = self.__Base.db_execute_query(f"SELECT module_name FROM {self.__Config.TABLE_MODULE}")
|
result = await self._ctx.Base.db_execute_query(f"SELECT module_name FROM {self._ctx.Config.TABLE_MODULE}")
|
||||||
for r in result.fetchall():
|
for r in result.fetchall():
|
||||||
self.load_one_module(uplink, r[0], 'sys', True)
|
await self.load_one_module(r[0], 'sys', True)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def db_is_module_exist(self, module_name: str) -> bool:
|
async def db_is_module_exist(self, module_name: str) -> bool:
|
||||||
"""Check if the module exist in the database
|
"""Check if the module exist in the database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -358,18 +420,18 @@ class Module:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if the module exist in the database
|
bool: True if the module exist in the database
|
||||||
"""
|
"""
|
||||||
query = f"SELECT id FROM {self.__Config.TABLE_MODULE} WHERE module_name = :module_name"
|
query = f"SELECT id FROM {self._ctx.Config.TABLE_MODULE} WHERE module_name = :module_name"
|
||||||
mes_donnes = {'module_name': module_name.lower()}
|
mes_donnes = {'module_name': module_name.lower()}
|
||||||
results = self.__Base.db_execute_query(query, mes_donnes)
|
results = await self._ctx.Base.db_execute_query(query, mes_donnes)
|
||||||
|
|
||||||
if results.fetchall():
|
if results.fetchall():
|
||||||
self.__Logs.debug(f"[DB MODULE EXIST] The module {module_name} exist in the database!")
|
self._ctx.Logs.debug(f"[DB MODULE EXIST] The module {module_name} exist in the database!")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.__Logs.debug(f"[DB MODULE EXIST] The module {module_name} is not available in the database!")
|
self._ctx.Logs.debug(f"[DB MODULE EXIST] The module {module_name} is not available in the database!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_register_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool:
|
async def db_register_module(self, module_name: str, nickname: str, is_default: bool = False) -> bool:
|
||||||
"""Insert a new module in the database
|
"""Insert a new module in the database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -377,49 +439,49 @@ class Module:
|
|||||||
nickname (str): The user who loaded the module
|
nickname (str): The user who loaded the module
|
||||||
isdefault (int): Is this a default module. Default 0
|
isdefault (int): Is this a default module. Default 0
|
||||||
"""
|
"""
|
||||||
if not self.db_is_module_exist(module_name):
|
if not await self.db_is_module_exist(module_name):
|
||||||
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._ctx.Config.TABLE_MODULE} (datetime, user, module_name, isdefault) VALUES (:datetime, :user, :module_name, :isdefault)"
|
||||||
mes_donnees = {'datetime': self.__Utils.get_sdatetime(), 'user': nickname, 'module_name': module_name.lower(), 'isdefault': is_default}
|
mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'user': nickname, 'module_name': module_name.lower(), 'isdefault': is_default}
|
||||||
insert = self.__Base.db_execute_query(insert_cmd_query, mes_donnees)
|
insert = await self._ctx.Base.db_execute_query(insert_cmd_query, mes_donnees)
|
||||||
if insert.rowcount > 0:
|
if insert.rowcount > 0:
|
||||||
self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} has been inserted to the database!")
|
self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} has been inserted to the database!")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} not inserted to the database!")
|
self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} not inserted to the database!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.__Logs.debug(f"[DB REGISTER MODULE] Module {module_name} already exist in the database! Nothing to insert!")
|
self._ctx.Logs.debug(f"[DB REGISTER MODULE] Module {module_name} already exist in the database! Nothing to insert!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_update_module(self, module_name: str, nickname: str) -> None:
|
async def db_update_module(self, module_name: str, nickname: str) -> None:
|
||||||
"""Update the datetime and the user that updated the module
|
"""Update the datetime and the user that updated the module
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
module_name (str): The module name to update
|
module_name (str): The module name to update
|
||||||
nickname (str): The nickname who updated the module
|
nickname (str): The nickname who updated the module
|
||||||
"""
|
"""
|
||||||
update_cmd_query = f"UPDATE {self.__Config.TABLE_MODULE} SET datetime = :datetime, LOWER(user) = :user WHERE LOWER(module_name) = :module_name"
|
update_cmd_query = f"UPDATE {self._ctx.Config.TABLE_MODULE} SET datetime = :datetime, LOWER(user) = :user WHERE LOWER(module_name) = :module_name"
|
||||||
mes_donnees = {'datetime': self.__Utils.get_sdatetime(), 'user': nickname.lower(), 'module_name': module_name.lower()}
|
mes_donnees = {'datetime': self._ctx.Utils.get_sdatetime(), 'user': nickname.lower(), 'module_name': module_name.lower()}
|
||||||
result = self.__Base.db_execute_query(update_cmd_query, mes_donnees)
|
result = await self._ctx.Base.db_execute_query(update_cmd_query, mes_donnees)
|
||||||
if result.rowcount > 0:
|
if result.rowcount > 0:
|
||||||
self.__Logs.debug(f"[DB UPDATE MODULE] Module {module_name} has been updated!")
|
self._ctx.Logs.debug(f"[DB UPDATE MODULE] Module {module_name} has been updated!")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.__Logs.debug(f"[DB UPDATE MODULE] Module {module_name} not found! Nothing to update!")
|
self._ctx.Logs.debug(f"[DB UPDATE MODULE] Module {module_name} not found! Nothing to update!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_delete_module(self, module_name:str) -> None:
|
async def db_delete_module(self, module_name:str) -> None:
|
||||||
"""Delete a module from the database
|
"""Delete a module from the database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
module_name (str): The module name you want to delete
|
module_name (str): The module name you want to delete
|
||||||
"""
|
"""
|
||||||
insert_cmd_query = f"DELETE FROM {self.__Config.TABLE_MODULE} WHERE LOWER(module_name) = :module_name"
|
insert_cmd_query = f"DELETE FROM {self._ctx.Config.TABLE_MODULE} WHERE LOWER(module_name) = :module_name"
|
||||||
mes_donnees = {'module_name': module_name.lower()}
|
mes_donnees = {'module_name': module_name.lower()}
|
||||||
delete = self.__Base.db_execute_query(insert_cmd_query, mes_donnees)
|
delete = await self._ctx.Base.db_execute_query(insert_cmd_query, mes_donnees)
|
||||||
if delete.rowcount > 0:
|
if delete.rowcount > 0:
|
||||||
self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} has been deleted from the dabatase!")
|
self._ctx.Logs.debug(f"[DB MODULE DELETE] The module {module_name} has been deleted from the dabatase!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.__Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!")
|
self._ctx.Logs.debug(f"[DB MODULE DELETE] The module {module_name} is not available in the database! Nothing to delete!")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
'''
|
"""
|
||||||
Main utils library.
|
Main utils library.
|
||||||
'''
|
"""
|
||||||
import gc
|
import gc
|
||||||
import ssl
|
import ssl
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from re import match, sub
|
from re import match, sub
|
||||||
from base64 import b64decode
|
|
||||||
from typing import Literal, Optional, Any, TYPE_CHECKING
|
from typing import Literal, Optional, Any, TYPE_CHECKING
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime
|
||||||
from time import time
|
from time import time
|
||||||
from random import choice
|
from random import choice
|
||||||
from hashlib import md5, sha3_512
|
from hashlib import md5, sha3_512
|
||||||
from core.classes.settings import global_settings
|
from core.classes.modules.settings import global_settings
|
||||||
|
from asyncio import iscoroutinefunction
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
@@ -84,9 +84,9 @@ def get_unixtime() -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
int: Current time in seconds since the Epoch (int)
|
int: Current time in seconds since the Epoch (int)
|
||||||
"""
|
"""
|
||||||
cet_offset = timezone(timedelta(hours=2))
|
# cet_offset = timezone(timedelta(hours=2))
|
||||||
now_cet = datetime.now(cet_offset)
|
# now_cet = datetime.now(cet_offset)
|
||||||
unixtime_cet = int(now_cet.timestamp())
|
# unixtime_cet = int(now_cet.timestamp())
|
||||||
return int(time())
|
return int(time())
|
||||||
|
|
||||||
def get_sdatetime() -> str:
|
def get_sdatetime() -> str:
|
||||||
@@ -142,9 +142,9 @@ def create_socket(uplink: 'Irc') -> None:
|
|||||||
except OSError as oe:
|
except OSError as oe:
|
||||||
uplink.Logs.critical(f"[OS Error]: {oe}")
|
uplink.Logs.critical(f"[OS Error]: {oe}")
|
||||||
if 'connection refused' in str(oe).lower():
|
if 'connection refused' in str(oe).lower():
|
||||||
sys.exit(oe)
|
sys.exit(oe.__str__())
|
||||||
if oe.errno == 10053:
|
if oe.errno == 10053:
|
||||||
sys.exit(oe)
|
sys.exit(oe.__str__())
|
||||||
except AttributeError as ae:
|
except AttributeError as ae:
|
||||||
uplink.Logs.critical(f"AttributeError: {ae}")
|
uplink.Logs.critical(f"AttributeError: {ae}")
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ def generate_random_string(lenght: int) -> str:
|
|||||||
|
|
||||||
return randomize
|
return randomize
|
||||||
|
|
||||||
def hash_password(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') -> str:
|
def hash_password(password: str, algorithm: Literal["md5", "sha3_512"] = 'md5') -> str:
|
||||||
"""Return the crypted password following the selected algorithm
|
"""Return the crypted password following the selected algorithm
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -191,16 +191,16 @@ def hash_password(password: str, algorithm: Literal["md5, sha3_512"] = 'md5') ->
|
|||||||
|
|
||||||
match algorithm:
|
match algorithm:
|
||||||
case 'md5':
|
case 'md5':
|
||||||
password = md5(password.encode()).hexdigest()
|
hashed_password = md5(password.encode()).hexdigest()
|
||||||
return password
|
return hashed_password
|
||||||
|
|
||||||
case 'sha3_512':
|
case 'sha3_512':
|
||||||
password = sha3_512(password.encode()).hexdigest()
|
hashed_password = sha3_512(password.encode()).hexdigest()
|
||||||
return password
|
return hashed_password
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
password = md5(password.encode()).hexdigest()
|
hashed_password = md5(password.encode()).hexdigest()
|
||||||
return password
|
return hashed_password
|
||||||
|
|
||||||
def get_all_modules() -> list[str]:
|
def get_all_modules() -> list[str]:
|
||||||
"""Get list of all main modules
|
"""Get list of all main modules
|
||||||
@@ -225,9 +225,9 @@ def clean_uid(uid: str) -> Optional[str]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
pattern = fr'[:|@|%|\+|~|\*]*'
|
pattern = fr'[:|@|%|\+|~|\*]*'
|
||||||
parsed_UID = sub(pattern, '', uid)
|
parsed_uid = sub(pattern, '', uid)
|
||||||
|
|
||||||
return parsed_UID
|
return parsed_uid
|
||||||
|
|
||||||
def hide_sensitive_data(srvmsg: list[str]) -> list[str]:
|
def hide_sensitive_data(srvmsg: list[str]) -> list[str]:
|
||||||
try:
|
try:
|
||||||
@@ -244,3 +244,14 @@ def hide_sensitive_data(srvmsg: list[str]) -> list[str]:
|
|||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return srvmsg
|
return srvmsg
|
||||||
|
|
||||||
|
def is_coroutinefunction(func: Any) -> bool:
|
||||||
|
"""Check if the function is a coroutine or not
|
||||||
|
|
||||||
|
Args:
|
||||||
|
func (Any): an callable object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the function is a coroutine
|
||||||
|
"""
|
||||||
|
return iscoroutinefunction(func)
|
||||||
20
defender.py
20
defender.py
@@ -1,22 +1,22 @@
|
|||||||
from core import installation
|
import asyncio
|
||||||
|
from core import install
|
||||||
|
|
||||||
#############################################
|
#############################################
|
||||||
# @Version : 6.3 #
|
# @Version : 6.4 #
|
||||||
# Requierements : #
|
# Requierements : #
|
||||||
# Python3.10 or higher #
|
# Python3.10 or higher #
|
||||||
# SQLAlchemy, requests, psutil #
|
# SQLAlchemy, requests, psutil #
|
||||||
# unrealircd-rpc-py, pyyaml #
|
# unrealircd-rpc-py, pyyaml #
|
||||||
|
# uvicorn, starlette, faker #
|
||||||
# UnrealIRCD 6.2.2 or higher #
|
# UnrealIRCD 6.2.2 or higher #
|
||||||
#############################################
|
#############################################
|
||||||
|
|
||||||
try:
|
async def main():
|
||||||
installation.Install()
|
install.update_packages()
|
||||||
from core.loader import Loader
|
from core.loader import Loader
|
||||||
loader = Loader()
|
loader = Loader()
|
||||||
loader.Irc.init_irc()
|
await loader.start()
|
||||||
|
await loader.Irc.run()
|
||||||
|
|
||||||
except AssertionError as ae:
|
if __name__ == "__main__":
|
||||||
print(f'Assertion Error -> {ae}')
|
asyncio.run(main())
|
||||||
except KeyboardInterrupt as k:
|
|
||||||
# ircInstance.Base.execute_periodic_action()
|
|
||||||
...
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class CloneManager:
|
|||||||
|
|
||||||
def __init__(self, uplink: 'Clone'):
|
def __init__(self, uplink: 'Clone'):
|
||||||
|
|
||||||
self.Logs = uplink.Logs
|
self.Logs = uplink.ctx.Logs
|
||||||
|
|
||||||
def insert(self, new_clone_object: MClone) -> bool:
|
def insert(self, new_clone_object: MClone) -> bool:
|
||||||
"""Create new Clone object
|
"""Create new Clone object
|
||||||
|
|||||||
@@ -1,90 +1,38 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
from typing import TYPE_CHECKING, Optional, Any
|
from typing import TYPE_CHECKING, Optional, Any
|
||||||
|
from core.classes.interfaces.imodule import IModule
|
||||||
import mods.clone.utils as utils
|
import mods.clone.utils as utils
|
||||||
import mods.clone.threads as thds
|
import mods.clone.threads as thds
|
||||||
import mods.clone.schemas as schemas
|
import mods.clone.schemas as schemas
|
||||||
from mods.clone.clone_manager import CloneManager
|
from mods.clone.clone_manager import CloneManager
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
class Clone:
|
class Clone(IModule):
|
||||||
|
|
||||||
def __init__(self, irc_instance: 'Irc') -> None:
|
@dataclass
|
||||||
|
class ModConfModel(schemas.ModConfModel):
|
||||||
|
...
|
||||||
|
|
||||||
# Module name (Mandatory)
|
MOD_HEADER: dict[str, str] = {
|
||||||
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
'name':'Clone',
|
||||||
|
'version':'1.0.0',
|
||||||
|
'description':'Connect thousands of clones to your IRCD, by group. You can use them as security moderation.',
|
||||||
|
'author':'Defender Team',
|
||||||
|
'core_version':'Defender-6'
|
||||||
|
}
|
||||||
|
|
||||||
# Add Irc Object to the module (Mandatory)
|
def __init__(self, context: 'Loader') -> None:
|
||||||
self.Irc = irc_instance
|
super().__init__(context)
|
||||||
|
self._mod_config: Optional[schemas.ModConfModel] = None
|
||||||
|
|
||||||
# Add Irc Protocol Object to the module (Mandatory)
|
@property
|
||||||
self.Protocol = irc_instance.Protocol
|
def mod_config(self) -> ModConfModel:
|
||||||
|
return self._mod_config
|
||||||
|
|
||||||
# Add Global Configuration to the module (Mandatory)
|
async def create_tables(self) -> None:
|
||||||
self.Config = irc_instance.Config
|
|
||||||
|
|
||||||
# Add Base object to the module (Mandatory)
|
|
||||||
self.Base = irc_instance.Base
|
|
||||||
|
|
||||||
# Add logs object to the module (Mandatory)
|
|
||||||
self.Logs = irc_instance.Loader.Logs
|
|
||||||
|
|
||||||
# Add User object to the module (Mandatory)
|
|
||||||
self.User = irc_instance.User
|
|
||||||
|
|
||||||
# Add Channel object to the module (Mandatory)
|
|
||||||
self.Channel = irc_instance.Channel
|
|
||||||
|
|
||||||
# Add global definitions
|
|
||||||
self.Definition = irc_instance.Loader.Definition
|
|
||||||
|
|
||||||
# The Global Settings
|
|
||||||
self.Settings = irc_instance.Loader.Settings
|
|
||||||
|
|
||||||
self.Schemas = schemas
|
|
||||||
|
|
||||||
self.Utils = utils
|
|
||||||
|
|
||||||
self.Threads = thds
|
|
||||||
|
|
||||||
self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB')
|
|
||||||
|
|
||||||
self.Clone = CloneManager(self)
|
|
||||||
|
|
||||||
metadata = self.Settings.get_cache('UID_CLONE_DB')
|
|
||||||
|
|
||||||
if metadata is not None:
|
|
||||||
self.Clone.UID_CLONE_DB = metadata
|
|
||||||
self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}")
|
|
||||||
|
|
||||||
# Créer les nouvelles commandes du module
|
|
||||||
self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
|
||||||
|
|
||||||
# Init the module (Mandatory)
|
|
||||||
self.__init_module()
|
|
||||||
|
|
||||||
# Log the module
|
|
||||||
self.Logs.debug(f'Module {self.module_name} loaded ...')
|
|
||||||
|
|
||||||
def __init_module(self) -> None:
|
|
||||||
|
|
||||||
# Créer les tables necessaire a votre module (ce n'es pas obligatoire)
|
|
||||||
self.__create_tables()
|
|
||||||
|
|
||||||
self.stop = False
|
|
||||||
|
|
||||||
# Load module configuration (Mandatory)
|
|
||||||
self.__load_module_configuration()
|
|
||||||
|
|
||||||
self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
|
||||||
self.Protocol.send_sjoin(self.Config.CLONE_CHANNEL)
|
|
||||||
self.Protocol.send_set_mode('+o', nickname=self.Config.SERVICE_NICKNAME, channel_name=self.Config.CLONE_CHANNEL)
|
|
||||||
self.Protocol.send_set_mode('+nts', channel_name=self.Config.CLONE_CHANNEL)
|
|
||||||
self.Protocol.send_set_mode('+k', channel_name=self.Config.CLONE_CHANNEL, params=self.Config.CLONE_CHANNEL_PASSWORD)
|
|
||||||
|
|
||||||
|
|
||||||
def __create_tables(self) -> None:
|
|
||||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||||
|
|
||||||
@@ -100,55 +48,69 @@ class Clone:
|
|||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# self.Base.db_execute_query(table_channel)
|
# await self.ctx.Base.db_execute_query(table_channel)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __load_module_configuration(self) -> None:
|
async def load(self) -> None:
|
||||||
"""### Load Module Configuration
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 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.Schemas.ModConfModel()
|
self._mod_config: schemas.ModConfModel = self.ModConfModel()
|
||||||
|
|
||||||
# Sync the configuration with core configuration (Mandatory)
|
# sync the database with local variable (Mandatory)
|
||||||
# self.Base.db_sync_core_config(self.module_name, self.ModConfig)
|
await self.sync_db()
|
||||||
|
|
||||||
return None
|
self.stop = False
|
||||||
|
self.Schemas = schemas
|
||||||
|
self.Utils = utils
|
||||||
|
self.Threads = thds
|
||||||
|
self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB')
|
||||||
|
self.Clone = CloneManager(self)
|
||||||
|
metadata = self.ctx.Settings.get_cache('UID_CLONE_DB')
|
||||||
|
|
||||||
except TypeError as te:
|
if metadata is not None:
|
||||||
self.Logs.critical(te)
|
self.Clone.UID_CLONE_DB = metadata
|
||||||
|
self.ctx.Logs.debug(f"Cache Size = {self.ctx.Settings.get_cache_size()}")
|
||||||
|
|
||||||
def unload(self) -> None:
|
# Créer les nouvelles commandes du module
|
||||||
|
self.ctx.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
||||||
|
|
||||||
|
await self.ctx.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||||
|
await self.ctx.Irc.Protocol.send_sjoin(self.ctx.Config.CLONE_CHANNEL)
|
||||||
|
await self.ctx.Irc.Protocol.send_set_mode('+o', nickname=self.ctx.Config.SERVICE_NICKNAME, channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||||
|
await self.ctx.Irc.Protocol.send_set_mode('+nts', channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||||
|
await self.ctx.Irc.Protocol.send_set_mode('+k', channel_name=self.ctx.Config.CLONE_CHANNEL, params=self.ctx.Config.CLONE_CHANNEL_PASSWORD)
|
||||||
|
|
||||||
|
async def unload(self) -> None:
|
||||||
"""Cette methode sera executée a chaque désactivation ou
|
"""Cette methode sera executée a chaque désactivation ou
|
||||||
rechargement de module
|
rechargement de module
|
||||||
"""
|
"""
|
||||||
# Store Clones DB into the global Settings to retrieve it after the reload.
|
# Store Clones DB into the global Settings to retrieve it after the reload.
|
||||||
self.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB)
|
self.ctx.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB)
|
||||||
|
|
||||||
self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
await self.ctx.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send_set_mode('-nts', channel_name=self.Config.CLONE_CHANNEL)
|
await self.ctx.Irc.Protocol.send_set_mode('-nts', channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send_set_mode('-k', channel_name=self.Config.CLONE_CHANNEL)
|
await self.ctx.Irc.Protocol.send_set_mode('-k', channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send_part_chan(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL)
|
await self.ctx.Irc.Protocol.send_part_chan(self.ctx.Config.SERVICE_NICKNAME, self.ctx.Config.CLONE_CHANNEL)
|
||||||
|
|
||||||
self.Irc.Commands.drop_command_by_module(self.module_name)
|
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def cmd(self, data:list) -> None:
|
async def cmd(self, data:list) -> None:
|
||||||
try:
|
try:
|
||||||
if not data or len(data) < 2:
|
if not data or len(data) < 2:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
||||||
index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
index, command = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
||||||
if index == -1:
|
if index == -1:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
match command:
|
match command:
|
||||||
|
|
||||||
case 'PRIVMSG':
|
case 'PRIVMSG':
|
||||||
self.Utils.handle_on_privmsg(self, cmd)
|
await self.Utils.handle_on_privmsg(self, cmd)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
case 'QUIT':
|
case 'QUIT':
|
||||||
@@ -158,10 +120,10 @@ class Clone:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'General Error: {err}', exc_info=True)
|
self.ctx.Logs.error(f'General Error: {err}', exc_info=True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None:
|
async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: list = []) -> None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
@@ -170,18 +132,18 @@ class Clone:
|
|||||||
|
|
||||||
command = str(cmd[0]).lower()
|
command = str(cmd[0]).lower()
|
||||||
fromuser = user
|
fromuser = user
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
dnickname = self.ctx.Config.SERVICE_NICKNAME
|
||||||
|
|
||||||
match command:
|
match command:
|
||||||
|
|
||||||
case 'clone':
|
case 'clone':
|
||||||
|
|
||||||
if len(cmd) == 1:
|
if len(cmd) < 2:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group_name | nickname]")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group_name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group_name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
option = str(cmd[1]).lower()
|
option = str(cmd[1]).lower()
|
||||||
@@ -196,15 +158,13 @@ class Clone:
|
|||||||
group = str(cmd[3]).lower()
|
group = str(cmd[3]).lower()
|
||||||
connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2
|
connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2
|
||||||
|
|
||||||
self.Base.create_thread(
|
self.ctx.Base.create_asynctask(
|
||||||
func=self.Threads.thread_connect_clones,
|
func=self.Threads.coro_connect_clones(self, number_of_clones, group, False, connection_interval)
|
||||||
func_args=(self, number_of_clones, group, False, connection_interval)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as err:
|
except IndexError:
|
||||||
self.Logs.error(f'{err}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group] [freq]")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group] [freq]")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Exemple /msg {dnickname} clone connect 6 Ambiance")
|
|
||||||
|
|
||||||
case 'kill':
|
case 'kill':
|
||||||
try:
|
try:
|
||||||
@@ -213,27 +173,26 @@ class Clone:
|
|||||||
option = str(cmd[2])
|
option = str(cmd[2])
|
||||||
|
|
||||||
if option.lower() == 'all':
|
if option.lower() == 'all':
|
||||||
self.Base.create_thread(func=self.Threads.thread_kill_clones, func_args=(self, ))
|
self.ctx.Base.create_asynctask(func=self.Threads.thread_kill_clones(self))
|
||||||
|
|
||||||
elif self.Clone.group_exists(option):
|
elif self.Clone.group_exists(option):
|
||||||
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||||
|
|
||||||
if len(list_of_clones_in_group) > 0:
|
if len(list_of_clones_in_group) > 0:
|
||||||
self.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}")
|
self.ctx.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}")
|
||||||
|
|
||||||
for clone in list_of_clones_in_group:
|
for clone in list_of_clones_in_group:
|
||||||
self.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False)
|
await self.ctx.Irc.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False)
|
||||||
self.Clone.delete(clone.uid)
|
self.Clone.delete(clone.uid)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
clone_obj = self.Clone.get_clone(option)
|
clone_obj = self.Clone.get_clone(option)
|
||||||
if not clone_obj is None:
|
if not clone_obj is None:
|
||||||
self.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False)
|
await self.ctx.Irc.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False)
|
||||||
self.Clone.delete(clone_obj.uid)
|
self.Clone.delete(clone_obj.uid)
|
||||||
|
|
||||||
except Exception as err:
|
except IndexError:
|
||||||
self.Logs.error(f'{err}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
|
|
||||||
|
|
||||||
case 'join':
|
case 'join':
|
||||||
try:
|
try:
|
||||||
@@ -244,25 +203,24 @@ class Clone:
|
|||||||
if option.lower() == 'all':
|
if option.lower() == 'all':
|
||||||
|
|
||||||
for clone in self.Clone.UID_CLONE_DB:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False)
|
await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False)
|
||||||
|
|
||||||
elif self.Clone.group_exists(option):
|
elif self.Clone.group_exists(option):
|
||||||
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||||
|
|
||||||
if len(list_of_clones_in_group) > 0:
|
if len(list_of_clones_in_group) > 0:
|
||||||
self.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}")
|
self.ctx.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}")
|
||||||
|
|
||||||
for clone in list_of_clones_in_group:
|
for clone in list_of_clones_in_group:
|
||||||
self.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False)
|
await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if self.Clone.nickname_exists(option):
|
if self.Clone.nickname_exists(option):
|
||||||
clone_uid = self.Clone.get_clone(option).uid
|
clone_uid = self.Clone.get_clone(option).uid
|
||||||
self.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False)
|
await self.ctx.Irc.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False)
|
||||||
|
|
||||||
except Exception as err:
|
except IndexError:
|
||||||
self.Logs.error(f'{err}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
|
|
||||||
|
|
||||||
case 'part':
|
case 'part':
|
||||||
try:
|
try:
|
||||||
@@ -273,67 +231,66 @@ class Clone:
|
|||||||
if option.lower() == 'all':
|
if option.lower() == 'all':
|
||||||
|
|
||||||
for clone in self.Clone.UID_CLONE_DB:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
||||||
|
|
||||||
elif self.Clone.group_exists(option):
|
elif self.Clone.group_exists(option):
|
||||||
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||||
|
|
||||||
if len(list_of_clones_in_group) > 0:
|
if len(list_of_clones_in_group) > 0:
|
||||||
self.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}")
|
self.ctx.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}")
|
||||||
|
|
||||||
for clone in list_of_clones_in_group:
|
for clone in list_of_clones_in_group:
|
||||||
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if self.Clone.nickname_exists(option):
|
if self.Clone.nickname_exists(option):
|
||||||
clone_uid = self.Clone.get_uid(option)
|
clone_uid = self.Clone.get_uid(option)
|
||||||
if not clone_uid is None:
|
if not clone_uid is None:
|
||||||
self.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False)
|
await self.ctx.Irc.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False)
|
||||||
|
|
||||||
except Exception as err:
|
except IndexError:
|
||||||
self.Logs.error(f'{err}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
|
|
||||||
|
|
||||||
case 'list':
|
case 'list':
|
||||||
try:
|
try:
|
||||||
# Syntax. /msg defender clone list <group_name>
|
# Syntax. /msg defender clone list <group_name>
|
||||||
header = f" {'Nickname':<12}| {'Real name':<25}| {'Group name':<15}| {'Connected':<35}"
|
header = f" {'Nickname':<12}| {'Real name':<25}| {'Group name':<15}| {'Connected':<35}"
|
||||||
line = "-"*67
|
line = "-"*67
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header)
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=header)
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
||||||
group_name = cmd[2] if len(cmd) > 2 else None
|
group_name = cmd[2] if len(cmd) > 2 else None
|
||||||
|
|
||||||
if group_name is None:
|
if group_name is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(self.Clone.UID_CLONE_DB)}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
||||||
for clone_name in self.Clone.UID_CLONE_DB:
|
for clone_name in self.Clone.UID_CLONE_DB:
|
||||||
self.Protocol.send_notice(
|
await self.ctx.Irc.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f" {clone_name.nickname:<12}| {clone_name.realname:<25}| {clone_name.group:<15}| {clone_name.connected:<35}")
|
msg=f" {clone_name.nickname:<12}| {clone_name.realname:<25}| {clone_name.group:<15}| {clone_name.connected:<35}")
|
||||||
else:
|
else:
|
||||||
if not self.Clone.group_exists(group_name):
|
if not self.Clone.group_exists(group_name):
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This Group name doesn't exist!")
|
||||||
return None
|
return None
|
||||||
clones = self.Clone.get_clones_from_groupname(group_name)
|
clones = self.Clone.get_clones_from_groupname(group_name)
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Number of connected clones: {len(clones)}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {line}")
|
||||||
for clone in clones:
|
for clone in clones:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||||
msg=f" {clone.nickname:<12}| {clone.realname:<25}| {clone.group:<15}| {clone.connected:<35}")
|
msg=f" {clone.nickname:<12}| {clone.realname:<25}| {clone.group:<15}| {clone.connected:<35}")
|
||||||
except Exception as err:
|
except IndexError:
|
||||||
self.Logs.error(f'{err}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
|
||||||
|
|
||||||
case 'say':
|
case 'say':
|
||||||
try:
|
try:
|
||||||
# clone say clone_nickname #channel message
|
# clone say clone_nickname #channel message
|
||||||
clone_name = str(cmd[2])
|
clone_name = str(cmd[2])
|
||||||
clone_channel = str(cmd[3]) if self.Channel.is_valid_channel(str(cmd[3])) else None
|
clone_channel = str(cmd[3]) if self.ctx.Channel.is_valid_channel(str(cmd[3])) else None
|
||||||
|
|
||||||
final_message = ' '.join(cmd[4:])
|
final_message = ' '.join(cmd[4:])
|
||||||
|
|
||||||
if clone_channel is None or not self.Clone.nickname_exists(clone_name):
|
if clone_channel is None or not self.Clone.nickname_exists(clone_name):
|
||||||
self.Protocol.send_notice(
|
await self.ctx.Irc.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f"/msg {dnickname} clone say [clone_nickname] #channel message"
|
msg=f"/msg {dnickname} clone say [clone_nickname] #channel message"
|
||||||
@@ -341,24 +298,21 @@ class Clone:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if self.Clone.nickname_exists(clone_name):
|
if self.Clone.nickname_exists(clone_name):
|
||||||
self.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel)
|
||||||
|
|
||||||
except Exception as err:
|
except IndexError:
|
||||||
self.Logs.error(f'{err}')
|
await self.ctx.Irc.Protocol.send_notice(
|
||||||
self.Protocol.send_notice(
|
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f"/msg {dnickname} clone say [clone_nickname] #channel message"
|
msg=f"/msg {dnickname} clone say [clone_nickname] #channel message"
|
||||||
)
|
)
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list [group name]")
|
||||||
|
|
||||||
except IndexError as ie:
|
|
||||||
self.Logs.error(f'Index Error: {ie}')
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'General Error: {err}')
|
self.ctx.Logs.error(f'General Error: {err}', exc_info=True)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import asyncio
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from mods.clone.mod_clone import Clone
|
from mods.clone.mod_clone import Clone
|
||||||
|
|
||||||
def thread_connect_clones(uplink: 'Clone',
|
async def coro_connect_clones(uplink: 'Clone',
|
||||||
number_of_clones:int ,
|
number_of_clones:int ,
|
||||||
group: str = 'Default',
|
group: str = 'Default',
|
||||||
auto_remote_ip: bool = False,
|
auto_remote_ip: bool = False,
|
||||||
@@ -27,18 +28,18 @@ def thread_connect_clones(uplink: 'Clone',
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not clone.connected:
|
if not clone.connected:
|
||||||
uplink.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
await uplink.ctx.Irc.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
||||||
uplink.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.Config.CLONE_CHANNEL, password=uplink.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.ctx.Config.CLONE_CHANNEL, password=uplink.ctx.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
||||||
|
|
||||||
sleep(interval)
|
await asyncio.sleep(interval)
|
||||||
clone.connected = True
|
clone.connected = True
|
||||||
|
|
||||||
def thread_kill_clones(uplink: 'Clone'):
|
async def thread_kill_clones(uplink: 'Clone'):
|
||||||
|
|
||||||
clone_to_kill = uplink.Clone.UID_CLONE_DB.copy()
|
clone_to_kill = uplink.Clone.UID_CLONE_DB.copy()
|
||||||
|
|
||||||
for clone in clone_to_kill:
|
for clone in clone_to_kill:
|
||||||
uplink.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False)
|
await uplink.ctx.Irc.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False)
|
||||||
uplink.Clone.delete(clone.uid)
|
uplink.Clone.delete(clone.uid)
|
||||||
|
|
||||||
del clone_to_kill
|
del clone_to_kill
|
||||||
|
|||||||
@@ -125,8 +125,8 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
|
|||||||
"""
|
"""
|
||||||
faker = faker_instance
|
faker = faker_instance
|
||||||
|
|
||||||
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID)
|
uid = generate_uid_for_clone(faker, uplink.ctx.Config.SERVEUR_ID)
|
||||||
umodes = uplink.Config.CLONE_UMODES
|
umodes = uplink.ctx.Config.CLONE_UMODES
|
||||||
|
|
||||||
# Generate Username
|
# Generate Username
|
||||||
username = generate_username_for_clone(faker)
|
username = generate_username_for_clone(faker)
|
||||||
@@ -153,7 +153,7 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
|
|||||||
checkNickname = uplink.Clone.nickname_exists(nickname)
|
checkNickname = uplink.Clone.nickname_exists(nickname)
|
||||||
|
|
||||||
while checkUid:
|
while checkUid:
|
||||||
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID)
|
uid = generate_uid_for_clone(faker, uplink.ctx.Config.SERVEUR_ID)
|
||||||
checkUid = uplink.Clone.uid_exists(uid=uid)
|
checkUid = uplink.Clone.uid_exists(uid=uid)
|
||||||
|
|
||||||
clone = uplink.Schemas.MClone(
|
clone = uplink.Schemas.MClone(
|
||||||
@@ -174,27 +174,25 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None:
|
async def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None:
|
||||||
|
|
||||||
parser = uplink.Protocol.parse_privmsg(srvmsg)
|
senderObj, recieverObj, channel, message = uplink.ctx.Irc.Protocol.parse_privmsg(srvmsg)
|
||||||
uid_sender = uplink.Irc.Utils.clean_uid(parser.get('uid_sender', None))
|
|
||||||
senderObj = uplink.User.get_user(uid_sender)
|
|
||||||
|
|
||||||
if senderObj is not None:
|
if senderObj is not None:
|
||||||
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT:
|
if senderObj.hostname in uplink.ctx.Config.CLONE_LOG_HOST_EXEMPT:
|
||||||
return
|
return
|
||||||
senderMsg = parser.get('message', None)
|
senderMsg = message
|
||||||
clone_obj = uplink.Clone.get_clone(parser.get('uid_reciever', None))
|
clone_obj = recieverObj
|
||||||
|
|
||||||
if clone_obj is None:
|
if clone_obj is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if clone_obj.uid != uplink.Config.SERVICE_ID:
|
if clone_obj.uid != uplink.ctx.Config.SERVICE_ID:
|
||||||
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
|
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=clone_obj.uid,
|
nick_from=clone_obj.uid,
|
||||||
msg=final_message,
|
msg=final_message,
|
||||||
channel=uplink.Config.CLONE_CHANNEL
|
channel=uplink.ctx.Config.CLONE_CHANNEL
|
||||||
)
|
)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,243 +4,243 @@ if TYPE_CHECKING:
|
|||||||
from mods.command.mod_command import Command
|
from mods.command.mod_command import Command
|
||||||
|
|
||||||
|
|
||||||
def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None:
|
async def set_automode(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||||
|
|
||||||
command: str = str(cmd[0]).lower()
|
command: str = str(cmd[0]).lower()
|
||||||
option: str = str(cmd[1]).lower()
|
option: str = str(cmd[1]).lower()
|
||||||
allowed_modes: list[str] = uplink.Loader.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v']
|
allowed_modes: list[str] = uplink.ctx.Settings.PROTOCTL_PREFIX # ['q','a','o','h','v']
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
fromuser = client
|
fromuser = client
|
||||||
|
|
||||||
match option:
|
match option:
|
||||||
case 'set':
|
case 'set':
|
||||||
if len(cmd) < 5:
|
if len(cmd) < 5:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]")
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
nickname = str(cmd[2])
|
nickname = str(cmd[2])
|
||||||
mode = str(cmd[3])
|
mode = str(cmd[3])
|
||||||
chan: str = str(cmd[4]).lower() if uplink.Channel.is_valid_channel(cmd[4]) else None
|
chan: str = str(cmd[4]).lower() if uplink.ctx.Channel.is_valid_channel(cmd[4]) else None
|
||||||
sign = mode[0] if mode.startswith( ('+', '-')) else None
|
sign = mode[0] if mode.startswith( ('+', '-')) else None
|
||||||
clean_mode = mode[1:] if len(mode) > 0 else None
|
clean_mode = mode[1:] if len(mode) > 0 else None
|
||||||
|
|
||||||
if sign is None:
|
if sign is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if clean_mode not in allowed_modes:
|
if clean_mode not in allowed_modes:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if chan is None:
|
if chan is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
db_data: dict[str, str] = {"nickname": nickname, "channel": chan}
|
db_data: dict[str, str] = {"nickname": nickname, "channel": chan}
|
||||||
db_query = uplink.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data)
|
db_query = await uplink.ctx.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data)
|
||||||
db_result = db_query.fetchone()
|
db_result = db_query.fetchone()
|
||||||
|
|
||||||
if db_result is not None:
|
if db_result is not None:
|
||||||
if sign == '+':
|
if sign == '+':
|
||||||
db_data = {"updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
db_data = {"updated_on": uplink.ctx.Utils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
||||||
db_result = uplink.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel",
|
db_result = await uplink.ctx.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel",
|
||||||
params=db_data)
|
params=db_data)
|
||||||
if db_result.rowcount > 0:
|
if db_result.rowcount > 0:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {nickname} in {chan}")
|
||||||
elif sign == '-':
|
elif sign == '-':
|
||||||
db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"}
|
db_data = {"nickname": nickname, "channel": chan, "mode": f"+{clean_mode}"}
|
||||||
db_result = uplink.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode",
|
db_result = await uplink.ctx.Base.db_execute_query(query="DELETE FROM command_automode WHERE nickname = :nickname and channel = :channel and mode = :mode",
|
||||||
params=db_data)
|
params=db_data)
|
||||||
if db_result.rowcount > 0:
|
if db_result.rowcount > 0:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} deleted for {nickname} in {chan}")
|
||||||
else:
|
else:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The mode [{mode}] has not been found for {nickname} in channel {chan}")
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Instert a new automode
|
# Instert a new automode
|
||||||
if sign == '+':
|
if sign == '+':
|
||||||
db_data = {"created_on": uplink.MainUtils.get_sdatetime(), "updated_on": uplink.MainUtils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
db_data = {"created_on": uplink.ctx.Utils.get_sdatetime(), "updated_on": uplink.ctx.Utils.get_sdatetime(), "nickname": nickname, "channel": chan, "mode": mode}
|
||||||
db_query = uplink.Base.db_execute_query(
|
db_query = await uplink.ctx.Base.db_execute_query(
|
||||||
query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)",
|
query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)",
|
||||||
params=db_data
|
params=db_data
|
||||||
)
|
)
|
||||||
|
|
||||||
if db_query.rowcount > 0:
|
if db_query.rowcount > 0:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {nickname} in {chan}")
|
||||||
if uplink.Channel.is_user_present_in_channel(chan, uplink.User.get_uid(nickname)):
|
if uplink.ctx.Channel.is_user_present_in_channel(chan, uplink.ctx.User.get_uid(nickname)):
|
||||||
uplink.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {nickname}")
|
||||||
else:
|
else:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AUTOMODE {mode} cannot be added to {nickname} in {chan} because it doesn't exist")
|
||||||
|
|
||||||
case 'list':
|
case 'list':
|
||||||
db_query = uplink.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode")
|
db_query = await uplink.ctx.Base.db_execute_query("SELECT nickname, channel, mode FROM command_automode")
|
||||||
db_results = db_query.fetchall()
|
db_results = db_query.fetchall()
|
||||||
|
|
||||||
if not db_results:
|
if not db_results:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||||
msg="There is no automode to display.")
|
msg="There is no automode to display.")
|
||||||
|
|
||||||
for db_result in db_results:
|
for db_result in db_results:
|
||||||
db_nickname, db_channel, db_mode = db_result
|
db_nickname, db_channel, db_mode = db_result
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,
|
||||||
msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}")
|
msg=f"Nickname: {db_nickname} | Channel: {db_channel} | Mode: {db_mode}")
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} SET [nickname] [+/-mode] [#channel]")
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} LIST")
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"[AUTOMODES AVAILABLE] are {' / '.join(allowed_modes)}")
|
||||||
|
|
||||||
def set_deopall(uplink: 'Command', channel_name: str) -> None:
|
async def set_deopall(uplink: 'Command', channel_name: str) -> None:
|
||||||
|
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -o")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_devoiceall(uplink: 'Command', channel_name: str) -> None:
|
async def set_devoiceall(uplink: 'Command', channel_name: str) -> None:
|
||||||
|
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
uplink.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} SVSMODE {channel_name} -v")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None:
|
async def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal['+', '-'], pmode: str) -> None:
|
||||||
|
|
||||||
chan_info = uplink.Channel.get_channel(channel_name)
|
chan_info = uplink.ctx.Channel.get_channel(channel_name)
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
set_mode = pmode
|
set_mode = pmode
|
||||||
mode:str = ''
|
mode:str = ''
|
||||||
users:str = ''
|
users:str = ''
|
||||||
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||||
|
|
||||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}")
|
||||||
for uid in uids_split:
|
for uid in uids_split:
|
||||||
for i in range(0, len(uid)):
|
for i in range(0, len(uid)):
|
||||||
mode += set_mode
|
mode += set_mode
|
||||||
users += f'{uplink.User.get_nickname(uplink.MainUtils.clean_uid(uid[i]))} '
|
users += f'{uplink.ctx.User.get_nickname(uplink.ctx.Utils.clean_uid(uid[i]))} '
|
||||||
if i == len(uid) - 1:
|
if i == len(uid) - 1:
|
||||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{mode} {users}")
|
||||||
mode = ''
|
mode = ''
|
||||||
users = ''
|
users = ''
|
||||||
|
|
||||||
def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None:
|
async def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str], client: str, mode: str) -> None:
|
||||||
|
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
if channel_name is None:
|
if channel_name is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {mode} [#SALON] [NICKNAME]")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if len(cmd) == 1:
|
if len(cmd) == 1:
|
||||||
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}")
|
# await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}")
|
||||||
uplink.Protocol.send_set_mode(mode, nickname=client, channel_name=channel_name)
|
await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=client, channel_name=channel_name)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# deop nickname
|
# deop nickname
|
||||||
if len(cmd) == 2:
|
if len(cmd) == 2:
|
||||||
nickname = cmd[1]
|
nickname = cmd[1]
|
||||||
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
# await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
||||||
uplink.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name)
|
await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
nickname = cmd[2]
|
nickname = cmd[2]
|
||||||
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
# await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
||||||
uplink.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name)
|
await uplink.ctx.Irc.Protocol.send_set_mode(mode, nickname=nickname, channel_name=channel_name)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None:
|
async def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None:
|
||||||
|
|
||||||
command = str(cmd[0])
|
command = str(cmd[0])
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
|
||||||
|
|
||||||
if sentchannel is None:
|
if sentchannel is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON] [NICKNAME]")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
nickname = cmd[2]
|
nickname = cmd[2]
|
||||||
|
|
||||||
uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {sentchannel} {action}b {nickname}!*@*")
|
||||||
uplink.Logs.debug(f'{client} has banned {nickname} from {sentchannel}')
|
uplink.ctx.Logs.debug(f'{client} has banned {nickname} from {sentchannel}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None:
|
async def set_kick(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||||
|
|
||||||
command = str(cmd[0])
|
command = str(cmd[0])
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
|
|
||||||
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
|
||||||
if sentchannel is None:
|
if sentchannel is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
nickname = cmd[2]
|
nickname = cmd[2]
|
||||||
final_reason = ' '.join(cmd[3:])
|
final_reason = ' '.join(cmd[3:])
|
||||||
|
|
||||||
uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
||||||
uplink.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}')
|
uplink.ctx.Logs.debug(f'{client} has kicked {nickname} from {sentchannel} : {final_reason}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None:
|
async def set_kickban(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||||
|
|
||||||
command = str(cmd[0])
|
command = str(cmd[0])
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
|
|
||||||
sentchannel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
sentchannel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
|
||||||
if sentchannel is None:
|
if sentchannel is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command} [#SALON] [NICKNAME]")
|
||||||
return False
|
return False
|
||||||
nickname = cmd[2]
|
nickname = cmd[2]
|
||||||
final_reason = ' '.join(cmd[3:])
|
final_reason = ' '.join(cmd[3:])
|
||||||
|
|
||||||
uplink.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} KICK {sentchannel} {nickname} {final_reason}")
|
||||||
uplink.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {sentchannel} +b {nickname}!*@*")
|
||||||
uplink.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}')
|
uplink.ctx.Logs.debug(f'{client} has kicked and banned {nickname} from {sentchannel} : {final_reason}')
|
||||||
|
|
||||||
def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
|
async def set_assign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||||
|
|
||||||
if len(cmd) < 2:
|
if len(cmd) < 2:
|
||||||
raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter")
|
raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter")
|
||||||
|
|
||||||
command = str(cmd[0])
|
command = str(cmd[0])
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
sent_channel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
|
||||||
if sent_channel is None:
|
if sent_channel is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}')
|
# self.Protocol.send2socket(f':{service_id} JOIN {sent_channel}')
|
||||||
uplink.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel)
|
await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname,channel=sent_channel)
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has joined {sent_channel}")
|
||||||
uplink.Channel.db_query_channel('add', uplink.module_name, sent_channel)
|
await uplink.ctx.Channel.db_query_channel('add', uplink.module_name, sent_channel)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
|
async def set_unassign_channel_to_service(uplink: 'Command', cmd: list[str], client: str) -> None:
|
||||||
|
|
||||||
if len(cmd) < 2:
|
if len(cmd) < 2:
|
||||||
raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter")
|
raise IndexError(f"{cmd[0].upper()} is expecting the channel parameter")
|
||||||
|
|
||||||
command = str(cmd[0])
|
command = str(cmd[0])
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
dchanlog = uplink.Config.SERVICE_CHANLOG
|
dchanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
|
|
||||||
sent_channel = str(cmd[1]) if uplink.Channel.is_valid_channel(cmd[1]) else None
|
sent_channel = str(cmd[1]) if uplink.ctx.Channel.is_valid_channel(cmd[1]) else None
|
||||||
if sent_channel is None:
|
if sent_channel is None:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Right command : /msg {dnickname} {command.upper()} [#SALON]")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if sent_channel == dchanlog:
|
if sent_channel == dchanlog:
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f"[!] CAN'T LEFT {sent_channel} AS IT IS LOG CHANNEL [!]")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
uplink.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel)
|
await uplink.ctx.Irc.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel)
|
||||||
uplink.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}")
|
await uplink.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=client, msg=f" Has left {sent_channel}")
|
||||||
|
|
||||||
uplink.Channel.db_query_channel('del', uplink.module_name, sent_channel)
|
await uplink.ctx.Channel.db_query_channel('del', uplink.module_name, sent_channel)
|
||||||
return None
|
return None
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ class ModConfModel(MainModel):
|
|||||||
autolimit: int = 0
|
autolimit: int = 0
|
||||||
autolimit_amount: int = 3
|
autolimit_amount: int = 3
|
||||||
autolimit_interval: int = 3
|
autolimit_interval: int = 3
|
||||||
|
sentinel: int = 0
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FloodUser(MainModel):
|
class FloodUser(MainModel):
|
||||||
|
|||||||
@@ -1,115 +1,116 @@
|
|||||||
|
import asyncio
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from mods.defender.mod_defender import Defender
|
from mods.defender.mod_defender import Defender
|
||||||
|
|
||||||
def thread_apply_reputation_sanctions(uplink: 'Defender'):
|
async def coro_apply_reputation_sanctions(uplink: 'Defender'):
|
||||||
while uplink.reputationTimer_isRunning:
|
while uplink.reputationTimer_isRunning:
|
||||||
uplink.Utils.action_apply_reputation_santions(uplink)
|
await uplink.mod_utils.action_apply_reputation_santions(uplink)
|
||||||
sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
def thread_cloudfilt_scan(uplink: 'Defender'):
|
async def coro_cloudfilt_scan(uplink: 'Defender'):
|
||||||
|
|
||||||
while uplink.cloudfilt_isRunning:
|
while uplink.cloudfilt_isRunning:
|
||||||
list_to_remove:list = []
|
list_to_remove:list = []
|
||||||
for user in uplink.Schemas.DB_CLOUDFILT_USERS:
|
for user in uplink.Schemas.DB_CLOUDFILT_USERS:
|
||||||
uplink.Utils.action_scan_client_with_cloudfilt(uplink, user)
|
uplink.mod_utils.action_scan_client_with_cloudfilt(uplink, user)
|
||||||
list_to_remove.append(user)
|
list_to_remove.append(user)
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
for user_model in list_to_remove:
|
for user_model in list_to_remove:
|
||||||
uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model)
|
uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model)
|
||||||
|
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def thread_freeipapi_scan(uplink: 'Defender'):
|
async def coro_freeipapi_scan(uplink: 'Defender'):
|
||||||
|
|
||||||
while uplink.freeipapi_isRunning:
|
while uplink.freeipapi_isRunning:
|
||||||
|
|
||||||
list_to_remove: list = []
|
list_to_remove: list = []
|
||||||
for user in uplink.Schemas.DB_FREEIPAPI_USERS:
|
for user in uplink.Schemas.DB_FREEIPAPI_USERS:
|
||||||
uplink.Utils.action_scan_client_with_freeipapi(uplink, user)
|
uplink.mod_utils.action_scan_client_with_freeipapi(uplink, user)
|
||||||
list_to_remove.append(user)
|
list_to_remove.append(user)
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
for user_model in list_to_remove:
|
for user_model in list_to_remove:
|
||||||
uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model)
|
uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model)
|
||||||
|
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def thread_abuseipdb_scan(uplink: 'Defender'):
|
async def coro_abuseipdb_scan(uplink: 'Defender'):
|
||||||
|
|
||||||
while uplink.abuseipdb_isRunning:
|
while uplink.abuseipdb_isRunning:
|
||||||
|
|
||||||
list_to_remove: list = []
|
list_to_remove: list = []
|
||||||
for user in uplink.Schemas.DB_ABUSEIPDB_USERS:
|
for user in uplink.Schemas.DB_ABUSEIPDB_USERS:
|
||||||
uplink.Utils.action_scan_client_with_abuseipdb(uplink, user)
|
uplink.mod_utils.action_scan_client_with_abuseipdb(uplink, user)
|
||||||
list_to_remove.append(user)
|
list_to_remove.append(user)
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
for user_model in list_to_remove:
|
for user_model in list_to_remove:
|
||||||
uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model)
|
uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model)
|
||||||
|
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def thread_local_scan(uplink: 'Defender'):
|
async def coro_local_scan(uplink: 'Defender'):
|
||||||
|
|
||||||
while uplink.localscan_isRunning:
|
while uplink.localscan_isRunning:
|
||||||
list_to_remove:list = []
|
list_to_remove:list = []
|
||||||
for user in uplink.Schemas.DB_LOCALSCAN_USERS:
|
for user in uplink.Schemas.DB_LOCALSCAN_USERS:
|
||||||
uplink.Utils.action_scan_client_with_local_socket(uplink, user)
|
uplink.mod_utils.action_scan_client_with_local_socket(uplink, user)
|
||||||
list_to_remove.append(user)
|
list_to_remove.append(user)
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
for user_model in list_to_remove:
|
for user_model in list_to_remove:
|
||||||
uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model)
|
uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model)
|
||||||
|
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def thread_psutil_scan(uplink: 'Defender'):
|
async def coro_psutil_scan(uplink: 'Defender'):
|
||||||
|
|
||||||
while uplink.psutil_isRunning:
|
while uplink.psutil_isRunning:
|
||||||
|
|
||||||
list_to_remove:list = []
|
list_to_remove:list = []
|
||||||
for user in uplink.Schemas.DB_PSUTIL_USERS:
|
for user in uplink.Schemas.DB_PSUTIL_USERS:
|
||||||
uplink.Utils.action_scan_client_with_psutil(uplink, user)
|
uplink.mod_utils.action_scan_client_with_psutil(uplink, user)
|
||||||
list_to_remove.append(user)
|
list_to_remove.append(user)
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
for user_model in list_to_remove:
|
for user_model in list_to_remove:
|
||||||
uplink.Schemas.DB_PSUTIL_USERS.remove(user_model)
|
uplink.Schemas.DB_PSUTIL_USERS.remove(user_model)
|
||||||
|
|
||||||
sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def thread_autolimit(uplink: 'Defender'):
|
async def coro_autolimit(uplink: 'Defender'):
|
||||||
|
|
||||||
if uplink.ModConfig.autolimit == 0:
|
if uplink.mod_config.autolimit == 0:
|
||||||
uplink.Logs.debug("autolimit deactivated ... canceling the thread")
|
uplink.ctx.Logs.debug("autolimit deactivated ... canceling the thread")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
while uplink.Irc.autolimit_started:
|
while uplink.ctx.Irc.autolimit_started:
|
||||||
sleep(0.2)
|
await asyncio.sleep(0.2)
|
||||||
|
|
||||||
uplink.Irc.autolimit_started = True
|
uplink.ctx.Irc.autolimit_started = True
|
||||||
init_amount = uplink.ModConfig.autolimit_amount
|
init_amount = uplink.mod_config.autolimit_amount
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
INIT = 1
|
INIT = 1
|
||||||
|
|
||||||
# Copy Channels to a list of dict
|
# Copy Channels to a list of dict
|
||||||
chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in uplink.Channel.UID_CHANNEL_DB]
|
chanObj_copy: list[dict[str, int]] = [{"name": c.name, "uids_count": len(c.uids)} for c in uplink.ctx.Channel.UID_CHANNEL_DB]
|
||||||
chan_list: list[str] = [c.name for c in uplink.Channel.UID_CHANNEL_DB]
|
chan_list: list[str] = [c.name for c in uplink.ctx.Channel.UID_CHANNEL_DB]
|
||||||
|
|
||||||
while uplink.autolimit_isRunning:
|
while uplink.autolimit_isRunning:
|
||||||
|
|
||||||
if uplink.ModConfig.autolimit == 0:
|
if uplink.mod_config.autolimit == 0:
|
||||||
uplink.Logs.debug("autolimit deactivated ... stopping the current thread")
|
uplink.ctx.Logs.debug("autolimit deactivated ... stopping the current thread")
|
||||||
break
|
break
|
||||||
|
|
||||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
for chan_copy in chanObj_copy:
|
for chan_copy in chanObj_copy:
|
||||||
if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]:
|
if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]:
|
||||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}")
|
await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
|
||||||
chan_copy["uids_count"] = len(chan.uids)
|
chan_copy["uids_count"] = len(chan.uids)
|
||||||
|
|
||||||
if chan.name not in chan_list:
|
if chan.name not in chan_list:
|
||||||
@@ -117,51 +118,55 @@ def thread_autolimit(uplink: 'Defender'):
|
|||||||
chanObj_copy.append({"name": chan.name, "uids_count": 0})
|
chanObj_copy.append({"name": chan.name, "uids_count": 0})
|
||||||
|
|
||||||
# Verifier si un salon a été vidé
|
# Verifier si un salon a été vidé
|
||||||
current_chan_in_list = [d.name for d in uplink.Channel.UID_CHANNEL_DB]
|
current_chan_in_list = [d.name for d in uplink.ctx.Channel.UID_CHANNEL_DB]
|
||||||
for c in chan_list:
|
for c in chan_list:
|
||||||
if c not in current_chan_in_list:
|
if c not in current_chan_in_list:
|
||||||
chan_list.remove(c)
|
chan_list.remove(c)
|
||||||
|
|
||||||
# Si c'est la premiere execution
|
# Si c'est la premiere execution
|
||||||
if INIT == 1:
|
if INIT == 1:
|
||||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}")
|
await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
|
||||||
|
|
||||||
# Si le nouveau amount est différent de l'initial
|
# Si le nouveau amount est différent de l'initial
|
||||||
if init_amount != uplink.ModConfig.autolimit_amount:
|
if init_amount != uplink.mod_config.autolimit_amount:
|
||||||
init_amount = uplink.ModConfig.autolimit_amount
|
init_amount = uplink.mod_config.autolimit_amount
|
||||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.ModConfig.autolimit_amount}")
|
await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
|
||||||
|
|
||||||
INIT = 0
|
INIT = 0
|
||||||
|
|
||||||
if uplink.autolimit_isRunning:
|
if uplink.autolimit_isRunning:
|
||||||
sleep(uplink.ModConfig.autolimit_interval)
|
await asyncio.sleep(uplink.mod_config.autolimit_interval)
|
||||||
|
|
||||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
p.send2socket(f":{uplink.Config.SERVICE_ID} MODE {chan.name} -l")
|
# await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} -l")
|
||||||
|
await p.send_set_mode('-l', channel_name=chan.name)
|
||||||
|
|
||||||
uplink.Irc.autolimit_started = False
|
uplink.ctx.Irc.autolimit_started = False
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def timer_release_mode_mute(uplink: 'Defender', action: str, channel: str):
|
async def coro_release_mode_mute(uplink: 'Defender', action: str, channel: str):
|
||||||
"""DO NOT EXECUTE THIS FUNCTION WITHOUT THREADING
|
"""DO NOT EXECUTE THIS FUNCTION DIRECTLY
|
||||||
|
IT WILL BLOCK THE PROCESS
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
action (str): _description_
|
action (str): mode-m
|
||||||
channel (str): The related channel
|
channel (str): The related channel
|
||||||
|
|
||||||
"""
|
"""
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
|
timeout = uplink.mod_config.flood_timer
|
||||||
|
await asyncio.sleep(timeout)
|
||||||
|
|
||||||
if not uplink.Channel.is_valid_channel(channel):
|
if not uplink.ctx.Channel.is_valid_channel(channel):
|
||||||
uplink.Logs.debug(f"Channel is not valid {channel}")
|
uplink.ctx.Logs.debug(f"Channel is not valid {channel}")
|
||||||
return
|
return
|
||||||
|
|
||||||
match action:
|
match action:
|
||||||
case 'mode-m':
|
case 'mode-m':
|
||||||
# Action -m sur le salon
|
# Action -m sur le salon
|
||||||
uplink.Protocol.send2socket(f":{service_id} MODE {channel} -m")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel} -m")
|
||||||
case _:
|
case _:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Optional
|
|||||||
from mods.defender.schemas import FloodUser
|
from mods.defender.schemas import FloodUser
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
from core.definition import MUser
|
from core.definition import MUser
|
||||||
from mods.defender.mod_defender import Defender
|
from mods.defender.mod_defender import Defender
|
||||||
|
|
||||||
@@ -28,10 +29,10 @@ def handle_on_reputation(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Possibilité de déclancher les bans a ce niveau.
|
# Possibilité de déclancher les bans a ce niveau.
|
||||||
if not uplink.Base.is_valid_ip(ip):
|
if not uplink.ctx.Base.is_valid_ip(ip):
|
||||||
return
|
return
|
||||||
|
|
||||||
def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
|
async def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""_summary_
|
"""_summary_
|
||||||
>>> srvmsg = ['@unrealircd.org/...', ':001C0MF01', 'MODE', '#services', '+l', '1']
|
>>> srvmsg = ['@unrealircd.org/...', ':001C0MF01', 'MODE', '#services', '+l', '1']
|
||||||
>>> srvmsg = ['...', ':001XSCU0Q', 'MODE', '#jail', '+b', '~security-group:unknown-users']
|
>>> srvmsg = ['...', ':001XSCU0Q', 'MODE', '#jail', '+b', '~security-group:unknown-users']
|
||||||
@@ -40,10 +41,10 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
srvmsg (list[str]): The Server MSG
|
srvmsg (list[str]): The Server MSG
|
||||||
confmodel (ModConfModel): The Module Configuration
|
confmodel (ModConfModel): The Module Configuration
|
||||||
"""
|
"""
|
||||||
irc = uplink.Irc
|
irc = uplink.ctx.Irc
|
||||||
gconfig = uplink.Config
|
gconfig = uplink.ctx.Config
|
||||||
p = uplink.Protocol
|
p = irc.Protocol
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
channel = str(srvmsg[3])
|
channel = str(srvmsg[3])
|
||||||
mode = str(srvmsg[4])
|
mode = str(srvmsg[4])
|
||||||
@@ -52,20 +53,25 @@ def handle_on_mode(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
|
|
||||||
if confmodel.autolimit == 1:
|
if confmodel.autolimit == 1:
|
||||||
if mode == '+l' or mode == '-l':
|
if mode == '+l' or mode == '-l':
|
||||||
chan = irc.Channel.get_channel(channel)
|
chan = uplink.ctx.Channel.get_channel(channel)
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}")
|
await p.send2socket(f":{gconfig.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + confmodel.autolimit_amount}")
|
||||||
|
|
||||||
if gconfig.SALON_JAIL == channel:
|
if gconfig.SALON_JAIL == channel:
|
||||||
if mode == '+b' and group_to_unban in group_to_check:
|
if mode == '+b' and group_to_unban in group_to_check:
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users")
|
await p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -b ~security-group:unknown-users")
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
await p.send2socket(f":{gconfig.SERVICE_ID} MODE {gconfig.SALON_JAIL} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
||||||
|
|
||||||
def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]):
|
async def handle_on_privmsg(uplink: 'Defender', srvmsg: list[str]):
|
||||||
# ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg']
|
# ['@mtag....',':python', 'PRIVMSG', '#defender', ':zefzefzregreg', 'regg', 'aerg']
|
||||||
action_on_flood(uplink, srvmsg)
|
|
||||||
|
sender, reciever, channel, message = uplink.ctx.Irc.Protocol.parse_privmsg(srvmsg)
|
||||||
|
if uplink.mod_config.sentinel == 1 and channel.name != uplink.ctx.Config.SERVICE_CHANLOG:
|
||||||
|
await uplink.ctx.Irc.Protocol.send_priv_msg(uplink.ctx.Config.SERVICE_NICKNAME, f"{sender.nickname} say on {channel.name}: {' '.join(message)}", uplink.ctx.Config.SERVICE_CHANLOG)
|
||||||
|
|
||||||
|
await action_on_flood(uplink, srvmsg)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
|
async def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""If Joining a new channel, it applies group bans.
|
"""If Joining a new channel, it applies group bans.
|
||||||
|
|
||||||
>>> srvmsg = ['@msgid..', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL']
|
>>> srvmsg = ['@msgid..', ':001', 'SJOIN', '1702138958', '#welcome', ':0015L1AHL']
|
||||||
@@ -75,37 +81,37 @@ def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
srvmsg (list[str]): The Server MSG
|
srvmsg (list[str]): The Server MSG
|
||||||
confmodel (ModConfModel): The Module Configuration
|
confmodel (ModConfModel): The Module Configuration
|
||||||
"""
|
"""
|
||||||
irc = uplink.Irc
|
irc = uplink.ctx.Irc
|
||||||
p = irc.Protocol
|
p = irc.Protocol
|
||||||
gconfig = uplink.Config
|
gconfig = uplink.ctx.Config
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
parsed_chan = srvmsg[4] if irc.Channel.is_valid_channel(srvmsg[4]) else None
|
parsed_chan = srvmsg[4] if uplink.ctx.Channel.is_valid_channel(srvmsg[4]) else None
|
||||||
parsed_UID = uplink.Loader.Utils.clean_uid(srvmsg[5])
|
parsed_UID = uplink.ctx.Utils.clean_uid(srvmsg[5])
|
||||||
|
|
||||||
if parsed_chan is None or parsed_UID is None:
|
if parsed_chan is None or parsed_UID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if confmodel.reputation == 1:
|
if confmodel.reputation == 1:
|
||||||
get_reputation = irc.Reputation.get_reputation(parsed_UID)
|
get_reputation = uplink.ctx.Reputation.get_reputation(parsed_UID)
|
||||||
|
|
||||||
if parsed_chan != gconfig.SALON_JAIL:
|
if parsed_chan != gconfig.SALON_JAIL:
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users")
|
await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users")
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
||||||
|
|
||||||
if get_reputation is not None:
|
if get_reputation is not None:
|
||||||
isWebirc = get_reputation.isWebirc
|
isWebirc = get_reputation.isWebirc
|
||||||
|
|
||||||
if not isWebirc:
|
if not isWebirc:
|
||||||
if parsed_chan != gconfig.SALON_JAIL:
|
if parsed_chan != gconfig.SALON_JAIL:
|
||||||
p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan)
|
await p.send_sapart(nick_to_sapart=get_reputation.nickname, channel_name=parsed_chan)
|
||||||
|
|
||||||
if confmodel.reputation_ban_all_chan == 1 and not isWebirc:
|
if confmodel.reputation_ban_all_chan == 1 and not isWebirc:
|
||||||
if parsed_chan != gconfig.SALON_JAIL:
|
if parsed_chan != gconfig.SALON_JAIL:
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*")
|
await p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b {get_reputation.nickname}!*@*")
|
||||||
p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}")
|
await p.send2socket(f":{gconfig.SERVICE_ID} KICK {parsed_chan} {get_reputation.nickname}")
|
||||||
|
|
||||||
irc.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}')
|
uplink.ctx.Logs.debug(f'SJOIN parsed_uid : {parsed_UID}')
|
||||||
|
|
||||||
def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
|
def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""Handling SLOG messages
|
"""Handling SLOG messages
|
||||||
@@ -117,27 +123,27 @@ def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
"""
|
"""
|
||||||
['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)']
|
['@unrealircd...', ':001', 'SLOG', 'info', 'blacklist', 'BLACKLIST_HIT', ':[Blacklist]', 'IP', '162.x.x.x', 'matches', 'blacklist', 'dronebl', '(dnsbl.dronebl.org/reply=6)']
|
||||||
|
|
||||||
if not uplink.Base.is_valid_ip(srvmsg[8]):
|
if not uplink.ctx.Base.is_valid_ip(srvmsg[8]):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# if self.ModConfig.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
# if self.mod_config.local_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||||
# self.localscan_remote_ip.append(cmd[7])
|
# self.localscan_remote_ip.append(cmd[7])
|
||||||
|
|
||||||
# if self.ModConfig.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
# if self.mod_config.psutil_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||||
# self.psutil_remote_ip.append(cmd[7])
|
# self.psutil_remote_ip.append(cmd[7])
|
||||||
|
|
||||||
# if self.ModConfig.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
# if self.mod_config.abuseipdb_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||||
# self.abuseipdb_remote_ip.append(cmd[7])
|
# self.abuseipdb_remote_ip.append(cmd[7])
|
||||||
|
|
||||||
# if self.ModConfig.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
# if self.mod_config.freeipapi_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||||
# self.freeipapi_remote_ip.append(cmd[7])
|
# self.freeipapi_remote_ip.append(cmd[7])
|
||||||
|
|
||||||
# if self.ModConfig.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
# if self.mod_config.cloudfilt_scan == 1 and not cmd[7] in self.Config.WHITELISTED_IP:
|
||||||
# self.cloudfilt_remote_ip.append(cmd[7])
|
# self.cloudfilt_remote_ip.append(cmd[7])
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
async def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""Handle nickname changes.
|
"""Handle nickname changes.
|
||||||
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712']
|
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712']
|
||||||
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
|
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
|
||||||
@@ -146,59 +152,67 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
srvmsg (list[str]): The Server MSG
|
srvmsg (list[str]): The Server MSG
|
||||||
confmodel (ModConfModel): The Module Configuration
|
confmodel (ModConfModel): The Module Configuration
|
||||||
"""
|
"""
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
parser = p.parse_nick(srvmsg)
|
u, new_nickname, timestamp = p.parse_nick(srvmsg)
|
||||||
uid = uplink.Loader.Utils.clean_uid(parser.get('uid', None))
|
|
||||||
confmodel = uplink.ModConfig
|
|
||||||
|
|
||||||
get_reputation = uplink.Reputation.get_reputation(uid)
|
if u is None:
|
||||||
jail_salon = uplink.Config.SALON_JAIL
|
uplink.ctx.Logs.error(f"[USER OBJ ERROR {timestamp}] - {srvmsg}")
|
||||||
service_id = uplink.Config.SERVICE_ID
|
return None
|
||||||
|
|
||||||
|
uid = u.uid
|
||||||
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
|
get_reputation = uplink.ctx.Reputation.get_reputation(uid)
|
||||||
|
jail_salon = uplink.ctx.Config.SALON_JAIL
|
||||||
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
|
|
||||||
if get_reputation is None:
|
if get_reputation is None:
|
||||||
uplink.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass')
|
uplink.ctx.Logs.debug(f'This UID: {uid} is not listed in the reputation dataclass')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Update the new nickname
|
# Update the new nickname
|
||||||
oldnick = get_reputation.nickname
|
oldnick = get_reputation.nickname
|
||||||
newnickname = parser.get('newnickname', None)
|
newnickname = new_nickname
|
||||||
get_reputation.nickname = newnickname
|
get_reputation.nickname = newnickname
|
||||||
|
|
||||||
# If ban in all channel is ON then unban old nickname an ban the new nickname
|
# If ban in all channel is ON then unban old nickname an ban the new nickname
|
||||||
if confmodel.reputation_ban_all_chan == 1:
|
if confmodel.reputation_ban_all_chan == 1:
|
||||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
if chan.name != jail_salon:
|
if chan.name != jail_salon:
|
||||||
p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*")
|
await p.send2socket(f":{service_id} MODE {chan.name} -b {oldnick}!*@*")
|
||||||
p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*")
|
await p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*")
|
||||||
|
|
||||||
def handle_on_quit(uplink: 'Defender', srvmsg: list[str]):
|
async def handle_on_quit(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""Handle on quit message
|
"""Handle on quit message
|
||||||
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'QUIT', ':Quit:', 'quit message']
|
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'QUIT', ':Quit:', 'quit message']
|
||||||
Args:
|
Args:
|
||||||
uplink (Irc): The Defender Module instance
|
uplink (Irc): The Defender Module instance
|
||||||
srvmsg (list[str]): The Server MSG
|
srvmsg (list[str]): The Server MSG
|
||||||
"""
|
"""
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
parser = p.parse_quit(srvmsg)
|
userobj, reason = p.parse_quit(srvmsg)
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan)
|
if userobj is None:
|
||||||
final_UID = uplink.Loader.Utils.clean_uid(str(parser.get('uid', None)))
|
uplink.ctx.Logs.debug(f"This UID do not exist anymore: {srvmsg}")
|
||||||
jail_salon = uplink.Config.SALON_JAIL
|
return None
|
||||||
service_id = uplink.Config.SERVICE_ID
|
|
||||||
get_user_reputation = uplink.Reputation.get_reputation(final_UID)
|
ban_all_chan = uplink.ctx.Base.int_if_possible(confmodel.reputation_ban_all_chan)
|
||||||
|
jail_salon = uplink.ctx.Config.SALON_JAIL
|
||||||
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
|
get_user_reputation = uplink.ctx.Reputation.get_reputation(userobj.uid)
|
||||||
|
|
||||||
if get_user_reputation is not None:
|
if get_user_reputation is not None:
|
||||||
final_nickname = get_user_reputation.nickname
|
final_nickname = get_user_reputation.nickname
|
||||||
for chan in uplink.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
if chan.name != jail_salon and ban_all_chan == 1:
|
if chan.name != jail_salon and ban_all_chan == 1:
|
||||||
p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*")
|
await p.send2socket(f":{service_id} MODE {chan.name} -b {final_nickname}!*@*")
|
||||||
uplink.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}")
|
uplink.ctx.Logs.debug(f"Mode -b {final_nickname} on channel {chan.name}")
|
||||||
|
|
||||||
uplink.Reputation.delete(final_UID)
|
uplink.ctx.Reputation.delete(userobj.uid)
|
||||||
uplink.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB")
|
uplink.ctx.Logs.debug(f"Client {get_user_reputation.nickname} has been removed from Reputation local DB")
|
||||||
|
|
||||||
def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
async def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""_summary_
|
"""_summary_
|
||||||
>>> ['@s2s-md...', ':001', 'UID', 'nickname', '0', '1754675249', '...', '125-168-141-239.hostname.net', '001BAPN8M',
|
>>> ['@s2s-md...', ':001', 'UID', 'nickname', '0', '1754675249', '...', '125-168-141-239.hostname.net', '001BAPN8M',
|
||||||
'0', '+iwx', '*', '32001BBE.25ACEFE7.429FE90D.IP', 'ZA2ic7w==', ':realname']
|
'0', '+iwx', '*', '32001BBE.25ACEFE7.429FE90D.IP', 'ZA2ic7w==', ':realname']
|
||||||
@@ -207,20 +221,18 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
uplink (Defender): The Defender instance
|
uplink (Defender): The Defender instance
|
||||||
srvmsg (list[str]): The Server MSG
|
srvmsg (list[str]): The Server MSG
|
||||||
"""
|
"""
|
||||||
parser_uid = uplink.Protocol.parse_uid(srvmsg)
|
irc = uplink.ctx.Irc
|
||||||
gconfig = uplink.Config
|
_User = irc.Protocol.parse_uid(srvmsg)
|
||||||
irc = uplink.Irc
|
gconfig = uplink.ctx.Config
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
# If Init then do nothing
|
# If Init then do nothing
|
||||||
if gconfig.DEFENDER_INIT == 1:
|
if gconfig.DEFENDER_INIT == 1:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Get User information
|
# Get User information
|
||||||
_User = irc.User.get_user(parser_uid.get('uid', None))
|
|
||||||
|
|
||||||
if _User is None:
|
if _User is None:
|
||||||
irc.Logs.warning(f'This UID: [{parser_uid.get("uid", None)}] is not available please check why')
|
uplink.ctx.Logs.warning(f'Error when parsing UID', exc_info=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# If user is not service or IrcOp then scan them
|
# If user is not service or IrcOp then scan them
|
||||||
@@ -239,38 +251,38 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
if not match(r'^.*[S|o?].*$', _User.umodes):
|
if not match(r'^.*[S|o?].*$', _User.umodes):
|
||||||
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
|
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
|
||||||
# currentDateTime = self.Base.get_datetime()
|
# currentDateTime = self.Base.get_datetime()
|
||||||
irc.Reputation.insert(
|
uplink.ctx.Reputation.insert(
|
||||||
irc.Loader.Definition.MReputation(
|
uplink.ctx.Definition.MReputation(
|
||||||
**_User.to_dict(),
|
**_User.to_dict(),
|
||||||
secret_code=irc.Utils.generate_random_string(8)
|
secret_code=uplink.ctx.Utils.generate_random_string(8)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if irc.Reputation.is_exist(_User.uid):
|
if uplink.ctx.Reputation.is_exist(_User.uid):
|
||||||
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
|
if reputation_flag == 1 and _User.score_connexion <= reputation_seuil:
|
||||||
action_add_reputation_sanctions(uplink, _User.uid)
|
await action_add_reputation_sanctions(uplink, _User.uid)
|
||||||
irc.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})')
|
uplink.ctx.Logs.info(f'[REPUTATION] Reputation system ON (Nickname: {_User.nickname}, uid: {_User.uid})')
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# ACTION FUNCTIONS #
|
# ACTION FUNCTIONS #
|
||||||
####################
|
####################
|
||||||
# [:<sid>] UID <uid> <ts> <nick> <real-host> <displayed-host> <real-user> <ip> <signon> <modes> [<mode-parameters>]+ :<real>
|
# [:<sid>] UID <uid> <ts> <nick> <real-host> <displayed-host> <real-user> <ip> <signon> <modes> [<mode-parameters>]+ :<real>
|
||||||
# [:<sid>] UID nickname hopcount timestamp username hostname uid servicestamp umodes virthost cloakedhost ip :gecos
|
# [:<sid>] UID nickname hopcount timestamp username hostname uid servicestamp umodes virthost cloakedhost ip :gecos
|
||||||
def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
async def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
||||||
|
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
if confmodel.flood == 0:
|
if confmodel.flood == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
irc = uplink.Irc
|
irc = uplink.ctx.Irc
|
||||||
gconfig = uplink.Config
|
gconfig = uplink.ctx.Config
|
||||||
p = uplink.Protocol
|
p = irc.Protocol
|
||||||
flood_users = uplink.Schemas.DB_FLOOD_USERS
|
flood_users = uplink.Schemas.DB_FLOOD_USERS
|
||||||
|
|
||||||
user_trigger = str(srvmsg[1]).replace(':','')
|
user_trigger = str(srvmsg[1]).replace(':','')
|
||||||
channel = srvmsg[3]
|
channel = srvmsg[3]
|
||||||
User = irc.User.get_user(user_trigger)
|
User = uplink.ctx.User.get_user(user_trigger)
|
||||||
|
|
||||||
if User is None or not irc.Channel.is_valid_channel(channel_to_check=channel):
|
if User is None or not uplink.ctx.Channel.is_valid_channel(channel_to_check=channel):
|
||||||
return
|
return
|
||||||
|
|
||||||
flood_time = confmodel.flood_time
|
flood_time = confmodel.flood_time
|
||||||
@@ -283,7 +295,7 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
|
|
||||||
get_detected_uid = User.uid
|
get_detected_uid = User.uid
|
||||||
get_detected_nickname = User.nickname
|
get_detected_nickname = User.nickname
|
||||||
unixtime = irc.Utils.get_unixtime()
|
unixtime = uplink.ctx.Utils.get_unixtime()
|
||||||
get_diff_secondes = 0
|
get_diff_secondes = 0
|
||||||
|
|
||||||
def get_flood_user(uid: str) -> Optional[FloodUser]:
|
def get_flood_user(uid: str) -> Optional[FloodUser]:
|
||||||
@@ -304,29 +316,29 @@ def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
fu.nbr_msg = 0
|
fu.nbr_msg = 0
|
||||||
get_diff_secondes = unixtime - fu.first_msg_time
|
get_diff_secondes = unixtime - fu.first_msg_time
|
||||||
elif fu.nbr_msg > flood_message:
|
elif fu.nbr_msg > flood_message:
|
||||||
irc.Logs.info('system de flood detecté')
|
uplink.ctx.Logs.info('system de flood detecté')
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)",
|
msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
p.send2socket(f":{service_id} MODE {channel} +m")
|
await p.send2socket(f":{service_id} MODE {channel} +m")
|
||||||
irc.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}')
|
uplink.ctx.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}')
|
||||||
fu.nbr_msg = 0
|
fu.nbr_msg = 0
|
||||||
fu.first_msg_time = unixtime
|
fu.first_msg_time = unixtime
|
||||||
irc.Base.create_timer(flood_timer, dthreads.timer_release_mode_mute, (uplink, 'mode-m', channel))
|
uplink.ctx.Base.create_asynctask(dthreads.coro_release_mode_mute(uplink, 'mode-m', channel))
|
||||||
|
|
||||||
def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
||||||
|
|
||||||
irc = uplink.Irc
|
irc = uplink.ctx.Irc
|
||||||
gconfig = uplink.Config
|
gconfig = uplink.ctx.Config
|
||||||
p = uplink.Protocol
|
p = irc.Protocol
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
get_reputation = irc.Reputation.get_reputation(jailed_uid)
|
get_reputation = uplink.ctx.Reputation.get_reputation(jailed_uid)
|
||||||
|
|
||||||
if get_reputation is None:
|
if get_reputation is None:
|
||||||
irc.Logs.warning(f'UID {jailed_uid} has not been found')
|
uplink.ctx.Logs.warning(f'UID {jailed_uid} has not been found')
|
||||||
return
|
return
|
||||||
|
|
||||||
salon_logs = gconfig.SERVICE_CHANLOG
|
salon_logs = gconfig.SERVICE_CHANLOG
|
||||||
@@ -346,33 +358,33 @@ def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
|||||||
|
|
||||||
if not get_reputation.isWebirc:
|
if not get_reputation.isWebirc:
|
||||||
# Si le user ne vient pas de webIrc
|
# Si le user ne vient pas de webIrc
|
||||||
p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail)
|
await p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail)
|
||||||
p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME,
|
await p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME,
|
||||||
msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}",
|
msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}",
|
||||||
channel=salon_logs
|
channel=salon_logs
|
||||||
)
|
)
|
||||||
p.send_notice(
|
await p.send_notice(
|
||||||
nick_from=gconfig.SERVICE_NICKNAME,
|
nick_from=gconfig.SERVICE_NICKNAME,
|
||||||
nick_to=jailed_nickname,
|
nick_to=jailed_nickname,
|
||||||
msg=f"[{color_red} {jailed_nickname} {color_black}] : Merci de tapez la commande suivante {color_bold}{service_prefix}code {code}{color_bold}"
|
msg=f"[{color_red} {jailed_nickname} {color_black}] : Merci de tapez la commande suivante {color_bold}{service_prefix}code {code}{color_bold}"
|
||||||
)
|
)
|
||||||
if reputation_ban_all_chan == 1:
|
if reputation_ban_all_chan == 1:
|
||||||
for chan in irc.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
if chan.name != salon_jail:
|
if chan.name != salon_jail:
|
||||||
p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*")
|
await p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*")
|
||||||
p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}")
|
await p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}")
|
||||||
|
|
||||||
irc.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})")
|
uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})")
|
||||||
else:
|
else:
|
||||||
irc.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)")
|
uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} skipped (trusted or WebIRC)")
|
||||||
irc.Reputation.delete(jailed_uid)
|
uplink.ctx.Reputation.delete(jailed_uid)
|
||||||
|
|
||||||
def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
async def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
||||||
|
|
||||||
irc = uplink.Irc
|
irc = uplink.ctx.Irc
|
||||||
gconfig = uplink.Config
|
gconfig = uplink.ctx.Config
|
||||||
p = uplink.Protocol
|
p = irc.Protocol
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.mod_config
|
||||||
|
|
||||||
reputation_flag = confmodel.reputation
|
reputation_flag = confmodel.reputation
|
||||||
reputation_timer = confmodel.reputation_timer
|
reputation_timer = confmodel.reputation_timer
|
||||||
@@ -385,36 +397,36 @@ def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
|||||||
salon_jail = gconfig.SALON_JAIL
|
salon_jail = gconfig.SALON_JAIL
|
||||||
uid_to_clean = []
|
uid_to_clean = []
|
||||||
|
|
||||||
if reputation_flag == 0 or reputation_timer == 0:
|
if reputation_flag == 0 or reputation_timer == 0 or not uplink.ctx.Reputation.UID_REPUTATION_DB:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for user in irc.Reputation.UID_REPUTATION_DB:
|
for user in uplink.ctx.Reputation.UID_REPUTATION_DB:
|
||||||
if not user.isWebirc: # Si il ne vient pas de WebIRC
|
if not user.isWebirc: # Si il ne vient pas de WebIRC
|
||||||
if irc.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil):
|
if uplink.ctx.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil):
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=service_id,
|
nick_from=service_id,
|
||||||
msg=f"[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité",
|
msg=f"[{color_red} REPUTATION {nogc}] : Action sur {user.nickname} aprés {str(reputation_timer)} minutes d'inactivité",
|
||||||
channel=dchanlog
|
channel=dchanlog
|
||||||
)
|
)
|
||||||
p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code")
|
await p.send2socket(f":{service_id} KILL {user.nickname} After {str(reputation_timer)} minutes of inactivity you should reconnect and type the password code")
|
||||||
p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0")
|
await p.send2socket(f":{gconfig.SERVEUR_LINK} REPUTATION {user.remote_ip} 0")
|
||||||
|
|
||||||
irc.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity")
|
uplink.ctx.Logs.info(f"Nickname: {user.nickname} KILLED after {str(reputation_timer)} minutes of inactivity")
|
||||||
uid_to_clean.append(user.uid)
|
uid_to_clean.append(user.uid)
|
||||||
|
|
||||||
for uid in uid_to_clean:
|
for uid in uid_to_clean:
|
||||||
# Suppression des éléments dans {UID_DB} et {REPUTATION_DB}
|
# Suppression des éléments dans {UID_DB} et {REPUTATION_DB}
|
||||||
for chan in irc.Channel.UID_CHANNEL_DB:
|
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||||
if chan.name != salon_jail and ban_all_chan == 1:
|
if chan.name != salon_jail and ban_all_chan == 1:
|
||||||
get_user_reputation = irc.Reputation.get_reputation(uid)
|
get_user_reputation = uplink.ctx.Reputation.get_reputation(uid)
|
||||||
p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*")
|
await p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*")
|
||||||
|
|
||||||
# Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}.
|
# Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}.
|
||||||
irc.Channel.delete_user_from_all_channel(uid)
|
uplink.ctx.Channel.delete_user_from_all_channel(uid)
|
||||||
irc.Reputation.delete(uid)
|
uplink.ctx.Reputation.delete(uid)
|
||||||
irc.User.delete(uid)
|
uplink.ctx.User.delete(uid)
|
||||||
|
|
||||||
def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
async def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||||
"""Analyse l'ip avec cloudfilt
|
"""Analyse l'ip avec cloudfilt
|
||||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||||
Args:
|
Args:
|
||||||
@@ -429,19 +441,19 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
username = user_model.username
|
username = user_model.username
|
||||||
hostname = user_model.hostname
|
hostname = user_model.hostname
|
||||||
nickname = user_model.nickname
|
nickname = user_model.nickname
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
|
|
||||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||||
return None
|
return None
|
||||||
if uplink.ModConfig.cloudfilt_scan == 0:
|
if uplink.mod_config.cloudfilt_scan == 0:
|
||||||
return None
|
return None
|
||||||
if uplink.cloudfilt_key == '':
|
if uplink.cloudfilt_key == '':
|
||||||
return None
|
return None
|
||||||
|
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
service_chanlog = uplink.Config.SERVICE_CHANLOG
|
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
color_red = uplink.Config.COLORS.red
|
color_red = uplink.ctx.Config.COLORS.red
|
||||||
nogc = uplink.Config.COLORS.nogc
|
nogc = uplink.ctx.Config.COLORS.nogc
|
||||||
|
|
||||||
url = "https://developers18334.cloudfilt.com/"
|
url = "https://developers18334.cloudfilt.com/"
|
||||||
|
|
||||||
@@ -455,7 +467,7 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
decoded_response: dict = loads(response.text)
|
decoded_response: dict = loads(response.text)
|
||||||
status_code = response.status_code
|
status_code = response.status_code
|
||||||
if status_code != 200:
|
if status_code != 200:
|
||||||
uplink.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
|
uplink.ctx.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
|
||||||
return
|
return
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
@@ -468,22 +480,22 @@ def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
# pseudo!ident@host
|
# pseudo!ident@host
|
||||||
fullname = f'{nickname}!{username}@{hostname}'
|
fullname = f'{nickname}!{username}@{hostname}'
|
||||||
|
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=service_id,
|
nick_from=service_id,
|
||||||
msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}",
|
msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}",
|
||||||
channel=service_chanlog)
|
channel=service_chanlog)
|
||||||
|
|
||||||
uplink.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}")
|
uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}")
|
||||||
|
|
||||||
if result['listed']:
|
if result['listed']:
|
||||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
|
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
|
||||||
uplink.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}")
|
uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}")
|
||||||
|
|
||||||
response.close()
|
response.close()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
async def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||||
"""Analyse l'ip avec Freeipapi
|
"""Analyse l'ip avec Freeipapi
|
||||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||||
Args:
|
Args:
|
||||||
@@ -493,21 +505,21 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
dict[str, any] | None: les informations du provider
|
dict[str, any] | None: les informations du provider
|
||||||
keys : 'countryCode', 'isProxy'
|
keys : 'countryCode', 'isProxy'
|
||||||
"""
|
"""
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
remote_ip = user_model.remote_ip
|
remote_ip = user_model.remote_ip
|
||||||
username = user_model.username
|
username = user_model.username
|
||||||
hostname = user_model.hostname
|
hostname = user_model.hostname
|
||||||
nickname = user_model.nickname
|
nickname = user_model.nickname
|
||||||
|
|
||||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||||
return None
|
return None
|
||||||
if uplink.ModConfig.freeipapi_scan == 0:
|
if uplink.mod_config.freeipapi_scan == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
service_chanlog = uplink.Config.SERVICE_CHANLOG
|
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
color_red = uplink.Config.COLORS.red
|
color_red = uplink.ctx.Config.COLORS.red
|
||||||
nogc = uplink.Config.COLORS.nogc
|
nogc = uplink.ctx.Config.COLORS.nogc
|
||||||
|
|
||||||
url = f'https://freeipapi.com/api/json/{remote_ip}'
|
url = f'https://freeipapi.com/api/json/{remote_ip}'
|
||||||
|
|
||||||
@@ -522,10 +534,10 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
|
|
||||||
status_code = response.status_code
|
status_code = response.status_code
|
||||||
if status_code == 429:
|
if status_code == 429:
|
||||||
uplink.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.')
|
uplink.ctx.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.')
|
||||||
return None
|
return None
|
||||||
elif status_code != 200:
|
elif status_code != 200:
|
||||||
uplink.Logs.warning(f'status code = {str(status_code)}')
|
uplink.ctx.Logs.warning(f'status code = {str(status_code)}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
@@ -536,21 +548,21 @@ def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
# pseudo!ident@host
|
# pseudo!ident@host
|
||||||
fullname = f'{nickname}!{username}@{hostname}'
|
fullname = f'{nickname}!{username}@{hostname}'
|
||||||
|
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=service_id,
|
nick_from=service_id,
|
||||||
msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}",
|
msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}",
|
||||||
channel=service_chanlog)
|
channel=service_chanlog)
|
||||||
uplink.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}")
|
uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}")
|
||||||
|
|
||||||
if result['isProxy']:
|
if result['isProxy']:
|
||||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
|
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
|
||||||
uplink.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}")
|
uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}")
|
||||||
|
|
||||||
response.close()
|
response.close()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
async def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||||
"""Analyse l'ip avec AbuseIpDB
|
"""Analyse l'ip avec AbuseIpDB
|
||||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||||
Args:
|
Args:
|
||||||
@@ -560,15 +572,15 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, str] | None: les informations du provider
|
dict[str, str] | None: les informations du provider
|
||||||
"""
|
"""
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
remote_ip = user_model.remote_ip
|
remote_ip = user_model.remote_ip
|
||||||
username = user_model.username
|
username = user_model.username
|
||||||
hostname = user_model.hostname
|
hostname = user_model.hostname
|
||||||
nickname = user_model.nickname
|
nickname = user_model.nickname
|
||||||
|
|
||||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||||
return None
|
return None
|
||||||
if uplink.ModConfig.abuseipdb_scan == 0:
|
if uplink.mod_config.abuseipdb_scan == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if uplink.abuseipdb_key == '':
|
if uplink.abuseipdb_key == '':
|
||||||
@@ -600,81 +612,81 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -
|
|||||||
'totalReports': decoded_response.get('data', {}).get('totalReports', 0)
|
'totalReports': decoded_response.get('data', {}).get('totalReports', 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.ctx.Config.SERVICE_ID
|
||||||
service_chanlog = uplink.Config.SERVICE_CHANLOG
|
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
color_red = uplink.Config.COLORS.red
|
color_red = uplink.ctx.Config.COLORS.red
|
||||||
nogc = uplink.Config.COLORS.nogc
|
nogc = uplink.ctx.Config.COLORS.nogc
|
||||||
|
|
||||||
# pseudo!ident@host
|
# pseudo!ident@host
|
||||||
fullname = f'{nickname}!{username}@{hostname}'
|
fullname = f'{nickname}!{username}@{hostname}'
|
||||||
|
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=service_id,
|
nick_from=service_id,
|
||||||
msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}",
|
msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}",
|
||||||
channel=service_chanlog
|
channel=service_chanlog
|
||||||
)
|
)
|
||||||
uplink.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}")
|
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}")
|
||||||
|
|
||||||
if result['isTor']:
|
if result['isTor']:
|
||||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
|
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
|
||||||
uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}")
|
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}")
|
||||||
elif result['score'] >= 95:
|
elif result['score'] >= 95:
|
||||||
p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
|
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
|
||||||
uplink.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}")
|
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}")
|
||||||
|
|
||||||
response.close()
|
response.close()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'):
|
async def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'):
|
||||||
"""local_scan
|
"""local_scan
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
uplink (Defender): Defender instance object
|
uplink (Defender): Defender instance object
|
||||||
user_model (MUser): l'objet User qui contient l'ip
|
user_model (MUser): l'objet User qui contient l'ip
|
||||||
"""
|
"""
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
remote_ip = user_model.remote_ip
|
remote_ip = user_model.remote_ip
|
||||||
username = user_model.username
|
username = user_model.username
|
||||||
hostname = user_model.hostname
|
hostname = user_model.hostname
|
||||||
nickname = user_model.nickname
|
nickname = user_model.nickname
|
||||||
fullname = f'{nickname}!{username}@{hostname}'
|
fullname = f'{nickname}!{username}@{hostname}'
|
||||||
|
|
||||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for port in uplink.Config.PORTS_TO_SCAN:
|
for port in uplink.ctx.Config.PORTS_TO_SCAN:
|
||||||
try:
|
try:
|
||||||
newSocket = ''
|
newSocket = ''
|
||||||
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
|
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
|
||||||
newSocket.settimeout(0.5)
|
newSocket.settimeout(0.5)
|
||||||
|
|
||||||
connection = (remote_ip, uplink.Base.int_if_possible(port))
|
connection = (remote_ip, uplink.ctx.Base.int_if_possible(port))
|
||||||
newSocket.connect(connection)
|
newSocket.connect(connection)
|
||||||
|
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
nick_from=uplink.ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[ {uplink.Config.COLORS.red}PROXY_SCAN{uplink.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]",
|
msg=f"[ {uplink.ctx.Config.COLORS.red}PROXY_SCAN{uplink.ctx.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]",
|
||||||
channel=uplink.Config.SERVICE_CHANLOG
|
channel=uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
# print(f"=======> Le port {str(port)} est ouvert !!")
|
# print(f"=======> Le port {str(port)} est ouvert !!")
|
||||||
uplink.Base.running_sockets.append(newSocket)
|
uplink.ctx.Base.running_sockets.append(newSocket)
|
||||||
# print(newSocket)
|
# print(newSocket)
|
||||||
newSocket.shutdown(socket.SHUT_RDWR)
|
newSocket.shutdown(socket.SHUT_RDWR)
|
||||||
newSocket.close()
|
newSocket.close()
|
||||||
|
|
||||||
except (socket.timeout, ConnectionRefusedError):
|
except (socket.timeout, ConnectionRefusedError):
|
||||||
uplink.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé")
|
uplink.ctx.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé")
|
||||||
except AttributeError as ae:
|
except AttributeError as ae:
|
||||||
uplink.Logs.warning(f"AttributeError ({remote_ip}): {ae}")
|
uplink.ctx.Logs.warning(f"AttributeError ({remote_ip}): {ae}")
|
||||||
except socket.gaierror as err:
|
except socket.gaierror as err:
|
||||||
uplink.Logs.warning(f"Address Info Error ({remote_ip}): {err}")
|
uplink.ctx.Logs.warning(f"Address Info Error ({remote_ip}): {err}")
|
||||||
finally:
|
finally:
|
||||||
# newSocket.shutdown(socket.SHUT_RDWR)
|
# newSocket.shutdown(socket.SHUT_RDWR)
|
||||||
newSocket.close()
|
newSocket.close()
|
||||||
uplink.Logs.info('=======> Fermeture de la socket')
|
uplink.ctx.Logs.info('=======> Fermeture de la socket')
|
||||||
|
|
||||||
def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]:
|
async def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]:
|
||||||
"""psutil_scan for Linux (should be run on the same location as the unrealircd server)
|
"""psutil_scan for Linux (should be run on the same location as the unrealircd server)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -683,13 +695,13 @@ def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> l
|
|||||||
Returns:
|
Returns:
|
||||||
list[int]: list of ports
|
list[int]: list of ports
|
||||||
"""
|
"""
|
||||||
p = uplink.Protocol
|
p = uplink.ctx.Irc.Protocol
|
||||||
remote_ip = user_model.remote_ip
|
remote_ip = user_model.remote_ip
|
||||||
username = user_model.username
|
username = user_model.username
|
||||||
hostname = user_model.hostname
|
hostname = user_model.hostname
|
||||||
nickname = user_model.nickname
|
nickname = user_model.nickname
|
||||||
|
|
||||||
if remote_ip in uplink.Config.WHITELISTED_IP:
|
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -697,16 +709,16 @@ def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> l
|
|||||||
fullname = f'{nickname}!{username}@{hostname}'
|
fullname = f'{nickname}!{username}@{hostname}'
|
||||||
|
|
||||||
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
|
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
|
||||||
uplink.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}")
|
uplink.ctx.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}")
|
||||||
|
|
||||||
if matching_ports:
|
if matching_ports:
|
||||||
p.send_priv_msg(
|
await p.send_priv_msg(
|
||||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
nick_from=uplink.ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[ {uplink.Config.COLORS.red}PSUTIL_SCAN{uplink.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}",
|
msg=f"[ {uplink.ctx.Config.COLORS.red}PSUTIL_SCAN{uplink.ctx.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}",
|
||||||
channel=uplink.Config.SERVICE_CHANLOG
|
channel=uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
|
|
||||||
return matching_ports
|
return matching_ports
|
||||||
|
|
||||||
except psutil.AccessDenied as ad:
|
except psutil.AccessDenied as ad:
|
||||||
uplink.Logs.critical(f'psutil_scan: Permission error: {ad}')
|
uplink.ctx.Logs.critical(f'psutil_scan: Permission error: {ad}')
|
||||||
@@ -1,149 +1,61 @@
|
|||||||
import logging
|
import logging
|
||||||
import asyncio
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
from unrealircd_rpc_py.objects.Definition import LiveRPCResult
|
from unrealircd_rpc_py.objects.Definition import LiveRPCResult
|
||||||
|
from core.classes.interfaces.imodule import IModule
|
||||||
|
import mods.jsonrpc.schemas as schemas
|
||||||
import mods.jsonrpc.utils as utils
|
import mods.jsonrpc.utils as utils
|
||||||
import mods.jsonrpc.threads as thds
|
import mods.jsonrpc.threads as thds
|
||||||
from time import sleep
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from unrealircd_rpc_py.ConnectionFactory import ConnectionFactory
|
from unrealircd_rpc_py.ConnectionFactory import ConnectionFactory
|
||||||
from unrealircd_rpc_py.LiveConnectionFactory import LiveConnectionFactory
|
from unrealircd_rpc_py.LiveConnectionFactory import LiveConnectionFactory
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.loader import Loader
|
||||||
|
|
||||||
class Jsonrpc():
|
class Jsonrpc(IModule):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ModConfModel:
|
class ModConfModel(schemas.ModConfModel):
|
||||||
"""The Model containing the module parameters
|
"""The Model containing the module parameters
|
||||||
"""
|
"""
|
||||||
jsonrpc: int = 0
|
...
|
||||||
|
|
||||||
def __init__(self, ircInstance: 'Irc') -> None:
|
MOD_HEADER: dict[str, str] = {
|
||||||
|
'name':'JsonRPC',
|
||||||
|
'version':'1.0.0',
|
||||||
|
'description':'Module using the unrealircd-rpc-py library',
|
||||||
|
'author':'Defender Team',
|
||||||
|
'core_version':'Defender-6'
|
||||||
|
}
|
||||||
|
|
||||||
# Module name (Mandatory)
|
def __init__(self, context: 'Loader') -> None:
|
||||||
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
super().__init__(context)
|
||||||
|
self._mod_config: Optional[schemas.ModConfModel] = None
|
||||||
|
|
||||||
# Add Irc Object to the module (Mandatory)
|
@property
|
||||||
self.Irc = ircInstance
|
def mod_config(self) -> ModConfModel:
|
||||||
|
return self._mod_config
|
||||||
|
|
||||||
# Add Protocol to the module (Mandatory)
|
async def callback_sent_to_irc(self, response: LiveRPCResult) -> None:
|
||||||
self.Protocol = ircInstance.Protocol
|
|
||||||
|
|
||||||
# Add Global Configuration to the module (Mandatory)
|
dnickname = self.ctx.Config.SERVICE_NICKNAME
|
||||||
self.Config = ircInstance.Config
|
dchanlog = self.ctx.Config.SERVICE_CHANLOG
|
||||||
|
green = self.ctx.Config.COLORS.green
|
||||||
# Add Base object to the module (Mandatory)
|
nogc = self.ctx.Config.COLORS.nogc
|
||||||
self.Base = ircInstance.Base
|
bold = self.ctx.Config.COLORS.bold
|
||||||
|
red = self.ctx.Config.COLORS.red
|
||||||
# Add Main Utils (Mandatory)
|
|
||||||
self.MainUtils = ircInstance.Utils
|
|
||||||
|
|
||||||
# Add logs object to the module (Mandatory)
|
|
||||||
self.Logs = ircInstance.Loader.Logs
|
|
||||||
|
|
||||||
# Add User object to the module (Mandatory)
|
|
||||||
self.User = ircInstance.User
|
|
||||||
|
|
||||||
# Add Channel object to the module (Mandatory)
|
|
||||||
self.Channel = ircInstance.Channel
|
|
||||||
|
|
||||||
# Is RPC Active?
|
|
||||||
self.is_streaming = False
|
|
||||||
|
|
||||||
# Module Utils
|
|
||||||
self.Utils = utils
|
|
||||||
|
|
||||||
# Module threads
|
|
||||||
self.Threads = thds
|
|
||||||
|
|
||||||
# Run Garbage collector.
|
|
||||||
self.Base.create_timer(10, self.MainUtils.run_python_garbage_collector)
|
|
||||||
|
|
||||||
# Create module commands (Mandatory)
|
|
||||||
self.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]')
|
|
||||||
self.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC')
|
|
||||||
self.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances')
|
|
||||||
|
|
||||||
# Init the module
|
|
||||||
self.__init_module()
|
|
||||||
|
|
||||||
# Log the module
|
|
||||||
self.Logs.debug(f'Module {self.module_name} loaded ...')
|
|
||||||
|
|
||||||
def __init_module(self) -> None:
|
|
||||||
|
|
||||||
logging.getLogger('websockets').setLevel(logging.WARNING)
|
|
||||||
logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL)
|
|
||||||
logging.getLogger('unrealircd-liverpc-py').setLevel(logging.CRITICAL)
|
|
||||||
|
|
||||||
# Create you own tables (Mandatory)
|
|
||||||
# self.__create_tables()
|
|
||||||
|
|
||||||
# Load module configuration and sync with core one (Mandatory)
|
|
||||||
self.__load_module_configuration()
|
|
||||||
# End of mandatory methods you can start your customization #
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.Rpc = ConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD)
|
|
||||||
self.LiveRpc = LiveConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD)
|
|
||||||
self.Rpc.setup({'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD})
|
|
||||||
self.LiveRpc.setup({'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD,
|
|
||||||
'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'})
|
|
||||||
|
|
||||||
if self.ModConfig.jsonrpc == 1:
|
|
||||||
self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True)
|
|
||||||
|
|
||||||
return None
|
|
||||||
except Exception as err:
|
|
||||||
self.Protocol.send_priv_msg(
|
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
|
||||||
msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {err.__str__()}",
|
|
||||||
channel=self.Config.SERVICE_CHANLOG
|
|
||||||
)
|
|
||||||
self.Logs.error(f"JSONRPC ERROR: {err.__str__()}")
|
|
||||||
|
|
||||||
def __create_tables(self) -> None:
|
|
||||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
|
||||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
|
||||||
Args:
|
|
||||||
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None: Aucun retour n'es attendu
|
|
||||||
"""
|
|
||||||
|
|
||||||
table_logs = '''CREATE TABLE IF NOT EXISTS test_logs (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
datetime TEXT,
|
|
||||||
server_msg TEXT
|
|
||||||
)
|
|
||||||
'''
|
|
||||||
|
|
||||||
self.Base.db_execute_query(table_logs)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def callback_sent_to_irc(self, response: LiveRPCResult) -> None:
|
|
||||||
|
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
|
||||||
dchanlog = self.Config.SERVICE_CHANLOG
|
|
||||||
green = self.Config.COLORS.green
|
|
||||||
nogc = self.Config.COLORS.nogc
|
|
||||||
bold = self.Config.COLORS.bold
|
|
||||||
red = self.Config.COLORS.red
|
|
||||||
|
|
||||||
if response.error.code != 0:
|
if response.error.code != 0:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"[{bold}{red}JSONRPC ERROR{nogc}{bold}] {response.error.message} ({response.error.code})",
|
msg=f"[{bold}{red}JSONRPC ERROR{nogc}{bold}] {response.error.message} ({response.error.code})",
|
||||||
channel=dchanlog)
|
channel=dchanlog)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if isinstance(response.result, bool):
|
if isinstance(response.result, bool):
|
||||||
if response.result:
|
if response.result:
|
||||||
self.Protocol.send_priv_msg(
|
await self.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
nick_from=self.ctx.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[{bold}{green}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.Config.JSONRPC_URL}",
|
msg=f"[{bold}{green}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.ctx.Config.JSONRPC_URL}",
|
||||||
channel=dchanlog)
|
channel=dchanlog)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -154,56 +66,92 @@ class Jsonrpc():
|
|||||||
msg = response.result.msg if hasattr(response.result, 'msg') else ''
|
msg = response.result.msg if hasattr(response.result, 'msg') else ''
|
||||||
|
|
||||||
build_msg = f"{green}{log_source}{nogc}: [{bold}{level}{bold}] {subsystem}.{event_id} - {msg}"
|
build_msg = f"{green}{log_source}{nogc}: [{bold}{level}{bold}] {subsystem}.{event_id} - {msg}"
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg=build_msg, channel=dchanlog)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=build_msg, channel=dchanlog)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __load_module_configuration(self) -> None:
|
def create_tables(self) -> None:
|
||||||
"""### Load Module Configuration
|
return None
|
||||||
"""
|
|
||||||
|
async def load(self) -> None:
|
||||||
|
|
||||||
|
logging.getLogger('websockets').setLevel(logging.WARNING)
|
||||||
|
logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL)
|
||||||
|
logging.getLogger('unrealircd-liverpc-py').setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
|
self._mod_config = self.ModConfModel(jsonrpc=0)
|
||||||
|
|
||||||
|
await self.sync_db()
|
||||||
|
|
||||||
|
if self.ctx.Config.SERVEUR_PROTOCOL.lower() != 'unreal6':
|
||||||
|
self.ctx.ModuleUtils.unload_one_module(self.module_name, False)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Is RPC Active?
|
||||||
|
self.is_streaming = False
|
||||||
|
|
||||||
|
# Create module commands (Mandatory)
|
||||||
|
self.ctx.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]')
|
||||||
|
self.ctx.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC')
|
||||||
|
self.ctx.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Build the default configuration model (Mandatory)
|
self.Rpc = ConnectionFactory(self.ctx.Config.DEBUG_LEVEL).get(self.ctx.Config.JSONRPC_METHOD)
|
||||||
self.ModConfig = self.ModConfModel(jsonrpc=0)
|
self.LiveRpc = LiveConnectionFactory(self.ctx.Config.DEBUG_LEVEL).get(self.ctx.Config.JSONRPC_METHOD)
|
||||||
|
|
||||||
# Sync the configuration with core configuration (Mandatory)
|
sync_unixsocket = {'path_to_socket_file': self.ctx.Config.JSONRPC_PATH_TO_SOCKET_FILE}
|
||||||
self.Base.db_sync_core_config(self.module_name, self.ModConfig)
|
sync_http = {'url': self.ctx.Config.JSONRPC_URL, 'username': self.ctx.Config.JSONRPC_USER, 'password': self.ctx.Config.JSONRPC_PASSWORD}
|
||||||
|
|
||||||
|
live_unixsocket = {'path_to_socket_file': self.ctx.Config.JSONRPC_PATH_TO_SOCKET_FILE,
|
||||||
|
'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'}
|
||||||
|
live_http = {'url': self.ctx.Config.JSONRPC_URL, 'username': self.ctx.Config.JSONRPC_USER, 'password': self.ctx.Config.JSONRPC_PASSWORD,
|
||||||
|
'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'}
|
||||||
|
|
||||||
|
sync_param = sync_unixsocket if self.ctx.Config.JSONRPC_METHOD == 'unixsocket' else sync_http
|
||||||
|
live_param = live_unixsocket if self.ctx.Config.JSONRPC_METHOD == 'unixsocket' else live_http
|
||||||
|
|
||||||
|
self.Rpc.setup(sync_param)
|
||||||
|
self.LiveRpc.setup(live_param)
|
||||||
|
|
||||||
|
if self.mod_config.jsonrpc == 1:
|
||||||
|
self.ctx.Base.create_asynctask(thds.thread_subscribe(self))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
except Exception as err:
|
||||||
except TypeError as te:
|
await self.ctx.Irc.Protocol.send_priv_msg(
|
||||||
self.Logs.critical(te)
|
nick_from=self.ctx.Config.SERVICE_NICKNAME,
|
||||||
|
msg=f"[{self.ctx.Config.COLORS.red}JSONRPC ERROR{self.ctx.Config.COLORS.nogc}] {err.__str__()}",
|
||||||
def update_configuration(self, param_key: str, param_value: str) -> None:
|
channel=self.ctx.Config.SERVICE_CHANLOG
|
||||||
"""Update the local and core configuration
|
|
||||||
|
|
||||||
Args:
|
|
||||||
param_key (str): The parameter key
|
|
||||||
param_value (str): The parameter value
|
|
||||||
"""
|
|
||||||
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value)
|
|
||||||
|
|
||||||
def unload(self) -> None:
|
|
||||||
if self.is_streaming:
|
|
||||||
self.Protocol.send_priv_msg(
|
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
|
||||||
msg=f"[{self.Config.COLORS.green}JSONRPC INFO{self.Config.COLORS.nogc}] Shutting down RPC system!",
|
|
||||||
channel=self.Config.SERVICE_CHANLOG
|
|
||||||
)
|
)
|
||||||
self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True)
|
self.ctx.Logs.error(f"JSONRPC ERROR: {err.__str__()}")
|
||||||
self.update_configuration('jsonrpc', 0)
|
|
||||||
self.Irc.Commands.drop_command_by_module(self.module_name)
|
async def unload(self) -> None:
|
||||||
self.Logs.debug(f"Unloading {self.module_name}")
|
|
||||||
|
if self.ctx.Config.SERVEUR_PROTOCOL != 'unreal6':
|
||||||
|
await self.ctx.ModuleUtils.unload_one_module(self.ctx.Irc, self.module_name, False)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def cmd(self, data: list) -> None:
|
if self.is_streaming:
|
||||||
|
await self.ctx.Irc.Protocol.send_priv_msg(
|
||||||
|
nick_from=self.ctx.Config.SERVICE_NICKNAME,
|
||||||
|
msg=f"[{self.ctx.Config.COLORS.green}JSONRPC INFO{self.ctx.Config.COLORS.nogc}] Shutting down RPC system!",
|
||||||
|
channel=self.ctx.Config.SERVICE_CHANLOG
|
||||||
|
)
|
||||||
|
self.ctx.Base.create_asynctask(thds.thread_unsubscribe(self))
|
||||||
|
# await self.update_configuration('jsonrpc', 0)
|
||||||
|
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||||
|
self.ctx.Logs.debug(f"Unloading {self.module_name}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def cmd(self, data: list[str]) -> None:
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
async def hcmds(self, user: str, channel: Any, cmd: list[str], fullcmd: list[str] = []) -> None:
|
||||||
|
|
||||||
command = str(cmd[0]).lower()
|
command = str(cmd[0]).lower()
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
dnickname = self.ctx.Config.SERVICE_NICKNAME
|
||||||
dchannel = self.Config.SERVICE_CHANLOG
|
dchannel = self.ctx.Config.SERVICE_CHANLOG
|
||||||
fromuser = user
|
fromuser = user
|
||||||
fromchannel = str(channel) if not channel is None else None
|
fromchannel = str(channel) if not channel is None else None
|
||||||
|
|
||||||
@@ -212,39 +160,30 @@ class Jsonrpc():
|
|||||||
case 'jsonrpc':
|
case 'jsonrpc':
|
||||||
try:
|
try:
|
||||||
if len(cmd) < 2:
|
if len(cmd) < 2:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc on')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc on')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc off')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jsonrpc off')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
option = str(cmd[1]).lower()
|
option = str(cmd[1]).lower()
|
||||||
match option:
|
match option:
|
||||||
|
|
||||||
case 'on':
|
case 'on':
|
||||||
thread_name = 'thread_subscribe'
|
self.ctx.Base.create_asynctask(thds.thread_subscribe(self))
|
||||||
if self.Base.is_thread_alive(thread_name):
|
await self.update_configuration('jsonrpc', 1)
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, channel=dchannel, msg=f"The Subscription is running")
|
|
||||||
return None
|
|
||||||
elif self.Base.is_thread_exist(thread_name):
|
|
||||||
self.Protocol.send_priv_msg(
|
|
||||||
nick_from=dnickname, channel=dchannel,
|
|
||||||
msg=f"The subscription is not running, wait untill the process will be cleaned up"
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
|
|
||||||
self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True)
|
|
||||||
self.update_configuration('jsonrpc', 1)
|
|
||||||
|
|
||||||
case 'off':
|
case 'off':
|
||||||
self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True)
|
self.ctx.Base.create_asynctask(thds.thread_unsubscribe(self))
|
||||||
self.update_configuration('jsonrpc', 0)
|
await self.update_configuration('jsonrpc', 0)
|
||||||
|
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(ie)
|
self.ctx.Logs.error(ie)
|
||||||
|
|
||||||
case 'jruser':
|
case 'jruser':
|
||||||
try:
|
try:
|
||||||
if len(cmd) < 2:
|
if len(cmd) < 2:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jruser get nickname')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'/msg {dnickname} jruser get nickname')
|
||||||
|
return None
|
||||||
|
|
||||||
option = str(cmd[1]).lower()
|
option = str(cmd[1]).lower()
|
||||||
match option:
|
match option:
|
||||||
case 'get':
|
case 'get':
|
||||||
@@ -253,42 +192,42 @@ class Jsonrpc():
|
|||||||
|
|
||||||
UserInfo = rpc.User.get(nickname)
|
UserInfo = rpc.User.get(nickname)
|
||||||
if UserInfo.error.code != 0:
|
if UserInfo.error.code != 0:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'{UserInfo.error.message}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'{UserInfo.error.message}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'UID : {UserInfo.id}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'UID : {UserInfo.id}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'NICKNAME : {UserInfo.name}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'NICKNAME : {UserInfo.name}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REALNAME : {UserInfo.user.realname}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REALNAME : {UserInfo.user.realname}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'MODES : {UserInfo.user.modes}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'MODES : {UserInfo.user.modes}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {[chan.name for chan in UserInfo.user.channels]}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CHANNELS : {[chan.name for chan in UserInfo.user.channels]}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SECURITY GROUP : {UserInfo.user.security_groups}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SECURITY GROUP : {UserInfo.user.security_groups}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REPUTATION : {UserInfo.user.reputation}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'REPUTATION : {UserInfo.user.reputation}')
|
||||||
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IP : {UserInfo.ip}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IP : {UserInfo.ip}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'COUNTRY CODE : {UserInfo.geoip.country_code}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'COUNTRY CODE : {UserInfo.geoip.country_code}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASN : {UserInfo.geoip.asn}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASN : {UserInfo.geoip.asn}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASNAME : {UserInfo.geoip.asname}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'ASNAME : {UserInfo.geoip.asname}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLOAKED HOST : {UserInfo.user.cloakedhost}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLOAKED HOST : {UserInfo.user.cloakedhost}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'HOSTNAME : {UserInfo.hostname}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'HOSTNAME : {UserInfo.hostname}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'VHOST : {UserInfo.user.vhost}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'VHOST : {UserInfo.user.vhost}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLIENT PORT : {UserInfo.client_port}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CLIENT PORT : {UserInfo.client_port}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SERVER PORT : {UserInfo.server_port}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'SERVER PORT : {UserInfo.server_port}')
|
||||||
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CERTFP : {UserInfo.tls.certfp}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CERTFP : {UserInfo.tls.certfp}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CIPHER : {UserInfo.tls.cipher}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CIPHER : {UserInfo.tls.cipher}')
|
||||||
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IDLE SINCE : {UserInfo.idle_since}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'IDLE SINCE : {UserInfo.idle_since}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CONNECTED SINCE : {UserInfo.connected_since}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'CONNECTED SINCE : {UserInfo.connected_since}')
|
||||||
|
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(ie)
|
self.ctx.Logs.error(ie)
|
||||||
|
|
||||||
case 'jrinstances':
|
case 'jrinstances':
|
||||||
try:
|
try:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"GC Collect: {self.MainUtils.run_python_garbage_collector()}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"GC Collect: {self.ctx.Utils.run_python_garbage_collector()}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveWebsock: {self.MainUtils.get_number_gc_objects(LiveConnectionFactory)}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveWebsock: {self.ctx.Utils.get_number_gc_objects(LiveConnectionFactory)}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance ConnectionFactory: {self.MainUtils.get_number_gc_objects(ConnectionFactory)}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance ConnectionFactory: {self.ctx.Utils.get_number_gc_objects(ConnectionFactory)}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.MainUtils.get_number_gc_objects()}")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.ctx.Utils.get_number_gc_objects()}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f"Unknown Error: {err}")
|
self.ctx.Logs.error(f"Unknown Error: {err}")
|
||||||
5
mods/jsonrpc/schemas.py
Normal file
5
mods/jsonrpc/schemas.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from core.definition import MainModel, dataclass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ModConfModel(MainModel):
|
||||||
|
jsonrpc: int = 0
|
||||||
@@ -4,16 +4,23 @@ from typing import TYPE_CHECKING
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from mods.jsonrpc.mod_jsonrpc import Jsonrpc
|
from mods.jsonrpc.mod_jsonrpc import Jsonrpc
|
||||||
|
|
||||||
def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
async def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
||||||
|
|
||||||
|
snickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
|
schannel = uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
|
if uplink.is_streaming:
|
||||||
|
await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=snickname,
|
||||||
|
msg=f"[{uplink.ctx.Config.COLORS.green}JSONRPC INFO{uplink.ctx.Config.COLORS.nogc}] IRCd Json-rpc already connected!",
|
||||||
|
channel=schannel
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
snickname = uplink.Config.SERVICE_NICKNAME
|
|
||||||
schannel = uplink.Config.SERVICE_CHANLOG
|
|
||||||
uplink.is_streaming = True
|
uplink.is_streaming = True
|
||||||
response = asyncio.run(uplink.LiveRpc.subscribe(["all"]))
|
response = await uplink.LiveRpc.subscribe(["all"])
|
||||||
|
|
||||||
if response.error.code != 0:
|
if response.error.code != 0:
|
||||||
uplink.Protocol.send_priv_msg(nick_from=snickname,
|
await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=snickname,
|
||||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {response.error.message}",
|
msg=f"[{uplink.ctx.Config.COLORS.red}JSONRPC ERROR{uplink.ctx.Config.COLORS.nogc}] {response.error.message}",
|
||||||
channel=schannel
|
channel=schannel
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,33 +28,41 @@ def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
|||||||
message = response.error.message
|
message = response.error.message
|
||||||
|
|
||||||
if code == 0:
|
if code == 0:
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=snickname,
|
nick_from=snickname,
|
||||||
msg=f"[{uplink.Config.COLORS.green}JSONRPC{uplink.Config.COLORS.nogc}] Stream is OFF",
|
msg=f"[{uplink.ctx.Config.COLORS.green}JSONRPC{uplink.ctx.Config.COLORS.nogc}] Stream is OFF",
|
||||||
|
channel=schannel
|
||||||
|
)
|
||||||
|
uplink.is_streaming = False
|
||||||
|
else:
|
||||||
|
await uplink.ctx.Irc.Protocol.send_priv_msg(
|
||||||
|
nick_from=snickname,
|
||||||
|
msg=f"[{uplink.ctx.Config.COLORS.red}JSONRPC{uplink.ctx.Config.COLORS.nogc}] Stream has crashed! {code} - {message}",
|
||||||
channel=schannel
|
channel=schannel
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
uplink.Protocol.send_priv_msg(
|
|
||||||
nick_from=snickname,
|
|
||||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC{uplink.Config.COLORS.nogc}] Stream has crashed! {code} - {message}",
|
|
||||||
channel=schannel
|
|
||||||
)
|
|
||||||
|
|
||||||
def thread_unsubscribe(uplink: 'Jsonrpc') -> None:
|
|
||||||
|
|
||||||
response = asyncio.run(uplink.LiveRpc.unsubscribe())
|
|
||||||
uplink.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!")
|
|
||||||
uplink.is_streaming = False
|
uplink.is_streaming = False
|
||||||
uplink.update_configuration('jsonrpc', 0)
|
|
||||||
snickname = uplink.Config.SERVICE_NICKNAME
|
|
||||||
schannel = uplink.Config.SERVICE_CHANLOG
|
|
||||||
|
|
||||||
|
async def thread_unsubscribe(uplink: 'Jsonrpc') -> None:
|
||||||
|
|
||||||
|
snickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
|
schannel = uplink.ctx.Config.SERVICE_CHANLOG
|
||||||
|
|
||||||
|
if not uplink.is_streaming:
|
||||||
|
await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=snickname,
|
||||||
|
msg=f"[{uplink.ctx.Config.COLORS.green}JSONRPC INFO{uplink.ctx.Config.COLORS.nogc}] IRCd Json-rpc is already off!",
|
||||||
|
channel=schannel
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
response = await uplink.LiveRpc.unsubscribe()
|
||||||
|
uplink.ctx.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!")
|
||||||
|
uplink.is_streaming = False
|
||||||
code = response.error.code
|
code = response.error.code
|
||||||
message = response.error.message
|
message = response.error.message
|
||||||
|
|
||||||
if code != 0:
|
if code != 0:
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=snickname,
|
nick_from=snickname,
|
||||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {message} ({code})",
|
msg=f"[{uplink.ctx.Config.COLORS.red}JSONRPC ERROR{uplink.ctx.Config.COLORS.nogc}] {message} ({code})",
|
||||||
channel=schannel
|
channel=schannel
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,79 +1,38 @@
|
|||||||
from typing import TYPE_CHECKING
|
import asyncio
|
||||||
from dataclasses import dataclass, fields
|
from typing import Any, TYPE_CHECKING, Optional
|
||||||
|
from core.classes.interfaces.imodule import IModule
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.loader import Loader
|
||||||
|
|
||||||
class Test():
|
class Test(IModule):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ModConfModel:
|
class ModConfModel:
|
||||||
"""The Model containing the module parameters
|
"""The Model containing the module parameters (Mandatory)
|
||||||
|
you can leave it without params.
|
||||||
|
just use pass | if you leave it empty, in the load() method just init empty object ==> self.ModConfig = ModConfModel()
|
||||||
"""
|
"""
|
||||||
param_exemple1: str
|
param_exemple1: str
|
||||||
param_exemple2: int
|
param_exemple2: int
|
||||||
|
|
||||||
def __init__(self, ircInstance: 'Irc') -> None:
|
MOD_HEADER: dict[str, str] = {
|
||||||
|
'name':'Test',
|
||||||
|
'version':'1.0.0',
|
||||||
|
'description':'The test module',
|
||||||
|
'author':'Defender Team',
|
||||||
|
'core_version':'Defender-6'
|
||||||
|
}
|
||||||
|
"""Module Header (Mandatory)"""
|
||||||
|
|
||||||
# Module name (Mandatory)
|
def __init__(self, uplink: 'Loader'):
|
||||||
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
super().__init__(uplink)
|
||||||
|
self._mod_config: Optional[Test.ModConfModel] = None
|
||||||
|
|
||||||
# Add Irc Object to the module (Mandatory)
|
def create_tables(self) -> None:
|
||||||
self.Irc = ircInstance
|
|
||||||
|
|
||||||
# Add Loader Object to the module (Mandatory)
|
|
||||||
self.Loader = ircInstance.Loader
|
|
||||||
|
|
||||||
# Add server protocol Object to the module (Mandatory)
|
|
||||||
self.Protocol = ircInstance.Protocol
|
|
||||||
|
|
||||||
# Add Global Configuration to the module (Mandatory)
|
|
||||||
self.Config = ircInstance.Config
|
|
||||||
|
|
||||||
# Add Base object to the module (Mandatory)
|
|
||||||
self.Base = ircInstance.Base
|
|
||||||
|
|
||||||
# Add logs object to the module (Mandatory)
|
|
||||||
self.Logs = ircInstance.Loader.Logs
|
|
||||||
|
|
||||||
# Add User object to the module (Mandatory)
|
|
||||||
self.User = ircInstance.User
|
|
||||||
|
|
||||||
# Add Channel object to the module (Mandatory)
|
|
||||||
self.Channel = ircInstance.Channel
|
|
||||||
|
|
||||||
# Add Reputation object to the module (Optional)
|
|
||||||
self.Reputation = ircInstance.Reputation
|
|
||||||
|
|
||||||
# Create module commands (Mandatory)
|
|
||||||
self.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command')
|
|
||||||
self.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command')
|
|
||||||
self.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command')
|
|
||||||
self.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command')
|
|
||||||
|
|
||||||
|
|
||||||
# Init the module
|
|
||||||
self.__init_module()
|
|
||||||
|
|
||||||
# Log the module
|
|
||||||
self.Logs.debug(f'Module {self.module_name} loaded ...')
|
|
||||||
|
|
||||||
def __init_module(self) -> None:
|
|
||||||
|
|
||||||
# Create you own tables (Mandatory)
|
|
||||||
self.__create_tables()
|
|
||||||
|
|
||||||
# Load module configuration and sync with core one (Mandatory)
|
|
||||||
self.__load_module_configuration()
|
|
||||||
# End of mandatory methods you can start your customization #
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __create_tables(self) -> None:
|
|
||||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||||
Args:
|
|
||||||
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
None: Aucun retour n'es attendu
|
None: Aucun retour n'es attendu
|
||||||
@@ -86,72 +45,97 @@ class Test():
|
|||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.Base.db_execute_query(table_logs)
|
# self.ctx.Base.db_execute_query(table_logs)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __load_module_configuration(self) -> None:
|
async def load(self) -> None:
|
||||||
"""### Load Module Configuration
|
"""### Load Module Configuration (Mandatory)
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
|
# Create module commands (Mandatory)
|
||||||
|
self.ctx.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command')
|
||||||
|
self.ctx.Irc.build_command(0, self.module_name, 'asyncio', 'Create a new asynchron task!')
|
||||||
|
self.ctx.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command')
|
||||||
|
self.ctx.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command')
|
||||||
|
self.ctx.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command')
|
||||||
|
|
||||||
# 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._mod_config = self.ModConfModel(param_exemple1='str', param_exemple2=1)
|
||||||
|
|
||||||
# Sync the configuration with core configuration (Mandatory)
|
# sync the database with local variable (Mandatory)
|
||||||
self.Base.db_sync_core_config(self.module_name, self.ModConfig)
|
await self.sync_db()
|
||||||
|
|
||||||
return None
|
if self.mod_config.param_exemple2 == 1:
|
||||||
|
await self.ctx.Irc.Protocol.send_priv_msg(self.ctx.Config.SERVICE_NICKNAME, "Param activated", self.ctx.Config.SERVICE_CHANLOG)
|
||||||
|
|
||||||
except TypeError as te:
|
@property
|
||||||
self.Logs.critical(te)
|
def mod_config(self) -> ModConfModel:
|
||||||
|
return self._mod_config
|
||||||
def __update_configuration(self, param_key: str, param_value: str):
|
|
||||||
"""Update the local and core configuration
|
|
||||||
|
|
||||||
Args:
|
|
||||||
param_key (str): The parameter key
|
|
||||||
param_value (str): The parameter value
|
|
||||||
"""
|
|
||||||
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value)
|
|
||||||
|
|
||||||
def unload(self) -> None:
|
def unload(self) -> None:
|
||||||
self.Irc.Commands.drop_command_by_module(self.module_name)
|
"""### This method is called when you unload, or you reload the module (Mandatory)"""
|
||||||
|
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def cmd(self, data:list) -> None:
|
def cmd(self, data: list[str]) -> None:
|
||||||
try:
|
"""All messages coming from the IRCD server will be handled using this method (Mandatory)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (list): Messages coming from the IRCD server.
|
||||||
|
"""
|
||||||
cmd = list(data).copy()
|
cmd = list(data).copy()
|
||||||
|
try:
|
||||||
return None
|
return None
|
||||||
except KeyError as ke:
|
|
||||||
self.Logs.error(f"Key Error: {ke}")
|
|
||||||
except IndexError as ie:
|
|
||||||
self.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}")
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f"General Error: {err}")
|
self.ctx.Logs.error(f"General Error: {err}")
|
||||||
|
|
||||||
def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
async def asyncio_func(self) -> None:
|
||||||
|
self.ctx.Logs.debug(f"Starting async method in a task: {self.__class__.__name__}")
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
self.ctx.Logs.debug(f"End of the task: {self.__class__.__name__}")
|
||||||
|
|
||||||
|
async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None:
|
||||||
|
"""All messages coming from the user commands (Mandatory)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (str): The user who send the request.
|
||||||
|
channel (Any): The channel from where is coming the message (could be None).
|
||||||
|
cmd (list): The messages coming from the IRCD server.
|
||||||
|
fullcmd (list, optional): The full messages coming from the IRCD server. Defaults to [].
|
||||||
|
"""
|
||||||
|
u = self.ctx.User.get_user(user)
|
||||||
|
c = self.ctx.Channel.get_channel(channel) if self.ctx.Channel.is_valid_channel(channel) else None
|
||||||
|
if u is None:
|
||||||
|
return None
|
||||||
|
|
||||||
command = str(cmd[0]).lower()
|
command = str(cmd[0]).lower()
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
dnickname = self.ctx.Config.SERVICE_NICKNAME
|
||||||
fromuser = user
|
|
||||||
fromchannel = str(channel) if not channel is None else None
|
|
||||||
|
|
||||||
match command:
|
match command:
|
||||||
|
|
||||||
|
case 'asyncio':
|
||||||
|
self.ctx.Base.create_asynctask(self.asyncio_func())
|
||||||
|
return None
|
||||||
|
|
||||||
case 'test-command':
|
case 'test-command':
|
||||||
try:
|
try:
|
||||||
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=u.nickname, msg="This is a notice to the sender ...")
|
||||||
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=u.nickname)
|
||||||
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="This is a notice to the sender ...")
|
if c is not None:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", nick_to=fromuser)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name)
|
||||||
|
|
||||||
if not fromchannel is None:
|
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=fromchannel)
|
|
||||||
|
|
||||||
# How to update your module configuration
|
# How to update your module configuration
|
||||||
self.__update_configuration('param_exemple2', 7)
|
self.update_configuration('param_exemple2', 7)
|
||||||
|
self.update_configuration('param_exemple1', 'my_value')
|
||||||
|
|
||||||
# Log if you want the result
|
# Log if you want the result
|
||||||
self.Logs.debug(f"Test logs ready")
|
self.ctx.Logs.debug(f"Test logs ready")
|
||||||
|
return None
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f"Unknown Error: {err}")
|
self.ctx.Logs.error(f"Unknown Error: {err}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
case _:
|
||||||
|
return None
|
||||||
@@ -1,95 +1,49 @@
|
|||||||
"""
|
"""
|
||||||
File : mod_votekick.py
|
File : mod_votekick.py
|
||||||
Version : 1.0.0
|
Version : 1.0.2
|
||||||
Description : Manages votekick sessions for multiple channels.
|
Description : Manages votekick sessions for multiple channels.
|
||||||
Handles activation, ongoing vote checks, and cleanup.
|
Handles activation, ongoing vote checks, and cleanup.
|
||||||
Author : adator
|
Author : adator
|
||||||
Created : 2025-08-16
|
Created : 2025-08-16
|
||||||
Last Updated: 2025-08-16
|
Last Updated: 2025-11-01
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
"""
|
"""
|
||||||
|
from dataclasses import dataclass
|
||||||
import re
|
import re
|
||||||
|
from core.classes.interfaces.imodule import IModule
|
||||||
import mods.votekick.schemas as schemas
|
import mods.votekick.schemas as schemas
|
||||||
import mods.votekick.utils as utils
|
import mods.votekick.utils as utils
|
||||||
from mods.votekick.votekick_manager import VotekickManager
|
from mods.votekick.votekick_manager import VotekickManager
|
||||||
import mods.votekick.threads as thds
|
import mods.votekick.threads as thds
|
||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class Votekick(IModule):
|
||||||
|
|
||||||
class Votekick:
|
@dataclass
|
||||||
|
class ModConfModel(schemas.VoteChannelModel):
|
||||||
|
...
|
||||||
|
|
||||||
def __init__(self, uplink: 'Irc') -> None:
|
MOD_HEADER: dict[str, str] = {
|
||||||
|
'name':'votekick',
|
||||||
|
'version':'1.0.2',
|
||||||
|
'description':'Channel Democraty',
|
||||||
|
'author':'Defender Team',
|
||||||
|
'core_version':'Defender-6'
|
||||||
|
}
|
||||||
|
|
||||||
# Module name (Mandatory)
|
def __init__(self, context: 'Loader') -> None:
|
||||||
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
|
super().__init__(context)
|
||||||
|
self._mod_config: Optional[schemas.VoteChannelModel] = None
|
||||||
|
|
||||||
# Add Irc Object to the module
|
@property
|
||||||
self.Irc = uplink
|
def mod_config(self) -> ModConfModel:
|
||||||
|
return self._mod_config
|
||||||
|
|
||||||
# Add Loader Object to the module (Mandatory)
|
def create_tables(self) -> None:
|
||||||
self.Loader = uplink.Loader
|
|
||||||
|
|
||||||
# Add server protocol Object to the module (Mandatory)
|
|
||||||
self.Protocol = uplink.Protocol
|
|
||||||
|
|
||||||
# Add Global Configuration to the module
|
|
||||||
self.Config = uplink.Config
|
|
||||||
|
|
||||||
# Add Base object to the module
|
|
||||||
self.Base = uplink.Base
|
|
||||||
|
|
||||||
# Add logs object to the module
|
|
||||||
self.Logs = uplink.Logs
|
|
||||||
|
|
||||||
# Add User object to the module
|
|
||||||
self.User = uplink.User
|
|
||||||
|
|
||||||
# Add Channel object to the module
|
|
||||||
self.Channel = uplink.Channel
|
|
||||||
|
|
||||||
# Add Utils.
|
|
||||||
self.Utils = uplink.Utils
|
|
||||||
|
|
||||||
# Add Utils module
|
|
||||||
self.ModUtils = utils
|
|
||||||
|
|
||||||
# Add Schemas module
|
|
||||||
self.Schemas = schemas
|
|
||||||
|
|
||||||
# Add Threads module
|
|
||||||
self.Threads = thds
|
|
||||||
|
|
||||||
# Add VoteKick Manager
|
|
||||||
self.VoteKickManager = VotekickManager(self)
|
|
||||||
|
|
||||||
metadata = uplink.Loader.Settings.get_cache('VOTEKICK')
|
|
||||||
|
|
||||||
if metadata is not None:
|
|
||||||
self.VoteKickManager.VOTE_CHANNEL_DB = metadata
|
|
||||||
# self.VOTE_CHANNEL_DB = metadata
|
|
||||||
|
|
||||||
# Créer les nouvelles commandes du module
|
|
||||||
self.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module')
|
|
||||||
|
|
||||||
# Init the module
|
|
||||||
self.__init_module()
|
|
||||||
|
|
||||||
# Log the module
|
|
||||||
self.Logs.debug(f'-- Module {self.module_name} loaded ...')
|
|
||||||
|
|
||||||
def __init_module(self) -> None:
|
|
||||||
|
|
||||||
# Add admin object to retrieve admin users
|
|
||||||
self.Admin = self.Irc.Admin
|
|
||||||
self.__create_tables()
|
|
||||||
self.ModUtils.join_saved_channels(self)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __create_tables(self) -> None:
|
|
||||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||||
|
|
||||||
@@ -111,30 +65,52 @@ class Votekick:
|
|||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.Base.db_execute_query(table_logs)
|
self.ctx.Base.db_execute_query(table_logs)
|
||||||
self.Base.db_execute_query(table_vote)
|
self.ctx.Base.db_execute_query(table_vote)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def unload(self) -> None:
|
async def load(self) -> None:
|
||||||
|
|
||||||
|
self._mod_config = self.ModConfModel()
|
||||||
|
await self.sync_db()
|
||||||
|
|
||||||
|
# Add VoteKick Manager
|
||||||
|
self.VoteKickManager = VotekickManager(self)
|
||||||
|
|
||||||
|
# Add Threads module
|
||||||
|
self.Threads = thds
|
||||||
|
|
||||||
|
await utils.join_saved_channels(self)
|
||||||
|
|
||||||
|
metadata = self.ctx.Settings.get_cache('VOTEKICK')
|
||||||
|
|
||||||
|
if metadata is not None:
|
||||||
|
self.VoteKickManager.VOTE_CHANNEL_DB = metadata
|
||||||
|
|
||||||
|
# Créer les nouvelles commandes du module
|
||||||
|
self.ctx.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module')
|
||||||
|
|
||||||
|
async def unload(self) -> None:
|
||||||
try:
|
try:
|
||||||
# Cache the local DB with current votes.
|
# Cache the local DB with current votes.
|
||||||
self.Loader.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB)
|
if self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||||
|
self.ctx.Settings.set_cache('VOTEKICK', self.VoteKickManager.VOTE_CHANNEL_DB)
|
||||||
|
|
||||||
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||||
self.Protocol.send_part_chan(uidornickname=self.Config.SERVICE_ID, channel=chan.channel_name)
|
await self.ctx.Irc.Protocol.send_part_chan(uidornickname=self.ctx.Config.SERVICE_ID, channel=chan.channel_name)
|
||||||
|
|
||||||
self.VoteKickManager.VOTE_CHANNEL_DB = []
|
self.VoteKickManager.VOTE_CHANNEL_DB = []
|
||||||
self.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VoteKickManager.VOTE_CHANNEL_DB}')
|
self.ctx.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VoteKickManager.VOTE_CHANNEL_DB}')
|
||||||
|
|
||||||
self.Irc.Commands.drop_command_by_module(self.module_name)
|
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
except UnboundLocalError as ne:
|
except UnboundLocalError as ne:
|
||||||
self.Logs.error(f'{ne}')
|
self.ctx.Logs.error(f'{ne}')
|
||||||
except NameError as ue:
|
except NameError as ue:
|
||||||
self.Logs.error(f'{ue}')
|
self.ctx.Logs.error(f'{ue}')
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'General Error: {err}')
|
self.ctx.Logs.error(f'General Error: {err}')
|
||||||
|
|
||||||
def cmd(self, data: list) -> None:
|
def cmd(self, data: list) -> None:
|
||||||
|
|
||||||
@@ -142,7 +118,7 @@ class Votekick:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
||||||
index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
index, command = self.ctx.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
||||||
if index == -1:
|
if index == -1:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -160,19 +136,19 @@ class Votekick:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
except KeyError as ke:
|
except KeyError as ke:
|
||||||
self.Logs.error(f"Key Error: {ke}")
|
self.ctx.Logs.error(f"Key Error: {ke}")
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}")
|
self.ctx.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f"General Error: {err}")
|
self.ctx.Logs.error(f"General Error: {err}")
|
||||||
|
|
||||||
def hcmds(self, user:str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None:
|
async def hcmds(self, user:str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None:
|
||||||
# cmd is the command starting from the user command
|
# cmd is the command starting from the user command
|
||||||
# full cmd is sending the entire server response
|
# full cmd is sending the entire server response
|
||||||
|
|
||||||
command = str(cmd[0]).lower()
|
command = str(cmd[0]).lower()
|
||||||
fullcmd = fullcmd
|
fullcmd = fullcmd
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
dnickname = self.ctx.Config.SERVICE_NICKNAME
|
||||||
fromuser = user
|
fromuser = user
|
||||||
fromchannel = channel
|
fromchannel = channel
|
||||||
|
|
||||||
@@ -181,14 +157,14 @@ class Votekick:
|
|||||||
case 'vote':
|
case 'vote':
|
||||||
|
|
||||||
if len(cmd) == 1:
|
if len(cmd) == 1:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
option = str(cmd[1]).lower()
|
option = str(cmd[1]).lower()
|
||||||
@@ -198,19 +174,19 @@ class Votekick:
|
|||||||
case 'activate':
|
case 'activate':
|
||||||
try:
|
try:
|
||||||
# vote activate #channel
|
# vote activate #channel
|
||||||
if self.Admin.get_admin(fromuser) is None:
|
if self.ctx.Admin.get_admin(fromuser) is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' :Your are not allowed to execute this command')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' :Your are not allowed to execute this command')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
sentchannel = str(cmd[2]).lower() if self.Channel.is_valid_channel(str(cmd[2]).lower()) else None
|
sentchannel = str(cmd[2]).lower() if self.ctx.Channel.is_valid_channel(str(cmd[2]).lower()) else None
|
||||||
if sentchannel is None:
|
if sentchannel is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.ctx.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
||||||
|
|
||||||
if self.VoteKickManager.activate_new_channel(sentchannel):
|
if self.VoteKickManager.activate_new_channel(sentchannel):
|
||||||
self.Channel.db_query_channel('add', self.module_name, sentchannel)
|
await self.ctx.Channel.db_query_channel('add', self.module_name, sentchannel)
|
||||||
self.Protocol.send_join_chan(uidornickname=dnickname, channel=sentchannel)
|
await self.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname, channel=sentchannel)
|
||||||
self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}")
|
await self.ctx.Irc.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} +o {dnickname}")
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg="You can now use !submit <nickname> to decide if he will stay or not on this channel ",
|
msg="You can now use !submit <nickname> to decide if he will stay or not on this channel ",
|
||||||
channel=sentchannel
|
channel=sentchannel
|
||||||
)
|
)
|
||||||
@@ -218,117 +194,117 @@ class Votekick:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} #channel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} #channel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} #welcome')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} #welcome')
|
||||||
|
|
||||||
case 'deactivate':
|
case 'deactivate':
|
||||||
try:
|
try:
|
||||||
# vote deactivate #channel
|
# vote deactivate #channel
|
||||||
if self.Admin.get_admin(fromuser) is None:
|
if self.ctx.Admin.get_admin(fromuser) is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Your are not allowed to execute this command")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Your are not allowed to execute this command")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
sentchannel = str(cmd[2]).lower() if self.Channel.is_valid_channel(str(cmd[2]).lower()) else None
|
sentchannel = str(cmd[2]).lower() if self.ctx.Channel.is_valid_channel(str(cmd[2]).lower()) else None
|
||||||
if sentchannel is None:
|
if sentchannel is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" The correct command is {self.ctx.Config.SERVICE_PREFIX}{command} {option} #CHANNEL")
|
||||||
|
|
||||||
self.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}")
|
await self.ctx.Irc.Protocol.send2socket(f":{dnickname} SAMODE {sentchannel} -o {dnickname}")
|
||||||
self.Protocol.send_part_chan(uidornickname=dnickname, channel=sentchannel)
|
await self.ctx.Irc.Protocol.send_part_chan(uidornickname=dnickname, channel=sentchannel)
|
||||||
|
|
||||||
if self.VoteKickManager.drop_vote_channel_model(sentchannel):
|
if self.VoteKickManager.drop_vote_channel_model(sentchannel):
|
||||||
self.Channel.db_query_channel('del', self.module_name, sentchannel)
|
await self.ctx.Channel.db_query_channel('del', self.module_name, sentchannel)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" /msg {dnickname} {command} {option} #channel")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" /msg {dnickname} {command} {option} #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Exemple /msg {dnickname} {command} {option} #welcome")
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f" Exemple /msg {dnickname} {command} {option} #welcome")
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
try:
|
try:
|
||||||
# vote +
|
# vote +
|
||||||
channel = fromchannel
|
channel = fromchannel
|
||||||
if self.VoteKickManager.action_vote(channel, fromuser, '+'):
|
if self.VoteKickManager.action_vote(channel, fromuser, '+'):
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel)
|
||||||
else:
|
else:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
try:
|
try:
|
||||||
# vote -
|
# vote -
|
||||||
channel = fromchannel
|
channel = fromchannel
|
||||||
if self.VoteKickManager.action_vote(channel, fromuser, '-'):
|
if self.VoteKickManager.action_vote(channel, fromuser, '-'):
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="Vote recorded, thank you",channel=channel)
|
||||||
else:
|
else:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel)
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg="You already submitted a vote", channel=channel)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
case 'cancel':
|
case 'cancel':
|
||||||
try:
|
try:
|
||||||
# vote cancel
|
# vote cancel
|
||||||
if self.Admin.get_admin(fromuser) is None:
|
if self.ctx.Admin.get_admin(fromuser) is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if channel is None:
|
if channel is None:
|
||||||
self.Logs.error(f"The channel is not known, defender can't cancel the vote")
|
self.ctx.Logs.error(f"The channel is not known, defender can't cancel the vote")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' You need to specify the channel => /msg {dnickname} vote_cancel #channel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' You need to specify the channel => /msg {dnickname} vote_cancel #channel')
|
||||||
|
|
||||||
for vote in self.VoteKickManager.VOTE_CHANNEL_DB:
|
for vote in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||||
if vote.channel_name == channel:
|
if vote.channel_name == channel:
|
||||||
if self.VoteKickManager.init_vote_system(channel):
|
if self.VoteKickManager.init_vote_system(channel):
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg="Vote system re-initiated",
|
msg="Vote system re-initiated",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
case 'status':
|
case 'status':
|
||||||
try:
|
try:
|
||||||
# vote status
|
# vote status
|
||||||
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||||
if chan.channel_name == channel:
|
if chan.channel_name == channel:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"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))}",
|
msg=f"Channel: {chan.channel_name} | Target: {self.ctx.User.get_nickname(chan.target_user)} | For: {chan.vote_for} | Against: {chan.vote_against} | Number of voters: {str(len(chan.voter_users))}",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
case 'submit':
|
case 'submit':
|
||||||
try:
|
try:
|
||||||
# vote submit nickname
|
# vote submit nickname
|
||||||
if self.Admin.get_admin(fromuser) is None:
|
if self.ctx.Admin.get_admin(fromuser) is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Your are not allowed to execute this command')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
nickname_submitted = cmd[2]
|
nickname_submitted = cmd[2]
|
||||||
uid_submitted = self.User.get_uid(nickname_submitted)
|
uid_submitted = self.ctx.User.get_uid(nickname_submitted)
|
||||||
user_submitted = self.User.get_user(nickname_submitted)
|
user_submitted = self.ctx.User.get_user(nickname_submitted)
|
||||||
ongoing_user = None
|
ongoing_user = None
|
||||||
|
|
||||||
# check if there is an ongoing vote
|
# check if there is an ongoing vote
|
||||||
if self.VoteKickManager.is_vote_ongoing(channel):
|
if self.VoteKickManager.is_vote_ongoing(channel):
|
||||||
votec = self.VoteKickManager.get_vote_channel_model(channel)
|
votec = self.VoteKickManager.get_vote_channel_model(channel)
|
||||||
if votec:
|
if votec:
|
||||||
ongoing_user = self.User.get_nickname(votec.target_user)
|
ongoing_user = self.ctx.User.get_nickname(votec.target_user)
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"There is an ongoing vote on {ongoing_user}",
|
msg=f"There is an ongoing vote on {ongoing_user}",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
@@ -336,24 +312,24 @@ class Votekick:
|
|||||||
|
|
||||||
# check if the user exist
|
# check if the user exist
|
||||||
if user_submitted is None:
|
if user_submitted is None:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"This nickname <{nickname_submitted}> do not exist",
|
msg=f"This nickname <{nickname_submitted}> do not exist",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
uid_cleaned = self.Loader.Utils.clean_uid(uid_submitted)
|
uid_cleaned = self.ctx.Utils.clean_uid(uid_submitted)
|
||||||
channel_obj = self.Channel.get_channel(channel)
|
channel_obj = self.ctx.Channel.get_channel(channel)
|
||||||
if channel_obj is None:
|
if channel_obj is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' This channel [{channel}] do not exist in the Channel Object')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' This channel [{channel}] do not exist in the Channel Object')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
clean_uids_in_channel: list = []
|
clean_uids_in_channel: list = []
|
||||||
for uid in channel_obj.uids:
|
for uid in channel_obj.uids:
|
||||||
clean_uids_in_channel.append(self.Loader.Utils.clean_uid(uid))
|
clean_uids_in_channel.append(self.ctx.Utils.clean_uid(uid))
|
||||||
|
|
||||||
if not uid_cleaned in clean_uids_in_channel:
|
if not uid_cleaned in clean_uids_in_channel:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"This nickname <{nickname_submitted}> is not available in this channel",
|
msg=f"This nickname <{nickname_submitted}> is not available in this channel",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
@@ -363,7 +339,7 @@ class Votekick:
|
|||||||
pattern = fr'[o|B|S]'
|
pattern = fr'[o|B|S]'
|
||||||
operator_user = re.findall(pattern, user_submitted.umodes)
|
operator_user = re.findall(pattern, user_submitted.umodes)
|
||||||
if operator_user:
|
if operator_user:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg="You cant vote for this user ! he/she is protected",
|
msg="You cant vote for this user ! he/she is protected",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
@@ -371,49 +347,49 @@ class Votekick:
|
|||||||
|
|
||||||
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
for chan in self.VoteKickManager.VOTE_CHANNEL_DB:
|
||||||
if chan.channel_name == channel:
|
if chan.channel_name == channel:
|
||||||
chan.target_user = self.User.get_uid(nickname_submitted)
|
chan.target_user = self.ctx.User.get_uid(nickname_submitted)
|
||||||
|
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"{nickname_submitted} has been targeted for a vote",
|
msg=f"{nickname_submitted} has been targeted for a vote",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
|
|
||||||
self.Base.create_timer(60, self.Threads.timer_vote_verdict, (self, channel))
|
self.ctx.Base.create_asynctask(thds.timer_vote_verdict(self, channel))
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg="This vote will end after 60 secondes",
|
msg="This vote will end after 60 secondes",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} nickname')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option} nickname')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} adator')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option} adator')
|
||||||
|
|
||||||
case 'verdict':
|
case 'verdict':
|
||||||
try:
|
try:
|
||||||
# vote verdict
|
# vote verdict
|
||||||
if self.Admin.get_admin(fromuser) is None:
|
if self.ctx.Admin.get_admin(fromuser) is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f'Your are not allowed to execute this command')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f'Your are not allowed to execute this command')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
votec = self.VoteKickManager.get_vote_channel_model(channel)
|
votec = self.VoteKickManager.get_vote_channel_model(channel)
|
||||||
if votec:
|
if votec:
|
||||||
target_user = self.User.get_nickname(votec.target_user)
|
target_user = self.ctx.User.get_nickname(votec.target_user)
|
||||||
if votec.vote_for >= votec.vote_against:
|
if votec.vote_for >= votec.vote_against:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
msg=f"User {self.ctx.Config.COLORS.bold}{target_user}{self.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
self.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
await self.ctx.Irc.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||||
else:
|
else:
|
||||||
self.Protocol.send_priv_msg(
|
await self.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
msg=f"User {self.Config.COLORS.bold}{target_user}{self.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
msg=f"User {self.ctx.Config.COLORS.bold}{target_user}{self.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.VoteKickManager.init_vote_system(channel):
|
if self.VoteKickManager.init_vote_system(channel):
|
||||||
self.Protocol.send_priv_msg(
|
await self.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
msg="System vote re initiated",
|
msg="System vote re initiated",
|
||||||
channel=channel
|
channel=channel
|
||||||
@@ -421,19 +397,19 @@ class Votekick:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.ctx.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} {command} {option}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' Exemple /msg {dnickname} {command} {option}')
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote activate #channel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote deactivate #channel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote +')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote -')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote cancel')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote status')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote submit nickname')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict')
|
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser,msg=f' /msg {dnickname} vote verdict')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
|
|||||||
@@ -1,35 +1,38 @@
|
|||||||
|
import asyncio
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from mods.votekick.mod_votekick import Votekick
|
from mods.votekick.mod_votekick import Votekick
|
||||||
|
|
||||||
def timer_vote_verdict(uplink: 'Votekick', channel: str) -> None:
|
async def timer_vote_verdict(uplink: 'Votekick', channel: str) -> None:
|
||||||
|
|
||||||
dnickname = uplink.Config.SERVICE_NICKNAME
|
dnickname = uplink.ctx.Config.SERVICE_NICKNAME
|
||||||
|
|
||||||
if not uplink.VoteKickManager.is_vote_ongoing(channel):
|
if not uplink.VoteKickManager.is_vote_ongoing(channel):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
asyncio.sleep(60)
|
||||||
|
|
||||||
votec = uplink.VoteKickManager.get_vote_channel_model(channel)
|
votec = uplink.VoteKickManager.get_vote_channel_model(channel)
|
||||||
if votec:
|
if votec:
|
||||||
target_user = uplink.User.get_nickname(votec.target_user)
|
target_user = uplink.ctx.User.get_nickname(votec.target_user)
|
||||||
|
|
||||||
if votec.vote_for >= votec.vote_against and votec.vote_for != 0:
|
if votec.vote_for >= votec.vote_against and votec.vote_for != 0:
|
||||||
uplink.Protocol.send_priv_msg(nick_from=dnickname,
|
await uplink.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"User {uplink.Config.COLORS.bold}{target_user}{uplink.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
msg=f"User {uplink.ctx.Config.COLORS.bold}{target_user}{uplink.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll be kicked from the channel",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
uplink.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{dnickname} KICK {channel} {target_user} Following the vote, you are not welcome in {channel}")
|
||||||
else:
|
else:
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
msg=f"User {uplink.Config.COLORS.bold}{target_user}{uplink.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
msg=f"User {uplink.ctx.Config.COLORS.bold}{target_user}{uplink.ctx.Config.COLORS.nogc} has {votec.vote_against} votes against and {votec.vote_for} votes for. For this reason, it\'ll remain in the channel",
|
||||||
channel=channel
|
channel=channel
|
||||||
)
|
)
|
||||||
|
|
||||||
if uplink.VoteKickManager.init_vote_system(channel):
|
if uplink.VoteKickManager.init_vote_system(channel):
|
||||||
uplink.Protocol.send_priv_msg(
|
await uplink.ctx.Irc.Protocol.send_priv_msg(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
msg="System vote re initiated",
|
msg="System vote re initiated",
|
||||||
channel=channel
|
channel=channel
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from mods.votekick.mod_votekick import Votekick
|
from mods.votekick.mod_votekick import Votekick
|
||||||
|
|
||||||
def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool:
|
async def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool:
|
||||||
"""Adds a new channel to the votekick database if it doesn't already exist.
|
"""Adds a new channel to the votekick database if it doesn't already exist.
|
||||||
|
|
||||||
This function checks if the specified channel is already registered in the
|
This function checks if the specified channel is already registered in the
|
||||||
@@ -18,16 +18,16 @@ def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool:
|
|||||||
bool: True if the channel was successfully inserted into the database.
|
bool: True if the channel was successfully inserted into the database.
|
||||||
False if the channel already exists or the insertion failed.
|
False if the channel already exists or the insertion failed.
|
||||||
"""
|
"""
|
||||||
current_datetime = uplink.Utils.get_sdatetime()
|
current_datetime = uplink.ctx.Utils.get_sdatetime()
|
||||||
mes_donnees = {'channel': channel}
|
mes_donnees = {'channel': channel}
|
||||||
|
|
||||||
response = uplink.Base.db_execute_query("SELECT id FROM votekick_channel WHERE channel = :channel", mes_donnees)
|
response = await uplink.ctx.Base.db_execute_query("SELECT id FROM votekick_channel WHERE channel = :channel", mes_donnees)
|
||||||
|
|
||||||
is_channel_exist = response.fetchone()
|
is_channel_exist = response.fetchone()
|
||||||
|
|
||||||
if is_channel_exist is None:
|
if is_channel_exist is None:
|
||||||
mes_donnees = {'datetime': current_datetime, 'channel': channel}
|
mes_donnees = {'datetime': current_datetime, 'channel': channel}
|
||||||
insert = uplink.Base.db_execute_query(f"INSERT INTO votekick_channel (datetime, channel) VALUES (:datetime, :channel)", mes_donnees)
|
insert = await uplink.ctx.Base.db_execute_query(f"INSERT INTO votekick_channel (datetime, channel) VALUES (:datetime, :channel)", mes_donnees)
|
||||||
if insert.rowcount > 0:
|
if insert.rowcount > 0:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -35,7 +35,7 @@ def add_vote_channel_to_database(uplink: 'Votekick', channel: str) -> bool:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool:
|
async def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool:
|
||||||
"""Deletes a channel entry from the votekick database.
|
"""Deletes a channel entry from the votekick database.
|
||||||
|
|
||||||
This function removes the specified channel from the `votekick_channel` table
|
This function removes the specified channel from the `votekick_channel` table
|
||||||
@@ -49,7 +49,7 @@ def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool:
|
|||||||
bool: True if the channel was successfully deleted, False if no rows were affected.
|
bool: True if the channel was successfully deleted, False if no rows were affected.
|
||||||
"""
|
"""
|
||||||
mes_donnes = {'channel': channel}
|
mes_donnes = {'channel': channel}
|
||||||
response = uplink.Base.db_execute_query("DELETE FROM votekick_channel WHERE channel = :channel", mes_donnes)
|
response = await uplink.ctx.Base.db_execute_query("DELETE FROM votekick_channel WHERE channel = :channel", mes_donnes)
|
||||||
|
|
||||||
affected_row = response.rowcount
|
affected_row = response.rowcount
|
||||||
|
|
||||||
@@ -58,17 +58,17 @@ def delete_vote_channel_from_database(uplink: 'Votekick', channel: str) -> bool:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def join_saved_channels(uplink: 'Votekick') -> None:
|
async def join_saved_channels(uplink: 'Votekick') -> None:
|
||||||
|
|
||||||
param = {'module_name': uplink.module_name}
|
param = {'module_name': uplink.module_name}
|
||||||
result = uplink.Base.db_execute_query(f"SELECT id, channel_name FROM {uplink.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param)
|
result = await uplink.ctx.Base.db_execute_query(f"SELECT id, channel_name FROM {uplink.ctx.Config.TABLE_CHANNEL} WHERE module_name = :module_name", param)
|
||||||
|
|
||||||
channels = result.fetchall()
|
channels = result.fetchall()
|
||||||
|
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
id_, chan = channel
|
id_, chan = channel
|
||||||
uplink.VoteKickManager.activate_new_channel(chan)
|
uplink.VoteKickManager.activate_new_channel(chan)
|
||||||
uplink.Protocol.send_sjoin(channel=chan)
|
await uplink.ctx.Irc.Protocol.send_sjoin(channel=chan)
|
||||||
uplink.Protocol.send2socket(f":{uplink.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.Config.SERVICE_NICKNAME}")
|
await uplink.ctx.Irc.Protocol.send2socket(f":{uplink.ctx.Config.SERVICE_NICKNAME} SAMODE {chan} +o {uplink.ctx.Config.SERVICE_NICKNAME}")
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -10,8 +10,8 @@ class VotekickManager:
|
|||||||
|
|
||||||
def __init__(self, uplink: 'Votekick'):
|
def __init__(self, uplink: 'Votekick'):
|
||||||
self.uplink = uplink
|
self.uplink = uplink
|
||||||
self.Logs = uplink.Logs
|
self.Logs = uplink.ctx.Logs
|
||||||
self.Utils = uplink.Utils
|
self.Utils = uplink.ctx.Utils
|
||||||
|
|
||||||
def activate_new_channel(self, channel_name: str) -> bool:
|
def activate_new_channel(self, channel_name: str) -> bool:
|
||||||
"""Activate a new channel in the votekick systeme
|
"""Activate a new channel in the votekick systeme
|
||||||
|
|||||||
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Faker==37.12.0
|
||||||
|
psutil==7.1.2
|
||||||
|
PyYAML==6.0.3
|
||||||
|
requests==2.32.5
|
||||||
|
SQLAlchemy==2.0.44
|
||||||
|
unrealircd_rpc_py==3.0.2
|
||||||
|
starlette==0.50.0
|
||||||
|
uvicorn==0.38.0
|
||||||
16
version.json
16
version.json
@@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"version": "6.3.2",
|
"version": "6.4.0",
|
||||||
|
|
||||||
"requests": "2.32.3",
|
"requests": "2.32.5",
|
||||||
"psutil": "6.0.0",
|
"psutil": "7.1.2",
|
||||||
"unrealircd_rpc_py": "3.0.1",
|
"unrealircd_rpc_py": "3.0.3",
|
||||||
"sqlalchemy": "2.0.35",
|
"sqlalchemy": "2.0.44",
|
||||||
"faker": "30.1.0",
|
"faker": "37.12.0",
|
||||||
"pyyaml": "6.0.2"
|
"pyyaml": "6.0.3",
|
||||||
|
"starlette":"0.50.0",
|
||||||
|
"uvicorn":"0.38.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user