mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-14 19:54:21 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b182aa8bcb | ||
|
|
e5a5f01603 | ||
|
|
99f8949681 | ||
|
|
05b15f2f18 | ||
|
|
35c3faf68c | ||
|
|
2e9bfd2c3b | ||
|
|
80131b7b7a | ||
|
|
ffb30f12ec | ||
|
|
b7b61081be | ||
|
|
030b706b65 | ||
|
|
c428ea2b41 | ||
|
|
9036e4f626 | ||
|
|
fd79ada13d | ||
|
|
8323f6cc9b | ||
|
|
6fcd553481 | ||
|
|
5cd82a174d | ||
|
|
beec16f39d | ||
|
|
a043a58f45 | ||
|
|
fd9643eddc | ||
|
|
ed1a048603 | ||
|
|
3dfde9b1aa | ||
|
|
5e35a10193 | ||
|
|
ff776541d7 | ||
|
|
6b7fd16a44 | ||
|
|
e79c15188e | ||
|
|
b306968115 | ||
|
|
184e90adce | ||
|
|
c7b88150b5 | ||
|
|
02f0608b75 | ||
|
|
25bbddf459 | ||
|
|
0c6fcb7710 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,9 +1,13 @@
|
|||||||
.pyenv/
|
.pyenv/
|
||||||
|
.vscode/
|
||||||
.venv/
|
.venv/
|
||||||
.idea/
|
.idea/
|
||||||
db/
|
db/
|
||||||
logs/
|
logs/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
configuration.json
|
configuration.json
|
||||||
|
configuration.yaml
|
||||||
|
configuration_inspircd.json
|
||||||
|
configuration_unreal6.json
|
||||||
*.log
|
*.log
|
||||||
test.py
|
test.py
|
||||||
62
Makefile
Normal file
62
Makefile
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
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)
|
||||||
|
@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
|
(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
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"SERVEUR_IP": "YOUR.SERVER.IP",
|
|
||||||
"SERVEUR_HOSTNAME": "YOUR.SERVER.HOST",
|
|
||||||
"SERVEUR_LINK": "LINK.DE.TON.SERVER",
|
|
||||||
"SERVEUR_PORT": 7002,
|
|
||||||
"SERVEUR_PASSWORD": "YOUR_LINK_PASSWORD",
|
|
||||||
"SERVEUR_ID": "006",
|
|
||||||
"SERVEUR_SSL": true,
|
|
||||||
|
|
||||||
"SERVICE_NAME": "defender",
|
|
||||||
"SERVICE_NICKNAME": "PyDefender",
|
|
||||||
"SERVICE_REALNAME": "Python Defender Security",
|
|
||||||
"SERVICE_USERNAME": "PyDefender",
|
|
||||||
"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",
|
|
||||||
"PASSWORD": "TON_PASSWORD",
|
|
||||||
|
|
||||||
"JSONRPC_URL": "https://your.domaine.com:8600/api",
|
|
||||||
"JSONRPC_PATH_TO_SOCKET_FILE": "/PATH/TO/YOUR/IRCD/data/rpc.socket",
|
|
||||||
"JSONRPC_METHOD": "socket",
|
|
||||||
"JSONRPC_USER": "YOUR_RPC_USER",
|
|
||||||
"JSONRPC_PASSWORD": "YOUR_RPC_PASSWORD",
|
|
||||||
|
|
||||||
"SALON_JAIL": "#jail",
|
|
||||||
"SALON_JAIL_MODES": "sS",
|
|
||||||
"SALON_LIBERER": "#welcome",
|
|
||||||
|
|
||||||
"CLONE_CHANNEL": "#clones",
|
|
||||||
"CLONE_CMODES": "+nts",
|
|
||||||
"CLONE_LOG_HOST_EXEMPT": ["HOST.TO.SKIP"],
|
|
||||||
"CLONE_CHANNEL_PASSWORD": "YOUR_CHANNEL_PASSWORD",
|
|
||||||
|
|
||||||
"API_TIMEOUT": 2,
|
|
||||||
|
|
||||||
"PORTS_TO_SCAN": [3028, 8080, 1080, 1085, 4145, 9050],
|
|
||||||
"WHITELISTED_IP": ["127.0.0.1"],
|
|
||||||
"GLINE_DURATION": "30",
|
|
||||||
|
|
||||||
"DEBUG_LEVEL": 20
|
|
||||||
|
|
||||||
}
|
|
||||||
47
config/exemple_configuration.yaml
Normal file
47
config/exemple_configuration.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
configuration:
|
||||||
|
SERVEUR_IP: "YOUR.SERVER.IP"
|
||||||
|
SERVEUR_HOSTNAME: "YOUR.SERVER.HOST"
|
||||||
|
SERVEUR_LINK: "LINK.DE.TON.SERVER"
|
||||||
|
SERVEUR_PORT: 7002
|
||||||
|
SERVEUR_PASSWORD: "YOUR_LINK_PASSWORD"
|
||||||
|
SERVEUR_ID: "006"
|
||||||
|
SERVEUR_SSL: true
|
||||||
|
|
||||||
|
SERVICE_NAME: "defender"
|
||||||
|
SERVICE_NICKNAME: "PyDefender"
|
||||||
|
SERVICE_REALNAME: "Python Defender Security"
|
||||||
|
SERVICE_USERNAME: "PyDefender"
|
||||||
|
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"
|
||||||
|
PASSWORD: "TON_PASSWORD"
|
||||||
|
|
||||||
|
JSONRPC_URL: "https://your.domaine.com:8600/api"
|
||||||
|
JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket"
|
||||||
|
JSONRPC_METHOD: "unixsocket"
|
||||||
|
JSONRPC_USER: "YOUR_RPC_USER"
|
||||||
|
JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD"
|
||||||
|
|
||||||
|
SALON_JAIL: "#jail"
|
||||||
|
SALON_JAIL_MODES: "sS"
|
||||||
|
SALON_LIBERER: "#welcome"
|
||||||
|
|
||||||
|
CLONE_CHANNEL: "#clones"
|
||||||
|
CLONE_CMODES: "+nts"
|
||||||
|
CLONE_LOG_HOST_EXEMPT: ["HOST.TO.SKIP"]
|
||||||
|
CLONE_CHANNEL_PASSWORD: "YOUR_CHANNEL_PASSWORD"
|
||||||
|
|
||||||
|
API_TIMEOUT: 2
|
||||||
|
|
||||||
|
PORTS_TO_SCAN: [3028 8080 1080 1085 4145 9050]
|
||||||
|
WHITELISTED_IP: ["127.0.0.1"]
|
||||||
|
GLINE_DURATION: "30"
|
||||||
|
|
||||||
|
DEBUG_LEVEL: 20
|
||||||
|
DEBUG_HARD: true
|
||||||
34
core/base.py
34
core/base.py
@@ -296,13 +296,14 @@ class Base:
|
|||||||
'password': password,
|
'password': password,
|
||||||
'hostname': '*',
|
'hostname': '*',
|
||||||
'vhost': '*',
|
'vhost': '*',
|
||||||
|
'language': 'EN',
|
||||||
'level': 5
|
'level': 5
|
||||||
}
|
}
|
||||||
self.db_execute_query(f"""
|
self.db_execute_query(f"""
|
||||||
INSERT INTO {self.Config.TABLE_ADMIN}
|
INSERT INTO {self.Config.TABLE_ADMIN}
|
||||||
(createdOn, user, password, hostname, vhost, level)
|
(createdOn, user, password, hostname, vhost, language, level)
|
||||||
VALUES
|
VALUES
|
||||||
(:createdOn, :user, :password, :hostname, :vhost, :level)"""
|
(:createdOn, :user, :password, :hostname, :vhost, :language, :level)"""
|
||||||
, mes_donnees)
|
, mes_donnees)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -564,6 +565,9 @@ class Base:
|
|||||||
self.db_execute_query(table_core_channel)
|
self.db_execute_query(table_core_channel)
|
||||||
self.db_execute_query(table_core_config)
|
self.db_execute_query(table_core_config)
|
||||||
|
|
||||||
|
# Patch database
|
||||||
|
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)
|
self.Loader.ModuleUtils.db_register_module('mod_command', 'sys', True)
|
||||||
self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
|
self.Loader.ModuleUtils.db_register_module('mod_defender', 'sys', True)
|
||||||
@@ -584,6 +588,27 @@ class Base:
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def db_is_column_exist(self, table_name: str, column_name: str) -> bool:
|
||||||
|
q = self.db_execute_query(f"PRAGMA table_info({table_name})")
|
||||||
|
existing_columns = [col[1] for col in q.fetchall()]
|
||||||
|
|
||||||
|
if column_name in existing_columns:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
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):
|
||||||
|
patch = f"ALTER TABLE {self.Config.TABLE_ADMIN} ADD COLUMN {column_name} {column_type}"
|
||||||
|
update_row = f"UPDATE {self.Config.TABLE_ADMIN} SET language = 'EN' WHERE language is null"
|
||||||
|
self.db_execute_query(patch)
|
||||||
|
self.db_execute_query(update_row)
|
||||||
|
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}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def db_close(self) -> None:
|
def db_close(self) -> None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -658,14 +683,13 @@ class Base:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def decode_ip(self, ip_b64encoded: str) -> Optional[str]:
|
def decode_ip(self, ip_b64encoded: str) -> Optional[str]:
|
||||||
|
|
||||||
binary_ip = b64decode(ip_b64encoded)
|
|
||||||
try:
|
try:
|
||||||
|
binary_ip = b64decode(ip_b64encoded)
|
||||||
decoded_ip = ipaddress.ip_address(binary_ip)
|
decoded_ip = ipaddress.ip_address(binary_ip)
|
||||||
|
|
||||||
return decoded_ip.exploded
|
return decoded_ip.exploded
|
||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
self.logs.critical(f'This remote ip is not valid : {ve}')
|
self.logs.critical(f'This remote ip ({ip_b64encoded}) is not valid : {ve}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def encode_ip(self, remote_ip_address: str) -> Optional[str]:
|
def encode_ip(self, remote_ip_address: str) -> Optional[str]:
|
||||||
|
|||||||
@@ -9,7 +9,17 @@ class Admin:
|
|||||||
UID_ADMIN_DB: list[MAdmin] = []
|
UID_ADMIN_DB: list[MAdmin] = []
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader') -> None:
|
def __init__(self, loader: 'Loader') -> None:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader Instance.
|
||||||
|
"""
|
||||||
self.Logs = loader.Logs
|
self.Logs = loader.Logs
|
||||||
|
self.Base = loader.Base
|
||||||
|
self.Setting = loader.Settings
|
||||||
|
self.Config = loader.Config
|
||||||
|
self.User = loader.User
|
||||||
|
self.Definition = loader.Definition
|
||||||
|
|
||||||
def insert(self, new_admin: MAdmin) -> bool:
|
def insert(self, new_admin: MAdmin) -> bool:
|
||||||
"""Insert a new admin object model
|
"""Insert a new admin object model
|
||||||
@@ -152,4 +162,66 @@ class Admin:
|
|||||||
if record.uid == uidornickname:
|
if record.uid == uidornickname:
|
||||||
return record.nickname
|
return record.nickname
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_language(self, uidornickname: str) -> Optional[str]:
|
||||||
|
"""Get the language of the admin
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uidornickname (str): The user ID or the Nickname of the admin
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[str]: The language selected by the admin.
|
||||||
|
"""
|
||||||
|
admin = self.get_admin(uidornickname)
|
||||||
|
|
||||||
|
if admin is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return admin.language
|
||||||
|
|
||||||
|
def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool:
|
||||||
|
"""Check the fingerprint
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fp (str): The unique fingerprint of the user
|
||||||
|
uidornickname (str): The UID or the Nickname of the user
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if found
|
||||||
|
"""
|
||||||
|
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp"
|
||||||
|
data = {'fp': fp}
|
||||||
|
exe = self.Base.db_execute_query(query, data)
|
||||||
|
result = exe.fetchone()
|
||||||
|
if result:
|
||||||
|
account = result[0]
|
||||||
|
level = result[1]
|
||||||
|
language = result[2]
|
||||||
|
user_obj = self.User.get_user(uidornickname)
|
||||||
|
if user_obj:
|
||||||
|
admin_obj = self.Definition.MAdmin(**user_obj.to_dict(),account=account, level=level, language=language)
|
||||||
|
if self.insert(admin_obj):
|
||||||
|
self.Setting.current_admin = admin_obj
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def db_is_admin_exist(self, admin_nickname: str) -> bool:
|
||||||
|
"""Verify if the admin exist in the database!
|
||||||
|
|
||||||
|
Args:
|
||||||
|
admin_nickname (str): The nickname admin to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the admin exist otherwise False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
mes_donnees = {'admin': admin_nickname}
|
||||||
|
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)
|
||||||
|
exist_user = r.fetchone()
|
||||||
|
if exist_user:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|||||||
@@ -11,14 +11,16 @@ class Channel:
|
|||||||
"""List that contains all the Channels objects (ChannelModel)
|
"""List that contains all the Channels objects (ChannelModel)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader') -> None:
|
def __init__(self, loader: 'Loader'):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader Instance
|
||||||
|
"""
|
||||||
self.Logs = loader.Logs
|
self.Logs = loader.Logs
|
||||||
self.Base = loader.Base
|
self.Base = loader.Base
|
||||||
self.Utils = loader.Utils
|
self.Utils = loader.Utils
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@@ -110,6 +112,7 @@ class Channel:
|
|||||||
return result
|
return result
|
||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
self.Logs.error(f'{ve}')
|
self.Logs.error(f'{ve}')
|
||||||
|
return False
|
||||||
|
|
||||||
def delete_user_from_all_channel(self, uid:str) -> bool:
|
def delete_user_from_all_channel(self, uid:str) -> bool:
|
||||||
"""Delete a client from all channels
|
"""Delete a client from all channels
|
||||||
@@ -134,6 +137,7 @@ class Channel:
|
|||||||
return result
|
return result
|
||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
self.Logs.error(f'{ve}')
|
self.Logs.error(f'{ve}')
|
||||||
|
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:
|
||||||
"""Add a client to a channel
|
"""Add a client to a channel
|
||||||
@@ -211,15 +215,6 @@ class Channel:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_channel_asdict(self, channel_name: str) -> Optional[dict[str, Any]]:
|
|
||||||
|
|
||||||
channel_obj: Optional['MChannel'] = self.get_channel(channel_name)
|
|
||||||
|
|
||||||
if channel_obj is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return channel_obj.to_dict()
|
|
||||||
|
|
||||||
def is_valid_channel(self, channel_to_check: str) -> bool:
|
def is_valid_channel(self, channel_to_check: str) -> bool:
|
||||||
"""Check if the string has the # caractere and return True if this is a valid channel
|
"""Check if the string has the # caractere and return True if this is a valid channel
|
||||||
|
|
||||||
@@ -235,16 +230,18 @@ class Channel:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
pattern = fr'^#'
|
pattern = fr'^#'
|
||||||
isChannel = findall(pattern, channel_to_check)
|
is_channel = findall(pattern, channel_to_check)
|
||||||
|
|
||||||
if not isChannel:
|
if not is_channel:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
except TypeError as te:
|
except TypeError as te:
|
||||||
self.Logs.error(f'TypeError: [{channel_to_check}] - {te}')
|
self.Logs.error(f'TypeError: [{channel_to_check}] - {te}')
|
||||||
|
return False
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'Error Not defined: {err}')
|
self.Logs.error(f'Error Not defined: {err}')
|
||||||
|
return False
|
||||||
|
|
||||||
def db_query_channel(self, action: Literal['add','del'], module_name: str, channel_name: str) -> bool:
|
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.
|
||||||
@@ -276,7 +273,7 @@ class Channel:
|
|||||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'channel_name': channel_name, 'module_name': module_name}
|
mes_donnees = {'datetime': self.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 = self.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'New channel added: channel={channel_name} / module_name={module_name}')
|
self.Logs.debug(f'Channel added to DB: channel={channel_name} / module_name={module_name}')
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -286,13 +283,12 @@ class Channel:
|
|||||||
response = self.Base.db_execute_query(f"DELETE FROM {core_table} WHERE channel_name = :channel_name AND module_name = :module_name", mes_donnes)
|
response = self.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: channel={channel_name} / module: {module_name}')
|
self.Logs.debug(f'Channel deleted from DB: channel={channel_name} / module: {module_name}')
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
case _:
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(err)
|
self.Logs.error(err)
|
||||||
|
return False
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ class Client:
|
|||||||
CLIENT_DB: list['MClient'] = []
|
CLIENT_DB: list['MClient'] = []
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader'):
|
def __init__(self, loader: 'Loader'):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader instance.
|
||||||
|
"""
|
||||||
self.Logs = loader.Logs
|
self.Logs = loader.Logs
|
||||||
self.Base = loader.Base
|
self.Base = loader.Base
|
||||||
|
|
||||||
@@ -34,12 +38,12 @@ class Client:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def update_nickname(self, uid: str, newNickname: str) -> bool:
|
def update_nickname(self, uid: str, new_nickname: str) -> bool:
|
||||||
"""Update the nickname starting from the UID
|
"""Update the nickname starting from the UID
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
uid (str): UID of the user
|
uid (str): UID of the user
|
||||||
newNickname (str): New nickname
|
new_nickname (str): New nickname
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if updated
|
bool: True if updated
|
||||||
@@ -49,7 +53,7 @@ class Client:
|
|||||||
if user_obj is None:
|
if user_obj is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
user_obj.nickname = newNickname
|
user_obj.nickname = new_nickname
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -181,7 +185,7 @@ class Client:
|
|||||||
|
|
||||||
return client_obj.to_dict()
|
return client_obj.to_dict()
|
||||||
|
|
||||||
def is_exist(self, uidornikname: str) -> bool:
|
def is_exist(self, uidornickname: str) -> bool:
|
||||||
"""Check if the UID or the nickname exist in the USER DB
|
"""Check if the UID or the nickname exist in the USER DB
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -190,7 +194,7 @@ class Client:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True if exist
|
bool: True if exist
|
||||||
"""
|
"""
|
||||||
user_obj = self.get_Client(uidornickname=uidornikname)
|
user_obj = self.get_Client(uidornickname=uidornickname)
|
||||||
|
|
||||||
if user_obj is None:
|
if user_obj is None:
|
||||||
return False
|
return False
|
||||||
@@ -231,9 +235,9 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
pattern = fr'[:|@|%|\+|~|\*]*'
|
pattern = fr'[:|@|%|\+|~|\*]*'
|
||||||
parsed_UID = sub(pattern, '', uid)
|
parsed_uid = sub(pattern, '', uid)
|
||||||
|
|
||||||
if not parsed_UID:
|
if not parsed_uid:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return parsed_UID
|
return parsed_uid
|
||||||
@@ -9,8 +9,13 @@ class Command:
|
|||||||
DB_COMMANDS: list['MCommand'] = []
|
DB_COMMANDS: list['MCommand'] = []
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader'):
|
def __init__(self, loader: 'Loader'):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader instance.
|
||||||
|
"""
|
||||||
self.Loader = loader
|
self.Loader = loader
|
||||||
self.Base = loader.Base
|
self.Base = loader.Base
|
||||||
|
self.Logs = loader.Logs
|
||||||
|
|
||||||
def build(self, new_command_obj: MCommand) -> bool:
|
def build(self, new_command_obj: MCommand) -> bool:
|
||||||
|
|
||||||
@@ -31,7 +36,7 @@ class Command:
|
|||||||
def get_command(self, command_name: str, module_name: str) -> Optional[MCommand]:
|
def get_command(self, command_name: str, module_name: str) -> Optional[MCommand]:
|
||||||
|
|
||||||
for command in self.DB_COMMANDS:
|
for command in self.DB_COMMANDS:
|
||||||
if command.command_name.lower() == command_name and command.module_name == module_name:
|
if command.command_name.lower() == command_name.lower() and command.module_name.lower() == module_name.lower():
|
||||||
return command
|
return command
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -45,6 +50,27 @@ class Command:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def drop_command_by_module(self, module_name: str) -> bool:
|
||||||
|
"""Drop all command by module
|
||||||
|
|
||||||
|
Args:
|
||||||
|
module_name (str): The module name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True
|
||||||
|
"""
|
||||||
|
tmp_model: list[MCommand] = []
|
||||||
|
|
||||||
|
for command in self.DB_COMMANDS:
|
||||||
|
if command.module_name.lower() == module_name.lower():
|
||||||
|
tmp_model.append(command)
|
||||||
|
|
||||||
|
for c in tmp_model:
|
||||||
|
self.DB_COMMANDS.remove(c)
|
||||||
|
|
||||||
|
self.Logs.debug(f"[COMMAND] Drop command for module {module_name}")
|
||||||
|
return True
|
||||||
|
|
||||||
def get_ordered_commands(self) -> list[MCommand]:
|
def get_ordered_commands(self) -> list[MCommand]:
|
||||||
return sorted(self.DB_COMMANDS, key=lambda c: (c.command_level, c.module_name))
|
return sorted(self.DB_COMMANDS, key=lambda c: (c.command_level, c.module_name))
|
||||||
|
|
||||||
@@ -64,7 +90,7 @@ class Command:
|
|||||||
admin_level = admin.level if admin else 0
|
admin_level = admin.level if admin else 0
|
||||||
commands = self.get_commands_by_level(admin_level)
|
commands = self.get_commands_by_level(admin_level)
|
||||||
|
|
||||||
if command_name in [command.command_name for command in commands]:
|
if command_name.lower() in [command.command_name.lower() for command in commands]:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import sys
|
||||||
|
import yaml
|
||||||
from json import load
|
from json import load
|
||||||
from sys import exit
|
from sys import exit
|
||||||
from os import sep
|
from os import sep
|
||||||
@@ -13,49 +15,43 @@ class Configuration:
|
|||||||
|
|
||||||
self.Loader = loader
|
self.Loader = loader
|
||||||
self.Logs = loader.Logs
|
self.Logs = loader.Logs
|
||||||
self._config_model: MConfig = self.__load_service_configuration()
|
self.configuration_model = self.__load_service_configuration()
|
||||||
loader.ServiceLogging.set_file_handler_level(self._config_model.DEBUG_LEVEL)
|
loader.ServiceLogging.set_file_handler_level(self._config_model.DEBUG_LEVEL)
|
||||||
loader.ServiceLogging.set_stdout_handler_level(self._config_model.DEBUG_LEVEL)
|
loader.ServiceLogging.set_stdout_handler_level(self._config_model.DEBUG_LEVEL)
|
||||||
loader.ServiceLogging.update_handler_format(self._config_model.DEBUG_HARD)
|
loader.ServiceLogging.update_handler_format(self._config_model.DEBUG_HARD)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_config_model(self) -> MConfig:
|
@property
|
||||||
|
def configuration_model(self) -> MConfig:
|
||||||
return self._config_model
|
return self._config_model
|
||||||
|
|
||||||
|
@configuration_model.setter
|
||||||
|
def configuration_model(self, conf_model: MConfig):
|
||||||
|
self._config_model = conf_model
|
||||||
|
|
||||||
def __load_json_service_configuration(self) -> Optional[dict[str, Any]]:
|
def __load_config_file(self) -> Optional[dict[str, Any]]:
|
||||||
try:
|
try:
|
||||||
conf_filename = f'config{sep}configuration.json'
|
conf_filename = f'config{sep}configuration.yaml'
|
||||||
with open(conf_filename, 'r') as configuration_data:
|
with open(conf_filename, 'r') as conf:
|
||||||
configuration: dict[str, Union[str, int, list, dict]] = load(configuration_data)
|
configuration: dict[str, dict[str, Any]] = yaml.safe_load(conf)
|
||||||
|
|
||||||
return configuration
|
return configuration.get('configuration', None)
|
||||||
|
|
||||||
except FileNotFoundError as fe:
|
except FileNotFoundError as fe:
|
||||||
self.Logs.error(f'FileNotFound: {fe}')
|
self.Logs.error(f'FileNotFound: {fe}')
|
||||||
self.Logs.error('Configuration file not found please create config/configuration.json')
|
self.Logs.error('Configuration file not found please create config/configuration.yaml')
|
||||||
exit(0)
|
exit("Configuration file not found please create config/configuration.yaml")
|
||||||
except KeyError as ke:
|
|
||||||
self.Logs.error(f'Key Error: {ke}')
|
|
||||||
self.Logs.error('The key must be defined in core/configuration.json')
|
|
||||||
|
|
||||||
def __load_service_configuration(self) -> MConfig:
|
def __load_service_configuration(self) -> MConfig:
|
||||||
try:
|
try:
|
||||||
import_config = self.__load_json_service_configuration()
|
import_config = self.__load_config_file()
|
||||||
|
if import_config is None:
|
||||||
|
self.Logs.error("Error While importing configuration file!", exc_info=True)
|
||||||
|
raise Exception("Error While importing yaml configuration")
|
||||||
|
|
||||||
Model_keys = MConfig().to_dict()
|
list_key_to_remove: list[str] = [key_to_del for key_to_del in import_config if key_to_del not in MConfig().get_attributes()]
|
||||||
model_key_list: list = []
|
for key_to_remove in list_key_to_remove:
|
||||||
json_config_key_list: list = []
|
import_config.pop(key_to_remove, None)
|
||||||
|
self.Logs.warning(f"[!] The key {key_to_remove} is not expected, it has been removed from the system ! please remove it from configuration.json file [!]")
|
||||||
for key in Model_keys:
|
|
||||||
model_key_list.append(key)
|
|
||||||
|
|
||||||
for key in import_config:
|
|
||||||
json_config_key_list.append(key)
|
|
||||||
|
|
||||||
for json_conf in json_config_key_list:
|
|
||||||
if not json_conf in model_key_list:
|
|
||||||
import_config.pop(json_conf, None)
|
|
||||||
self.Logs.warning(f"[!] The key {json_conf} is not expected, it has been removed from the system ! please remove it from configuration.json file [!]")
|
|
||||||
|
|
||||||
self.Logs.debug(f"[LOADING CONFIGURATION]: Loading configuration with {len(import_config)} parameters!")
|
self.Logs.debug(f"[LOADING CONFIGURATION]: Loading configuration with {len(import_config)} parameters!")
|
||||||
return MConfig(**import_config)
|
return MConfig(**import_config)
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
from typing import Literal, TYPE_CHECKING
|
|
||||||
from .protocols.unreal6 import Unrealircd6
|
|
||||||
from .protocols.inspircd import Inspircd
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from core.irc import Irc
|
|
||||||
|
|
||||||
class Protocol:
|
|
||||||
|
|
||||||
def __init__(self, protocol: Literal['unreal6','inspircd'], ircInstance: 'Irc'):
|
|
||||||
|
|
||||||
self.Protocol = None
|
|
||||||
match protocol:
|
|
||||||
case 'unreal6':
|
|
||||||
self.Protocol: Unrealircd6 = Unrealircd6(ircInstance)
|
|
||||||
case 'inspircd':
|
|
||||||
self.Protocol: Inspircd = Inspircd(ircInstance)
|
|
||||||
case _:
|
|
||||||
self.Protocol: Unrealircd6 = Unrealircd6(ircInstance)
|
|
||||||
54
core/classes/protocols/command_handler.py
Normal file
54
core/classes/protocols/command_handler.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.definition import MIrcdCommand
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
class CommandHandler:
|
||||||
|
|
||||||
|
DB_IRCDCOMMS: list['MIrcdCommand'] = []
|
||||||
|
DB_SUBSCRIBE: list = []
|
||||||
|
|
||||||
|
def __init__(self, loader: 'Loader'):
|
||||||
|
"""Init method
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The loader Object
|
||||||
|
"""
|
||||||
|
self.__Logs = loader.Logs
|
||||||
|
|
||||||
|
def register(self, ircd_command_model: 'MIrcdCommand') -> None:
|
||||||
|
"""Register a new command in the Handler
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ircd_command_model (MIrcdCommand): The IRCD Command Object
|
||||||
|
"""
|
||||||
|
ircd_command = self.get_registred_ircd_command(ircd_command_model.command_name)
|
||||||
|
if ircd_command is None:
|
||||||
|
self.__Logs.debug(f'[IRCD COMMAND HANDLER] New IRCD command ({ircd_command_model.command_name}) added to the handler.')
|
||||||
|
self.DB_IRCDCOMMS.append(ircd_command_model)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
self.__Logs.debug(f'[IRCD COMMAND HANDLER] This IRCD command ({ircd_command.command_name}) already exist in the handler.')
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_registred_ircd_command(self, command_name: str) -> Optional['MIrcdCommand']:
|
||||||
|
"""Get the registred IRCD command model
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
MIrcdCommand: The IRCD Command object
|
||||||
|
"""
|
||||||
|
com = command_name.upper()
|
||||||
|
for ircd_com in self.DB_IRCDCOMMS:
|
||||||
|
if com == ircd_com.command_name.upper():
|
||||||
|
return ircd_com
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_ircd_commands(self) -> list['MIrcdCommand']:
|
||||||
|
"""Get the list of IRCD Commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[MIrcdCommand]: a list of all registred commands
|
||||||
|
"""
|
||||||
|
return self.DB_IRCDCOMMS.copy()
|
||||||
33
core/classes/protocols/factory.py
Normal file
33
core/classes/protocols/factory.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
from .unreal6 import Unrealircd6
|
||||||
|
from .inspircd import Inspircd
|
||||||
|
from .interface import IProtocol
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.irc import Irc
|
||||||
|
|
||||||
|
class ProtocolFactorty:
|
||||||
|
|
||||||
|
def __init__(self, uplink: 'Irc'):
|
||||||
|
"""ProtocolFactory init.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uplink (Irc): The Irc object
|
||||||
|
"""
|
||||||
|
self.__Config = uplink.Config
|
||||||
|
self.__uplink = uplink
|
||||||
|
|
||||||
|
def get(self) -> Optional[IProtocol]:
|
||||||
|
|
||||||
|
protocol = self.__Config.SERVEUR_PROTOCOL
|
||||||
|
|
||||||
|
match protocol:
|
||||||
|
case 'unreal6':
|
||||||
|
self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
|
||||||
|
return Unrealircd6(self.__uplink)
|
||||||
|
case 'inspircd':
|
||||||
|
self.__uplink.Logs.debug(f"[PROTOCOL] {protocol} has been loaded")
|
||||||
|
return Inspircd(self.__uplink)
|
||||||
|
case _:
|
||||||
|
self.__uplink.Logs.critical(f"[PROTOCOL ERROR] This protocol name ({protocol} is not valid!)")
|
||||||
|
raise Exception("Unknown protocol!")
|
||||||
File diff suppressed because it is too large
Load Diff
547
core/classes/protocols/interface.py
Normal file
547
core/classes/protocols/interface.py
Normal file
@@ -0,0 +1,547 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
from core.classes.protocols.command_handler import CommandHandler
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.definition import MClient, MSasl
|
||||||
|
|
||||||
|
|
||||||
|
class IProtocol(ABC):
|
||||||
|
|
||||||
|
Handler: Optional[CommandHandler] = None
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_ircd_protocol_poisition(self, cmd: list[str], log: bool = False) -> tuple[int, Optional[str]]:
|
||||||
|
"""Get the position of known commands
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cmd (list[str]): The server response
|
||||||
|
log (bool): If true it will log in the logger
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[int, Optional[str]]: The position and the command.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def register_command(self):
|
||||||
|
"""Register all commands that you need to handle
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send2socket(self, message: str, print_log: bool = True) -> None:
|
||||||
|
"""Envoit les commandes à envoyer au serveur.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message (str): contient la commande à envoyer au serveur.
|
||||||
|
print_log (bool): If True then print logs
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
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
|
||||||
|
could be either channel or nickname not both together
|
||||||
|
Args:
|
||||||
|
msg (str): The message to send
|
||||||
|
nick_from (str): The sender nickname
|
||||||
|
channel (str, optional): The receiver channel. Defaults to None.
|
||||||
|
nick_to (str, optional): The reciever nickname. Defaults to None.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_notice(self, nick_from: str, nick_to: str, msg: str) -> None:
|
||||||
|
"""Sending NOTICE by batches
|
||||||
|
|
||||||
|
Args:
|
||||||
|
msg (str): The message to send to the server
|
||||||
|
nick_from (str): The sender Nickname
|
||||||
|
nick_to (str): The reciever nickname
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_link(self) -> None:
|
||||||
|
"""Créer le link et envoyer les informations nécessaires pour la
|
||||||
|
connexion au serveur.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
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
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): The nickname of the client.
|
||||||
|
hostname (str): The hostname of the client.
|
||||||
|
set_by (str): The nickname who send the gline
|
||||||
|
expire_timestamp (int): Expire timestamp
|
||||||
|
set_at_timestamp (int): Set at timestamp
|
||||||
|
reason (str): The reason of the gline.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_set_nick(self, newnickname: str) -> None:
|
||||||
|
"""Change nickname of the server
|
||||||
|
\n This method will also update the User object
|
||||||
|
Args:
|
||||||
|
newnickname (str): New nickname of the server
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
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
|
||||||
|
|
||||||
|
Args:
|
||||||
|
modes (str): The selected mode
|
||||||
|
nickname (Optional[str]): The nickname
|
||||||
|
channel_name (Optional[str]): The channel name
|
||||||
|
params (Optional[str]): Parameters like password.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
server_id (str): _description_
|
||||||
|
server_link (str): _description_
|
||||||
|
reason (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_ungline(self, nickname:str, hostname: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): _description_
|
||||||
|
hostname (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_kline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): _description_
|
||||||
|
hostname (str): _description_
|
||||||
|
set_by (str): _description_
|
||||||
|
expire_timestamp (int): _description_
|
||||||
|
set_at_timestamp (int): _description_
|
||||||
|
reason (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_unkline(self, nickname:str, hostname: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): _description_
|
||||||
|
hostname (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_sjoin(self, channel: str) -> None:
|
||||||
|
"""Server will join a channel with pre defined umodes
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel (str): Channel to join
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_sapart(self, nick_to_sapart: str, channel_name: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nick_to_sapart (str): _description_
|
||||||
|
channel_name (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_sajoin(self, nick_to_sajoin: str, channel_name: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nick_to_sajoin (str): _description_
|
||||||
|
channel_name (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_svspart(self, nick_to_part: str, channels: list[str], reason: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nick_to_part (str): _description_
|
||||||
|
channels (list[str]): _description_
|
||||||
|
reason (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_svsjoin(self, nick_to_part: str, channels: list[str], keys: list[str]) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nick_to_part (str): _description_
|
||||||
|
channels (list[str]): _description_
|
||||||
|
keys (list[str]): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_svsmode(self, nickname: str, user_mode: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): _description_
|
||||||
|
user_mode (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_svs2mode(self, nickname: str, user_mode: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): _description_
|
||||||
|
user_mode (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_svslogin(self, client_uid: str, user_account: str) -> None:
|
||||||
|
"""Log a client into his account.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
client_uid (str): Client UID
|
||||||
|
user_account (str): The account of the user
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_svslogout(self, client_obj: 'MClient') -> None:
|
||||||
|
"""Logout a client from his account
|
||||||
|
|
||||||
|
Args:
|
||||||
|
client_obj (MClient): The Client UID
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_quit(self, uid: str, reason: str, print_log: bool = True) -> None:
|
||||||
|
"""Send quit message
|
||||||
|
- Delete uid from User object
|
||||||
|
- Delete uid from Reputation object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uid (str): The UID or the Nickname
|
||||||
|
reason (str): The reason for the quit
|
||||||
|
print_log (bool): If True then print logs
|
||||||
|
"""
|
||||||
|
|
||||||
|
@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:
|
||||||
|
"""Send UID to the server
|
||||||
|
- Insert User to User Object
|
||||||
|
Args:
|
||||||
|
nickname (str): Nickname of the client
|
||||||
|
username (str): Username of the client
|
||||||
|
hostname (str): Hostname of the client you want to create
|
||||||
|
uid (str): UID of the client you want to create
|
||||||
|
umodes (str): umodes of the client you want to create
|
||||||
|
vhost (str): vhost of the client you want to create
|
||||||
|
remote_ip (str): remote_ip of the client you want to create
|
||||||
|
realname (str): realname of the client you want to create
|
||||||
|
print_log (bool, optional): print logs if true. Defaults to True.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_join_chan(self, uidornickname: str, channel: str, password: str = None, print_log: bool = True) -> None:
|
||||||
|
"""Joining a channel
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uidornickname (str): UID or nickname that need to join
|
||||||
|
channel (str): channel to join
|
||||||
|
password (str, optional): The password of the channel to join. Default to None
|
||||||
|
print_log (bool, optional): Write logs. Defaults to True.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_part_chan(self, uidornickname:str, channel: str, print_log: bool = True) -> None:
|
||||||
|
"""Part from a channel
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uidornickname (str): UID or nickname that need to join
|
||||||
|
channel (str): channel to join
|
||||||
|
print_log (bool, optional): Write logs. Defaults to True.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_mode_chan(self, channel_name: str, channel_mode: str) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
channel_name (str): _description_
|
||||||
|
channel_mode (str): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def send_raw(self, raw_command: str) -> None:
|
||||||
|
"""Send raw message to the server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
raw_command (str): The raw command you want to send.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# COMMON IRC PARSER
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def parse_uid(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse UID and return dictionary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The UID IRCD message
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str]: The response as dictionary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def parse_quit(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse quit and return dictionary.
|
||||||
|
>>> [':97KAAAAAB', 'QUIT', ':Quit:', 'this', 'is', 'my', 'reason', 'to', 'quit']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message to parse
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str]: The response as dictionary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def parse_nick(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse nick changes and return dictionary.
|
||||||
|
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message to parse
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str]: The response as dictionary.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def parse_privmsg(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse PRIVMSG message.
|
||||||
|
>>> [':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message to parse
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str]: The response as dictionary.
|
||||||
|
```python
|
||||||
|
response = {
|
||||||
|
"uid": '97KAAAAAE',
|
||||||
|
"channel": '#welcome',
|
||||||
|
"message": 'This is my public message'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# EVENT HANDLER
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_svs2mode(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle svs2mode coming from a server
|
||||||
|
>>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_mode(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle mode coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_umode2(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle umode2 coming from a server
|
||||||
|
>>> [':adator_', 'UMODE2', '-i']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_quit(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle quit coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_squit(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle squit coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_protoctl(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle protoctl coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_nick(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle nick coming from a server
|
||||||
|
new nickname
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_sjoin(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle sjoin coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_part(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle part coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_eos(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle EOS coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_reputation(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle REPUTATION coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_uid(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle uid message coming from the server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_privmsg(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle PRIVMSG message coming from the server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_server_ping(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Send a PONG message to the server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): List of str coming from the server
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_server(self, serverMsg: list[str]) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): _description_
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_version(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Sending Server Version to the server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): List of str coming from the server
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_time(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Sending TIME answer to a requestor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): List of str coming from the server
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_ping(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Sending a PING answer to requestor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): List of str coming from the server
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_version_msg(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle version coming from the server
|
||||||
|
\n ex. /version Defender
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original message from the server
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_smod(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle SMOD message coming from the server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_sasl(self, serverMsg: list[str]) -> Optional['MSasl']:
|
||||||
|
"""Handle SASL coming from a server
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): Original server message
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool:
|
||||||
|
"""Finalize sasl authentication
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sasl_model (MSasl): The sasl dataclass model
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if success
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_md(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle MD responses
|
||||||
|
[':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server reply
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def on_kick(self, serverMsg: list[str]) -> None:
|
||||||
|
"""When a user is kicked out from a channel
|
||||||
|
|
||||||
|
Eg. ['@unrealircd.org...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message
|
||||||
|
"""
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from re import match, findall, search
|
from re import match, findall, search
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
from ssl import SSLEOFError, SSLError
|
from ssl import SSLEOFError, SSLError
|
||||||
|
|
||||||
|
from core.classes.protocols.command_handler import CommandHandler
|
||||||
|
from core.classes.protocols.interface import IProtocol
|
||||||
|
from core.utils import tr
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
from core.classes.sasl import Sasl
|
from core.classes.sasl import Sasl
|
||||||
from core.definition import MClient, MSasl
|
from core.definition import MClient, MSasl
|
||||||
|
|
||||||
class Unrealircd6:
|
class Unrealircd6(IProtocol):
|
||||||
|
|
||||||
def __init__(self, ircInstance: 'Irc'):
|
def __init__(self, ircInstance: 'Irc'):
|
||||||
self.name = 'UnrealIRCD-6'
|
self.name = 'UnrealIRCD-6'
|
||||||
@@ -25,17 +29,20 @@ class Unrealircd6:
|
|||||||
self.known_protocol: set[str] = {'SJOIN', 'UID', 'MD', 'QUIT', 'SQUIT',
|
self.known_protocol: set[str] = {'SJOIN', 'UID', 'MD', 'QUIT', 'SQUIT',
|
||||||
'EOS', 'PRIVMSG', 'MODE', 'UMODE2',
|
'EOS', 'PRIVMSG', 'MODE', 'UMODE2',
|
||||||
'VERSION', 'REPUTATION', 'SVS2MODE',
|
'VERSION', 'REPUTATION', 'SVS2MODE',
|
||||||
'SLOG', 'NICK', 'PART', 'PONG', 'SASL',
|
'SLOG', 'NICK', 'PART', 'PONG', 'SASL', 'PING',
|
||||||
'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO',
|
'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO',
|
||||||
'006', '007', '018'}
|
'006', '007', '018'}
|
||||||
|
|
||||||
self.__Logs.info(f"** Loading protocol [{__name__}]")
|
self.Handler = CommandHandler(ircInstance.Loader)
|
||||||
|
|
||||||
def get_ircd_protocol_poisition(self, cmd: list[str]) -> tuple[int, Optional[str]]:
|
self.__Logs.info(f"[PROTOCOL] Protocol [{__name__}] loaded!")
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
cmd (list[str]): The server response
|
cmd (list[str]): The server response
|
||||||
|
log (bool): If true it will log in the logger
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple[int, Optional[str]]: The position and the command.
|
tuple[int, Optional[str]]: The position and the command.
|
||||||
@@ -44,10 +51,35 @@ class Unrealircd6:
|
|||||||
if token.upper() in self.known_protocol:
|
if token.upper() in self.known_protocol:
|
||||||
return index, token.upper()
|
return index, token.upper()
|
||||||
|
|
||||||
self.__Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}")
|
if log:
|
||||||
|
self.__Logs.debug(f"[IRCD LOGS] You need to handle this response: {cmd}")
|
||||||
|
|
||||||
return (-1, None)
|
return (-1, None)
|
||||||
|
|
||||||
|
def register_command(self) -> None:
|
||||||
|
m = self.__Irc.Loader.Definition.MIrcdCommand
|
||||||
|
self.Handler.register(m(command_name="PING", func=self.on_server_ping))
|
||||||
|
self.Handler.register(m(command_name="UID", func=self.on_uid))
|
||||||
|
self.Handler.register(m(command_name="QUIT", func=self.on_quit))
|
||||||
|
self.Handler.register(m(command_name="SERVER", func=self.on_server))
|
||||||
|
self.Handler.register(m(command_name="SJOIN", func=self.on_sjoin))
|
||||||
|
self.Handler.register(m(command_name="EOS", func=self.on_eos))
|
||||||
|
self.Handler.register(m(command_name="PROTOCTL", func=self.on_protoctl))
|
||||||
|
self.Handler.register(m(command_name="SVS2MODE", func=self.on_svs2mode))
|
||||||
|
self.Handler.register(m(command_name="SQUIT", func=self.on_squit))
|
||||||
|
self.Handler.register(m(command_name="PART", func=self.on_part))
|
||||||
|
self.Handler.register(m(command_name="VERSION", func=self.on_version_msg))
|
||||||
|
self.Handler.register(m(command_name="UMODE2", func=self.on_umode2))
|
||||||
|
self.Handler.register(m(command_name="NICK", func=self.on_nick))
|
||||||
|
self.Handler.register(m(command_name="REPUTATION", func=self.on_reputation))
|
||||||
|
self.Handler.register(m(command_name="SMOD", func=self.on_smod))
|
||||||
|
self.Handler.register(m(command_name="SASL", func=self.on_sasl))
|
||||||
|
self.Handler.register(m(command_name="MD", func=self.on_md))
|
||||||
|
self.Handler.register(m(command_name="PRIVMSG", func=self.on_privmsg))
|
||||||
|
self.Handler.register(m(command_name="KICK", func=self.on_kick))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def parse_server_msg(self, server_msg: list[str]) -> Optional[str]:
|
def parse_server_msg(self, server_msg: list[str]) -> Optional[str]:
|
||||||
"""Parse the server message and return the command
|
"""Parse the server message and return the command
|
||||||
|
|
||||||
@@ -171,42 +203,52 @@ class Unrealircd6:
|
|||||||
"""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.
|
||||||
"""
|
"""
|
||||||
|
service_id = self.__Config.SERVICE_ID
|
||||||
nickname = self.__Config.SERVICE_NICKNAME
|
service_nickname = self.__Config.SERVICE_NICKNAME
|
||||||
username = self.__Config.SERVICE_USERNAME
|
service_username = self.__Config.SERVICE_USERNAME
|
||||||
realname = self.__Config.SERVICE_REALNAME
|
service_realname = self.__Config.SERVICE_REALNAME
|
||||||
chan = self.__Config.SERVICE_CHANLOG
|
service_channel_log = self.__Config.SERVICE_CHANLOG
|
||||||
info = self.__Config.SERVICE_INFO
|
service_info = self.__Config.SERVICE_INFO
|
||||||
smodes = self.__Config.SERVICE_SMODES
|
service_smodes = self.__Config.SERVICE_SMODES
|
||||||
cmodes = self.__Config.SERVICE_CMODES
|
service_cmodes = self.__Config.SERVICE_CMODES
|
||||||
umodes = self.__Config.SERVICE_UMODES
|
service_umodes = self.__Config.SERVICE_UMODES
|
||||||
host = self.__Config.SERVICE_HOST
|
service_hostname = self.__Config.SERVICE_HOST
|
||||||
service_name = self.__Config.SERVICE_NAME
|
service_name = self.__Config.SERVICE_NAME
|
||||||
protocolversion = self.protocol_version
|
protocolversion = self.protocol_version
|
||||||
|
|
||||||
password = self.__Config.SERVEUR_PASSWORD
|
server_password = self.__Config.SERVEUR_PASSWORD
|
||||||
link = self.__Config.SERVEUR_LINK
|
server_link = self.__Config.SERVEUR_LINK
|
||||||
server_id = self.__Config.SERVEUR_ID
|
server_id = self.__Config.SERVEUR_ID
|
||||||
service_id = self.__Config.SERVICE_ID
|
|
||||||
|
|
||||||
version = self.__Config.CURRENT_VERSION
|
version = self.__Config.CURRENT_VERSION
|
||||||
unixtime = self.__Utils.get_unixtime()
|
unixtime = self.__Utils.get_unixtime()
|
||||||
|
|
||||||
self.send2socket(f":{server_id} PASS :{password}", print_log=False)
|
self.send2socket(f":{server_id} PASS :{server_password}", print_log=False)
|
||||||
self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS")
|
self.send2socket(f":{server_id} PROTOCTL SID NOQUIT NICKv2 SJOIN SJ3 NICKIP TKLEXT2 NEXTBANS CLK EXTSWHOIS MLOCK MTAGS")
|
||||||
self.send2socket(f":{server_id} PROTOCTL EAUTH={link},{protocolversion},,{service_name}-v{version}")
|
self.send2socket(f":{server_id} PROTOCTL EAUTH={server_link},{protocolversion},,{service_name}-v{version}")
|
||||||
self.send2socket(f":{server_id} PROTOCTL SID={server_id}")
|
self.send2socket(f":{server_id} PROTOCTL SID={server_id}")
|
||||||
self.send2socket(f":{server_id} PROTOCTL BOOTED={unixtime}")
|
self.send2socket(f":{server_id} PROTOCTL BOOTED={unixtime}")
|
||||||
self.send2socket(f":{server_id} SERVER {link} 1 :{info}")
|
self.send2socket(f":{server_id} SERVER {server_link} 1 :{service_info}")
|
||||||
self.send2socket(f":{server_id} {nickname} :Reserved for services")
|
self.send2socket("EOS")
|
||||||
self.send2socket(f":{server_id} UID {nickname} 1 {unixtime} {username} {host} {service_id} * {smodes} * * fwAAAQ== :{realname}")
|
self.send2socket(f":{server_id} {service_nickname} :Reserved for services")
|
||||||
self.send_sjoin(chan)
|
self.send2socket(f":{server_id} UID {service_nickname} 1 {unixtime} {service_username} {service_hostname} {service_id} * {service_smodes} * * fwAAAQ== :{service_realname}")
|
||||||
self.send2socket(f":{server_id} TKL + Q * {nickname} {host} 0 {unixtime} :Reserved for services")
|
self.send_sjoin(service_channel_log)
|
||||||
self.send2socket(f":{service_id} MODE {chan} {cmodes}")
|
self.send2socket(f":{server_id} TKL + Q * {service_nickname} {service_hostname} 0 {unixtime} :Reserved for services")
|
||||||
|
self.send2socket(f":{service_id} MODE {service_channel_log} {service_cmodes}")
|
||||||
|
|
||||||
self.__Logs.debug(f'>> {__name__} Link information sent to the server')
|
self.__Logs.debug(f'>> {__name__} Link information sent to the server')
|
||||||
|
|
||||||
def send_gline(self, nickname: str, hostname: str, set_by: str, expire_timestamp: int, set_at_timestamp: int, reason: str) -> None:
|
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
|
||||||
|
|
||||||
|
Args:
|
||||||
|
nickname (str): The nickname of the client.
|
||||||
|
hostname (str): The hostname of the client.
|
||||||
|
set_by (str): The nickname who send the gline
|
||||||
|
expire_timestamp (int): Expire timestamp
|
||||||
|
set_at_timestamp (int): Set at timestamp
|
||||||
|
reason (str): The reason of the gline.
|
||||||
|
"""
|
||||||
# TKL + G user host set_by expire_timestamp set_at_timestamp :reason
|
# TKL + G user host set_by expire_timestamp set_at_timestamp :reason
|
||||||
|
|
||||||
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}")
|
self.send2socket(f":{self.__Config.SERVEUR_ID} TKL + G {nickname} {hostname} {set_by} {expire_timestamp} {set_at_timestamp} :{reason}")
|
||||||
@@ -225,6 +267,42 @@ class Unrealircd6:
|
|||||||
self.__Irc.User.update_nickname(userObj.uid, newnickname)
|
self.__Irc.User.update_nickname(userObj.uid, newnickname)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Args:
|
||||||
|
modes (str): The selected mode
|
||||||
|
nickname (Optional[str]): The nickname
|
||||||
|
channel_name (Optional[str]): The channel name
|
||||||
|
params (Optional[str]): Parameters like password.
|
||||||
|
"""
|
||||||
|
service_id = self.__Config.SERVICE_ID
|
||||||
|
|
||||||
|
if modes[0] not in ['+', '-']:
|
||||||
|
self.__Logs.error(f"[MODE ERROR] The mode you have provided is missing the sign: {modes}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if nickname and channel_name:
|
||||||
|
# :98KAAAAAB MODE #services +o defenderdev
|
||||||
|
if not self.__Irc.Channel.is_valid_channel(channel_name):
|
||||||
|
self.__Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}")
|
||||||
|
return None
|
||||||
|
self.send2socket(f":{service_id} MODE {channel_name} {modes} {nickname}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if nickname and channel_name is None:
|
||||||
|
self.send2socket(f":{service_id} MODE {nickname} {modes}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if nickname is None and channel_name:
|
||||||
|
if not self.__Irc.Channel.is_valid_channel(channel_name):
|
||||||
|
self.__Logs.error(f"[MODE ERROR] The channel is not valid: {channel_name}")
|
||||||
|
return None
|
||||||
|
self.send2socket(f":{service_id} MODE {channel_name} {modes} {params}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
def send_squit(self, server_id: str, server_link: str, reason: str) -> None:
|
||||||
|
|
||||||
if not reason:
|
if not reason:
|
||||||
@@ -427,7 +505,7 @@ class Unrealircd6:
|
|||||||
reason (str): The reason for the quit
|
reason (str): The reason for the quit
|
||||||
"""
|
"""
|
||||||
user_obj = self.__Irc.User.get_user(uidornickname=uid)
|
user_obj = self.__Irc.User.get_user(uidornickname=uid)
|
||||||
reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid)
|
reputationObj = self.__Irc.Reputation.get_reputation(uidornickname=uid)
|
||||||
|
|
||||||
if not user_obj is None:
|
if not user_obj is None:
|
||||||
self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log)
|
self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log)
|
||||||
@@ -561,12 +639,112 @@ class Unrealircd6:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# COMMON IRC PARSER
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def parse_uid(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse UID and return dictionary.
|
||||||
|
>>> ['@s2s-md/geoip=cc=GBtag...', ':001', 'UID', 'albatros', '0', '1721564597', 'albatros', 'hostname...', '001HB8G04', '0', '+iwxz', 'hostname-vhost', 'hostname-vhost', 'MyZBwg==', ':...']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The UID ircd response
|
||||||
|
"""
|
||||||
|
umodes = str(serverMsg[10])
|
||||||
|
remote_ip = self.__Base.decode_ip(str(serverMsg[13])) if 'S' not in umodes else '127.0.0.1'
|
||||||
|
|
||||||
|
# Extract Geoip information
|
||||||
|
pattern = r'^.*geoip=cc=(\S{2}).*$'
|
||||||
|
geoip_match = match(pattern, serverMsg[0])
|
||||||
|
geoip = geoip_match.group(1) if geoip_match else None
|
||||||
|
|
||||||
|
response = {
|
||||||
|
'uid': str(serverMsg[8]),
|
||||||
|
'nickname': str(serverMsg[3]),
|
||||||
|
'username': str(serverMsg[6]),
|
||||||
|
'hostname': str(serverMsg[7]),
|
||||||
|
'umodes': umodes,
|
||||||
|
'vhost': str(serverMsg[11]),
|
||||||
|
'ip': remote_ip,
|
||||||
|
'realname': ' '.join(serverMsg[12:]).lstrip(':'),
|
||||||
|
'geoip': geoip,
|
||||||
|
'reputation_score': 0,
|
||||||
|
'iswebirc': True if 'webirc' in serverMsg[0] else False,
|
||||||
|
'iswebsocket': True if 'websocket' in serverMsg[0] else False
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def parse_quit(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse quit and return dictionary.
|
||||||
|
>>> # ['@unrealtag...', ':001JKNY0N', 'QUIT', ':Quit:', '....']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message to parse
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str]: The dictionary.
|
||||||
|
"""
|
||||||
|
scopy = serverMsg.copy()
|
||||||
|
if scopy[0].startswith('@'):
|
||||||
|
scopy.pop(0)
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"uid": scopy[0].replace(':', ''),
|
||||||
|
"reason": " ".join(scopy[3:])
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def parse_nick(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse nick changes and return dictionary.
|
||||||
|
>>> ['@unrealircd.org/geoip=FR;unrealircd.org/', ':001OOU2H3', 'NICK', 'WebIrc', '1703795844']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message to parse
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The response as dictionary.
|
||||||
|
|
||||||
|
>>> {"uid": "", "newnickname": "", "timestamp": ""}
|
||||||
|
"""
|
||||||
|
scopy = serverMsg.copy()
|
||||||
|
if scopy[0].startswith('@'):
|
||||||
|
scopy.pop(0)
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"uid": scopy[0].replace(':', ''),
|
||||||
|
"newnickname": scopy[2],
|
||||||
|
"timestamp": scopy[3]
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def parse_privmsg(self, serverMsg: list[str]) -> dict[str, str]:
|
||||||
|
"""Parse PRIVMSG message.
|
||||||
|
>>> ['@....', ':97KAAAAAE', 'PRIVMSG', '#welcome', ':This', 'is', 'my', 'public', 'message']
|
||||||
|
>>> [':97KAAAAAF', 'PRIVMSG', '98KAAAAAB', ':sasa']
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message to parse
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict[str, str]: The response as dictionary.
|
||||||
|
"""
|
||||||
|
scopy = serverMsg.copy()
|
||||||
|
if scopy[0].startswith('@'):
|
||||||
|
scopy.pop(0)
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"uid_sender": scopy[0].replace(':', ''),
|
||||||
|
"uid_reciever": self.__Irc.User.get_uid(scopy[2]),
|
||||||
|
"channel": scopy[2] if self.__Irc.Channel.is_valid_channel(scopy[2]) else None,
|
||||||
|
"message": " ".join(scopy[3:])
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
# HANDLE EVENTS #
|
# HANDLE EVENTS #
|
||||||
#####################
|
#####################
|
||||||
|
|
||||||
def on_svs2mode(self, serverMsg: list[str]) -> None:
|
def on_svs2mode(self, serverMsg: list[str]) -> None:
|
||||||
"""Handle svs2mode coming from a server
|
"""Handle svs2mode coming from a server
|
||||||
|
>>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r']
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
serverMsg (list[str]): Original server message
|
||||||
@@ -604,6 +782,7 @@ class Unrealircd6:
|
|||||||
|
|
||||||
def on_umode2(self, serverMsg: list[str]) -> None:
|
def on_umode2(self, serverMsg: list[str]) -> None:
|
||||||
"""Handle umode2 coming from a server
|
"""Handle umode2 coming from a server
|
||||||
|
>>> [':adator_', 'UMODE2', '-i']
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): Original server message
|
serverMsg (list[str]): Original server message
|
||||||
@@ -730,6 +909,7 @@ class Unrealircd6:
|
|||||||
self.__Irc.User.update_nickname(uid, newnickname)
|
self.__Irc.User.update_nickname(uid, newnickname)
|
||||||
self.__Irc.Client.update_nickname(uid, newnickname)
|
self.__Irc.Client.update_nickname(uid, newnickname)
|
||||||
self.__Irc.Admin.update_nickname(uid, newnickname)
|
self.__Irc.Admin.update_nickname(uid, newnickname)
|
||||||
|
self.__Irc.Reputation.update(uid, newnickname)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -850,6 +1030,8 @@ class Unrealircd6:
|
|||||||
self.__Logs.info(f"# VERSION : {version} ")
|
self.__Logs.info(f"# VERSION : {version} ")
|
||||||
self.__Logs.info(f"################################################")
|
self.__Logs.info(f"################################################")
|
||||||
|
|
||||||
|
self.send_sjoin(self.__Config.SERVICE_CHANLOG)
|
||||||
|
|
||||||
if self.__Base.check_for_new_version(False):
|
if self.__Base.check_for_new_version(False):
|
||||||
self.send_priv_msg(
|
self.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self.__Config.SERVICE_NICKNAME,
|
||||||
@@ -860,7 +1042,7 @@ class Unrealircd6:
|
|||||||
# Initialisation terminé aprés le premier PING
|
# Initialisation terminé aprés le premier PING
|
||||||
self.send_priv_msg(
|
self.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self.__Config.SERVICE_NICKNAME,
|
||||||
msg=f"[{self.__Config.COLORS.green}INFORMATION{self.__Config.COLORS.nogc}] >> Defender is ready",
|
msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self.__Config.COLORS.green, self.__Config.COLORS.nogc, self.__Config.SERVICE_NICKNAME),
|
||||||
channel=self.__Config.SERVICE_CHANLOG
|
channel=self.__Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.__Config.DEFENDER_INIT = 0
|
self.__Config.DEFENDER_INIT = 0
|
||||||
@@ -869,6 +1051,10 @@ class Unrealircd6:
|
|||||||
for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy():
|
for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy():
|
||||||
module.class_instance.cmd(server_msg_copy)
|
module.class_instance.cmd(server_msg_copy)
|
||||||
|
|
||||||
|
# Join saved channels & load existing modules
|
||||||
|
self.__Irc.join_saved_channels()
|
||||||
|
self.__Irc.ModuleUtils.db_load_all_existing_modules(self.__Irc)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.__Logs.error(f"{__name__} - Key Error: {ie}")
|
self.__Logs.error(f"{__name__} - Key Error: {ie}")
|
||||||
@@ -946,6 +1132,11 @@ class Unrealircd6:
|
|||||||
fp_match = match(pattern, serverMsg[0])
|
fp_match = match(pattern, serverMsg[0])
|
||||||
fingerprint = fp_match.group(1) if fp_match else None
|
fingerprint = fp_match.group(1) if fp_match else None
|
||||||
|
|
||||||
|
# Extract tls_cipher information
|
||||||
|
pattern = r'^.*tls_cipher=([^;]+).*$'
|
||||||
|
tlsc_match = match(pattern, serverMsg[0])
|
||||||
|
tls_cipher = tlsc_match.group(1) if tlsc_match else None
|
||||||
|
|
||||||
if geoip_match:
|
if geoip_match:
|
||||||
geoip = geoip_match.group(1)
|
geoip = geoip_match.group(1)
|
||||||
else:
|
else:
|
||||||
@@ -963,6 +1154,7 @@ class Unrealircd6:
|
|||||||
umodes=umodes,
|
umodes=umodes,
|
||||||
vhost=vhost,
|
vhost=vhost,
|
||||||
fingerprint=fingerprint,
|
fingerprint=fingerprint,
|
||||||
|
tls_cipher=tls_cipher,
|
||||||
isWebirc=isWebirc,
|
isWebirc=isWebirc,
|
||||||
isWebsocket=isWebsocket,
|
isWebsocket=isWebsocket,
|
||||||
remote_ip=remote_ip,
|
remote_ip=remote_ip,
|
||||||
@@ -971,6 +1163,49 @@ class Unrealircd6:
|
|||||||
connexion_datetime=datetime.now()
|
connexion_datetime=datetime.now()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Auto Auth admin via fingerprint
|
||||||
|
dnickname = self.__Config.SERVICE_NICKNAME
|
||||||
|
dchanlog = self.__Config.SERVICE_CHANLOG
|
||||||
|
GREEN = self.__Config.COLORS.green
|
||||||
|
RED = self.__Config.COLORS.red
|
||||||
|
NOGC = self.__Config.COLORS.nogc
|
||||||
|
|
||||||
|
for module in self.__Irc.ModuleUtils.model_get_loaded_modules().copy():
|
||||||
|
module.class_instance.cmd(serverMsg)
|
||||||
|
|
||||||
|
# SASL authentication
|
||||||
|
# ['@s2s-md/..', ':001', 'UID', 'adator__', '0', '1755987444', '...', 'desktop-h1qck20.mshome.net', '001XLTT0U', '0', '+iwxz', '*', 'Clk-EC2256B2.mshome.net', 'rBKAAQ==', ':...']
|
||||||
|
|
||||||
|
uid = serverMsg[8]
|
||||||
|
nickname = serverMsg[3]
|
||||||
|
sasl_obj = self.__Irc.Sasl.get_sasl_obj(uid)
|
||||||
|
if sasl_obj:
|
||||||
|
if sasl_obj.auth_success:
|
||||||
|
self.__Irc.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level, sasl_obj.language)
|
||||||
|
self.send_priv_msg(nick_from=dnickname,
|
||||||
|
msg=tr("[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, sasl_obj.username, dnickname),
|
||||||
|
channel=dchanlog)
|
||||||
|
self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname))
|
||||||
|
else:
|
||||||
|
self.send_priv_msg(nick_from=dnickname,
|
||||||
|
msg=tr("[ %sSASL AUTH%s ] - %s provided a wrong password for this username %s", RED, NOGC, nickname, sasl_obj.username),
|
||||||
|
channel=dchanlog)
|
||||||
|
self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Wrong password!"))
|
||||||
|
|
||||||
|
# Delete sasl object!
|
||||||
|
self.__Irc.Sasl.delete_sasl_client(uid)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# If no sasl authentication then auto connect via fingerprint
|
||||||
|
if self.__Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid):
|
||||||
|
admin = self.__Irc.Admin.get_admin(uid)
|
||||||
|
account = admin.account if admin else ''
|
||||||
|
self.send_priv_msg(nick_from=dnickname,
|
||||||
|
msg=tr("[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, account, dnickname),
|
||||||
|
channel=dchanlog)
|
||||||
|
self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
self.__Logs.error(f"{__name__} - Index Error: {ie}")
|
||||||
@@ -1010,15 +1245,6 @@ class Unrealircd6:
|
|||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# if not arg[0].lower() in self.__Irc.module_commands_list:
|
|
||||||
# self.__Logs.debug(f"This command {arg[0]} is not available")
|
|
||||||
# self.send_notice(
|
|
||||||
# nick_from=self.__Config.SERVICE_NICKNAME,
|
|
||||||
# nick_to=user_trigger,
|
|
||||||
# msg=f"This command [{self.__Config.COLORS.bold}{arg[0]}{self.__Config.COLORS.bold}] is not available"
|
|
||||||
# )
|
|
||||||
# return None
|
|
||||||
|
|
||||||
cmd_to_send = convert_to_string.replace(':','')
|
cmd_to_send = convert_to_string.replace(':','')
|
||||||
self.__Base.log_cmd(user_trigger, cmd_to_send)
|
self.__Base.log_cmd(user_trigger, cmd_to_send)
|
||||||
|
|
||||||
@@ -1072,7 +1298,7 @@ class Unrealircd6:
|
|||||||
except AttributeError as ae:
|
except AttributeError as ae:
|
||||||
self.__Logs.error(f"Attribute Error: {ae}")
|
self.__Logs.error(f"Attribute Error: {ae}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.__Logs.error(f"General Error: {err} - {srv_msg}")
|
self.__Logs.error(f"General Error: {err} - {srv_msg}" , exc_info=True)
|
||||||
|
|
||||||
def on_server_ping(self, serverMsg: list[str]) -> None:
|
def on_server_ping(self, serverMsg: list[str]) -> None:
|
||||||
"""Send a PONG message to the server
|
"""Send a PONG message to the server
|
||||||
@@ -1081,7 +1307,6 @@ class Unrealircd6:
|
|||||||
serverMsg (list[str]): List of str coming from the server
|
serverMsg (list[str]): List of str coming from the server
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
#
|
|
||||||
pong = str(serverMsg[1]).replace(':','')
|
pong = str(serverMsg[1]).replace(':','')
|
||||||
self.send2socket(f"PONG :{pong}", print_log=False)
|
self.send2socket(f"PONG :{pong}", print_log=False)
|
||||||
|
|
||||||
@@ -1090,6 +1315,11 @@ class Unrealircd6:
|
|||||||
self.__Logs.error(f"{__name__} - General Error: {err}")
|
self.__Logs.error(f"{__name__} - General Error: {err}")
|
||||||
|
|
||||||
def on_server(self, serverMsg: list[str]) -> None:
|
def on_server(self, serverMsg: list[str]) -> None:
|
||||||
|
"""_summary_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): _description_
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# ['SERVER', 'irc.local.org', '1', ':U6100-Fhn6OoE-001', 'Local', 'Server']
|
# ['SERVER', 'irc.local.org', '1', ':U6100-Fhn6OoE-001', 'Local', 'Server']
|
||||||
sCopy = serverMsg.copy()
|
sCopy = serverMsg.copy()
|
||||||
@@ -1152,7 +1382,7 @@ class Unrealircd6:
|
|||||||
Args:
|
Args:
|
||||||
serverMsg (list[str]): List of str coming from the server
|
serverMsg (list[str]): List of str coming from the server
|
||||||
"""
|
"""
|
||||||
# ['@unrealircd.org/userhost=StatServ@stats.deb.biz.st;draft/bot;bot;msgid=ehfAq3m2yjMjhgWEfi1UCS;time=2024-10-26T13:49:06.299Z', ':001INC60B', 'PRIVMSG', '12ZAAAAAB', ':\x01PING', '762382207\x01']
|
# ['@unrealircd.org/...', ':001INC60B', 'PRIVMSG', '12ZAAAAAB', ':\x01PING', '762382207\x01']
|
||||||
# Réponse a un CTCP VERSION
|
# Réponse a un CTCP VERSION
|
||||||
try:
|
try:
|
||||||
|
|
||||||
@@ -1161,6 +1391,7 @@ class Unrealircd6:
|
|||||||
arg = serverMsg[4].replace(':', '')
|
arg = serverMsg[4].replace(':', '')
|
||||||
|
|
||||||
if nickname is None:
|
if nickname is None:
|
||||||
|
self.__Logs.debug(serverMsg)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if arg == '\x01PING':
|
if arg == '\x01PING':
|
||||||
@@ -1174,6 +1405,7 @@ class Unrealircd6:
|
|||||||
nick_to=nickname,
|
nick_to=nickname,
|
||||||
msg=f"\x01PING {ping_response} secs\x01"
|
msg=f"\x01PING {ping_response} secs\x01"
|
||||||
)
|
)
|
||||||
|
self.__Logs.debug(serverMsg)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -1230,7 +1462,7 @@ class Unrealircd6:
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.__Logs.error(f'General Error: {err}')
|
self.__Logs.error(f'General Error: {err}')
|
||||||
|
|
||||||
def on_sasl(self, serverMsg: list[str], psasl: 'Sasl') -> Optional['MSasl']:
|
def on_sasl(self, serverMsg: list[str]) -> Optional['MSasl']:
|
||||||
"""Handle SASL coming from a server
|
"""Handle SASL coming from a server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -1243,7 +1475,7 @@ class Unrealircd6:
|
|||||||
# [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey']
|
# [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '0014ZZH1F', 'S', 'EXTERNAL', 'zzzzzzzkey']
|
||||||
# [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey==']
|
# [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'C', 'sasakey==']
|
||||||
# [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A']
|
# [':irc.local.org', 'SASL', 'defender-dev.deb.biz.st', '00157Z26U', 'D', 'A']
|
||||||
|
psasl = self.__Irc.Sasl
|
||||||
sasl_enabled = False
|
sasl_enabled = False
|
||||||
for smod in self.__Settings.SMOD_MODULES:
|
for smod in self.__Settings.SMOD_MODULES:
|
||||||
if smod.name == 'sasl':
|
if smod.name == 'sasl':
|
||||||
@@ -1283,6 +1515,7 @@ class Unrealircd6:
|
|||||||
sasl_obj.fingerprint = str(sCopy[6])
|
sasl_obj.fingerprint = str(sCopy[6])
|
||||||
self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +")
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +")
|
||||||
|
|
||||||
|
self.on_sasl_authentication_process(sasl_obj)
|
||||||
return sasl_obj
|
return sasl_obj
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
@@ -1295,10 +1528,105 @@ class Unrealircd6:
|
|||||||
sasl_obj.username = username
|
sasl_obj.username = username
|
||||||
sasl_obj.password = password
|
sasl_obj.password = password
|
||||||
|
|
||||||
|
self.on_sasl_authentication_process(sasl_obj)
|
||||||
return sasl_obj
|
return sasl_obj
|
||||||
elif sasl_obj.mechanisme == "EXTERNAL":
|
elif sasl_obj.mechanisme == "EXTERNAL":
|
||||||
sasl_obj.message_type = sasl_message_type
|
sasl_obj.message_type = sasl_message_type
|
||||||
|
|
||||||
|
self.on_sasl_authentication_process(sasl_obj)
|
||||||
return sasl_obj
|
return sasl_obj
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.__Logs.error(f'General Error: {err}', exc_info=True)
|
self.__Logs.error(f'General Error: {err}', exc_info=True)
|
||||||
|
|
||||||
|
def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool:
|
||||||
|
s = sasl_model
|
||||||
|
if sasl_model:
|
||||||
|
def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]:
|
||||||
|
if fingerprint:
|
||||||
|
mes_donnees = {'fingerprint': fingerprint}
|
||||||
|
query = f"SELECT user, level, language FROM {self.__Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint"
|
||||||
|
else:
|
||||||
|
mes_donnees = {'user': username, 'password': self.__Utils.hash_password(password)}
|
||||||
|
query = f"SELECT user, level, language FROM {self.__Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
||||||
|
|
||||||
|
result = self.__Base.db_execute_query(query, mes_donnees)
|
||||||
|
user_from_db = result.fetchone()
|
||||||
|
if user_from_db:
|
||||||
|
return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]}
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if s.message_type == 'C' and s.mechanisme == 'PLAIN':
|
||||||
|
# Connection via PLAIN
|
||||||
|
admin_info = db_get_admin_info(username=s.username, password=s.password)
|
||||||
|
if admin_info is not None:
|
||||||
|
s.auth_success = True
|
||||||
|
s.level = admin_info.get('level', 0)
|
||||||
|
s.language = admin_info.get('language', 'EN')
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
||||||
|
else:
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F")
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed")
|
||||||
|
|
||||||
|
elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL':
|
||||||
|
# Connection using fingerprints
|
||||||
|
admin_info = db_get_admin_info(fingerprint=s.fingerprint)
|
||||||
|
|
||||||
|
if admin_info is not None:
|
||||||
|
s.auth_success = True
|
||||||
|
s.level = admin_info.get('level', 0)
|
||||||
|
s.username = admin_info.get('user', None)
|
||||||
|
s.language = admin_info.get('language', 'EN')
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
||||||
|
else:
|
||||||
|
# "904 <nick> :SASL authentication failed"
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} SASL {self.__Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F")
|
||||||
|
self.send2socket(f":{self.__Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed")
|
||||||
|
|
||||||
|
def on_md(self, serverMsg: list[str]) -> None:
|
||||||
|
"""Handle MD responses
|
||||||
|
[':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server reply
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
scopy = serverMsg.copy()
|
||||||
|
available_vars = ['creationtime', 'certfp', 'tls_cipher']
|
||||||
|
|
||||||
|
uid = str(scopy[3])
|
||||||
|
var = str(scopy[4]).lower()
|
||||||
|
value = str(scopy[5]).replace(':', '')
|
||||||
|
|
||||||
|
user_obj = self.__Irc.User.get_user(uid)
|
||||||
|
if user_obj is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
match var:
|
||||||
|
case 'certfp':
|
||||||
|
user_obj.fingerprint = value
|
||||||
|
case 'tls_cipher':
|
||||||
|
user_obj.tls_cipher = value
|
||||||
|
case _:
|
||||||
|
return None
|
||||||
|
|
||||||
|
...
|
||||||
|
except Exception as e:
|
||||||
|
self.__Logs.error(f"General Error: {e}")
|
||||||
|
|
||||||
|
def on_kick(self, serverMsg: list[str]) -> None:
|
||||||
|
"""When a user is kicked out from a channel
|
||||||
|
|
||||||
|
['@unrealircd.org/issued-by=RPC:admin-for-test@...', ':001', 'KICK', '#jsonrpc', '001ELW13T', ':Kicked', 'from', 'JSONRPC', 'User']
|
||||||
|
Args:
|
||||||
|
serverMsg (list[str]): The server message
|
||||||
|
"""
|
||||||
|
scopy = serverMsg.copy()
|
||||||
|
uid = scopy[4]
|
||||||
|
channel = scopy[3]
|
||||||
|
|
||||||
|
# Delete the user from the channel.
|
||||||
|
self.__Irc.Channel.delete_user_from_channel(channel, uid)
|
||||||
|
return None
|
||||||
@@ -3,7 +3,6 @@ import sys
|
|||||||
import time
|
import time
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
import socket
|
import socket
|
||||||
from core.classes.protocol import Protocol
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
@@ -15,14 +14,20 @@ REHASH_MODULES = [
|
|||||||
'core.classes.config',
|
'core.classes.config',
|
||||||
'core.base',
|
'core.base',
|
||||||
'core.classes.commands',
|
'core.classes.commands',
|
||||||
|
'core.classes.protocols.interface',
|
||||||
|
'core.classes.protocols.factory',
|
||||||
'core.classes.protocols.unreal6',
|
'core.classes.protocols.unreal6',
|
||||||
'core.classes.protocols.inspircd',
|
'core.classes.protocols.inspircd'
|
||||||
'core.classes.protocol'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -> None:
|
def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -> None:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
uplink (Irc): The Irc instance
|
||||||
|
reason (str): The reason of the restart.
|
||||||
|
"""
|
||||||
# reload modules.
|
# reload 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)
|
uplink.ModuleUtils.unload_one_module(uplink, module.module_name)
|
||||||
@@ -33,14 +38,8 @@ def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -
|
|||||||
uplink.Client.CLIENT_DB.clear() # Clear Client object
|
uplink.Client.CLIENT_DB.clear() # Clear Client object
|
||||||
uplink.Base.garbage_collector_thread()
|
uplink.Base.garbage_collector_thread()
|
||||||
|
|
||||||
# Reload configuration
|
|
||||||
uplink.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).get_config_model()
|
|
||||||
uplink.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
|
|
||||||
uplink.Protocol = Protocol(uplink.Config.SERVEUR_PROTOCOL, uplink.ircObject).Protocol
|
|
||||||
uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!')
|
uplink.Logs.debug(f'[{uplink.Config.SERVICE_NICKNAME} RESTART]: Reloading configuration!')
|
||||||
|
uplink.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason=reason)
|
||||||
uplink.Protocol.send_squit(server_id=uplink.Config.SERVEUR_ID, server_link=uplink.Config.SERVEUR_LINK, reason="Defender Power off")
|
|
||||||
|
|
||||||
uplink.Logs.debug('Restarting Defender ...')
|
uplink.Logs.debug('Restarting Defender ...')
|
||||||
uplink.IrcSocket.shutdown(socket.SHUT_RDWR)
|
uplink.IrcSocket.shutdown(socket.SHUT_RDWR)
|
||||||
uplink.IrcSocket.close()
|
uplink.IrcSocket.close()
|
||||||
@@ -49,11 +48,19 @@ def restart_service(uplink: 'Irc', reason: str = "Restarting with no reason!") -
|
|||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
uplink.Logs.warning('-- Waiting for socket to close ...')
|
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.init_service_user()
|
||||||
uplink.Utils.create_socket(uplink)
|
uplink.Utils.create_socket(uplink)
|
||||||
uplink.Protocol.send_link()
|
uplink.Protocol.send_link()
|
||||||
uplink.join_saved_channels()
|
|
||||||
uplink.ModuleUtils.db_load_all_existing_modules(uplink)
|
|
||||||
uplink.Config.DEFENDER_RESTART = 0
|
uplink.Config.DEFENDER_RESTART = 0
|
||||||
|
|
||||||
def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
||||||
@@ -69,8 +76,8 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
|||||||
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.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).get_config_model()
|
uplink.Config = uplink.Loader.ConfModule.Configuration(uplink.Loader).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
|
||||||
@@ -105,8 +112,9 @@ def rehash_service(uplink: 'Irc', nickname: str) -> None:
|
|||||||
uplink.Commands = uplink.Loader.CommandModule.Command(uplink.Loader)
|
uplink.Commands = uplink.Loader.CommandModule.Command(uplink.Loader)
|
||||||
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
|
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
|
||||||
|
|
||||||
uplink.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
|
uplink.Loader.Base = uplink.Loader.BaseModule.Base(uplink.Loader)
|
||||||
uplink.Protocol = Protocol(uplink.Config.SERVEUR_PROTOCOL, uplink.ircObject).Protocol
|
uplink.Protocol = uplink.Loader.PFactory.get()
|
||||||
|
uplink.Protocol.register_command()
|
||||||
|
|
||||||
# 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():
|
||||||
|
|||||||
@@ -9,9 +9,14 @@ class Reputation:
|
|||||||
UID_REPUTATION_DB: list[MReputation] = []
|
UID_REPUTATION_DB: list[MReputation] = []
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader'):
|
def __init__(self, loader: 'Loader'):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader instance.
|
||||||
|
"""
|
||||||
|
|
||||||
self.Logs = loader.Logs
|
self.Logs = loader.Logs
|
||||||
self.MReputation: MReputation = MReputation
|
self.MReputation: Optional[MReputation] = None
|
||||||
|
|
||||||
def insert(self, new_reputation_user: MReputation) -> bool:
|
def insert(self, new_reputation_user: MReputation) -> bool:
|
||||||
"""Insert a new Reputation User object
|
"""Insert a new Reputation User object
|
||||||
@@ -47,13 +52,13 @@ class Reputation:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
uid (str): UID of the user
|
uid (str): UID of the user
|
||||||
newNickname (str): New nickname
|
new_nickname (str): New nickname
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if updated
|
bool: True if updated
|
||||||
"""
|
"""
|
||||||
|
|
||||||
reputation_obj = self.get_Reputation(uid)
|
reputation_obj = self.get_reputation(uid)
|
||||||
|
|
||||||
if reputation_obj is None:
|
if reputation_obj is None:
|
||||||
return False
|
return False
|
||||||
@@ -89,7 +94,7 @@ class Reputation:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_Reputation(self, uidornickname: str) -> Optional[MReputation]:
|
def get_reputation(self, uidornickname: str) -> Optional[MReputation]:
|
||||||
"""Get The User Object model
|
"""Get The User Object model
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -116,7 +121,7 @@ class Reputation:
|
|||||||
str|None: Return the UID
|
str|None: Return the UID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
reputation_obj = self.get_Reputation(uidornickname)
|
reputation_obj = self.get_reputation(uidornickname)
|
||||||
|
|
||||||
if reputation_obj is None:
|
if reputation_obj is None:
|
||||||
return None
|
return None
|
||||||
@@ -132,7 +137,7 @@ class Reputation:
|
|||||||
Returns:
|
Returns:
|
||||||
str|None: the nickname
|
str|None: the nickname
|
||||||
"""
|
"""
|
||||||
reputation_obj = self.get_Reputation(uidornickname)
|
reputation_obj = self.get_reputation(uidornickname)
|
||||||
|
|
||||||
if reputation_obj is None:
|
if reputation_obj is None:
|
||||||
return None
|
return None
|
||||||
@@ -149,7 +154,7 @@ class Reputation:
|
|||||||
bool: True if exist
|
bool: True if exist
|
||||||
"""
|
"""
|
||||||
|
|
||||||
reputation_obj = self.get_Reputation(uidornickname)
|
reputation_obj = self.get_reputation(uidornickname)
|
||||||
|
|
||||||
if isinstance(reputation_obj, MReputation):
|
if isinstance(reputation_obj, MReputation):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Optional, Union, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.definition import MSasl
|
from core.definition import MSasl
|
||||||
@@ -9,13 +9,18 @@ class Sasl:
|
|||||||
DB_SASL: list['MSasl'] = []
|
DB_SASL: list['MSasl'] = []
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader'):
|
def __init__(self, loader: 'Loader'):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader instance.
|
||||||
|
"""
|
||||||
self.Logs = loader.Logs # logger
|
self.Logs = loader.Logs # logger
|
||||||
|
|
||||||
def insert_sasl_client(self, psasl: 'MSasl') -> bool:
|
def insert_sasl_client(self, psasl: 'MSasl') -> bool:
|
||||||
"""Insert a new Sasl authentication
|
"""Insert a new Sasl authentication
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
new_user (UserModel): New userModel object
|
psasl (MSasl): New userModel object
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if inserted
|
bool: True if inserted
|
||||||
@@ -38,7 +43,7 @@ class Sasl:
|
|||||||
"""Delete the User starting from the UID
|
"""Delete the User starting from the UID
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
uid (str): UID of the user
|
client_uid (str): UID of the user
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if deleted
|
bool: True if deleted
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
'''This class should never be reloaded.
|
"""This class should never be reloaded.
|
||||||
'''
|
"""
|
||||||
|
from logging import Logger
|
||||||
from threading import Timer, Thread, RLock
|
from threading import Timer, Thread, RLock
|
||||||
from socket import socket
|
from socket import socket
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
from core.definition import MSModule
|
from core.definition import MSModule, MAdmin
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.classes.user import User
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
"""This Class will never be reloaded.
|
"""This Class will never be reloaded.
|
||||||
@@ -11,24 +15,42 @@ class Settings:
|
|||||||
the whole life of the app
|
the whole life of the app
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RUNNING_TIMERS: list[Timer] = []
|
RUNNING_TIMERS: list[Timer] = []
|
||||||
RUNNING_THREADS: list[Thread] = []
|
RUNNING_THREADS: list[Thread] = []
|
||||||
RUNNING_SOCKETS: list[socket] = []
|
RUNNING_SOCKETS: list[socket] = []
|
||||||
PERIODIC_FUNC: dict[object] = {}
|
PERIODIC_FUNC: dict[str, Any] = {}
|
||||||
LOCK: RLock = RLock()
|
LOCK: RLock = RLock()
|
||||||
|
|
||||||
CONSOLE: bool = False
|
CONSOLE: bool = False
|
||||||
|
|
||||||
MAIN_SERVER_HOSTNAME: str = None
|
MAIN_SERVER_HOSTNAME: str = None
|
||||||
PROTOCTL_USER_MODES: list[str] = []
|
MAIN_SERVER_ID: str = None
|
||||||
PROTOCTL_PREFIX: list[str] = []
|
PROTOCTL_PREFIX_MODES_SIGNES : dict[str, str] = {}
|
||||||
|
PROTOCTL_PREFIX_SIGNES_MODES : dict[str, str] = {}
|
||||||
|
PROTOCTL_USER_MODES: list[str] = []
|
||||||
|
PROTOCTL_CHANNEL_MODES: list[str] = []
|
||||||
|
PROTOCTL_PREFIX: list[str] = []
|
||||||
|
|
||||||
SMOD_MODULES: list[MSModule] = []
|
SMOD_MODULES: list[MSModule] = []
|
||||||
"""List contains all Server modules"""
|
"""List contains all Server modules"""
|
||||||
|
|
||||||
__CACHE: dict[str, Any] = {}
|
__CACHE: dict[str, Any] = {}
|
||||||
"""Use set_cache or get_cache instead"""
|
"""Use set_cache or get_cache instead"""
|
||||||
|
|
||||||
|
__TRANSLATION: dict[str, list[list[str]]] = dict()
|
||||||
|
"""Translation Varibale"""
|
||||||
|
|
||||||
|
__LANG: str = "EN"
|
||||||
|
|
||||||
|
__INSTANCE_OF_USER_UTILS: Optional['User'] = None
|
||||||
|
"""Instance of the User Utils class"""
|
||||||
|
|
||||||
|
__CURRENT_ADMIN: Optional['MAdmin'] = None
|
||||||
|
"""The Current Admin Object Model"""
|
||||||
|
|
||||||
|
__LOGGER: Optional[Logger] = None
|
||||||
|
"""Instance of the logger"""
|
||||||
|
|
||||||
def set_cache(self, key: str, value_to_cache: Any):
|
def set_cache(self, key: str, value_to_cache: Any):
|
||||||
"""When you want to store a variable
|
"""When you want to store a variable
|
||||||
|
|
||||||
@@ -56,4 +78,50 @@ class Settings:
|
|||||||
self.__CACHE.clear()
|
self.__CACHE.clear()
|
||||||
|
|
||||||
def show_cache(self) -> dict[str, Any]:
|
def show_cache(self) -> dict[str, Any]:
|
||||||
return self.__CACHE.copy()
|
return self.__CACHE.copy()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_translation(self) -> dict[str, list[list[str]]]:
|
||||||
|
"""Get/set global translation variable"""
|
||||||
|
return self.__TRANSLATION
|
||||||
|
|
||||||
|
@global_translation.setter
|
||||||
|
def global_translation(self, translation_var: dict) -> None:
|
||||||
|
self.__TRANSLATION = translation_var
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_lang(self) -> str:
|
||||||
|
"""Global default language."""
|
||||||
|
return self.__LANG
|
||||||
|
|
||||||
|
@global_lang.setter
|
||||||
|
def global_lang(self, lang: str) -> None:
|
||||||
|
self.__LANG = lang
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_user(self) -> 'User':
|
||||||
|
return self.__INSTANCE_OF_USER_UTILS
|
||||||
|
|
||||||
|
@global_user.setter
|
||||||
|
def global_user(self, user_utils_instance: 'User') -> None:
|
||||||
|
self.__INSTANCE_OF_USER_UTILS = user_utils_instance
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_admin(self) -> MAdmin:
|
||||||
|
"""Current admin data model."""
|
||||||
|
return self.__CURRENT_ADMIN
|
||||||
|
|
||||||
|
@current_admin.setter
|
||||||
|
def current_admin(self, current_admin: MAdmin) -> None:
|
||||||
|
self.__CURRENT_ADMIN = current_admin
|
||||||
|
|
||||||
|
@property
|
||||||
|
def global_logger(self) -> Logger:
|
||||||
|
"""Global logger Instance"""
|
||||||
|
return self.__LOGGER
|
||||||
|
|
||||||
|
@global_logger.setter
|
||||||
|
def global_logger(self, logger: Logger) -> None:
|
||||||
|
self.__LOGGER = logger
|
||||||
|
|
||||||
|
global_settings = Settings()
|
||||||
96
core/classes/translation.py
Normal file
96
core/classes/translation.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import yaml
|
||||||
|
import yaml.scanner
|
||||||
|
from os import sep
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
|
|
||||||
|
class Translation:
|
||||||
|
|
||||||
|
def __init__(self, loader: 'Loader') -> None:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
loader (Loader): The Loader instance.
|
||||||
|
"""
|
||||||
|
self.Logs = loader.Logs
|
||||||
|
self.Settings = loader.Settings
|
||||||
|
|
||||||
|
def get_translation(self) -> dict[str, list[list[str]]]:
|
||||||
|
try:
|
||||||
|
translation: dict[str, list[list[str]]] = dict()
|
||||||
|
sfs: dict[str, list[list[str]]] = {}
|
||||||
|
|
||||||
|
module_translation_directory = Path("mods")
|
||||||
|
core_translation_directory = Path("core")
|
||||||
|
sfs_core = self.get_subfolders_name(core_translation_directory.__str__())
|
||||||
|
sfs_module = self.get_subfolders_name(module_translation_directory.__str__())
|
||||||
|
|
||||||
|
# Combine the 2 dict
|
||||||
|
for d in (sfs_core, sfs_module):
|
||||||
|
for k, v in d.items():
|
||||||
|
sfs.setdefault(k, []).extend(v)
|
||||||
|
|
||||||
|
loaded_files: list[str] = []
|
||||||
|
|
||||||
|
for module, filenames in sfs.items():
|
||||||
|
translation[module] = []
|
||||||
|
for filename in filenames:
|
||||||
|
with open(f"{filename}", "r", encoding="utf-8") as fyaml:
|
||||||
|
data: dict[str, list[dict[str, str]]] = yaml.safe_load(fyaml)
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for key, list_trad in data.items():
|
||||||
|
for vlist in list_trad:
|
||||||
|
translation[module].append([vlist["orig"], vlist["trad"]])
|
||||||
|
|
||||||
|
loaded_files.append(f"{filename}")
|
||||||
|
|
||||||
|
return translation
|
||||||
|
|
||||||
|
except yaml.scanner.ScannerError as se:
|
||||||
|
self.Logs.error(f"[!] {se} [!]")
|
||||||
|
return {}
|
||||||
|
except yaml.YAMLError as ye:
|
||||||
|
if hasattr(ye, 'problem_mark'):
|
||||||
|
mark = ye.problem_mark
|
||||||
|
self.Logs.error(f"Error YAML: {ye.with_traceback(None)}")
|
||||||
|
self.Logs.error("Error position: (%s:%s)" % (mark.line+1, mark.column+1))
|
||||||
|
return {}
|
||||||
|
except yaml.error.MarkedYAMLError as me:
|
||||||
|
self.Logs.error(f"[!] {me} [!]")
|
||||||
|
return {}
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'General Error: {err}', exc_info=True)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.Logs.debug("Translation files loaded")
|
||||||
|
for f in loaded_files:
|
||||||
|
self.Logs.debug(f" - {f}")
|
||||||
|
|
||||||
|
def get_subfolders_name(self, directory: str) -> dict[str, list[str]]:
|
||||||
|
try:
|
||||||
|
translation_information: dict[str, list[str]] = dict()
|
||||||
|
main_directory = Path(directory)
|
||||||
|
|
||||||
|
# Init the dictionnary
|
||||||
|
for subfolder in main_directory.rglob(f'*language{sep}*{sep}*.yaml'):
|
||||||
|
if subfolder.name != '__pycache__':
|
||||||
|
translation_information[subfolder.parent.name.lower()] = []
|
||||||
|
|
||||||
|
|
||||||
|
for subfolder in main_directory.rglob(f'*language{sep}*{sep}*.yaml'):
|
||||||
|
if subfolder.name != '__pycache__':
|
||||||
|
translation_information[subfolder.parent.name.lower()].append(subfolder)
|
||||||
|
|
||||||
|
return translation_information
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
self.Logs.error(f'General Error: {err}')
|
||||||
|
return {}
|
||||||
@@ -10,10 +10,15 @@ class User:
|
|||||||
|
|
||||||
UID_DB: list['MUser'] = []
|
UID_DB: list['MUser'] = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_current_user(self) -> 'MUser':
|
||||||
|
return self.current_user
|
||||||
|
|
||||||
def __init__(self, loader: 'Loader'):
|
def __init__(self, loader: 'Loader'):
|
||||||
|
|
||||||
self.Logs = loader.Logs
|
self.Logs = loader.Logs
|
||||||
self.Base = loader.Base
|
self.Base = loader.Base
|
||||||
|
self.current_user: Optional['MUser'] = None
|
||||||
|
|
||||||
def insert(self, new_user: 'MUser') -> bool:
|
def insert(self, new_user: 'MUser') -> bool:
|
||||||
"""Insert a new User object
|
"""Insert a new User object
|
||||||
@@ -50,7 +55,7 @@ class User:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
user_obj.nickname = new_nickname
|
user_obj.nickname = new_nickname
|
||||||
|
self.Logs.debug(f"UID ({uid}) has benn update with new nickname ({new_nickname}).")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def update_mode(self, uidornickname: str, modes: str) -> bool:
|
def update_mode(self, uidornickname: str, modes: str) -> bool:
|
||||||
@@ -126,8 +131,10 @@ class User:
|
|||||||
"""
|
"""
|
||||||
for record in self.UID_DB:
|
for record in self.UID_DB:
|
||||||
if record.uid == uidornickname:
|
if record.uid == uidornickname:
|
||||||
|
self.current_user = record
|
||||||
return record
|
return record
|
||||||
elif record.nickname == uidornickname:
|
elif record.nickname == uidornickname:
|
||||||
|
self.current_user = record
|
||||||
return record
|
return record
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -147,6 +154,7 @@ class User:
|
|||||||
if user_obj is None:
|
if user_obj is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
self.current_user = user_obj
|
||||||
return user_obj.uid
|
return user_obj.uid
|
||||||
|
|
||||||
def get_nickname(self, uidornickname:str) -> Optional[str]:
|
def get_nickname(self, uidornickname:str) -> Optional[str]:
|
||||||
@@ -163,6 +171,7 @@ class User:
|
|||||||
if user_obj is None:
|
if user_obj is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
self.current_user = user_obj
|
||||||
return user_obj.nickname
|
return user_obj.nickname
|
||||||
|
|
||||||
def get_user_asdict(self, uidornickname: str) -> Optional[dict[str, Any]]:
|
def get_user_asdict(self, uidornickname: str) -> Optional[dict[str, Any]]:
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class MClient(MainModel):
|
|||||||
umodes: str = None
|
umodes: str = None
|
||||||
vhost: str = None
|
vhost: str = None
|
||||||
fingerprint: str = None
|
fingerprint: str = None
|
||||||
|
tls_cipher: str = None
|
||||||
isWebirc: bool = False
|
isWebirc: bool = False
|
||||||
isWebsocket: bool = False
|
isWebsocket: bool = False
|
||||||
remote_ip: str = None
|
remote_ip: str = None
|
||||||
@@ -50,6 +51,7 @@ class MUser(MainModel):
|
|||||||
umodes: str = None
|
umodes: str = None
|
||||||
vhost: str = None
|
vhost: str = None
|
||||||
fingerprint: str = None
|
fingerprint: str = None
|
||||||
|
tls_cipher: str = None
|
||||||
isWebirc: bool = False
|
isWebirc: bool = False
|
||||||
isWebsocket: bool = False
|
isWebsocket: bool = False
|
||||||
remote_ip: str = None
|
remote_ip: str = None
|
||||||
@@ -70,12 +72,14 @@ class MAdmin(MainModel):
|
|||||||
umodes: str = None
|
umodes: str = None
|
||||||
vhost: str = None
|
vhost: str = None
|
||||||
fingerprint: str = None
|
fingerprint: str = None
|
||||||
|
tls_cipher: str = None
|
||||||
isWebirc: bool = False
|
isWebirc: bool = False
|
||||||
isWebsocket: bool = False
|
isWebsocket: bool = False
|
||||||
remote_ip: str = None
|
remote_ip: str = None
|
||||||
score_connexion: int = 0
|
score_connexion: int = 0
|
||||||
geoip: str = None
|
geoip: str = None
|
||||||
connexion_datetime: datetime = field(default=datetime.now())
|
connexion_datetime: datetime = field(default=datetime.now())
|
||||||
|
language: str = "EN"
|
||||||
level: int = 0
|
level: int = 0
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -89,6 +93,7 @@ class MReputation(MainModel):
|
|||||||
umodes: str = None
|
umodes: str = None
|
||||||
vhost: str = None
|
vhost: str = None
|
||||||
fingerprint: str = None
|
fingerprint: str = None
|
||||||
|
tls_cipher: str = None
|
||||||
isWebirc: bool = False
|
isWebirc: bool = False
|
||||||
isWebsocket: bool = False
|
isWebsocket: bool = False
|
||||||
remote_ip: str = None
|
remote_ip: str = None
|
||||||
@@ -191,6 +196,9 @@ class MConfig(MainModel):
|
|||||||
SERVICE_ID: str = field(init=False)
|
SERVICE_ID: str = field(init=False)
|
||||||
"""The service unique ID"""
|
"""The service unique ID"""
|
||||||
|
|
||||||
|
LANG: str = "EN"
|
||||||
|
"""The default language of Defender. default: EN"""
|
||||||
|
|
||||||
OWNER: str = "admin"
|
OWNER: str = "admin"
|
||||||
"""The nickname of the admin of the service"""
|
"""The nickname of the admin of the service"""
|
||||||
|
|
||||||
@@ -359,5 +367,16 @@ class MSasl(MainModel):
|
|||||||
username: Optional[str] = None
|
username: Optional[str] = None
|
||||||
password: Optional[str] = None
|
password: Optional[str] = None
|
||||||
fingerprint: Optional[str] = None
|
fingerprint: Optional[str] = None
|
||||||
|
language: str = "EN"
|
||||||
auth_success: bool = False
|
auth_success: bool = False
|
||||||
level: int = 0
|
level: int = 0
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MRegister:
|
||||||
|
command_name: str
|
||||||
|
func: Any
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MIrcdCommand:
|
||||||
|
command_name: str
|
||||||
|
func: Any
|
||||||
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,331 +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[str, str, str]
|
|
||||||
python_current_version: str
|
|
||||||
defender_install_folder: str
|
|
||||||
venv_folder: str
|
|
||||||
venv_cmd_installation: list
|
|
||||||
venv_cmd_requirements: list
|
|
||||||
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',
|
|
||||||
python_current_version_tuple=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','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.json')):
|
|
||||||
# If configuration file do not exist
|
|
||||||
exit("/!\\ Configuration file (core/configuration.json) 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 = 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_major, required_minor, required_patch = required_version.split('.')
|
|
||||||
installed_major, installed_minor, installed_patch = installed_version.split('.')
|
|
||||||
|
|
||||||
if required_major > installed_major:
|
|
||||||
print(f'> New version of {package.name} is available {installed_version} ==> {required_version}')
|
|
||||||
newVersion = True
|
|
||||||
elif required_major == installed_major and required_minor > installed_minor:
|
|
||||||
print(f'> New version of {package.name} is available {installed_version} ==> {required_version}')
|
|
||||||
newVersion = True
|
|
||||||
elif required_major == installed_major and required_minor == installed_minor and required_patch > installed_patch:
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
# Current system version
|
|
||||||
sys_major, sys_minor, sys_patch = self.config.python_current_version_tuple
|
|
||||||
|
|
||||||
# min python version required
|
|
||||||
python_required_version = self.config.python_min_version.split('.')
|
|
||||||
min_major, min_minor = tuple((python_required_version[0], python_required_version[1]))
|
|
||||||
|
|
||||||
if int(sys_major) < int(min_major):
|
|
||||||
print(f"## Your python version must be greather than or equal to {self.config.python_min_version} ##")
|
|
||||||
return False
|
|
||||||
|
|
||||||
elif (int(sys_major) <= int(min_major)) and (int(sys_minor) < int(min_minor)):
|
|
||||||
print(f"## Your python version must be greather than or equal to {self.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:
|
|
||||||
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)
|
|
||||||
317
core/irc.py
317
core/irc.py
@@ -7,12 +7,12 @@ from ssl import SSLSocket
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||||
from core.classes import rehash
|
from core.classes import rehash
|
||||||
from core.loader import Loader
|
from core.classes.protocols.interface import IProtocol
|
||||||
from core.classes.protocol import Protocol
|
from core.utils import tr
|
||||||
from core.classes.commands import Command
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.definition import MSasl
|
from core.definition import MSasl
|
||||||
|
from core.loader import Loader
|
||||||
|
|
||||||
class Irc:
|
class Irc:
|
||||||
_instance = None
|
_instance = None
|
||||||
@@ -24,7 +24,7 @@ class Irc:
|
|||||||
|
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self, loader: Loader) -> 'Irc':
|
def __init__(self, loader: 'Loader'):
|
||||||
|
|
||||||
# Loader class
|
# Loader class
|
||||||
self.Loader = loader
|
self.Loader = loader
|
||||||
@@ -135,7 +135,7 @@ class Irc:
|
|||||||
##############################################
|
##############################################
|
||||||
# CONNEXION IRC #
|
# CONNEXION IRC #
|
||||||
##############################################
|
##############################################
|
||||||
def init_irc(self, ircInstance: 'Irc') -> None:
|
def init_irc(self) -> None:
|
||||||
"""Create a socket and connect to irc server
|
"""Create a socket and connect to irc server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -143,8 +143,8 @@ class Irc:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.init_service_user()
|
self.init_service_user()
|
||||||
self.Utils.create_socket(ircInstance)
|
self.Utils.create_socket(self)
|
||||||
self.__connect_to_irc(ircInstance)
|
self.__connect_to_irc()
|
||||||
|
|
||||||
except AssertionError as ae:
|
except AssertionError as ae:
|
||||||
self.Logs.critical(f'Assertion error: {ae}')
|
self.Logs.critical(f'Assertion error: {ae}')
|
||||||
@@ -161,23 +161,20 @@ class Irc:
|
|||||||
))
|
))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __connect_to_irc(self, ircInstance: 'Irc') -> None:
|
def __connect_to_irc(self) -> None:
|
||||||
try:
|
try:
|
||||||
self.init_service_user()
|
self.init_service_user()
|
||||||
self.ircObject = ircInstance # créer une copie de l'instance Irc
|
self.Protocol: 'IProtocol' = self.Loader.PFactory.get()
|
||||||
self.Protocol = Protocol(
|
self.Protocol.register_command()
|
||||||
protocol=self.Config.SERVEUR_PROTOCOL,
|
|
||||||
ircInstance=self.ircObject
|
|
||||||
).Protocol
|
|
||||||
self.Protocol.send_link() # Etablir le link en fonction du protocol choisi
|
self.Protocol.send_link() # Etablir le link en fonction du protocol choisi
|
||||||
self.signal = True # Une variable pour initier la boucle infinie
|
self.signal = True # Une variable pour initier la boucle infinie
|
||||||
self.join_saved_channels() # Join existing channels
|
# self.join_saved_channels() # Join existing channels
|
||||||
self.ModuleUtils.db_load_all_existing_modules(self)
|
# self.ModuleUtils.db_load_all_existing_modules(self)
|
||||||
|
|
||||||
while self.signal:
|
while self.signal:
|
||||||
try:
|
try:
|
||||||
if self.Config.DEFENDER_RESTART == 1:
|
if self.Config.DEFENDER_RESTART == 1:
|
||||||
rehash.restart_service(self.ircObject)
|
rehash.restart_service(self)
|
||||||
|
|
||||||
# 4072 max what the socket can grab
|
# 4072 max what the socket can grab
|
||||||
buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
|
buffer_size = self.IrcSocket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
|
||||||
@@ -202,9 +199,11 @@ class Irc:
|
|||||||
self.Logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}")
|
self.Logs.error(f"SSLEOFError __connect_to_irc: {soe} - {data}")
|
||||||
except ssl.SSLError as se:
|
except ssl.SSLError as se:
|
||||||
self.Logs.error(f"SSLError __connect_to_irc: {se} - {data}")
|
self.Logs.error(f"SSLError __connect_to_irc: {se} - {data}")
|
||||||
sys.exit(1)
|
sys.exit(-1)
|
||||||
except OSError as oe:
|
except OSError as oe:
|
||||||
self.Logs.error(f"SSLError __connect_to_irc: {oe} - {data}")
|
self.Logs.error(f"SSLError __connect_to_irc: {oe} {oe.errno}")
|
||||||
|
if oe.errno == 10053:
|
||||||
|
sys.exit(-1)
|
||||||
except (socket.error, ConnectionResetError):
|
except (socket.error, ConnectionResetError):
|
||||||
self.Logs.debug("Connexion reset")
|
self.Logs.debug("Connexion reset")
|
||||||
|
|
||||||
@@ -220,7 +219,7 @@ class Irc:
|
|||||||
except ssl.SSLEOFError as soe:
|
except ssl.SSLEOFError as soe:
|
||||||
self.Logs.error(f"SSLEOFError: {soe}")
|
self.Logs.error(f"SSLEOFError: {soe}")
|
||||||
except AttributeError as atte:
|
except AttributeError as atte:
|
||||||
self.Logs.critical(f"AttributeError: {atte}")
|
self.Logs.critical(f"AttributeError: {atte}", exc_info=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.Logs.critical(f"General Error: {e}", exc_info=True)
|
self.Logs.critical(f"General Error: {e}", exc_info=True)
|
||||||
|
|
||||||
@@ -261,9 +260,9 @@ class Irc:
|
|||||||
# This is only to reference the method
|
# This is only to reference the method
|
||||||
return None
|
return None
|
||||||
|
|
||||||
##############################################
|
# --------------------------------------------
|
||||||
# FIN CONNEXION IRC #
|
# FIN CONNEXION IRC #
|
||||||
##############################################
|
# --------------------------------------------
|
||||||
|
|
||||||
def build_command(self, level: int, module_name: str, command_name: str, command_description: str) -> None:
|
def build_command(self, level: int, module_name: str, command_name: str, command_description: str) -> None:
|
||||||
"""This method build the commands variable
|
"""This method build the commands variable
|
||||||
@@ -313,15 +312,15 @@ class Irc:
|
|||||||
def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]:
|
def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]:
|
||||||
if fingerprint:
|
if fingerprint:
|
||||||
mes_donnees = {'fingerprint': fingerprint}
|
mes_donnees = {'fingerprint': fingerprint}
|
||||||
query = f"SELECT user, level FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint"
|
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint"
|
||||||
else:
|
else:
|
||||||
mes_donnees = {'user': username, 'password': self.Utils.hash_password(password)}
|
mes_donnees = {'user': username, 'password': self.Utils.hash_password(password)}
|
||||||
query = f"SELECT user, level FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
||||||
|
|
||||||
result = self.Base.db_execute_query(query, mes_donnees)
|
result = self.Base.db_execute_query(query, mes_donnees)
|
||||||
user_from_db = result.fetchone()
|
user_from_db = result.fetchone()
|
||||||
if user_from_db:
|
if user_from_db:
|
||||||
return {'user': user_from_db[0], 'level': user_from_db[1]}
|
return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]}
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -331,6 +330,7 @@ class Irc:
|
|||||||
if admin_info is not None:
|
if admin_info is not None:
|
||||||
s.auth_success = True
|
s.auth_success = True
|
||||||
s.level = admin_info.get('level', 0)
|
s.level = admin_info.get('level', 0)
|
||||||
|
s.language = admin_info.get('language', 'EN')
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
||||||
else:
|
else:
|
||||||
@@ -345,6 +345,7 @@ class Irc:
|
|||||||
s.auth_success = True
|
s.auth_success = True
|
||||||
s.level = admin_info.get('level', 0)
|
s.level = admin_info.get('level', 0)
|
||||||
s.username = admin_info.get('user', None)
|
s.username = admin_info.get('user', None)
|
||||||
|
s.language = admin_info.get('language', 'EN')
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} SASL {self.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
self.Protocol.send2socket(f":{self.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
||||||
else:
|
else:
|
||||||
@@ -380,14 +381,16 @@ class Irc:
|
|||||||
time.sleep(beat)
|
time.sleep(beat)
|
||||||
self.Base.execute_periodic_action()
|
self.Base.execute_periodic_action()
|
||||||
|
|
||||||
def insert_db_admin(self, uid: str, account: str, level: int) -> None:
|
def insert_db_admin(self, uid: str, account: str, level: int, language: str) -> None:
|
||||||
user_obj = self.User.get_user(uid)
|
user_obj = self.User.get_user(uid)
|
||||||
|
|
||||||
if user_obj is None:
|
if user_obj is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.Admin.insert(
|
self.Admin.insert(
|
||||||
self.Loader.Definition.MAdmin(
|
self.Loader.Definition.MAdmin(
|
||||||
**user_obj.to_dict(),
|
**user_obj.to_dict(),
|
||||||
|
language=language,
|
||||||
account=account,
|
account=account,
|
||||||
level=int(level)
|
level=int(level)
|
||||||
)
|
)
|
||||||
@@ -405,57 +408,58 @@ class Irc:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def create_defender_user(self, nickname: str, level: int, password: str) -> str:
|
def create_defender_user(self, sender: str, new_admin: str, new_level: int, new_password: str) -> bool:
|
||||||
|
"""Create a new admin user for defender
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sender (str): The current admin sending the request
|
||||||
|
new_admin (str): The new admin to create
|
||||||
|
new_level (int): The level of the admin
|
||||||
|
new_password (str): The clear password
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if created.
|
||||||
|
"""
|
||||||
|
|
||||||
# > addaccess [nickname] [level] [password]
|
# > addaccess [nickname] [level] [password]
|
||||||
|
dnick = self.Config.SERVICE_NICKNAME
|
||||||
|
p = self.Protocol
|
||||||
|
|
||||||
get_user = self.User.get_user(nickname)
|
get_user = self.User.get_user(new_admin)
|
||||||
level = self.Base.convert_to_int(level)
|
level = self.Base.convert_to_int(new_level)
|
||||||
password = password
|
password = new_password
|
||||||
|
|
||||||
if get_user is None:
|
if get_user is None:
|
||||||
response = f'This nickname {nickname} does not exist, it is not possible to create this user'
|
response = tr("The nickname (%s) is not currently connected! please create a new admin when the nickname is connected to the network!", new_admin)
|
||||||
self.Logs.warning(response)
|
p.send_notice(dnick, sender, response)
|
||||||
return response
|
self.Logs.debug(f"New admin {new_admin} sent by {sender} is not connected")
|
||||||
|
return False
|
||||||
|
|
||||||
if level is None:
|
if level is None or level > 4 or level == 0:
|
||||||
response = f'The level [{level}] must be a number from 1 to 4'
|
p.send_notice(dnick, sender, tr("The level (%s) must be a number from 1 to 4", level))
|
||||||
self.Logs.warning(response)
|
self.Logs.debug(f"Level must a number between 1 to 4 (sent by {sender})")
|
||||||
return response
|
return False
|
||||||
|
|
||||||
if level > 4:
|
|
||||||
response = "Impossible d'ajouter un niveau > 4"
|
|
||||||
self.Logs.warning(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
nickname = get_user.nickname
|
nickname = get_user.nickname
|
||||||
response = ''
|
|
||||||
|
|
||||||
hostname = get_user.hostname
|
hostname = get_user.hostname
|
||||||
vhost = get_user.vhost
|
vhost = get_user.vhost
|
||||||
spassword = self.Loader.Utils.hash_password(password)
|
spassword = self.Loader.Utils.hash_password(password)
|
||||||
|
|
||||||
mes_donnees = {'admin': nickname}
|
# Check if the user already exist
|
||||||
query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user=:admin"
|
if not self.Admin.db_is_admin_exist(nickname):
|
||||||
r = self.Base.db_execute_query(query_search_user, mes_donnees)
|
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level, 'language': 'EN'}
|
||||||
exist_user = r.fetchone()
|
|
||||||
|
|
||||||
# On verifie si le user exist dans la base
|
|
||||||
if not exist_user:
|
|
||||||
mes_donnees = {'datetime': self.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level}
|
|
||||||
self.Base.db_execute_query(f'''INSERT INTO {self.Config.TABLE_ADMIN}
|
self.Base.db_execute_query(f'''INSERT INTO {self.Config.TABLE_ADMIN}
|
||||||
(createdOn, user, password, hostname, vhost, level) VALUES
|
(createdOn, user, password, hostname, vhost, level, language) VALUES
|
||||||
(:datetime, :user, :password, :hostname, :vhost, :level)
|
(:datetime, :user, :password, :hostname, :vhost, :level, :language)
|
||||||
''', mes_donnees)
|
''', mes_donnees)
|
||||||
response = f"{nickname} ajouté en tant qu'administrateur de niveau {level}"
|
|
||||||
self.Protocol.send_notice(nick_from=self.Config.SERVICE_NICKNAME, nick_to=nickname, msg=response)
|
p.send_notice(dnick, sender, tr("New admin (%s) has been added with level %s", nickname, level))
|
||||||
self.Logs.info(response)
|
self.Logs.info(f"A new admin ({nickname}) has been created by {sender}!")
|
||||||
return response
|
return True
|
||||||
else:
|
else:
|
||||||
response = f'{nickname} Existe déjà dans les users enregistrés'
|
p.send_notice(dnick, sender, tr("The nickname (%s) Already exist!", nickname))
|
||||||
self.Protocol.send_notice(nick_from=self.Config.SERVICE_NICKNAME, nick_to=nickname, msg=response)
|
self.Logs.info(f"The nickname {nickname} already exist! (sent by {sender})")
|
||||||
self.Logs.info(response)
|
return False
|
||||||
return response
|
|
||||||
|
|
||||||
def thread_check_for_new_version(self, fromuser: str) -> None:
|
def thread_check_for_new_version(self, fromuser: str) -> None:
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
dnickname = self.Config.SERVICE_NICKNAME
|
||||||
@@ -476,123 +480,21 @@ class Irc:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
original_response: list[str] = data.copy()
|
original_response: list[str] = data.copy()
|
||||||
|
RED = self.Config.COLORS.red
|
||||||
|
GREEN = self.Config.COLORS.green
|
||||||
|
NOGC = self.Config.COLORS.nogc
|
||||||
|
|
||||||
if len(original_response) < 2:
|
if len(original_response) < 2:
|
||||||
self.Logs.warning(f'Size ({str(len(original_response))}) - {original_response}')
|
self.Logs.warning(f'Size ({str(len(original_response))}) - {original_response}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.Logs.debug(f">> {self.Utils.hide_sensitive_data(original_response)}")
|
self.Logs.debug(f">> {self.Utils.hide_sensitive_data(original_response)}")
|
||||||
parsed_protocol = self.Protocol.parse_server_msg(original_response.copy())
|
|
||||||
match parsed_protocol:
|
|
||||||
|
|
||||||
case 'PING':
|
pos, parsed_protocol = self.Protocol.get_ircd_protocol_poisition(cmd=original_response, log=True)
|
||||||
self.Protocol.on_server_ping(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'SERVER':
|
for parsed in self.Protocol.Handler.get_ircd_commands():
|
||||||
self.Protocol.on_server(serverMsg=original_response)
|
if parsed.command_name.upper() == parsed_protocol:
|
||||||
|
parsed.func(original_response)
|
||||||
case 'SJOIN':
|
|
||||||
self.Protocol.on_sjoin(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'EOS':
|
|
||||||
self.Protocol.on_eos(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'UID':
|
|
||||||
try:
|
|
||||||
self.Protocol.on_uid(serverMsg=original_response)
|
|
||||||
for module in self.ModuleUtils.model_get_loaded_modules().copy():
|
|
||||||
module.class_instance.cmd(original_response)
|
|
||||||
|
|
||||||
# SASL authentication
|
|
||||||
# ['@s2s-md/..', ':001', 'UID', 'adator__', '0', '1755987444', '...', 'desktop-h1qck20.mshome.net', '001XLTT0U', '0', '+iwxz', '*', 'Clk-EC2256B2.mshome.net', 'rBKAAQ==', ':...']
|
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
|
||||||
dchanlog = self.Config.SERVICE_CHANLOG
|
|
||||||
uid = original_response[8]
|
|
||||||
nickname = original_response[3]
|
|
||||||
sasl_obj = self.Sasl.get_sasl_obj(uid)
|
|
||||||
if sasl_obj:
|
|
||||||
if sasl_obj.auth_success:
|
|
||||||
self.insert_db_admin(sasl_obj.client_uid, sasl_obj.username, sasl_obj.level)
|
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
|
||||||
msg=f"[ {self.Config.COLORS.green}SASL AUTH{self.Config.COLORS.nogc} ] - {nickname} ({sasl_obj.username}) est désormais connecté a {dnickname}",
|
|
||||||
channel=dchanlog)
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=nickname, msg=f"Connexion a {dnickname} réussie!")
|
|
||||||
else:
|
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
|
||||||
msg=f"[ {self.Config.COLORS.red}SASL AUTH{self.Config.COLORS.nogc} ] - {nickname} a tapé un mauvais mot de pass pour le username ({sasl_obj.username})",
|
|
||||||
channel=dchanlog)
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=nickname, msg=f"Mot de passe incorrecte")
|
|
||||||
|
|
||||||
# Delete sasl object!
|
|
||||||
self.Sasl.delete_sasl_client(uid)
|
|
||||||
|
|
||||||
return None
|
|
||||||
except Exception as err:
|
|
||||||
self.Logs.error(f'General Error: {err}')
|
|
||||||
|
|
||||||
case 'QUIT':
|
|
||||||
self.Protocol.on_quit(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'PROTOCTL':
|
|
||||||
self.Protocol.on_protoctl(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'SVS2MODE':
|
|
||||||
# >> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r']
|
|
||||||
self.Protocol.on_svs2mode(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'SQUIT':
|
|
||||||
self.Protocol.on_squit(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'PART':
|
|
||||||
self.Protocol.on_part(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'VERSION':
|
|
||||||
self.Protocol.on_version_msg(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'UMODE2':
|
|
||||||
# [':adator_', 'UMODE2', '-i']
|
|
||||||
self.Protocol.on_umode2(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'NICK':
|
|
||||||
self.Protocol.on_nick(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'REPUTATION':
|
|
||||||
self.Protocol.on_reputation(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'SMOD':
|
|
||||||
self.Protocol.on_smod(original_response)
|
|
||||||
|
|
||||||
case 'SASL':
|
|
||||||
sasl_response = self.Protocol.on_sasl(original_response, self.Sasl)
|
|
||||||
self.on_sasl_authentication_process(sasl_response)
|
|
||||||
|
|
||||||
case 'SLOG': # TODO
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}")
|
|
||||||
|
|
||||||
case 'MD': # TODO
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}")
|
|
||||||
|
|
||||||
case 'PRIVMSG':
|
|
||||||
self.Protocol.on_privmsg(serverMsg=original_response)
|
|
||||||
|
|
||||||
case 'PONG': # TODO
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}")
|
|
||||||
|
|
||||||
case 'MODE': # TODO
|
|
||||||
#['@msgid=d0ySx56Yd0nc35oHts2SkC-/J9mVUA1hfM6...', ':001', 'MODE', '#a', '+nt', '1723207536']
|
|
||||||
#['@unrealircd.org/userhost=adator@localhost;...', ':001LQ0L0C', 'MODE', '#services', '-l']
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}")
|
|
||||||
|
|
||||||
case '320': # TODO
|
|
||||||
#:irc.deb.biz.st 320 PyDefender IRCParis07 :is in security-groups: known-users,webirc-users,tls-and-known-users,tls-users
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}")
|
|
||||||
|
|
||||||
case '318': # TODO
|
|
||||||
#:irc.deb.biz.st 318 PyDefender IRCParis93 :End of /WHOIS list.
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}")
|
|
||||||
|
|
||||||
case None:
|
|
||||||
self.Logs.debug(f"[!] TO HANDLE: {original_response}")
|
|
||||||
|
|
||||||
if len(original_response) > 2:
|
if len(original_response) > 2:
|
||||||
if original_response[2] != 'UID':
|
if original_response[2] != 'UID':
|
||||||
@@ -619,7 +521,8 @@ class Irc:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
fromuser = self.User.get_nickname(user) # Nickname qui a lancé la commande
|
fromuser = self.User.get_nickname(user) # Nickname qui a lancé la commande
|
||||||
uid = self.User.get_uid(fromuser) # Récuperer le uid de l'utilisateur
|
uid = self.User.get_uid(user) # Récuperer le uid de l'utilisateur
|
||||||
|
self.Settings.current_admin = self.Admin.get_admin(user) # set Current admin if any.
|
||||||
|
|
||||||
RED = self.Config.COLORS.red
|
RED = self.Config.COLORS.red
|
||||||
GREEN = self.Config.COLORS.green
|
GREEN = self.Config.COLORS.green
|
||||||
@@ -646,9 +549,9 @@ class Irc:
|
|||||||
|
|
||||||
case 'notallowed':
|
case 'notallowed':
|
||||||
try:
|
try:
|
||||||
current_command = cmd[0]
|
current_command = str(cmd[0])
|
||||||
self.Protocol.send_priv_msg(
|
self.Protocol.send_priv_msg(
|
||||||
msg=f'[ {RED}{current_command}{NOGC} ] - Accès Refusé à {self.User.get_nickname(fromuser)}',
|
msg=tr('[ %s%s%s ] - Access denied to %s', RED, current_command.upper(), NOGC, fromuser),
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
channel=dchanlog
|
channel=dchanlog
|
||||||
)
|
)
|
||||||
@@ -656,7 +559,7 @@ class Irc:
|
|||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f'Accès Refusé'
|
msg=tr('Access denied!')
|
||||||
)
|
)
|
||||||
|
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
@@ -664,16 +567,19 @@ class Irc:
|
|||||||
|
|
||||||
case 'deauth':
|
case 'deauth':
|
||||||
|
|
||||||
current_command = cmd[0]
|
current_command = str(cmd[0]).upper()
|
||||||
uid_to_deauth = self.User.get_uid(fromuser)
|
uid_to_deauth = self.User.get_uid(fromuser)
|
||||||
self.delete_db_admin(uid_to_deauth)
|
self.delete_db_admin(uid_to_deauth)
|
||||||
|
|
||||||
self.Protocol.send_priv_msg(
|
self.Protocol.send_priv_msg(
|
||||||
msg=f"[ {RED}{str(current_command).upper()}{NOGC} ] - {self.User.get_nickname(fromuser)} est désormais déconnecter de {dnickname}",
|
msg=tr("[ %s%s%s ] - %s has been disconnected from %s", RED, current_command, NOGC, fromuser, dnickname),
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
channel=dchanlog
|
channel=dchanlog
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.Protocol.send_notice(dnickname, fromuser, tr("You have been successfully disconnected from %s", dnickname))
|
||||||
|
return None
|
||||||
|
|
||||||
case 'firstauth':
|
case 'firstauth':
|
||||||
# firstauth OWNER_NICKNAME OWNER_PASSWORD
|
# firstauth OWNER_NICKNAME OWNER_PASSWORD
|
||||||
current_nickname = self.User.get_nickname(fromuser)
|
current_nickname = self.User.get_nickname(fromuser)
|
||||||
@@ -688,7 +594,7 @@ class Irc:
|
|||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f"You can't use this command anymore ! Please use [{self.Config.SERVICE_PREFIX}auth] instead"
|
msg=tr("You can't use this command anymore ! Please use [%sauth] instead", self.Config.SERVICE_PREFIX)
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -733,7 +639,7 @@ class Irc:
|
|||||||
|
|
||||||
if cmd_owner == config_owner and cmd_password == config_password:
|
if cmd_owner == config_owner and cmd_password == config_password:
|
||||||
self.Base.db_create_first_admin()
|
self.Base.db_create_first_admin()
|
||||||
self.insert_db_admin(current_uid, cmd_owner, 5)
|
self.insert_db_admin(current_uid, cmd_owner, 5, self.Config.LANG)
|
||||||
self.Protocol.send_priv_msg(
|
self.Protocol.send_priv_msg(
|
||||||
msg=f"[ {self.Config.COLORS.green}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}",
|
msg=f"[ {self.Config.COLORS.green}{str(current_command).upper()} ]{self.Config.COLORS.black} - {self.User.get_nickname(fromuser)} est désormais connecté a {dnickname}",
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
@@ -779,19 +685,21 @@ class Irc:
|
|||||||
|
|
||||||
if admin_obj:
|
if admin_obj:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - You are already connected to {dnickname}",
|
msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - {fromuser} is already connected to {dnickname}",
|
||||||
channel=dchanlog)
|
channel=dchanlog)
|
||||||
|
self.Protocol.send_notice(dnickname, fromuser, tr("You are already connected to %s", dnickname))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
mes_donnees = {'user': user_to_log, 'password': self.Loader.Utils.hash_password(password)}
|
mes_donnees = {'user': user_to_log, 'password': self.Loader.Utils.hash_password(password)}
|
||||||
query = f"SELECT id, user, level FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
query = f"SELECT id, user, level, language FROM {self.Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
||||||
result = self.Base.db_execute_query(query, mes_donnees)
|
result = self.Base.db_execute_query(query, mes_donnees)
|
||||||
user_from_db = result.fetchone()
|
user_from_db = result.fetchone()
|
||||||
|
|
||||||
if user_from_db:
|
if user_from_db:
|
||||||
account = user_from_db[1]
|
account = str(user_from_db[1])
|
||||||
level = user_from_db[2]
|
level = int(user_from_db[2])
|
||||||
self.insert_db_admin(current_client.uid, account, level)
|
language = str(user_from_db[3])
|
||||||
|
self.insert_db_admin(current_client.uid, account, level, language)
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - {current_client.nickname} ({account}) est désormais connecté a {dnickname}",
|
msg=f"[ {GREEN}{str(current_command).upper()}{NOGC} ] - {current_client.nickname} ({account}) est désormais connecté a {dnickname}",
|
||||||
channel=dchanlog)
|
channel=dchanlog)
|
||||||
@@ -810,15 +718,14 @@ class Irc:
|
|||||||
if len(cmd) < 4:
|
if len(cmd) < 4:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} addaccess [nickname] [level] [password]")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} addaccess [nickname] [level] [password]")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4")
|
||||||
|
return None
|
||||||
|
|
||||||
newnickname = cmd[1]
|
new_admin = str(cmd[1])
|
||||||
newlevel = self.Base.int_if_possible(cmd[2])
|
level = self.Base.int_if_possible(cmd[2])
|
||||||
password = cmd[3]
|
password = str(cmd[3])
|
||||||
|
|
||||||
response = self.create_defender_user(newnickname, newlevel, password)
|
self.create_defender_user(fromuser, new_admin, level, password)
|
||||||
|
return None
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{response}")
|
|
||||||
self.Logs.info(response)
|
|
||||||
|
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(f'_hcmd addaccess: {ie}')
|
self.Logs.error(f'_hcmd addaccess: {ie}')
|
||||||
@@ -940,12 +847,15 @@ class Irc:
|
|||||||
try:
|
try:
|
||||||
admin_obj = self.Admin.get_admin(fromuser)
|
admin_obj = self.Admin.get_admin(fromuser)
|
||||||
if admin_obj:
|
if admin_obj:
|
||||||
query = f'UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user = :user'
|
if admin_obj.fingerprint is not None:
|
||||||
r = self.Base.db_execute_query(query, {'fingerprint': admin_obj.fingerprint, 'user': admin_obj.account})
|
query = f'UPDATE {self.Config.TABLE_ADMIN} SET fingerprint = :fingerprint WHERE user = :user'
|
||||||
if r.rowcount > 0:
|
r = self.Base.db_execute_query(query, {'fingerprint': admin_obj.fingerprint, 'user': admin_obj.account})
|
||||||
self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your new fingerprint has been attached to your account. {admin_obj.fingerprint}')
|
if r.rowcount > 0:
|
||||||
|
self.Protocol.send_notice(dnickname, fromuser, f'[ {GREEN}CERT{NOGC} ] Your new fingerprint has been attached to your account. {admin_obj.fingerprint}')
|
||||||
|
else:
|
||||||
|
self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to add your fingerprint.{admin_obj.fingerprint}')
|
||||||
else:
|
else:
|
||||||
self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] Impossible to add your fingerprint.{admin_obj.fingerprint}')
|
self.Protocol.send_notice(dnickname, fromuser, f'[ {RED}CERT{NOGC} ] There is no fingerprint to add.')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.Logs.error(e)
|
self.Logs.error(e)
|
||||||
@@ -1107,7 +1017,7 @@ class Irc:
|
|||||||
except KeyError as ke:
|
except KeyError as ke:
|
||||||
self.Logs.error(f"Key Error: {ke} - list recieved: {cmd}")
|
self.Logs.error(f"Key Error: {ke} - list recieved: {cmd}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f"General Error: {ke} - list recieved: {cmd}")
|
self.Logs.error(f"General Error: {err} - list recieved: {cmd}", exc_info=True)
|
||||||
|
|
||||||
case 'unload':
|
case 'unload':
|
||||||
# unload mod_defender
|
# unload mod_defender
|
||||||
@@ -1143,7 +1053,8 @@ class Irc:
|
|||||||
self.Base.execute_periodic_action()
|
self.Base.execute_periodic_action()
|
||||||
|
|
||||||
for chan_name in self.Channel.UID_CHANNEL_DB:
|
for chan_name in self.Channel.UID_CHANNEL_DB:
|
||||||
self.Protocol.send_mode_chan(chan_name.name, '-l')
|
# self.Protocol.send_mode_chan(chan_name.name, '-l')
|
||||||
|
self.Protocol.send_set_mode('-l', channel_name=chan_name.name)
|
||||||
|
|
||||||
for client in self.Client.CLIENT_DB:
|
for client in self.Client.CLIENT_DB:
|
||||||
self.Protocol.send_svslogout(client)
|
self.Protocol.send_svslogout(client)
|
||||||
@@ -1168,7 +1079,7 @@ class Irc:
|
|||||||
self.Config.DEFENDER_INIT = 1 # set init to 1 saying that the service will be re initiated
|
self.Config.DEFENDER_INIT = 1 # set init to 1 saying that the service will be re initiated
|
||||||
|
|
||||||
case 'rehash':
|
case 'rehash':
|
||||||
rehash.rehash_service(self.ircObject, fromuser)
|
rehash.rehash_service(self, fromuser)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
case 'show_modules':
|
case 'show_modules':
|
||||||
@@ -1189,14 +1100,14 @@ class Irc:
|
|||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f"{module} - {GREEN}Loaded{NOGC} by {loaded_user} on {loaded_datetime}"
|
msg=tr('%s - %sLoaded%s by %s on %s', module, GREEN, NOGC, loaded_user, loaded_datetime)
|
||||||
)
|
)
|
||||||
loaded = False
|
loaded = False
|
||||||
else:
|
else:
|
||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f"{module} - {RED}Not Loaded{NOGC}"
|
msg=tr('%s - %sNot Loaded%s', module, RED, NOGC)
|
||||||
)
|
)
|
||||||
|
|
||||||
case 'show_timers':
|
case 'show_timers':
|
||||||
@@ -1266,7 +1177,7 @@ class Irc:
|
|||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f"UID : {db_admin.uid} - Nickname: {db_admin.nickname} - Account: {db_admin.account} - Level: {db_admin.level} - Connection: {db_admin.connexion_datetime}"
|
msg=f"UID : {db_admin.uid} - Nickname: {db_admin.nickname} - Account: {db_admin.account} - Level: {db_admin.level} - Language: {db_admin.language} - Connection: {db_admin.connexion_datetime}"
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1309,7 +1220,7 @@ class Irc:
|
|||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
msg=f">> Defender V.{self.Config.CURRENT_VERSION} Developped by adator®."
|
msg=f">> Defender V{self.Config.CURRENT_VERSION} Developped by adator®."
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
13
core/language/fr/core-fr.yaml
Normal file
13
core/language/fr/core-fr.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
traduction:
|
||||||
|
# Message help
|
||||||
|
- orig: "Access denied!"
|
||||||
|
trad: "Accès refusé."
|
||||||
|
- orig: "%s - %sLoaded%s by %s on %s"
|
||||||
|
trad: "%s - %sChargé%s par %s le %s"
|
||||||
|
- orig: "%s - %sNot Loaded%s"
|
||||||
|
trad: "%s - %sNon chargé%s"
|
||||||
|
- orig: "Successfuly connected to %s"
|
||||||
|
trad: "Connecter a %s avec succés"
|
||||||
|
- orig: "[ %sINFORMATION%s ] >> %s is ready!"
|
||||||
|
trad: "[ %sINFORMATION%s ] >> %s est prêt!"
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
from logging import Logger
|
from logging import Logger
|
||||||
from core.classes import user, admin, client, channel, reputation, settings, sasl
|
from core.classes.settings import global_settings
|
||||||
|
from core.classes 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
|
||||||
@@ -7,49 +8,65 @@ 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.commands as commands_mod
|
||||||
import core.classes.config as conf_mod
|
import core.classes.config as conf_mod
|
||||||
|
import core.irc as irc
|
||||||
|
import core.classes.protocols.factory as factory
|
||||||
|
|
||||||
class Loader:
|
class Loader:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
# Load Main Modules
|
# Load Main Modules
|
||||||
self.Definition: df = df
|
self.Definition: df = df
|
||||||
|
|
||||||
self.ConfModule: conf_mod = conf_mod
|
self.ConfModule: conf_mod = conf_mod
|
||||||
|
|
||||||
self.BaseModule: base_mod = base_mod
|
self.BaseModule: base_mod = base_mod
|
||||||
|
|
||||||
self.CommandModule: commands_mod = commands_mod
|
self.CommandModule: commands_mod = commands_mod
|
||||||
|
|
||||||
self.LoggingModule: logs = logs
|
self.LoggingModule: logs = logs
|
||||||
|
|
||||||
self.Utils: utils = utils
|
self.Utils: utils = utils
|
||||||
|
|
||||||
# Load Classes
|
# Load Classes
|
||||||
self.ServiceLogging: logs.ServiceLogging = self.LoggingModule.ServiceLogging()
|
self.Settings: settings.Settings = global_settings
|
||||||
|
|
||||||
self.Logs: Logger = self.ServiceLogging.get_logger()
|
self.ServiceLogging: logs.ServiceLogging = self.LoggingModule.ServiceLogging()
|
||||||
|
|
||||||
self.Settings: settings.Settings = settings.Settings()
|
self.Logs: Logger = self.ServiceLogging.get_logger()
|
||||||
|
|
||||||
self.Config: df.MConfig = self.ConfModule.Configuration(self).get_config_model()
|
self.Config: df.MConfig = self.ConfModule.Configuration(self).configuration_model
|
||||||
|
|
||||||
self.Base: base_mod.Base = self.BaseModule.Base(self)
|
self.Settings.global_lang = self.Config.LANG if self.Config.LANG else "EN"
|
||||||
|
|
||||||
self.User: user.User = user.User(self)
|
self.Settings.global_logger = self.Logs
|
||||||
|
|
||||||
self.Client: client.Client = client.Client(self)
|
self.Translation: translation.Translation = translation.Translation(self)
|
||||||
|
|
||||||
self.Admin: admin.Admin = admin.Admin(self)
|
self.Settings.global_translation = self.Translation.get_translation()
|
||||||
|
|
||||||
self.Channel: channel.Channel = channel.Channel(self)
|
self.Base: base_mod.Base = self.BaseModule.Base(self)
|
||||||
|
|
||||||
self.Reputation: reputation.Reputation = reputation.Reputation(self)
|
self.User: user.User = user.User(self)
|
||||||
|
|
||||||
self.Commands: commands_mod.Command = commands_mod.Command(self)
|
self.Settings.global_user = self.User
|
||||||
|
|
||||||
self.ModuleUtils: module_mod.Module = module_mod.Module(self)
|
self.Client: client.Client = client.Client(self)
|
||||||
|
|
||||||
self.Sasl: sasl.Sasl = sasl.Sasl(self)
|
self.Admin: admin.Admin = admin.Admin(self)
|
||||||
|
|
||||||
self.Logs.debug("LOADER Success!")
|
self.Channel: channel.Channel = channel.Channel(self)
|
||||||
|
|
||||||
|
self.Reputation: reputation.Reputation = reputation.Reputation(self)
|
||||||
|
|
||||||
|
self.Commands: commands_mod.Command = commands_mod.Command(self)
|
||||||
|
|
||||||
|
self.ModuleUtils: module_mod.Module = module_mod.Module(self)
|
||||||
|
|
||||||
|
self.Sasl: sasl.Sasl = sasl.Sasl(self)
|
||||||
|
|
||||||
|
self.Irc: irc.Irc = irc.Irc(self)
|
||||||
|
|
||||||
|
self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self.Irc)
|
||||||
|
|
||||||
|
self.Logs.debug(self.Utils.tr("Loader %s success", __name__))
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class ServiceLogging:
|
|||||||
self.SERVER_PREFIX = None
|
self.SERVER_PREFIX = None
|
||||||
self.LOGGING_CONSOLE = True
|
self.LOGGING_CONSOLE = True
|
||||||
|
|
||||||
self.LOG_FILTERS: list[str] = ['PING', f":{self.SERVER_PREFIX}auth", "['PASS'"]
|
self.LOG_FILTERS: list[str] = ["PING", f":{self.SERVER_PREFIX}auth", "['PASS'"]
|
||||||
|
|
||||||
self.file_handler = None
|
self.file_handler = None
|
||||||
self.stdout_handler = None
|
self.stdout_handler = None
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ class Module:
|
|||||||
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.__Logs.debug(f"[ UNLOAD MODULE ERROR ] This module {module_name} is not loaded!")
|
||||||
|
self.db_delete_module(module_name)
|
||||||
uplink.Protocol.send_priv_msg(
|
uplink.Protocol.send_priv_msg(
|
||||||
nick_from=self.__Config.SERVICE_NICKNAME,
|
nick_from=self.__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!",
|
||||||
|
|||||||
@@ -13,10 +13,56 @@ from datetime import datetime, timedelta, timezone
|
|||||||
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
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
|
|
||||||
|
def tr(message: str, *args) -> str:
|
||||||
|
"""Translation Engine system
|
||||||
|
```python
|
||||||
|
example:
|
||||||
|
_('Hello my firstname is %s and my lastname is %s', firstname, lastname)
|
||||||
|
```
|
||||||
|
Args:
|
||||||
|
message (str): The message to translate
|
||||||
|
*args (any) : Whatever the variable you want to pass
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The translated message
|
||||||
|
"""
|
||||||
|
count_args = len(args) # Count number of args sent
|
||||||
|
count_placeholder = message.count('%s') # Count number of placeholder in the message
|
||||||
|
is_args_available = True if args else False
|
||||||
|
g = global_settings
|
||||||
|
try:
|
||||||
|
# Access to admin object
|
||||||
|
client_language = g.current_admin.language if g.current_admin else g.global_lang
|
||||||
|
|
||||||
|
if count_args != count_placeholder:
|
||||||
|
g.global_logger.error(f"Translation: Original message: {message} | Args: {count_args} - Placeholder: {count_placeholder}")
|
||||||
|
return message
|
||||||
|
|
||||||
|
if g.global_lang is None:
|
||||||
|
return message % args if is_args_available else message
|
||||||
|
|
||||||
|
if client_language.lower() == 'en':
|
||||||
|
return message % args if is_args_available else message
|
||||||
|
|
||||||
|
for trads in g.global_translation[client_language.lower()]:
|
||||||
|
if sub(r"\s+", "", message) == sub(r"\s+", "", trads[0]):
|
||||||
|
return trads[1] % args if is_args_available else trads[1]
|
||||||
|
|
||||||
|
return message % args if is_args_available else message
|
||||||
|
|
||||||
|
except KeyError as ke:
|
||||||
|
g.global_logger.error(f"KeyError: {ke}")
|
||||||
|
return message % args if is_args_available else message
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
global_settings.global_logger.error(f"General Error: {err} / {message}")
|
||||||
|
return message
|
||||||
|
|
||||||
def convert_to_int(value: Any) -> Optional[int]:
|
def convert_to_int(value: Any) -> Optional[int]:
|
||||||
"""Convert a value to int
|
"""Convert a value to int
|
||||||
|
|
||||||
@@ -97,6 +143,8 @@ def create_socket(uplink: 'Irc') -> None:
|
|||||||
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)
|
||||||
|
if oe.errno == 10053:
|
||||||
|
sys.exit(oe)
|
||||||
except AttributeError as ae:
|
except AttributeError as ae:
|
||||||
uplink.Logs.critical(f"AttributeError: {ae}")
|
uplink.Logs.critical(f"AttributeError: {ae}")
|
||||||
|
|
||||||
@@ -195,4 +243,4 @@ def hide_sensitive_data(srvmsg: list[str]) -> list[str]:
|
|||||||
return srv_msg
|
return srv_msg
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return srvmsg
|
return srvmsg
|
||||||
|
|||||||
18
defender.py
18
defender.py
@@ -1,24 +1,22 @@
|
|||||||
from core import installation
|
from core import install
|
||||||
|
|
||||||
#############################################
|
#############################################
|
||||||
# @Version : 6.2 #
|
# @Version : 6.3 #
|
||||||
# Requierements : #
|
# Requierements : #
|
||||||
# Python3.10 or higher #
|
# Python3.10 or higher #
|
||||||
# SQLAlchemy, requests, psutil #
|
# SQLAlchemy, requests, psutil #
|
||||||
# unrealircd-rpc-py #
|
# unrealircd-rpc-py, pyyaml #
|
||||||
# UnrealIRCD 6.2.2 or higher #
|
# UnrealIRCD 6.2.2 or higher #
|
||||||
#############################################
|
#############################################
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
install.update_packages()
|
||||||
installation.Install()
|
|
||||||
|
|
||||||
from core.loader import Loader
|
from core.loader import Loader
|
||||||
from core.irc import Irc
|
loader = Loader()
|
||||||
ircInstance = Irc(Loader())
|
loader.Irc.init_irc()
|
||||||
ircInstance.init_irc(ircInstance)
|
|
||||||
|
|
||||||
except AssertionError as ae:
|
except AssertionError as ae:
|
||||||
print(f'Assertion Error -> {ae}')
|
print(f'Assertion Error -> {ae}')
|
||||||
except KeyboardInterrupt as k:
|
except KeyboardInterrupt as k:
|
||||||
ircInstance.Base.execute_periodic_action()
|
# ircInstance.Base.execute_periodic_action()
|
||||||
|
...
|
||||||
4
mods/clone/language/es/clone-es_1.yaml
Normal file
4
mods/clone/language/es/clone-es_1.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
traduction:
|
||||||
|
# Message help
|
||||||
|
- orig: "Hi my name is clone-es"
|
||||||
|
trad: "Hola mi name is clone-es"
|
||||||
6
mods/clone/language/fr/clone-fr_1.yaml
Normal file
6
mods/clone/language/fr/clone-fr_1.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
traduction:
|
||||||
|
# Message help
|
||||||
|
- orig: "You are now logged in"
|
||||||
|
trad: "Vous étes désomais identifier"
|
||||||
|
- orig: "NSUser ==> nsuid: %s | cuid: %s | Account: %s | Nickname: %s | email: %s"
|
||||||
|
trad: "NSUser ==> nsuid: %s | cuid: %s | Compte: %s | Pseudo: %s | email: %s"
|
||||||
0
mods/clone/language/fr/clone-fr_2.yaml
Normal file
0
mods/clone/language/fr/clone-fr_2.yaml
Normal file
@@ -78,11 +78,11 @@ class Clone:
|
|||||||
self.__load_module_configuration()
|
self.__load_module_configuration()
|
||||||
|
|
||||||
self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
self.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send_join_chan(self.Config.SERVICE_NICKNAME, 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)
|
||||||
|
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} SAMODE {self.Config.CLONE_CHANNEL} +o {self.Config.SERVICE_NICKNAME}")
|
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} +nts")
|
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} +k {self.Config.CLONE_CHANNEL_PASSWORD}")
|
|
||||||
|
|
||||||
def __create_tables(self) -> 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.
|
||||||
@@ -127,10 +127,12 @@ class Clone:
|
|||||||
self.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB)
|
self.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)
|
self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -nts")
|
self.Protocol.send_set_mode('-nts', channel_name=self.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -k {self.Config.CLONE_CHANNEL_PASSWORD}")
|
self.Protocol.send_set_mode('-k', channel_name=self.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send_part_chan(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL)
|
self.Protocol.send_part_chan(self.Config.SERVICE_NICKNAME, self.Config.CLONE_CHANNEL)
|
||||||
|
|
||||||
|
self.Irc.Commands.drop_command_by_module(self.module_name)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def cmd(self, data:list) -> None:
|
def cmd(self, data:list) -> None:
|
||||||
@@ -146,7 +148,8 @@ class Clone:
|
|||||||
match command:
|
match command:
|
||||||
|
|
||||||
case 'PRIVMSG':
|
case 'PRIVMSG':
|
||||||
return self.Utils.handle_on_privmsg(self, cmd)
|
self.Utils.handle_on_privmsg(self, cmd)
|
||||||
|
return None
|
||||||
|
|
||||||
case 'QUIT':
|
case 'QUIT':
|
||||||
return None
|
return None
|
||||||
@@ -200,7 +203,7 @@ class Clone:
|
|||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect [number of clone you want to connect] [Group]")
|
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]")
|
||||||
self.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':
|
||||||
@@ -230,8 +233,7 @@ class Clone:
|
|||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill all")
|
self.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 clone_nickname")
|
|
||||||
|
|
||||||
case 'join':
|
case 'join':
|
||||||
try:
|
try:
|
||||||
@@ -260,8 +262,7 @@ class Clone:
|
|||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join all #channel")
|
self.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 clone_nickname #channel")
|
|
||||||
|
|
||||||
case 'part':
|
case 'part':
|
||||||
try:
|
try:
|
||||||
@@ -291,8 +292,7 @@ class Clone:
|
|||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.Logs.error(f'{err}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part all #channel")
|
self.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 clone_nickname #channel")
|
|
||||||
|
|
||||||
case 'list':
|
case 'list':
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -174,17 +174,17 @@ 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]):
|
def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]) -> None:
|
||||||
|
|
||||||
uid_sender = uplink.Irc.Utils.clean_uid(srvmsg[1])
|
parser = uplink.Protocol.parse_privmsg(srvmsg)
|
||||||
|
uid_sender = uplink.Irc.Utils.clean_uid(parser.get('uid_sender', None))
|
||||||
senderObj = uplink.User.get_user(uid_sender)
|
senderObj = uplink.User.get_user(uid_sender)
|
||||||
|
|
||||||
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT:
|
if senderObj is not None:
|
||||||
return
|
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT:
|
||||||
|
return
|
||||||
if not senderObj is None:
|
senderMsg = parser.get('message', None)
|
||||||
senderMsg = ' '.join(srvmsg[4:])
|
clone_obj = uplink.Clone.get_clone(parser.get('uid_reciever', None))
|
||||||
clone_obj = uplink.Clone.get_clone(srvmsg[3])
|
|
||||||
|
|
||||||
if clone_obj is None:
|
if clone_obj is None:
|
||||||
return
|
return
|
||||||
@@ -196,3 +196,5 @@ def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]):
|
|||||||
msg=final_message,
|
msg=final_message,
|
||||||
channel=uplink.Config.CLONE_CHANNEL
|
channel=uplink.Config.CLONE_CHANNEL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|||||||
@@ -53,16 +53,16 @@ class Command:
|
|||||||
# Module Utils
|
# Module Utils
|
||||||
self.mod_utils = utils
|
self.mod_utils = utils
|
||||||
|
|
||||||
self.Irc.build_command(1, self.module_name, 'join', 'Join a channel')
|
self.Irc.build_command(2, self.module_name, 'join', 'Join a channel')
|
||||||
self.Irc.build_command(1, self.module_name, 'assign', 'Assign a user to a role or task')
|
self.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task')
|
||||||
self.Irc.build_command(1, self.module_name, 'part', 'Leave a channel')
|
self.Irc.build_command(2, self.module_name, 'part', 'Leave a channel')
|
||||||
self.Irc.build_command(1, self.module_name, 'unassign', 'Remove a user from a role or task')
|
self.Irc.build_command(2, self.module_name, 'unassign', 'Remove a user from a role or task')
|
||||||
self.Irc.build_command(1, self.module_name, 'owner', 'Give channel ownership to a user')
|
self.Irc.build_command(2, self.module_name, 'owner', 'Give channel ownership to a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'deowner', 'Remove channel ownership from a user')
|
self.Irc.build_command(2, self.module_name, 'deowner', 'Remove channel ownership from a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'protect', 'Protect a user from being kicked')
|
self.Irc.build_command(2, self.module_name, 'protect', 'Protect a user from being kicked')
|
||||||
self.Irc.build_command(1, self.module_name, 'deprotect', 'Remove protection from a user')
|
self.Irc.build_command(2, self.module_name, 'deprotect', 'Remove protection from a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'op', 'Grant operator privileges to a user')
|
self.Irc.build_command(2, self.module_name, 'op', 'Grant operator privileges to a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'deop', 'Remove operator privileges from a user')
|
self.Irc.build_command(2, self.module_name, 'deop', 'Remove operator privileges from a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'halfop', 'Grant half-operator privileges to a user')
|
self.Irc.build_command(1, self.module_name, 'halfop', 'Grant half-operator privileges to a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'dehalfop', 'Remove half-operator privileges from a user')
|
self.Irc.build_command(1, self.module_name, 'dehalfop', 'Remove half-operator privileges from a user')
|
||||||
self.Irc.build_command(1, self.module_name, 'voice', 'Grant voice privileges to a user')
|
self.Irc.build_command(1, self.module_name, 'voice', 'Grant voice privileges to a user')
|
||||||
@@ -172,7 +172,7 @@ class Command:
|
|||||||
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_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)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def cmd(self, data: list[str]) -> None:
|
def cmd(self, data: list[str]) -> None:
|
||||||
|
|||||||
@@ -134,17 +134,20 @@ def set_operation(uplink: 'Command', cmd: list[str], channel_name: Optional[str]
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
if len(cmd) == 1:
|
if len(cmd) == 1:
|
||||||
uplink.Protocol.send2socket(f":{dnickname} MODE {channel_name} {mode} {client}")
|
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {client}")
|
||||||
|
uplink.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}")
|
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
||||||
|
uplink.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}")
|
# uplink.Protocol.send2socket(f":{service_id} MODE {channel_name} {mode} {nickname}")
|
||||||
|
uplink.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:
|
def set_ban(uplink: 'Command', cmd: list[str], action: Literal['+', '-'], client: str) -> None:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import traceback
|
from typing import TYPE_CHECKING
|
||||||
import mods.defender.schemas as schemas
|
import mods.defender.schemas as schemas
|
||||||
import mods.defender.utils as utils
|
import mods.defender.utils as utils
|
||||||
import mods.defender.threads as thds
|
import mods.defender.threads as thds
|
||||||
from typing import TYPE_CHECKING
|
from core.utils import tr
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
@@ -202,6 +202,8 @@ class Defender:
|
|||||||
self.reputationTimer_isRunning:bool = False
|
self.reputationTimer_isRunning:bool = False
|
||||||
self.autolimit_isRunning: bool = False
|
self.autolimit_isRunning: bool = False
|
||||||
|
|
||||||
|
self.Irc.Commands.drop_command_by_module(self.module_name)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def insert_db_trusted(self, uid: str, nickname:str) -> None:
|
def insert_db_trusted(self, uid: str, nickname:str) -> None:
|
||||||
@@ -215,7 +217,7 @@ class Defender:
|
|||||||
|
|
||||||
if response is not None:
|
if response is not None:
|
||||||
q_insert = "INSERT INTO def_trusted (datetime, user, host, vhost) VALUES (?, ?, ?, ?)"
|
q_insert = "INSERT INTO def_trusted (datetime, user, host, vhost) VALUES (?, ?, ?, ?)"
|
||||||
mes_donnees = {'datetime': self.Base.get_datetime(), 'user': nickname, 'host': '*', 'vhost': '*'}
|
mes_donnees = {'datetime': self.Loader.Utils.get_datetime(), 'user': nickname, 'host': '*', 'vhost': '*'}
|
||||||
exec_query = self.Base.db_execute_query(q_insert, mes_donnees)
|
exec_query = self.Base.db_execute_query(q_insert, mes_donnees)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -320,8 +322,7 @@ class Defender:
|
|||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(f"{ie} / {cmd} / length {str(len(cmd))}")
|
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.Logs.error(f"General Error: {err}", exc_info=True)
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
def hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
||||||
|
|
||||||
@@ -364,7 +365,7 @@ class Defender:
|
|||||||
release_code = cmd[1]
|
release_code = cmd[1]
|
||||||
jailed_nickname = self.User.get_nickname(fromuser)
|
jailed_nickname = self.User.get_nickname(fromuser)
|
||||||
jailed_UID = self.User.get_uid(fromuser)
|
jailed_UID = self.User.get_uid(fromuser)
|
||||||
get_reputation = self.Reputation.get_Reputation(jailed_UID)
|
get_reputation = self.Reputation.get_reputation(jailed_UID)
|
||||||
|
|
||||||
if get_reputation is None:
|
if get_reputation is None:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" No code is requested ...")
|
||||||
@@ -550,7 +551,7 @@ class Defender:
|
|||||||
msg=f"This nickname ({str(cmd[2])}) is not connected to the network!")
|
msg=f"This nickname ({str(cmd[2])}) is not connected to the network!")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
client_to_release = self.Reputation.get_Reputation(client_obj.uid)
|
client_to_release = self.Reputation.get_reputation(client_obj.uid)
|
||||||
|
|
||||||
if client_to_release is None:
|
if client_to_release is None:
|
||||||
p.send_notice(nick_from=dnickname,
|
p.send_notice(nick_from=dnickname,
|
||||||
@@ -948,7 +949,7 @@ class Defender:
|
|||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}')
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' WebWebsocket : {UserObject.isWebsocket}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}')
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' REPUTATION : {UserObject.score_connexion}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}')
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' MODES : {UserObject.umodes}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {channels}')
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CHANNELS : {", ".join(channels)}')
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}')
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' CONNECTION TIME : {UserObject.connexion_datetime}')
|
||||||
else:
|
else:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {nickoruid} doesn't exist")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {nickoruid} doesn't exist")
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ def handle_on_sjoin(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if confmodel.reputation == 1:
|
if confmodel.reputation == 1:
|
||||||
get_reputation = irc.Reputation.get_Reputation(parsed_UID)
|
get_reputation = irc.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")
|
p.send2socket(f":{gconfig.SERVICE_ID} MODE {parsed_chan} +b ~security-group:unknown-users")
|
||||||
@@ -138,18 +138,20 @@ def handle_on_slog(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""_summary_
|
"""Handle nickname changes.
|
||||||
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712']
|
>>> srvmsg = ['@unrealircd.org...', ':001MZQ0RB', 'NICK', 'newnickname', '1754663712']
|
||||||
|
>>> [':97KAAAAAC', 'NICK', 'testinspir', '1757360740']
|
||||||
Args:
|
Args:
|
||||||
irc_instance (Irc): The Irc instance
|
irc_instance (Irc): The Irc instance
|
||||||
srvmsg (list[str]): The Server MSG
|
srvmsg (list[str]): The Server MSG
|
||||||
confmodel (ModConfModel): The Module Configuration
|
confmodel (ModConfModel): The Module Configuration
|
||||||
"""
|
"""
|
||||||
uid = uplink.Loader.Utils.clean_uid(str(srvmsg[1]))
|
|
||||||
p = uplink.Protocol
|
p = uplink.Protocol
|
||||||
|
parser = p.parse_nick(srvmsg)
|
||||||
|
uid = uplink.Loader.Utils.clean_uid(parser.get('uid', None))
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.ModConfig
|
||||||
|
|
||||||
get_reputation = uplink.Reputation.get_Reputation(uid)
|
get_reputation = uplink.Reputation.get_reputation(uid)
|
||||||
jail_salon = uplink.Config.SALON_JAIL
|
jail_salon = uplink.Config.SALON_JAIL
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.Config.SERVICE_ID
|
||||||
|
|
||||||
@@ -159,7 +161,7 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
|
|
||||||
# Update the new nickname
|
# Update the new nickname
|
||||||
oldnick = get_reputation.nickname
|
oldnick = get_reputation.nickname
|
||||||
newnickname = srvmsg[3]
|
newnickname = parser.get('newnickname', None)
|
||||||
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
|
||||||
@@ -170,20 +172,21 @@ def handle_on_nick(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*")
|
p.send2socket(f":{service_id} MODE {chan.name} +b {newnickname}!*@*")
|
||||||
|
|
||||||
def handle_on_quit(uplink: 'Defender', srvmsg: list[str]):
|
def handle_on_quit(uplink: 'Defender', srvmsg: list[str]):
|
||||||
"""_summary_
|
"""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.Protocol
|
||||||
|
parser = p.parse_quit(srvmsg)
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.ModConfig
|
||||||
|
|
||||||
ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan)
|
ban_all_chan = uplink.Base.int_if_possible(confmodel.reputation_ban_all_chan)
|
||||||
final_UID = uplink.Loader.Utils.clean_uid(str(srvmsg[1]))
|
final_UID = uplink.Loader.Utils.clean_uid(str(parser.get('uid', None)))
|
||||||
jail_salon = uplink.Config.SALON_JAIL
|
jail_salon = uplink.Config.SALON_JAIL
|
||||||
service_id = uplink.Config.SERVICE_ID
|
service_id = uplink.Config.SERVICE_ID
|
||||||
get_user_reputation = uplink.Reputation.get_Reputation(final_UID)
|
get_user_reputation = uplink.Reputation.get_reputation(final_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
|
||||||
@@ -204,6 +207,7 @@ 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)
|
||||||
gconfig = uplink.Config
|
gconfig = uplink.Config
|
||||||
irc = uplink.Irc
|
irc = uplink.Irc
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.ModConfig
|
||||||
@@ -213,10 +217,10 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# Get User information
|
# Get User information
|
||||||
_User = irc.User.get_user(str(srvmsg[8]))
|
_User = irc.User.get_user(parser_uid.get('uid', None))
|
||||||
|
|
||||||
if _User is None:
|
if _User is None:
|
||||||
irc.Logs.warning(f'This UID: [{srvmsg[8]}] is not available please check why')
|
irc.Logs.warning(f'This UID: [{parser_uid.get("uid", None)}] is not available please check why')
|
||||||
return
|
return
|
||||||
|
|
||||||
# If user is not service or IrcOp then scan them
|
# If user is not service or IrcOp then scan them
|
||||||
@@ -249,7 +253,8 @@ def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
|||||||
####################
|
####################
|
||||||
# ACTION FUNCTIONS #
|
# ACTION FUNCTIONS #
|
||||||
####################
|
####################
|
||||||
|
# [:<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
|
||||||
def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
||||||
|
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.ModConfig
|
||||||
@@ -318,7 +323,7 @@ def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
|||||||
p = uplink.Protocol
|
p = uplink.Protocol
|
||||||
confmodel = uplink.ModConfig
|
confmodel = uplink.ModConfig
|
||||||
|
|
||||||
get_reputation = irc.Reputation.get_Reputation(jailed_uid)
|
get_reputation = irc.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')
|
irc.Logs.warning(f'UID {jailed_uid} has not been found')
|
||||||
@@ -378,14 +383,11 @@ def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
|||||||
color_red = gconfig.COLORS.red
|
color_red = gconfig.COLORS.red
|
||||||
nogc = gconfig.COLORS.nogc
|
nogc = gconfig.COLORS.nogc
|
||||||
salon_jail = gconfig.SALON_JAIL
|
salon_jail = gconfig.SALON_JAIL
|
||||||
|
|
||||||
if reputation_flag == 0:
|
|
||||||
return None
|
|
||||||
elif reputation_timer == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
uid_to_clean = []
|
uid_to_clean = []
|
||||||
|
|
||||||
|
if reputation_flag == 0 or reputation_timer == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
for user in irc.Reputation.UID_REPUTATION_DB:
|
for user in irc.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 irc.User.get_user_uptime_in_minutes(user.uid) >= reputation_timer and int(user.score_connexion) <= int(reputation_seuil):
|
||||||
@@ -404,7 +406,7 @@ def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
|||||||
# 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 irc.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 = irc.Reputation.get_reputation(uid)
|
||||||
p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*")
|
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}.
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from unrealircd_rpc_py.objects.Definition import LiveRPCResult
|
||||||
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 time import sleep
|
||||||
from types import SimpleNamespace
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from unrealircd_rpc_py.Live import LiveWebsocket, LiveUnixSocket
|
from unrealircd_rpc_py.ConnectionFactory import ConnectionFactory
|
||||||
from unrealircd_rpc_py.Loader import Loader
|
from unrealircd_rpc_py.LiveConnectionFactory import LiveConnectionFactory
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
@@ -85,43 +85,35 @@ class Jsonrpc():
|
|||||||
self.__load_module_configuration()
|
self.__load_module_configuration()
|
||||||
# End of mandatory methods you can start your customization #
|
# End of mandatory methods you can start your customization #
|
||||||
|
|
||||||
self.UnrealIrcdRpcLive: LiveWebsocket = LiveWebsocket(
|
try:
|
||||||
url=self.Config.JSONRPC_URL,
|
self.Rpc = ConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD)
|
||||||
username=self.Config.JSONRPC_USER,
|
self.LiveRpc = LiveConnectionFactory(self.Config.DEBUG_LEVEL).get(self.Config.JSONRPC_METHOD)
|
||||||
password=self.Config.JSONRPC_PASSWORD,
|
|
||||||
callback_object_instance=self,
|
sync_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE}
|
||||||
callback_method_or_function_name='callback_sent_to_irc'
|
sync_http = {'url': self.Config.JSONRPC_URL, 'username': self.Config.JSONRPC_USER, 'password': self.Config.JSONRPC_PASSWORD}
|
||||||
)
|
|
||||||
|
live_unixsocket = {'path_to_socket_file': self.Config.JSONRPC_PATH_TO_SOCKET_FILE,
|
||||||
if self.UnrealIrcdRpcLive.get_error.code != 0:
|
'callback_object_instance' : self, 'callback_method_or_function_name': 'callback_sent_to_irc'}
|
||||||
self.Logs.error(f"{self.UnrealIrcdRpcLive.get_error.message} ({self.UnrealIrcdRpcLive.get_error.code})")
|
live_http = {'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'}
|
||||||
|
|
||||||
|
sync_param = sync_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else sync_http
|
||||||
|
live_param = live_unixsocket if self.Config.JSONRPC_METHOD == 'unixsocket' else live_http
|
||||||
|
|
||||||
|
self.Rpc.setup(sync_param)
|
||||||
|
self.LiveRpc.setup(live_param)
|
||||||
|
|
||||||
|
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(
|
self.Protocol.send_priv_msg(
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
nick_from=self.Config.SERVICE_NICKNAME,
|
||||||
msg=f"[{self.Config.COLORS.red}ERROR{self.Config.COLORS.nogc}] {self.UnrealIrcdRpcLive.get_error.message}",
|
msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {err.__str__()}",
|
||||||
channel=self.Config.SERVICE_CHANLOG
|
channel=self.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
raise Exception(f"[LIVE-JSONRPC ERROR] {self.UnrealIrcdRpcLive.get_error.message}")
|
self.Logs.error(f"JSONRPC ERROR: {err.__str__()}")
|
||||||
|
|
||||||
self.Rpc: Loader = Loader(
|
|
||||||
req_method=self.Config.JSONRPC_METHOD,
|
|
||||||
url=self.Config.JSONRPC_URL,
|
|
||||||
username=self.Config.JSONRPC_USER,
|
|
||||||
password=self.Config.JSONRPC_PASSWORD
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.Rpc.get_error.code != 0:
|
|
||||||
self.Logs.error(f"{self.Rpc.get_error.message} ({self.Rpc.get_error.code})")
|
|
||||||
self.Protocol.send_priv_msg(
|
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
|
||||||
msg=f"[{self.Config.COLORS.red}JSONRPC ERROR{self.Config.COLORS.nogc}] {self.Rpc.get_error.message}",
|
|
||||||
channel=self.Config.SERVICE_CHANLOG
|
|
||||||
)
|
|
||||||
raise Exception(f"[JSONRPC ERROR] {self.Rpc.get_error.message}")
|
|
||||||
|
|
||||||
if self.ModConfig.jsonrpc == 1:
|
|
||||||
self.Base.create_thread(func=self.Threads.thread_subscribe, func_args=(self, ), run_once=True)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def __create_tables(self) -> 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.
|
||||||
@@ -143,7 +135,7 @@ class Jsonrpc():
|
|||||||
self.Base.db_execute_query(table_logs)
|
self.Base.db_execute_query(table_logs)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def callback_sent_to_irc(self, response: SimpleNamespace) -> None:
|
def callback_sent_to_irc(self, response: LiveRPCResult) -> None:
|
||||||
|
|
||||||
dnickname = self.Config.SERVICE_NICKNAME
|
dnickname = self.Config.SERVICE_NICKNAME
|
||||||
dchanlog = self.Config.SERVICE_CHANLOG
|
dchanlog = self.Config.SERVICE_CHANLOG
|
||||||
@@ -152,29 +144,19 @@ class Jsonrpc():
|
|||||||
bold = self.Config.COLORS.bold
|
bold = self.Config.COLORS.bold
|
||||||
red = self.Config.COLORS.red
|
red = self.Config.COLORS.red
|
||||||
|
|
||||||
if self.UnrealIrcdRpcLive.get_error.code != 0:
|
if response.error.code != 0:
|
||||||
self.Protocol.send_priv_msg(nick_from=dnickname,
|
self.Protocol.send_priv_msg(nick_from=dnickname,
|
||||||
msg=f"[{bold}{red}JSONRPC ERROR{nogc}{bold}] {self.UnrealIrcdRpcLive.get_error.message}",
|
msg=f"[{bold}{red}JSONRPC ERROR{nogc}{bold}] {response.error.message} ({response.error.code})",
|
||||||
channel=dchanlog)
|
channel=dchanlog)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if hasattr(response, 'error'):
|
if isinstance(response.result, bool):
|
||||||
if response.error.code != 0:
|
if response.result:
|
||||||
self.Protocol.send_priv_msg(
|
self.Protocol.send_priv_msg(
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
|
||||||
msg=f"[{bold}{red}JSONRPC{nogc}{bold}] JSONRPC Event activated on {self.Config.JSONRPC_URL}",
|
|
||||||
channel=dchanlog)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
if hasattr(response, 'result'):
|
|
||||||
if isinstance(response.result, bool):
|
|
||||||
if response.result:
|
|
||||||
self.Protocol.send_priv_msg(
|
|
||||||
nick_from=self.Config.SERVICE_NICKNAME,
|
nick_from=self.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.Config.JSONRPC_URL}",
|
||||||
channel=dchanlog)
|
channel=dchanlog)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
level = response.result.level if hasattr(response.result, 'level') else ''
|
level = response.result.level if hasattr(response.result, 'level') else ''
|
||||||
subsystem = response.result.subsystem if hasattr(response.result, 'subsystem') else ''
|
subsystem = response.result.subsystem if hasattr(response.result, 'subsystem') else ''
|
||||||
@@ -220,6 +202,7 @@ class Jsonrpc():
|
|||||||
)
|
)
|
||||||
self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True)
|
self.Base.create_thread(func=self.Threads.thread_unsubscribe, func_args=(self, ), run_once=True)
|
||||||
self.update_configuration('jsonrpc', 0)
|
self.update_configuration('jsonrpc', 0)
|
||||||
|
self.Irc.Commands.drop_command_by_module(self.module_name)
|
||||||
self.Logs.debug(f"Unloading {self.module_name}")
|
self.Logs.debug(f"Unloading {self.module_name}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -277,18 +260,13 @@ class Jsonrpc():
|
|||||||
match option:
|
match option:
|
||||||
case 'get':
|
case 'get':
|
||||||
nickname = str(cmd[2])
|
nickname = str(cmd[2])
|
||||||
uid_to_get = self.User.get_uid(nickname)
|
|
||||||
if uid_to_get is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
rpc = self.Rpc
|
rpc = self.Rpc
|
||||||
|
|
||||||
UserInfo = rpc.User.get(uid_to_get)
|
UserInfo = rpc.User.get(nickname)
|
||||||
if rpc.get_error.code != 0:
|
if UserInfo.error.code != 0:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'{rpc.get_error.message}')
|
self.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}')
|
self.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}')
|
self.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}')
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f'USERNAME : {UserInfo.user.username}')
|
||||||
@@ -320,9 +298,8 @@ class Jsonrpc():
|
|||||||
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()}")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"GC Collect: {self.MainUtils.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(LiveWebsocket)}")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveWebsock: {self.MainUtils.get_number_gc_objects(LiveConnectionFactory)}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance LiveUnixSocket: {self.MainUtils.get_number_gc_objects(LiveUnixSocket)}")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance ConnectionFactory: {self.MainUtils.get_number_gc_objects(ConnectionFactory)}")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre d'instance Loader: {self.MainUtils.get_number_gc_objects(Loader)}")
|
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.MainUtils.get_number_gc_objects()}")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nombre de toute les instances: {self.MainUtils.get_number_gc_objects()}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f"Unknown Error: {err}")
|
self.Logs.error(f"Unknown Error: {err}")
|
||||||
@@ -5,24 +5,20 @@ if TYPE_CHECKING:
|
|||||||
from mods.jsonrpc.mod_jsonrpc import Jsonrpc
|
from mods.jsonrpc.mod_jsonrpc import Jsonrpc
|
||||||
|
|
||||||
def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
||||||
response: dict[str, dict] = {}
|
|
||||||
snickname = uplink.Config.SERVICE_NICKNAME
|
snickname = uplink.Config.SERVICE_NICKNAME
|
||||||
schannel = uplink.Config.SERVICE_CHANLOG
|
schannel = uplink.Config.SERVICE_CHANLOG
|
||||||
|
uplink.is_streaming = True
|
||||||
|
response = asyncio.run(uplink.LiveRpc.subscribe(["all"]))
|
||||||
|
|
||||||
if uplink.UnrealIrcdRpcLive.get_error.code == 0:
|
if response.error.code != 0:
|
||||||
uplink.is_streaming = True
|
|
||||||
response = asyncio.run(uplink.UnrealIrcdRpcLive.subscribe(["all"]))
|
|
||||||
else:
|
|
||||||
uplink.Protocol.send_priv_msg(nick_from=snickname,
|
uplink.Protocol.send_priv_msg(nick_from=snickname,
|
||||||
msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {uplink.UnrealIrcdRpcLive.get_error.message}",
|
msg=f"[{uplink.Config.COLORS.red}JSONRPC ERROR{uplink.Config.COLORS.nogc}] {response.error.message}",
|
||||||
channel=schannel
|
channel=schannel
|
||||||
)
|
)
|
||||||
|
|
||||||
if response is None:
|
code = response.error.code
|
||||||
return
|
message = response.error.message
|
||||||
|
|
||||||
code = response.get('error', {}).get('code', 0)
|
|
||||||
message = response.get('error', {}).get('message', None)
|
|
||||||
|
|
||||||
if code == 0:
|
if code == 0:
|
||||||
uplink.Protocol.send_priv_msg(
|
uplink.Protocol.send_priv_msg(
|
||||||
@@ -39,18 +35,15 @@ def thread_subscribe(uplink: 'Jsonrpc') -> None:
|
|||||||
|
|
||||||
def thread_unsubscribe(uplink: 'Jsonrpc') -> None:
|
def thread_unsubscribe(uplink: 'Jsonrpc') -> None:
|
||||||
|
|
||||||
response: dict[str, dict] = asyncio.run(uplink.UnrealIrcdRpcLive.unsubscribe())
|
response = asyncio.run(uplink.LiveRpc.unsubscribe())
|
||||||
uplink.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!")
|
uplink.Logs.debug("[JSONRPC UNLOAD] Unsubscribe from the stream!")
|
||||||
uplink.is_streaming = False
|
uplink.is_streaming = False
|
||||||
uplink.update_configuration('jsonrpc', 0)
|
uplink.update_configuration('jsonrpc', 0)
|
||||||
snickname = uplink.Config.SERVICE_NICKNAME
|
snickname = uplink.Config.SERVICE_NICKNAME
|
||||||
schannel = uplink.Config.SERVICE_CHANLOG
|
schannel = uplink.Config.SERVICE_CHANLOG
|
||||||
|
|
||||||
if response is None:
|
code = response.error.code
|
||||||
return None
|
message = response.error.message
|
||||||
|
|
||||||
code = response.get('error', {}).get('code', 0)
|
|
||||||
message = response.get('error', {}).get('message', None)
|
|
||||||
|
|
||||||
if code != 0:
|
if code != 0:
|
||||||
uplink.Protocol.send_priv_msg(
|
uplink.Protocol.send_priv_msg(
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class Test():
|
|||||||
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_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)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def cmd(self, data:list) -> None:
|
def cmd(self, data:list) -> None:
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ class Votekick:
|
|||||||
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.Logs.debug(f'Delete memory DB VOTE_CHANNEL_DB: {self.VoteKickManager.VOTE_CHANNEL_DB}')
|
||||||
|
|
||||||
|
self.Irc.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.Logs.error(f'{ne}')
|
||||||
|
|||||||
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
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
|
||||||
15
version.json
15
version.json
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"version": "6.2.2",
|
"version": "6.3.2",
|
||||||
|
|
||||||
"requests": "2.32.3",
|
"requests": "2.32.5",
|
||||||
"psutil": "6.0.0",
|
"psutil": "7.1.2",
|
||||||
"unrealircd_rpc_py": "2.0.5",
|
"unrealircd_rpc_py": "3.0.1",
|
||||||
"sqlalchemy": "2.0.35",
|
"sqlalchemy": "2.0.44",
|
||||||
"faker": "30.1.0"
|
"faker": "37.12.0",
|
||||||
}
|
"pyyaml": "6.0.3"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user