mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 11:14:23 +00:00
174
core/base.py
174
core/base.py
@@ -2,17 +2,18 @@ import asyncio
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import time
|
||||
import socket
|
||||
import threading
|
||||
import ipaddress
|
||||
import ast
|
||||
import requests
|
||||
import concurrent.futures
|
||||
from dataclasses import fields
|
||||
from typing import Any, Callable, Iterable, Optional, TYPE_CHECKING
|
||||
from typing import Any, Awaitable, Callable, Optional, TYPE_CHECKING, Union
|
||||
from base64 import b64decode, b64encode
|
||||
from sqlalchemy import create_engine, Engine, Connection, CursorResult
|
||||
from sqlalchemy.sql import text
|
||||
import core.definition as dfn
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
@@ -36,12 +37,15 @@ class Base:
|
||||
# Liste des threads en cours
|
||||
self.running_threads: list[threading.Thread] = self.Settings.RUNNING_THREADS
|
||||
|
||||
# List of all async tasks
|
||||
self.running_asynctasks: list[asyncio.Task] = self.Settings.RUNNING_ASYNCTASKS
|
||||
|
||||
# Les sockets ouvert
|
||||
self.running_sockets: list[socket.socket] = self.Settings.RUNNING_SOCKETS
|
||||
|
||||
# List of all asyncio tasks
|
||||
self.running_iotasks: list[asyncio.Task] = self.Settings.RUNNING_ASYNC_TASKS
|
||||
|
||||
# List of all asyncio threads pool executors
|
||||
self.running_iothreads: list[dfn.MThread] = self.Settings.RUNNING_ASYNC_THREADS
|
||||
|
||||
# Liste des fonctions en attentes
|
||||
self.periodic_func: dict[object] = self.Settings.PERIODIC_FUNC
|
||||
|
||||
@@ -71,32 +75,32 @@ class Base:
|
||||
return None
|
||||
|
||||
def __get_latest_defender_version(self) -> None:
|
||||
try:
|
||||
self.logs.debug(f'-- Looking for a new version available on Github')
|
||||
token = ''
|
||||
json_url = f'https://raw.githubusercontent.com/adator85/DEFENDER/main/version.json'
|
||||
headers = {
|
||||
'Authorization': f'token {token}',
|
||||
'Accept': 'application/vnd.github.v3.raw' # Indique à GitHub que nous voulons le contenu brut du fichier
|
||||
}
|
||||
self.logs.debug(f'-- Looking for a new version available on Github')
|
||||
token = ''
|
||||
json_url = f'https://raw.githubusercontent.com/adator85/DEFENDER/main/version.json'
|
||||
headers = {
|
||||
'Authorization': f'token {token}',
|
||||
'Accept': 'application/vnd.github.v3.raw' # Indique à GitHub que nous voulons le contenu brut du fichier
|
||||
}
|
||||
|
||||
if token == '':
|
||||
response = requests.get(json_url, timeout=self.Config.API_TIMEOUT)
|
||||
else:
|
||||
response = requests.get(json_url, headers=headers, timeout=self.Config.API_TIMEOUT)
|
||||
with requests.Session() as sess:
|
||||
try:
|
||||
if token == '':
|
||||
response = sess.get(json_url, timeout=self.Config.API_TIMEOUT)
|
||||
else:
|
||||
response = sess.get(json_url, headers=headers, timeout=self.Config.API_TIMEOUT)
|
||||
|
||||
response.raise_for_status() # Vérifie si la requête a réussi
|
||||
json_response:dict = response.json()
|
||||
# self.LATEST_DEFENDER_VERSION = json_response["version"]
|
||||
self.Config.LATEST_VERSION = json_response['version']
|
||||
response.raise_for_status() # Vérifie si la requête a réussi
|
||||
json_response:dict = response.json()
|
||||
self.Config.LATEST_VERSION = json_response.get('version', '')
|
||||
return None
|
||||
|
||||
return None
|
||||
except requests.HTTPError as err:
|
||||
self.logs.error(f'Github not available to fetch latest version: {err}')
|
||||
except:
|
||||
self.logs.warning(f'Github not available to fetch latest version')
|
||||
except requests.HTTPError as err:
|
||||
self.logs.error(f'Github not available to fetch latest version: {err}')
|
||||
except:
|
||||
self.logs.warning(f'Github not available to fetch latest version')
|
||||
|
||||
def check_for_new_version(self, online:bool) -> bool:
|
||||
def check_for_new_version(self, online: bool) -> bool:
|
||||
"""Check if there is a new version available
|
||||
|
||||
Args:
|
||||
@@ -359,8 +363,8 @@ class Base:
|
||||
except Exception as err:
|
||||
self.logs.error(err, exc_info=True)
|
||||
|
||||
def create_asynctask(self, func: Any, *, async_name: str = None, run_once: bool = False) -> asyncio.Task:
|
||||
"""Create a new asynchrone and store it into running_asynctasks variable
|
||||
def create_asynctask(self, func: Callable[..., Awaitable[Any]], *, async_name: str = None, run_once: bool = False) -> Optional[asyncio.Task]:
|
||||
"""Create a new asynchrone and store it into running_iotasks variable
|
||||
|
||||
Args:
|
||||
func (Callable): The function you want to call in asynchrone way
|
||||
@@ -379,26 +383,71 @@ class Base:
|
||||
|
||||
task = asyncio.create_task(func, name=name)
|
||||
task.add_done_callback(self.asynctask_done)
|
||||
self.running_asynctasks.append(task)
|
||||
self.running_iotasks.append(task)
|
||||
|
||||
self.logs.debug(f"++ New asynchrone task created as: {task.get_name()}")
|
||||
self.logs.debug(f"=== New IO task created as: {task.get_name()}")
|
||||
return task
|
||||
|
||||
def asynctask_done(self, task: asyncio.Task):
|
||||
async def create_thread_io(self, func: Callable[..., Any], *args, run_once: bool = False, thread_flag: bool = False) -> Optional[Any]:
|
||||
"""Run threads via asyncio.
|
||||
|
||||
Args:
|
||||
func (Callable[..., Any]): The blocking IO function
|
||||
run_once (bool, optional): If it should be run once.. Defaults to False.
|
||||
thread_flag (bool, optional): If you are using a endless loop, use the threading Event object. Defaults to False.
|
||||
|
||||
Returns:
|
||||
Any: The final result of the blocking IO function
|
||||
"""
|
||||
if run_once:
|
||||
for iothread in self.running_iothreads:
|
||||
if func.__name__.lower() == iothread.name.lower():
|
||||
return None
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=1, thread_name_prefix=func.__name__) as executor:
|
||||
loop = asyncio.get_event_loop()
|
||||
largs = list(args)
|
||||
thread_event: Optional[threading.Event] = None
|
||||
if thread_flag:
|
||||
thread_event = threading.Event()
|
||||
thread_event.set()
|
||||
largs.insert(0, thread_event)
|
||||
|
||||
future = loop.run_in_executor(executor, func, *tuple(largs))
|
||||
future.add_done_callback(self.asynctask_done)
|
||||
|
||||
id_obj = self.Loader.Definition.MThread(
|
||||
name=func.__name__,
|
||||
thread_id=list(executor._threads)[0].native_id,
|
||||
thread_event=thread_event,
|
||||
thread_obj=list(executor._threads)[0],
|
||||
executor=executor,
|
||||
future=future)
|
||||
|
||||
self.running_iothreads.append(id_obj)
|
||||
self.logs.debug(f"=== New thread started {func.__name__} with max workers set to: {executor._max_workers}")
|
||||
result = await future
|
||||
|
||||
self.running_iothreads.remove(id_obj)
|
||||
return result
|
||||
|
||||
def asynctask_done(self, task: Union[asyncio.Task, asyncio.Future]):
|
||||
"""Log task when done
|
||||
|
||||
Args:
|
||||
task (asyncio.Task): The Asyncio Task callback
|
||||
"""
|
||||
name = task.get_name() if isinstance(task, asyncio.Task) else "Thread"
|
||||
task_or_future = "Task" if isinstance(task, asyncio.Task) else "Future"
|
||||
try:
|
||||
if task.exception():
|
||||
self.logs.error(f"[ASYNCIO] Task {task.get_name()} failed with exception: {task.exception()}")
|
||||
self.logs.error(f"[ASYNCIO] {task_or_future} {name} failed with exception: {task.exception()}")
|
||||
else:
|
||||
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} completed successfully.")
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {name} completed successfully.")
|
||||
except asyncio.CancelledError as ce:
|
||||
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with cancelled error.")
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {name} terminated with cancelled error. {ce}")
|
||||
except asyncio.InvalidStateError as ie:
|
||||
self.logs.debug(f"[ASYNCIO] Task {task.get_name()} terminated with invalid state error.")
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {name} terminated with invalid state error. {ie}")
|
||||
|
||||
def is_thread_alive(self, thread_name: str) -> bool:
|
||||
"""Check if the thread is still running! using the is_alive method of Threads.
|
||||
@@ -492,59 +541,6 @@ class Base:
|
||||
self.running_sockets.remove(soc)
|
||||
self.logs.debug(f"-- Socket ==> closed {str(soc.fileno())}")
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
"""Methode qui va préparer l'arrêt complêt du service
|
||||
"""
|
||||
# Stop RpcServer if running
|
||||
await self.Loader.RpcServer.stop_server()
|
||||
|
||||
# unload modules.
|
||||
self.logs.debug(f"=======> Unloading all modules!")
|
||||
for module in self.Loader.ModuleUtils.model_get_loaded_modules().copy():
|
||||
await self.Loader.ModuleUtils.unload_one_module(module.module_name)
|
||||
|
||||
self.logs.debug(f"=======> Closing all Coroutines!")
|
||||
try:
|
||||
await asyncio.wait_for(asyncio.gather(*self.running_asynctasks), timeout=5)
|
||||
except asyncio.exceptions.TimeoutError as te:
|
||||
self.logs.debug(f"Asyncio Timeout reached! {te}")
|
||||
for task in self.running_asynctasks:
|
||||
task.cancel()
|
||||
except asyncio.exceptions.CancelledError as cerr:
|
||||
self.logs.debug(f"Asyncio CancelledError reached! {cerr}")
|
||||
|
||||
|
||||
# Nettoyage des timers
|
||||
self.logs.debug(f"=======> Checking for Timers to stop")
|
||||
for timer in self.running_timers:
|
||||
while timer.is_alive():
|
||||
self.logs.debug(f"> waiting for {timer.name} to close")
|
||||
timer.cancel()
|
||||
await asyncio.sleep(0.2)
|
||||
self.running_timers.remove(timer)
|
||||
self.logs.debug(f"> Cancelling {timer.name} {timer.native_id}")
|
||||
|
||||
self.logs.debug(f"=======> Checking for Threads to stop")
|
||||
for thread in self.running_threads:
|
||||
if thread.name == 'heartbeat' and thread.is_alive():
|
||||
self.execute_periodic_action()
|
||||
self.logs.debug(f"> Running the last periodic action")
|
||||
self.running_threads.remove(thread)
|
||||
self.logs.debug(f"> Cancelling {thread.name} {thread.native_id}")
|
||||
|
||||
self.logs.debug(f"=======> Checking for Sockets to stop")
|
||||
for soc in self.running_sockets:
|
||||
soc.close()
|
||||
while soc.fileno() != -1:
|
||||
soc.close()
|
||||
|
||||
self.running_sockets.remove(soc)
|
||||
self.logs.debug(f"> Socket ==> closed {str(soc.fileno())}")
|
||||
|
||||
self.db_close()
|
||||
|
||||
return None
|
||||
|
||||
def db_init(self) -> tuple[Engine, Connection]:
|
||||
|
||||
db_directory = self.Config.DB_PATH
|
||||
|
||||
@@ -12,12 +12,14 @@ class IRPC:
|
||||
self.http_status_code = http_status_code
|
||||
self.response_model = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'unknown',
|
||||
"id": 123
|
||||
}
|
||||
|
||||
def reset(self):
|
||||
self.response_model = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": 'unknown',
|
||||
"id": 123
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,7 @@ class Admin:
|
||||
Args:
|
||||
loader (Loader): The Loader Instance.
|
||||
"""
|
||||
self.Logs = loader.Logs
|
||||
self.Base = loader.Base
|
||||
self.Setting = loader.Settings
|
||||
self.Config = loader.Config
|
||||
self.User = loader.User
|
||||
self.Definition = loader.Definition
|
||||
self._ctx = loader
|
||||
|
||||
def insert(self, new_admin: MAdmin) -> bool:
|
||||
"""Insert a new admin object model
|
||||
@@ -33,11 +28,11 @@ class Admin:
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.uid == new_admin.uid:
|
||||
self.Logs.debug(f'{record.uid} already exist')
|
||||
self._ctx.Logs.debug(f'{record.uid} already exist')
|
||||
return False
|
||||
|
||||
self.UID_ADMIN_DB.append(new_admin)
|
||||
self.Logs.debug(f'A new admin ({new_admin.nickname}) has been created')
|
||||
self._ctx.Logs.debug(f'A new admin ({new_admin.nickname}) has been created')
|
||||
return True
|
||||
|
||||
def update_nickname(self, uid: str, new_admin_nickname: str) -> bool:
|
||||
@@ -55,11 +50,11 @@ class Admin:
|
||||
if record.uid == uid:
|
||||
# If the admin exist, update and do not go further
|
||||
record.nickname = new_admin_nickname
|
||||
self.Logs.debug(f'UID ({record.uid}) has been updated with new nickname {new_admin_nickname}')
|
||||
self._ctx.Logs.debug(f'UID ({record.uid}) has been updated with new nickname {new_admin_nickname}')
|
||||
return True
|
||||
|
||||
|
||||
self.Logs.debug(f'The new nickname {new_admin_nickname} was not updated, uid = {uid} - The Client is not an admin')
|
||||
self._ctx.Logs.debug(f'The new nickname {new_admin_nickname} was not updated, uid = {uid} - The Client is not an admin')
|
||||
return False
|
||||
|
||||
def update_level(self, nickname: str, new_admin_level: int) -> bool:
|
||||
@@ -77,10 +72,10 @@ class Admin:
|
||||
if record.nickname == nickname:
|
||||
# If the admin exist, update and do not go further
|
||||
record.level = new_admin_level
|
||||
self.Logs.debug(f'Admin ({record.nickname}) has been updated with new level {new_admin_level}')
|
||||
self._ctx.Logs.debug(f'Admin ({record.nickname}) has been updated with new level {new_admin_level}')
|
||||
return True
|
||||
|
||||
self.Logs.debug(f'The new level {new_admin_level} was not updated, nickname = {nickname} - The Client is not an admin')
|
||||
self._ctx.Logs.debug(f'The new level {new_admin_level} was not updated, nickname = {nickname} - The Client is not an admin')
|
||||
|
||||
return False
|
||||
|
||||
@@ -96,10 +91,10 @@ class Admin:
|
||||
admin_obj = self.get_admin(uidornickname)
|
||||
if admin_obj:
|
||||
self.UID_ADMIN_DB.remove(admin_obj)
|
||||
self.Logs.debug(f'UID ({admin_obj.uid}) has been deleted')
|
||||
self._ctx.Logs.debug(f'UID ({admin_obj.uid}) has been deleted')
|
||||
return True
|
||||
|
||||
self.Logs.debug(f'The UID {uidornickname} was not deleted')
|
||||
self._ctx.Logs.debug(f'The UID {uidornickname} was not deleted')
|
||||
|
||||
return False
|
||||
|
||||
@@ -186,20 +181,20 @@ class Admin:
|
||||
if fp is None:
|
||||
return False
|
||||
|
||||
query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp"
|
||||
query = f"SELECT user, level, language FROM {self._ctx.Config.TABLE_ADMIN} WHERE fingerprint = :fp"
|
||||
data = {'fp': fp}
|
||||
exe = await self.Base.db_execute_query(query, data)
|
||||
exe = await self._ctx.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)
|
||||
user_obj = self._ctx.User.get_user(uidornickname)
|
||||
if user_obj:
|
||||
admin_obj = self.Definition.MAdmin(**user_obj.to_dict(), account=account, level=level, language=language)
|
||||
admin_obj = self._ctx.Definition.MAdmin(**user_obj.to_dict(), account=account, level=level, language=language)
|
||||
if self.insert(admin_obj):
|
||||
self.Setting.current_admin = admin_obj
|
||||
self.Logs.debug(f"[Fingerprint login] {user_obj.nickname} ({admin_obj.account}) has been logged in successfully!")
|
||||
self._ctx.Settings.current_admin = admin_obj
|
||||
self._ctx.Logs.debug(f"[Fingerprint login] {user_obj.nickname} ({admin_obj.account}) has been logged in successfully!")
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -215,8 +210,8 @@ class Admin:
|
||||
"""
|
||||
|
||||
mes_donnees = {'admin': admin_nickname}
|
||||
query_search_user = f"SELECT id FROM {self.Config.TABLE_ADMIN} WHERE user = :admin"
|
||||
r = await self.Base.db_execute_query(query_search_user, mes_donnees)
|
||||
query_search_user = f"SELECT id FROM {self._ctx.Config.TABLE_ADMIN} WHERE user = :admin"
|
||||
r = await self._ctx.Base.db_execute_query(query_search_user, mes_donnees)
|
||||
exist_user = r.fetchone()
|
||||
if exist_user:
|
||||
return True
|
||||
|
||||
@@ -15,8 +15,7 @@ class Client:
|
||||
Args:
|
||||
loader (Loader): The Loader instance.
|
||||
"""
|
||||
self.Logs = loader.Logs
|
||||
self.Base = loader.Base
|
||||
self._ctx = loader
|
||||
|
||||
def insert(self, new_client: 'MClient') -> bool:
|
||||
"""Insert a new User object
|
||||
@@ -28,7 +27,7 @@ class Client:
|
||||
bool: True if inserted
|
||||
"""
|
||||
|
||||
client_obj = self.get_Client(new_client.uid)
|
||||
client_obj = self.get_client(new_client.uid)
|
||||
|
||||
if not client_obj is None:
|
||||
# User already created return False
|
||||
@@ -48,7 +47,7 @@ class Client:
|
||||
Returns:
|
||||
bool: True if updated
|
||||
"""
|
||||
user_obj = self.get_Client(uidornickname=uid)
|
||||
user_obj = self.get_client(uidornickname=uid)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -68,7 +67,7 @@ class Client:
|
||||
bool: True if user mode has been updaed
|
||||
"""
|
||||
response = True
|
||||
user_obj = self.get_Client(uidornickname=uidornickname)
|
||||
user_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -93,7 +92,7 @@ class Client:
|
||||
return False
|
||||
|
||||
liste_umodes = list(umodes)
|
||||
final_umodes_liste = [x for x in self.Base.Settings.PROTOCTL_USER_MODES if x in liste_umodes]
|
||||
final_umodes_liste = [x for x in self._ctx.Base.Settings.PROTOCTL_USER_MODES if x in liste_umodes]
|
||||
final_umodes = ''.join(final_umodes_liste)
|
||||
|
||||
user_obj.umodes = f"+{final_umodes}"
|
||||
@@ -110,7 +109,7 @@ class Client:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
user_obj = self.get_Client(uidornickname=uid)
|
||||
user_obj = self.get_client(uidornickname=uid)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -119,7 +118,7 @@ class Client:
|
||||
|
||||
return True
|
||||
|
||||
def get_Client(self, uidornickname: str) -> Optional['MClient']:
|
||||
def get_client(self, uidornickname: str) -> Optional['MClient']:
|
||||
"""Get The Client Object model
|
||||
|
||||
Args:
|
||||
@@ -146,7 +145,7 @@ class Client:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
|
||||
client_obj = self.get_Client(uidornickname=uidornickname)
|
||||
client_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if client_obj is None:
|
||||
return None
|
||||
@@ -162,29 +161,13 @@ class Client:
|
||||
Returns:
|
||||
str|None: the nickname
|
||||
"""
|
||||
client_obj = self.get_Client(uidornickname=uidornickname)
|
||||
client_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return client_obj.nickname
|
||||
|
||||
def get_client_asdict(self, uidornickname: str) -> Optional[dict[str, Any]]:
|
||||
"""Transform User Object to a dictionary
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or The nickname
|
||||
|
||||
Returns:
|
||||
Union[dict[str, any], None]: User Object as a dictionary or None
|
||||
"""
|
||||
client_obj = self.get_Client(uidornickname=uidornickname)
|
||||
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return client_obj.to_dict()
|
||||
|
||||
def is_exist(self, uidornickname: str) -> bool:
|
||||
"""Check if the UID or the nickname exist in the USER DB
|
||||
|
||||
@@ -194,7 +177,7 @@ class Client:
|
||||
Returns:
|
||||
bool: True if exist
|
||||
"""
|
||||
user_obj = self.get_Client(uidornickname=uidornickname)
|
||||
user_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
@@ -211,15 +194,15 @@ class Client:
|
||||
bool: True if exist
|
||||
"""
|
||||
|
||||
table_client = self.Base.Config.TABLE_CLIENT
|
||||
table_client = self._ctx.Base.Config.TABLE_CLIENT
|
||||
account_to_check = {'account': account.lower()}
|
||||
account_to_check_query = await self.Base.db_execute_query(f"""
|
||||
account_to_check_query = await self._ctx.Base.db_execute_query(f"""
|
||||
SELECT id FROM {table_client} WHERE LOWER(account) = :account
|
||||
""", account_to_check)
|
||||
|
||||
account_to_check_result = account_to_check_query.fetchone()
|
||||
if account_to_check_result:
|
||||
self.Logs.error(f"Account ({account}) already exist")
|
||||
self._ctx.Logs.error(f"Account ({account}) already exist")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -13,11 +13,21 @@ class Command:
|
||||
Args:
|
||||
loader (Loader): The Loader instance.
|
||||
"""
|
||||
self.Loader = loader
|
||||
self.Base = loader.Base
|
||||
self.Logs = loader.Logs
|
||||
self._ctx = loader
|
||||
|
||||
def build(self, new_command_obj: MCommand) -> bool:
|
||||
def build_command(self, level: int, module_name: str, command_name: str, command_description: str) -> bool:
|
||||
"""This method build the commands variable
|
||||
|
||||
Args:
|
||||
level (int): The Level of the command
|
||||
module_name (str): The module name
|
||||
command_name (str): The command name
|
||||
command_description (str): The description of the command
|
||||
"""
|
||||
# Build Model.
|
||||
return self._build(self._ctx.Definition.MCommand(module_name, command_name, command_description, level))
|
||||
|
||||
def _build(self, new_command_obj: MCommand) -> bool:
|
||||
|
||||
command = self.get_command(new_command_obj.command_name, new_command_obj.module_name)
|
||||
if command is None:
|
||||
@@ -68,7 +78,7 @@ class Command:
|
||||
for c in tmp_model:
|
||||
self.DB_COMMANDS.remove(c)
|
||||
|
||||
self.Logs.debug(f"[COMMAND] Drop command for module {module_name}")
|
||||
self._ctx.Logs.debug(f"[COMMAND] Drop command for module {module_name}")
|
||||
return True
|
||||
|
||||
def get_ordered_commands(self) -> list[MCommand]:
|
||||
@@ -86,7 +96,7 @@ class Command:
|
||||
return new_list
|
||||
|
||||
def is_client_allowed_to_run_command(self, nickname: str, command_name: str) -> bool:
|
||||
admin = self.Loader.Admin.get_admin(nickname)
|
||||
admin = self._ctx.Admin.get_admin(nickname)
|
||||
admin_level = admin.level if admin else 0
|
||||
commands = self.get_commands_by_level(admin_level)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import importlib
|
||||
import sys
|
||||
import time
|
||||
@@ -26,7 +27,6 @@ REHASH_MODULES = [
|
||||
'core.classes.protocols.inspircd'
|
||||
]
|
||||
|
||||
|
||||
async def restart_service(uplink: 'Loader', reason: str = "Restarting with no reason!") -> None:
|
||||
"""
|
||||
|
||||
@@ -69,7 +69,7 @@ async def rehash_service(uplink: 'Loader', nickname: str) -> None:
|
||||
need_a_restart = ["SERVEUR_ID"]
|
||||
uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS)
|
||||
|
||||
await uplink.RpcServer.stop_server()
|
||||
await uplink.RpcServer.stop_rpc_server()
|
||||
|
||||
restart_flag = False
|
||||
config_model_bakcup = uplink.Config
|
||||
@@ -122,10 +122,68 @@ async def rehash_service(uplink: 'Loader', nickname: str) -> None:
|
||||
uplink.Irc.Protocol.register_command()
|
||||
|
||||
uplink.RpcServer = uplink.RpcServerModule.JSonRpcServer(uplink)
|
||||
uplink.Base.create_asynctask(uplink.RpcServer.start_server())
|
||||
uplink.Base.create_asynctask(uplink.RpcServer.start_rpc_server())
|
||||
|
||||
# Reload Service modules
|
||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||
await uplink.ModuleUtils.reload_one_module(module.module_name, nickname)
|
||||
|
||||
return None
|
||||
|
||||
async def shutdown(uplink: 'Loader') -> None:
|
||||
"""Methode qui va préparer l'arrêt complêt du service
|
||||
"""
|
||||
# Stop RpcServer if running
|
||||
await uplink.RpcServer.stop_rpc_server()
|
||||
|
||||
# unload modules.
|
||||
uplink.Logs.debug(f"=======> Unloading all modules!")
|
||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||
await uplink.ModuleUtils.unload_one_module(module.module_name)
|
||||
|
||||
# Nettoyage des timers
|
||||
uplink.Logs.debug(f"=======> Closing all timers!")
|
||||
for timer in uplink.Base.running_timers:
|
||||
while timer.is_alive():
|
||||
uplink.Logs.debug(f"> waiting for {timer.name} to close")
|
||||
timer.cancel()
|
||||
await asyncio.sleep(0.2)
|
||||
uplink.Logs.debug(f"> Cancelling {timer.name} {timer.native_id}")
|
||||
|
||||
uplink.Logs.debug(f"=======> Closing all Threads!")
|
||||
for thread in uplink.Base.running_threads:
|
||||
if thread.name == 'heartbeat' and thread.is_alive():
|
||||
uplink.Base.execute_periodic_action()
|
||||
uplink.Logs.debug(f"> Running the last periodic action")
|
||||
uplink.Logs.debug(f"> Cancelling {thread.name} {thread.native_id}")
|
||||
|
||||
uplink.Logs.debug(f"=======> Closing all IO Threads!")
|
||||
[th.thread_event.clear() for th in uplink.Base.running_iothreads]
|
||||
|
||||
uplink.Logs.debug(f"=======> Closing all IO TASKS!")
|
||||
try:
|
||||
await asyncio.wait_for(asyncio.gather(*uplink.Base.running_iotasks), timeout=5)
|
||||
except asyncio.exceptions.TimeoutError as te:
|
||||
uplink.Logs.debug(f"Asyncio Timeout reached! {te}")
|
||||
for task in uplink.Base.running_iotasks:
|
||||
task.cancel()
|
||||
except asyncio.exceptions.CancelledError as cerr:
|
||||
uplink.Logs.debug(f"Asyncio CancelledError reached! {cerr}")
|
||||
|
||||
uplink.Logs.debug(f"=======> Closing all Sockets!")
|
||||
for soc in uplink.Base.running_sockets:
|
||||
soc.close()
|
||||
while soc.fileno() != -1:
|
||||
soc.close()
|
||||
uplink.Base.running_sockets.remove(soc)
|
||||
uplink.Logs.debug(f"> Socket ==> closed {str(soc.fileno())}")
|
||||
|
||||
uplink.Base.running_timers.clear()
|
||||
uplink.Base.running_threads.clear()
|
||||
uplink.Base.running_iotasks.clear()
|
||||
uplink.Base.running_iothreads.clear()
|
||||
uplink.Base.running_sockets.clear()
|
||||
|
||||
uplink.Base.db_close()
|
||||
|
||||
return None
|
||||
@@ -14,9 +14,7 @@ class Reputation:
|
||||
Args:
|
||||
loader (Loader): The Loader instance.
|
||||
"""
|
||||
|
||||
self.Logs = loader.Logs
|
||||
self.MReputation: Optional[MReputation] = None
|
||||
self._ctx = loader
|
||||
|
||||
def insert(self, new_reputation_user: MReputation) -> bool:
|
||||
"""Insert a new Reputation User object
|
||||
@@ -34,16 +32,16 @@ class Reputation:
|
||||
if record.uid == new_reputation_user.uid:
|
||||
# If the user exist then return False and do not go further
|
||||
exist = True
|
||||
self.Logs.debug(f'{record.uid} already exist')
|
||||
self._ctx.Logs.debug(f'{record.uid} already exist')
|
||||
return result
|
||||
|
||||
if not exist:
|
||||
self.UID_REPUTATION_DB.append(new_reputation_user)
|
||||
result = True
|
||||
self.Logs.debug(f'New Reputation User Captured: ({new_reputation_user})')
|
||||
self._ctx.Logs.debug(f'New Reputation User Captured: ({new_reputation_user})')
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The Reputation User Object was not inserted {new_reputation_user}')
|
||||
self._ctx.Logs.critical(f'The Reputation User Object was not inserted {new_reputation_user}')
|
||||
|
||||
return result
|
||||
|
||||
@@ -86,11 +84,11 @@ class Reputation:
|
||||
# If the user exist then remove and return True and do not go further
|
||||
self.UID_REPUTATION_DB.remove(record)
|
||||
result = True
|
||||
self.Logs.debug(f'UID ({record.uid}) has been deleted')
|
||||
self._ctx.Logs.debug(f'UID ({record.uid}) has been deleted')
|
||||
return result
|
||||
|
||||
if not result:
|
||||
self.Logs.critical(f'The UID {uid} was not deleted')
|
||||
self._ctx.Logs.critical(f'The UID {uid} was not deleted')
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
__version__ = '1.0.0'
|
||||
__all__ = ['start_rpc_server', 'stop_rpc_server']
|
||||
@@ -17,11 +17,11 @@ if TYPE_CHECKING:
|
||||
|
||||
class JSonRpcServer:
|
||||
|
||||
def __init__(self, context: 'Loader', *, hostname: str = 'localhost', port: int = 5000):
|
||||
def __init__(self, context: 'Loader'):
|
||||
self._ctx = context
|
||||
self.live: bool = False
|
||||
self.host = hostname
|
||||
self.port = port
|
||||
self.host = context.Config.RPC_HOST
|
||||
self.port = context.Config.RPC_PORT
|
||||
self.routes: list[Route] = []
|
||||
self.server: Optional[uvicorn.Server] = None
|
||||
|
||||
@@ -34,12 +34,12 @@ class JSonRpcServer:
|
||||
'command.get.by.module': RPCCommand(context).command_get_by_module
|
||||
}
|
||||
|
||||
async def start_server(self):
|
||||
async def start_rpc_server(self):
|
||||
|
||||
if not self.live:
|
||||
self.routes = [Route('/api', self.request_handler, methods=['POST'])]
|
||||
self.app_jsonrpc = Starlette(debug=False, routes=self.routes)
|
||||
config = uvicorn.Config(self.app_jsonrpc, host=self.host, port=self.port, log_level=self._ctx.Config.DEBUG_LEVEL)
|
||||
config = uvicorn.Config(self.app_jsonrpc, host=self.host, port=self.port, log_level=self._ctx.Config.DEBUG_LEVEL+10)
|
||||
self.server = uvicorn.Server(config)
|
||||
self.live = True
|
||||
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||
@@ -52,7 +52,7 @@ class JSonRpcServer:
|
||||
else:
|
||||
self._ctx.Logs.debug("Server already running")
|
||||
|
||||
async def stop_server(self):
|
||||
async def stop_rpc_server(self):
|
||||
|
||||
if self.server:
|
||||
self.server.should_exit = True
|
||||
@@ -77,10 +77,10 @@ class JSonRpcServer:
|
||||
|
||||
response_data = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": method,
|
||||
"id": request_data.get('id', 123)
|
||||
}
|
||||
|
||||
response_data['method'] = method
|
||||
rip = request.client.host
|
||||
rport = request.client.port
|
||||
http_code = http_status_code.HTTP_200_OK
|
||||
@@ -89,6 +89,7 @@ class JSonRpcServer:
|
||||
r: JSONResponse = self.methods[method](**params)
|
||||
resp = json.loads(r.body)
|
||||
resp['id'] = request_data.get('id', 123)
|
||||
resp['method'] = method
|
||||
return JSONResponse(resp, r.status_code)
|
||||
|
||||
response_data['error'] = rpcerr.create_error_response(rpcerr.JSONRPCErrorCode.METHOD_NOT_FOUND)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from starlette.responses import JSONResponse
|
||||
from core.classes.interfaces.irpc_endpoint import IRPC
|
||||
from core.classes.modules.rpc.rpc_errors import JSONRPCErrorCode
|
||||
|
||||
@@ -42,4 +42,4 @@ class RPCUser(IRPC):
|
||||
return JSONResponse(self.response_model)
|
||||
|
||||
self.response_model['result'] = 'User not found!'
|
||||
return JSONResponse(self.response_model, self.http_status_code.HTTP_204_NO_CONTENT)
|
||||
return JSONResponse(self.response_model, self.http_status_code.HTTP_404_NOT_FOUND)
|
||||
@@ -6,7 +6,7 @@ from threading import Timer, Thread, RLock
|
||||
from asyncio.locks import Lock
|
||||
from socket import socket
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
from core.definition import MSModule, MAdmin
|
||||
from core.definition import MSModule, MAdmin, MThread
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.classes.modules.user import User
|
||||
@@ -19,10 +19,12 @@ class Settings:
|
||||
|
||||
RUNNING_TIMERS: list[Timer] = []
|
||||
RUNNING_THREADS: list[Thread] = []
|
||||
RUNNING_ASYNCTASKS: list[asyncio.Task] = []
|
||||
RUNNING_SOCKETS: list[socket] = []
|
||||
RUNNING_ASYNC_TASKS: list[asyncio.Task] = []
|
||||
RUNNING_ASYNC_THREADS: list[MThread] = []
|
||||
PERIODIC_FUNC: dict[str, Any] = {}
|
||||
LOCK: RLock = RLock()
|
||||
|
||||
THLOCK: RLock = RLock()
|
||||
AILOCK: Lock = Lock()
|
||||
|
||||
CONSOLE: bool = False
|
||||
|
||||
@@ -93,4 +93,4 @@ class Translation:
|
||||
|
||||
except Exception as err:
|
||||
self.Logs.error(f'General Error: {err}')
|
||||
return {}
|
||||
return dict()
|
||||
|
||||
@@ -11,14 +11,16 @@ class User:
|
||||
UID_DB: list['MUser'] = []
|
||||
|
||||
@property
|
||||
def get_current_user(self) -> 'MUser':
|
||||
return self.current_user
|
||||
def current_user(self) -> 'MUser':
|
||||
return self._current_user
|
||||
|
||||
@current_user.setter
|
||||
def current_user(self, muser: 'MUser') -> None:
|
||||
self._current_user = muser
|
||||
|
||||
def __init__(self, loader: 'Loader'):
|
||||
|
||||
self.Logs = loader.Logs
|
||||
self.Base = loader.Base
|
||||
self.current_user: Optional['MUser'] = None
|
||||
self._ctx = loader
|
||||
self._current_user: Optional['MUser'] = None
|
||||
|
||||
def insert(self, new_user: 'MUser') -> bool:
|
||||
"""Insert a new User object
|
||||
@@ -55,7 +57,7 @@ class User:
|
||||
return False
|
||||
|
||||
user_obj.nickname = new_nickname
|
||||
self.Logs.debug(f"UID ({uid}) has benn update with new nickname ({new_nickname}).")
|
||||
self._ctx.Logs.debug(f"UID ({uid}) has benn update with new nickname ({new_nickname}).")
|
||||
return True
|
||||
|
||||
def update_mode(self, uidornickname: str, modes: str) -> bool:
|
||||
@@ -94,7 +96,7 @@ class User:
|
||||
return False
|
||||
|
||||
liste_umodes = list(umodes)
|
||||
final_umodes_liste = [x for x in self.Base.Settings.PROTOCTL_USER_MODES if x in liste_umodes]
|
||||
final_umodes_liste = [x for x in self._ctx.Base.Settings.PROTOCTL_USER_MODES if x in liste_umodes]
|
||||
final_umodes = ''.join(final_umodes_liste)
|
||||
|
||||
user_obj.umodes = f"+{final_umodes}"
|
||||
|
||||
@@ -4,7 +4,7 @@ from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
from ssl import SSLEOFError, SSLError
|
||||
from core.classes.interfaces.iprotocol import IProtocol
|
||||
from core.utils import tr
|
||||
from core.utils import is_coroutinefunction, tr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MClient, MSasl, MUser, MChannel
|
||||
@@ -258,6 +258,7 @@ class Unrealircd6(IProtocol):
|
||||
|
||||
async def send_set_mode(self, modes: str, *, nickname: Optional[str] = None, channel_name: Optional[str] = None, params: Optional[str] = None) -> None:
|
||||
"""Set a mode to channel or to a nickname or for a user in a channel
|
||||
This method will always send as the command as Defender's nickname (service_id)
|
||||
|
||||
Args:
|
||||
modes (str): The selected mode
|
||||
@@ -478,7 +479,7 @@ class Unrealircd6(IProtocol):
|
||||
c_uid = client_obj.uid
|
||||
c_nickname = client_obj.nickname
|
||||
await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SVSLOGIN {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0")
|
||||
self.send_svs2mode(c_nickname, '-r')
|
||||
await self.send_svs2mode(c_nickname, '-r')
|
||||
|
||||
except Exception as err:
|
||||
self._ctx.Logs.error(f'General Error: {err}')
|
||||
@@ -1020,7 +1021,7 @@ class Unrealircd6(IProtocol):
|
||||
|
||||
# Send EOF to other modules
|
||||
for module in self._ctx.ModuleUtils.model_get_loaded_modules().copy():
|
||||
module.class_instance.cmd(server_msg_copy)
|
||||
await module.class_instance.cmd(server_msg_copy) if self._ctx.Utils.is_coroutinefunction(module.class_instance.cmd) else module.class_instance.cmd(server_msg_copy)
|
||||
|
||||
# Join saved channels & load existing modules
|
||||
await self._ctx.Channel.db_join_saved_channels()
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import asyncio
|
||||
import concurrent
|
||||
import concurrent.futures
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from json import dumps
|
||||
from dataclasses import dataclass, field, asdict, fields, replace
|
||||
@@ -210,6 +214,12 @@ class MConfig(MainModel):
|
||||
PASSWORD: str = "password"
|
||||
"""The password of the admin of the service"""
|
||||
|
||||
RPC_HOST: str = "127.0.0.1"
|
||||
"""The host to bind. Default: 127.0.0.1"""
|
||||
|
||||
RPC_PORT: int = 5000
|
||||
"""The port of the defender json rpc. Default: 5000"""
|
||||
|
||||
RPC_USERS: list[dict] = field(default_factory=list)
|
||||
"""The Defender rpc users"""
|
||||
|
||||
@@ -344,6 +354,15 @@ class MConfig(MainModel):
|
||||
self.SERVEUR_CHARSET: list = ["utf-8", "iso-8859-1"]
|
||||
"""0: utf-8 | 1: iso-8859-1"""
|
||||
|
||||
@dataclass
|
||||
class MThread(MainModel):
|
||||
name: str
|
||||
thread_id: Optional[int]
|
||||
thread_event: Optional[threading.Event]
|
||||
thread_obj: threading.Thread
|
||||
executor: concurrent.futures.ThreadPoolExecutor
|
||||
future: asyncio.Future
|
||||
|
||||
@dataclass
|
||||
class MCommand(MainModel):
|
||||
module_name: str = None
|
||||
|
||||
225
core/irc.py
225
core/irc.py
@@ -1,8 +1,7 @@
|
||||
import asyncio
|
||||
import socket
|
||||
import re
|
||||
import time
|
||||
from ssl import SSLSocket
|
||||
import ssl
|
||||
import threading
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||
from core.classes.modules import rehash
|
||||
@@ -30,6 +29,10 @@ class Irc:
|
||||
# Load Context class (Loader)
|
||||
self.ctx = loader
|
||||
|
||||
# Define Reader and Writer
|
||||
self.reader: Optional[asyncio.StreamReader] = None
|
||||
self.writer: Optional[asyncio.StreamWriter] = None
|
||||
|
||||
# Date et heure de la premiere connexion de Defender
|
||||
self.defender_connexion_datetime = self.ctx.Config.DEFENDER_CONNEXION_DATETIME
|
||||
|
||||
@@ -58,50 +61,56 @@ class Irc:
|
||||
# Load Commands Utils
|
||||
# self.Commands = self.Loader.Commands
|
||||
"""Command utils"""
|
||||
self.ctx.Commands.build_command(0, 'core', 'help', 'This provide the help')
|
||||
self.ctx.Commands.build_command(0, 'core', 'auth', 'Login to the IRC Service')
|
||||
self.ctx.Commands.build_command(0, 'core', 'copyright', 'Give some information about the IRC Service')
|
||||
self.ctx.Commands.build_command(0, 'core', 'uptime', 'Give you since when the service is connected')
|
||||
self.ctx.Commands.build_command(0, 'core', 'firstauth', 'First authentication of the Service')
|
||||
self.ctx.Commands.build_command(0, 'core', 'register', f'Register your nickname /msg {self.ctx.Config.SERVICE_NICKNAME} REGISTER <password> <email>')
|
||||
self.ctx.Commands.build_command(0, 'core', 'identify', f'Identify yourself with your password /msg {self.ctx.Config.SERVICE_NICKNAME} IDENTIFY <account> <password>')
|
||||
self.ctx.Commands.build_command(0, 'core', 'logout', 'Reverse the effect of the identify command')
|
||||
self.ctx.Commands.build_command(1, 'core', 'load', 'Load an existing module')
|
||||
self.ctx.Commands.build_command(1, 'core', 'unload', 'Unload a module')
|
||||
self.ctx.Commands.build_command(1, 'core', 'reload', 'Reload a module')
|
||||
self.ctx.Commands.build_command(1, 'core', 'deauth', 'Deauth from the irc service')
|
||||
self.ctx.Commands.build_command(1, 'core', 'checkversion', 'Check the version of the irc service')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_modules', 'Display a list of loaded modules')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_timers', 'Display active timers')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_threads', 'Display active threads in the system')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_asyncio', 'Display active asyncio')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_channels', 'Display a list of active channels')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_users', 'Display a list of connected users')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_clients', 'Display a list of connected clients')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_admins', 'Display a list of administrators')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_configuration', 'Display the current configuration settings')
|
||||
self.ctx.Commands.build_command(2, 'core', 'show_cache', 'Display the current cache')
|
||||
self.ctx.Commands.build_command(2, 'core', 'clear_cache', 'Clear the cache!')
|
||||
self.ctx.Commands.build_command(3, 'core', 'quit', 'Disconnect the bot or user from the server.')
|
||||
self.ctx.Commands.build_command(3, 'core', 'restart', 'Restart the bot or service.')
|
||||
self.ctx.Commands.build_command(3, 'core', 'addaccess', 'Add a user or entity to an access list with specific permissions.')
|
||||
self.ctx.Commands.build_command(3, 'core', 'editaccess', 'Modify permissions for an existing user or entity in the access list.')
|
||||
self.ctx.Commands.build_command(3, 'core', 'delaccess', 'Remove a user or entity from the access list.')
|
||||
self.ctx.Commands.build_command(3, 'core', 'cert', 'Append your new fingerprint to your account!')
|
||||
self.ctx.Commands.build_command(4, 'core', 'rehash', 'Reload the configuration file without restarting')
|
||||
self.ctx.Commands.build_command(4, 'core', 'raw', 'Send a raw command directly to the IRC server')
|
||||
self.ctx.Commands.build_command(4, 'core', 'print_vars', 'Print users in a file.')
|
||||
self.ctx.Commands.build_command(4, 'core', 'start_rpc', 'Start defender jsonrpc server')
|
||||
self.ctx.Commands.build_command(4, 'core', 'stop_rpc', 'Stop defender jsonrpc server')
|
||||
|
||||
self.build_command(0, 'core', 'help', 'This provide the help')
|
||||
self.build_command(0, 'core', 'auth', 'Login to the IRC Service')
|
||||
self.build_command(0, 'core', 'copyright', 'Give some information about the IRC Service')
|
||||
self.build_command(0, 'core', 'uptime', 'Give you since when the service is connected')
|
||||
self.build_command(0, 'core', 'firstauth', 'First authentication of the Service')
|
||||
self.build_command(0, 'core', 'register', f'Register your nickname /msg {self.ctx.Config.SERVICE_NICKNAME} REGISTER <password> <email>')
|
||||
self.build_command(0, 'core', 'identify', f'Identify yourself with your password /msg {self.ctx.Config.SERVICE_NICKNAME} IDENTIFY <account> <password>')
|
||||
self.build_command(0, 'core', 'logout', 'Reverse the effect of the identify command')
|
||||
self.build_command(1, 'core', 'load', 'Load an existing module')
|
||||
self.build_command(1, 'core', 'unload', 'Unload a module')
|
||||
self.build_command(1, 'core', 'reload', 'Reload a module')
|
||||
self.build_command(1, 'core', 'deauth', 'Deauth from the irc service')
|
||||
self.build_command(1, 'core', 'checkversion', 'Check the version of the irc service')
|
||||
self.build_command(2, 'core', 'show_modules', 'Display a list of loaded modules')
|
||||
self.build_command(2, 'core', 'show_timers', 'Display active timers')
|
||||
self.build_command(2, 'core', 'show_threads', 'Display active threads in the system')
|
||||
self.build_command(2, 'core', 'show_asyncio', 'Display active asyncio')
|
||||
self.build_command(2, 'core', 'show_channels', 'Display a list of active channels')
|
||||
self.build_command(2, 'core', 'show_users', 'Display a list of connected users')
|
||||
self.build_command(2, 'core', 'show_clients', 'Display a list of connected clients')
|
||||
self.build_command(2, 'core', 'show_admins', 'Display a list of administrators')
|
||||
self.build_command(2, 'core', 'show_configuration', 'Display the current configuration settings')
|
||||
self.build_command(2, 'core', 'show_cache', 'Display the current cache')
|
||||
self.build_command(2, 'core', 'clear_cache', 'Clear the cache!')
|
||||
self.build_command(3, 'core', 'quit', 'Disconnect the bot or user from the server.')
|
||||
self.build_command(3, 'core', 'restart', 'Restart the bot or service.')
|
||||
self.build_command(3, 'core', 'addaccess', 'Add a user or entity to an access list with specific permissions.')
|
||||
self.build_command(3, 'core', 'editaccess', 'Modify permissions for an existing user or entity in the access list.')
|
||||
self.build_command(3, 'core', 'delaccess', 'Remove a user or entity from the access list.')
|
||||
self.build_command(3, 'core', 'cert', 'Append your new fingerprint to your account!')
|
||||
self.build_command(4, 'core', 'rehash', 'Reload the configuration file without restarting')
|
||||
self.build_command(4, 'core', 'raw', 'Send a raw command directly to the IRC server')
|
||||
self.build_command(4, 'core', 'print_vars', 'Print users in a file.')
|
||||
self.build_command(4, 'core', 'start_rpc', 'Start defender jsonrpc server')
|
||||
self.build_command(4, 'core', 'stop_rpc', 'Stop defender jsonrpc server')
|
||||
##############################################
|
||||
# CONNEXION IRC #
|
||||
##############################################
|
||||
|
||||
# Define the IrcSocket object
|
||||
self.IrcSocket: Optional[Union[socket.socket, SSLSocket]] = None
|
||||
|
||||
self.reader: Optional[asyncio.StreamReader] = None
|
||||
self.writer: Optional[asyncio.StreamWriter] = None
|
||||
|
||||
self.ctx.Base.create_asynctask(self.heartbeat(self.beat))
|
||||
async def run(self):
|
||||
try:
|
||||
await self.connect()
|
||||
await self.listen()
|
||||
except asyncio.exceptions.IncompleteReadError as ie:
|
||||
# When IRCd server is down
|
||||
# asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of undefined expected bytes
|
||||
self.ctx.Logs.critical(f"The IRCd server is no more connected! {ie}")
|
||||
except asyncio.exceptions.CancelledError as cerr:
|
||||
self.ctx.Logs.debug(f"Asyncio CancelledError reached! {cerr}")
|
||||
|
||||
async def connect(self):
|
||||
|
||||
@@ -116,24 +125,36 @@ class Irc:
|
||||
await self.Protocol.send_link()
|
||||
|
||||
async def listen(self):
|
||||
self.ctx.Base.create_asynctask(
|
||||
self.ctx.Base.create_thread_io(
|
||||
self.ctx.Utils.heartbeat,
|
||||
self.ctx, self.beat,
|
||||
run_once=True, thread_flag=True
|
||||
)
|
||||
)
|
||||
|
||||
while self.signal:
|
||||
data = await self.reader.readuntil(b'\r\n')
|
||||
await self.send_response(data.splitlines())
|
||||
|
||||
async def run(self):
|
||||
async def send_response(self, responses:list[bytes]) -> None:
|
||||
try:
|
||||
await self.connect()
|
||||
await self.listen()
|
||||
except asyncio.exceptions.IncompleteReadError as ie:
|
||||
# When IRCd server is down
|
||||
# asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of undefined expected bytes
|
||||
self.ctx.Logs.critical(f"The IRCd server is no more connected! {ie}")
|
||||
except asyncio.exceptions.CancelledError as cerr:
|
||||
self.ctx.Logs.debug(f"Asyncio CancelledError reached! {cerr}")
|
||||
for data in responses:
|
||||
response = data.decode(self.CHARSET[0]).split()
|
||||
await self.cmd(response)
|
||||
|
||||
##############################################
|
||||
# CONNEXION IRC #
|
||||
##############################################
|
||||
except (UnicodeEncodeError, UnicodeDecodeError) as ue:
|
||||
for data in responses:
|
||||
response = data.decode(self.CHARSET[1], 'replace').split()
|
||||
await self.cmd(response)
|
||||
self.ctx.Logs.error(f'UnicodeEncodeError: {ue}')
|
||||
self.ctx.Logs.error(responses)
|
||||
except AssertionError as ae:
|
||||
self.ctx.Logs.error(f"Assertion error : {ae}")
|
||||
|
||||
# --------------------------------------------
|
||||
# FIN CONNEXION IRC #
|
||||
# --------------------------------------------
|
||||
|
||||
def init_service_user(self) -> None:
|
||||
|
||||
@@ -157,51 +178,6 @@ class Irc:
|
||||
chan = chan_name[0]
|
||||
await self.Protocol.send_sjoin(channel=chan)
|
||||
|
||||
async def send_response(self, responses:list[bytes]) -> None:
|
||||
try:
|
||||
for data in responses:
|
||||
response = data.decode(self.CHARSET[0]).split()
|
||||
await self.cmd(response)
|
||||
|
||||
except UnicodeEncodeError as ue:
|
||||
for data in responses:
|
||||
response = data.decode(self.CHARSET[1],'replace').split()
|
||||
await self.cmd(response)
|
||||
self.ctx.Logs.error(f'UnicodeEncodeError: {ue}')
|
||||
self.ctx.Logs.error(response)
|
||||
|
||||
except UnicodeDecodeError as ud:
|
||||
for data in responses:
|
||||
response = data.decode(self.CHARSET[1],'replace').split()
|
||||
await self.cmd(response)
|
||||
self.ctx.Logs.error(f'UnicodeDecodeError: {ud}')
|
||||
self.ctx.Logs.error(response)
|
||||
|
||||
except AssertionError as ae:
|
||||
self.ctx.Logs.error(f"Assertion error : {ae}")
|
||||
|
||||
def unload(self) -> None:
|
||||
# This is only to reference the method
|
||||
return None
|
||||
|
||||
# --------------------------------------------
|
||||
# FIN CONNEXION IRC #
|
||||
# --------------------------------------------
|
||||
|
||||
def build_command(self, level: int, module_name: str, command_name: str, command_description: str) -> None:
|
||||
"""This method build the commands variable
|
||||
|
||||
Args:
|
||||
level (int): The Level of the command
|
||||
module_name (str): The module name
|
||||
command_name (str): The command name
|
||||
command_description (str): The description of the command
|
||||
"""
|
||||
# Build Model.
|
||||
self.ctx.Commands.build(self.ctx.Definition.MCommand(module_name, command_name, command_description, level))
|
||||
|
||||
return None
|
||||
|
||||
async def generate_help_menu(self, nickname: str, module: Optional[str] = None) -> None:
|
||||
|
||||
# Check if the nickname is an admin
|
||||
@@ -289,17 +265,6 @@ class Irc:
|
||||
|
||||
return uptime
|
||||
|
||||
async def heartbeat(self, beat: float) -> None:
|
||||
"""Execute certaines commandes de nettoyage toutes les x secondes
|
||||
x étant définit a l'initialisation de cette class (self.beat)
|
||||
|
||||
Args:
|
||||
beat (float): Nombre de secondes entre chaque exécution
|
||||
"""
|
||||
while self.hb_active:
|
||||
await asyncio.sleep(beat)
|
||||
self.ctx.Base.execute_periodic_action()
|
||||
|
||||
def insert_db_admin(self, uid: str, account: str, level: int, language: str) -> None:
|
||||
user_obj = self.ctx.User.get_user(uid)
|
||||
|
||||
@@ -382,8 +347,13 @@ class Irc:
|
||||
|
||||
async def thread_check_for_new_version(self, fromuser: str) -> None:
|
||||
dnickname = self.ctx.Config.SERVICE_NICKNAME
|
||||
response = self.ctx.Base.create_asynctask(
|
||||
self.ctx.Base.create_thread_io(
|
||||
self.ctx.Base.check_for_new_version, True
|
||||
)
|
||||
)
|
||||
|
||||
if self.ctx.Base.check_for_new_version(True):
|
||||
if response:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" New Version available : {self.ctx.Config.CURRENT_VERSION} >>> {self.ctx.Config.LATEST_VERSION}")
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" Please run (git pull origin main) in the current folder")
|
||||
else:
|
||||
@@ -413,12 +383,6 @@ class Irc:
|
||||
for module in modules:
|
||||
await module.class_instance.cmd(original_response) if self.ctx.Utils.is_coroutinefunction(module.class_instance.cmd) else module.class_instance.cmd(original_response)
|
||||
|
||||
# if len(original_response) > 2:
|
||||
# if original_response[2] != 'UID':
|
||||
# # Envoyer la commande aux classes dynamiquement chargées
|
||||
# for module in self.ctx.ModuleUtils.model_get_loaded_modules().copy():
|
||||
# module.class_instance.cmd(original_response)
|
||||
|
||||
except IndexError as ie:
|
||||
self.ctx.Logs.error(f"IndexError: {ie}")
|
||||
except Exception as err:
|
||||
@@ -441,7 +405,7 @@ class Irc:
|
||||
if u is None:
|
||||
return None
|
||||
|
||||
c = self.ctx.Client.get_Client(u.uid)
|
||||
c = self.ctx.Client.get_client(u.uid)
|
||||
"""The Client Object"""
|
||||
|
||||
fromuser = u.nickname
|
||||
@@ -627,7 +591,7 @@ class Irc:
|
||||
level = self.ctx.Base.int_if_possible(cmd[2])
|
||||
password = str(cmd[3])
|
||||
|
||||
self.create_defender_user(fromuser, new_admin, level, password)
|
||||
await self.create_defender_user(fromuser, new_admin, level, password)
|
||||
return None
|
||||
|
||||
except IndexError as ie:
|
||||
@@ -982,11 +946,10 @@ class Irc:
|
||||
try:
|
||||
final_reason = ' '.join(cmd[1:])
|
||||
self.hb_active = False
|
||||
await self.ctx.Base.shutdown()
|
||||
await rehash.shutdown(self.ctx)
|
||||
self.ctx.Base.execute_periodic_action()
|
||||
|
||||
for chan_name in self.ctx.Channel.UID_CHANNEL_DB:
|
||||
# self.Protocol.send_mode_chan(chan_name.name, '-l')
|
||||
await self.Protocol.send_set_mode('-l', channel_name=chan_name.name)
|
||||
|
||||
for client in self.ctx.Client.CLIENT_DB:
|
||||
@@ -1002,7 +965,6 @@ class Irc:
|
||||
self.ctx.Logs.info(f'Arrêt du server {dnickname}')
|
||||
self.ctx.Config.DEFENDER_RESTART = 0
|
||||
|
||||
await self.writer.drain()
|
||||
self.writer.close()
|
||||
await self.writer.wait_closed()
|
||||
|
||||
@@ -1011,6 +973,8 @@ class Irc:
|
||||
except ConnectionResetError:
|
||||
if self.writer.is_closing():
|
||||
self.ctx.Logs.debug(f"Defender stopped properly!")
|
||||
except ssl.SSLError as serr:
|
||||
self.ctx.Logs.error(f"Defender has ended with an SSL Error! - {serr}")
|
||||
|
||||
case 'restart':
|
||||
final_reason = ' '.join(cmd[1:])
|
||||
@@ -1080,6 +1044,13 @@ class Irc:
|
||||
msg=f">> {thread.name} ({thread.is_alive()})"
|
||||
)
|
||||
|
||||
for thread in threading.enumerate():
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f">> Thread name: {thread.name} - Is alive: {thread.is_alive()} - Daemon: {thread.daemon}"
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
case 'show_asyncio':
|
||||
@@ -1209,10 +1180,10 @@ class Irc:
|
||||
return None
|
||||
|
||||
case 'start_rpc':
|
||||
self.ctx.Base.create_asynctask(self.ctx.RpcServer.start_server())
|
||||
self.ctx.Base.create_asynctask(self.ctx.RpcServer.start_rpc_server())
|
||||
|
||||
case 'stop_rpc':
|
||||
self.ctx.Base.create_asynctask(self.ctx.RpcServer.stop_server())
|
||||
self.ctx.Base.create_asynctask(self.ctx.RpcServer.stop_rpc_server())
|
||||
|
||||
case _:
|
||||
pass
|
||||
|
||||
@@ -81,7 +81,7 @@ class Loader:
|
||||
|
||||
self.PFactory: factory.ProtocolFactorty = factory.ProtocolFactorty(self)
|
||||
|
||||
self.RpcServer: rpc_mod.JSonRpcServer = rpc_mod.JSonRpcServer(self, hostname='0.0.0.0')
|
||||
self.RpcServer: rpc_mod.JSonRpcServer = rpc_mod.JSonRpcServer(self)
|
||||
|
||||
self.Logs.debug(self.Utils.tr("Loader %s success", __name__))
|
||||
|
||||
|
||||
@@ -3,20 +3,20 @@ Main utils library.
|
||||
"""
|
||||
import gc
|
||||
import ssl
|
||||
import socket
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from re import match, sub
|
||||
import threading
|
||||
from typing import Literal, Optional, Any, TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
from time import time, sleep
|
||||
from random import choice
|
||||
from hashlib import md5, sha3_512
|
||||
from core.classes.modules.settings import global_settings
|
||||
from asyncio import iscoroutinefunction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.irc import Irc
|
||||
from threading import Event
|
||||
from core.loader import Loader
|
||||
|
||||
def tr(message: str, *args) -> str:
|
||||
"""Translation Engine system
|
||||
@@ -115,39 +115,6 @@ def get_ssl_context() -> ssl.SSLContext:
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
return ctx
|
||||
|
||||
def create_socket(uplink: 'Irc') -> None:
|
||||
"""Create a socket to connect SSL or Normal connection
|
||||
"""
|
||||
try:
|
||||
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
|
||||
connexion_information = (uplink.Config.SERVEUR_IP, uplink.Config.SERVEUR_PORT)
|
||||
|
||||
if uplink.Config.SERVEUR_SSL:
|
||||
# Create SSL Context object
|
||||
ssl_context = get_ssl_context()
|
||||
ssl_connexion = ssl_context.wrap_socket(soc, server_hostname=uplink.Config.SERVEUR_HOSTNAME)
|
||||
ssl_connexion.connect(connexion_information)
|
||||
uplink.IrcSocket = ssl_connexion
|
||||
uplink.Config.SSL_VERSION = uplink.IrcSocket.version()
|
||||
uplink.Logs.info(f"-- Connected using SSL : Version = {uplink.Config.SSL_VERSION}")
|
||||
else:
|
||||
soc.connect(connexion_information)
|
||||
uplink.IrcSocket = soc
|
||||
uplink.Logs.info("-- Connected in a normal mode!")
|
||||
|
||||
return None
|
||||
|
||||
except (ssl.SSLEOFError, ssl.SSLError) as soe:
|
||||
uplink.Logs.critical(f"[SSL ERROR]: {soe}")
|
||||
except OSError as oe:
|
||||
uplink.Logs.critical(f"[OS Error]: {oe}")
|
||||
if 'connection refused' in str(oe).lower():
|
||||
sys.exit(oe.__str__())
|
||||
if oe.errno == 10053:
|
||||
sys.exit(oe.__str__())
|
||||
except AttributeError as ae:
|
||||
uplink.Logs.critical(f"AttributeError: {ae}")
|
||||
|
||||
def run_python_garbage_collector() -> int:
|
||||
"""Run Python garbage collector
|
||||
|
||||
@@ -167,6 +134,21 @@ def get_number_gc_objects(your_object_to_count: Optional[Any] = None) -> int:
|
||||
|
||||
return sum(1 for obj in gc.get_objects() if isinstance(obj, your_object_to_count))
|
||||
|
||||
def heartbeat(event: 'Event', loader: 'Loader', beat: float) -> None:
|
||||
"""Execute certaines commandes de nettoyage toutes les x secondes
|
||||
x étant définit a l'initialisation de cette class (self.beat)
|
||||
|
||||
Args:
|
||||
beat (float): Nombre de secondes entre chaque exécution
|
||||
"""
|
||||
|
||||
while event.is_set():
|
||||
loader.Base.execute_periodic_action()
|
||||
sleep(beat)
|
||||
|
||||
loader.Logs.debug("Heartbeat is off!")
|
||||
return None
|
||||
|
||||
def generate_random_string(lenght: int) -> str:
|
||||
"""Retourn une chaîne aléatoire en fonction de la longueur spécifiée.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import asyncio
|
||||
from core import install
|
||||
|
||||
#############################################
|
||||
# @Version : 6.4 #
|
||||
# Requierements : #
|
||||
@@ -19,4 +18,4 @@ async def main():
|
||||
await loader.Irc.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
asyncio.run(main(), debug=False)
|
||||
|
||||
@@ -73,7 +73,7 @@ class Clone(IModule):
|
||||
self.ctx.Logs.debug(f"Cache Size = {self.ctx.Settings.get_cache_size()}")
|
||||
|
||||
# Créer les nouvelles commandes du module
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
||||
|
||||
await self.ctx.Channel.db_query_channel(action='add', module_name=self.module_name, channel_name=self.ctx.Config.CLONE_CHANNEL)
|
||||
await self.ctx.Irc.Protocol.send_sjoin(self.ctx.Config.CLONE_CHANNEL)
|
||||
|
||||
@@ -65,56 +65,56 @@ class Command(IModule):
|
||||
for c in new_cmds:
|
||||
self.ctx.Irc.Protocol.known_protocol.add(c)
|
||||
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'join', 'Join a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'part', 'Leave a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'unassign', 'Remove a user from a role or task')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'owner', 'Give channel ownership to a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'deowner', 'Remove channel ownership from a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'protect', 'Protect a user from being kicked')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'deprotect', 'Remove protection from a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'op', 'Grant operator privileges to a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'deop', 'Remove operator privileges from a user')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'halfop', 'Grant half-operator privileges to a user')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'dehalfop', 'Remove half-operator privileges from a user')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'voice', 'Grant voice privileges to a user')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'devoice', 'Remove voice privileges from a user')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'topic', 'Change the topic of a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'opall', 'Grant operator privileges to all users')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'deopall', 'Remove operator privileges from all users')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'devoiceall', 'Remove voice privileges from all users')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'voiceall', 'Grant voice privileges to all users')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'ban', 'Ban a user from a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'automode', 'Automatically set user modes upon join')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'unban', 'Remove a ban from a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'kick', 'Kick a user from a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'kickban', 'Kick and ban a user from a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'umode', 'Set user mode')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'mode', 'Set channel mode')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'get_mode', 'Retrieve current channel mode')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'svsjoin', 'Force a user to join a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'svspart', 'Force a user to leave a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'svsnick', 'Force a user to change their nickname')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'wallops', 'Send a message to all operators')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'globops', 'Send a global operator message')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'gnotice', 'Send a global notice')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'whois', 'Get information about a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'names', 'List users in a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'invite', 'Invite a user to a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'inviteme', 'Invite yourself to a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'sajoin', 'Force yourself into a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'sapart', 'Force yourself to leave a channel')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'kill', 'Disconnect a user from the server')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'gline', 'Ban a user from the entire server')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'ungline', 'Remove a global server ban')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'kline', 'Ban a user based on their hostname')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'unkline', 'Remove a K-line ban')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'shun', 'Prevent a user from sending messages')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'unshun', 'Remove a shun from a user')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'glinelist', 'List all global bans')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'shunlist', 'List all shunned users')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'klinelist', 'List all K-line bans')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'map', 'Show the server network map')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'join', 'Join a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'assign', 'Assign a user to a role or task')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'part', 'Leave a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'unassign', 'Remove a user from a role or task')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'owner', 'Give channel ownership to a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'deowner', 'Remove channel ownership from a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'protect', 'Protect a user from being kicked')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'deprotect', 'Remove protection from a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'op', 'Grant operator privileges to a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'deop', 'Remove operator privileges from a user')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'halfop', 'Grant half-operator privileges to a user')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'dehalfop', 'Remove half-operator privileges from a user')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'voice', 'Grant voice privileges to a user')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'devoice', 'Remove voice privileges from a user')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'topic', 'Change the topic of a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'opall', 'Grant operator privileges to all users')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'deopall', 'Remove operator privileges from all users')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'devoiceall', 'Remove voice privileges from all users')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'voiceall', 'Grant voice privileges to all users')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'ban', 'Ban a user from a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'automode', 'Automatically set user modes upon join')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'unban', 'Remove a ban from a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'kick', 'Kick a user from a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'kickban', 'Kick and ban a user from a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'umode', 'Set user mode')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'mode', 'Set channel mode')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'get_mode', 'Retrieve current channel mode')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'svsjoin', 'Force a user to join a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'svspart', 'Force a user to leave a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'svsnick', 'Force a user to change their nickname')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'wallops', 'Send a message to all operators')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'globops', 'Send a global operator message')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'gnotice', 'Send a global notice')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'whois', 'Get information about a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'names', 'List users in a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'invite', 'Invite a user to a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'inviteme', 'Invite yourself to a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'sajoin', 'Force yourself into a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'sapart', 'Force yourself to leave a channel')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'kill', 'Disconnect a user from the server')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'gline', 'Ban a user from the entire server')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'ungline', 'Remove a global server ban')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'kline', 'Ban a user based on their hostname')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'unkline', 'Remove a K-line ban')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'shun', 'Prevent a user from sending messages')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'unshun', 'Remove a shun from a user')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'glinelist', 'List all global bans')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'shunlist', 'List all shunned users')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'klinelist', 'List all K-line bans')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'map', 'Show the server network map')
|
||||
|
||||
def unload(self) -> None:
|
||||
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||
@@ -214,7 +214,7 @@ class Command(IModule):
|
||||
user_uid = self.ctx.User.clean_uid(cmd[5])
|
||||
userObj: MUser = self.ctx.User.get_user(user_uid)
|
||||
channel_name = cmd[4] if self.ctx.Channel.is_valid_channel(cmd[4]) else None
|
||||
client_obj = self.ctx.Client.get_Client(user_uid)
|
||||
client_obj = self.ctx.Client.get_client(user_uid)
|
||||
nickname = userObj.nickname if userObj is not None else None
|
||||
|
||||
if client_obj is not None:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Any, TYPE_CHECKING, Optional
|
||||
from core.classes.interfaces.imodule import IModule
|
||||
import mods.defender.schemas as schemas
|
||||
@@ -26,6 +27,8 @@ class Defender(IModule):
|
||||
def __init__(self, context: 'Loader') -> None:
|
||||
super().__init__(context)
|
||||
self._mod_config: Optional[schemas.ModConfModel] = None
|
||||
self.Schemas = schemas.RepDB()
|
||||
self.Threads = thds
|
||||
|
||||
@property
|
||||
def mod_config(self) -> ModConfModel:
|
||||
@@ -55,40 +58,43 @@ class Defender(IModule):
|
||||
return None
|
||||
|
||||
async def load(self):
|
||||
|
||||
# Variable qui va contenir les options de configuration du module Defender
|
||||
self._mod_config: schemas.ModConfModel = self.ModConfModel()
|
||||
|
||||
# sync the database with local variable (Mandatory)
|
||||
await self.sync_db()
|
||||
|
||||
# Add module schemas
|
||||
self.Schemas = schemas
|
||||
|
||||
# Add module utils functions
|
||||
self.mod_utils = utils
|
||||
|
||||
# Create module commands (Mandatory)
|
||||
self.ctx.Irc.build_command(0, self.module_name, 'code', 'Display the code or key for access')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'info', 'Provide information about the channel or server')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'autolimit', 'Automatically set channel user limits')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'reputation', 'Check or manage user reputation')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'proxy_scan', 'Scan users for proxy connections')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'flood', 'Handle flood detection and mitigation')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'status', 'Check the status of the server or bot')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'show_reputation', 'Display reputation information')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'sentinel', 'Monitor and guard the channel or server')
|
||||
self.ctx.Commands.build_command(0, self.module_name, 'code', 'Display the code or key for access')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'info', 'Provide information about the channel or server')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'autolimit', 'Automatically set channel user limits')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'reputation', 'Check or manage user reputation')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'proxy_scan', 'Scan users for proxy connections')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'flood', 'Handle flood detection and mitigation')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'status', 'Check the status of the server or bot')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'show_reputation', 'Display reputation information')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'sentinel', 'Monitor and guard the channel or server')
|
||||
|
||||
self.timeout = self.ctx.Config.API_TIMEOUT
|
||||
|
||||
# Listes qui vont contenir les ip a scanner avec les différentes API
|
||||
self.Schemas.DB_ABUSEIPDB_USERS = self.Schemas.DB_FREEIPAPI_USERS = self.Schemas.DB_CLOUDFILT_USERS = []
|
||||
self.Schemas.DB_PSUTIL_USERS = self.Schemas.DB_LOCALSCAN_USERS = []
|
||||
self.Schemas.DB_ABUSEIPDB_USERS = []
|
||||
self.Schemas.DB_FREEIPAPI_USERS = []
|
||||
self.Schemas.DB_CLOUDFILT_USERS = []
|
||||
self.Schemas.DB_PSUTIL_USERS = []
|
||||
self.Schemas.DB_LOCALSCAN_USERS = []
|
||||
|
||||
# Variables qui indique que les threads sont en cours d'éxecutions
|
||||
self.abuseipdb_isRunning = self.freeipapi_isRunning = self.cloudfilt_isRunning = True
|
||||
self.psutil_isRunning = self.localscan_isRunning = self.reputationTimer_isRunning = True
|
||||
self.autolimit_isRunning = True
|
||||
self.abuseipdb_isRunning = True if self.mod_config.abuseipdb_scan == 1 else False
|
||||
self.freeipapi_isRunning = True if self.mod_config.freeipapi_scan == 1 else False
|
||||
self.cloudfilt_isRunning = True if self.mod_config.cloudfilt_scan == 1 else False
|
||||
self.psutil_isRunning = True if self.mod_config.psutil_scan == 1 else False
|
||||
self.localscan_isRunning = True if self.mod_config.local_scan == 1 else False
|
||||
self.reputationTimer_isRunning = True if self.mod_config.reputation == 1 else False
|
||||
self.autolimit_isRunning = True if self.mod_config.autolimit == 1 else False
|
||||
|
||||
# Variable qui va contenir les users
|
||||
self.flood_system = {}
|
||||
@@ -101,19 +107,21 @@ class Defender(IModule):
|
||||
self.cloudfilt_key = 'r1gEtjtfgRQjtNBDMxsg'
|
||||
|
||||
# Démarrer les threads pour démarrer les api
|
||||
self.ctx.Base.create_asynctask(thds.coro_freeipapi_scan(self))
|
||||
self.ctx.Base.create_asynctask(thds.coro_cloudfilt_scan(self))
|
||||
self.ctx.Base.create_asynctask(thds.coro_abuseipdb_scan(self))
|
||||
self.ctx.Base.create_asynctask(thds.coro_local_scan(self))
|
||||
self.ctx.Base.create_asynctask(thds.coro_psutil_scan(self))
|
||||
self.ctx.Base.create_asynctask(thds.coro_apply_reputation_sanctions(self))
|
||||
|
||||
if self.mod_config.autolimit == 1:
|
||||
self.ctx.Base.create_asynctask(thds.coro_autolimit(self))
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_freeipapi_scan(self)) if self.mod_config.freeipapi_scan == 1 else None
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_cloudfilt_scan(self)) if self.mod_config.cloudfilt_scan == 1 else None
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_abuseipdb_scan(self)) if self.mod_config.abuseipdb_scan == 1 else None
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_local_scan(self)) if self.mod_config.local_scan == 1 else None
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_psutil_scan(self)) if self.mod_config.psutil_scan == 1 else None
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_apply_reputation_sanctions(self)) if self.mod_config.reputation == 1 else None
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_autolimit(self)) if self.mod_config.autolimit == 1 else None
|
||||
|
||||
if self.mod_config.reputation == 1:
|
||||
await self.ctx.Irc.Protocol.send_sjoin(self.ctx.Config.SALON_JAIL)
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{self.ctx.Config.SERVICE_NICKNAME} SAMODE {self.ctx.Config.SALON_JAIL} +o {self.ctx.Config.SERVICE_NICKNAME}")
|
||||
for chan in self.ctx.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != self.ctx.Config.SALON_JAIL:
|
||||
await self.ctx.Irc.Protocol.send_set_mode('+b', channel_name=chan.name, params='~security-group:unknown-users')
|
||||
await self.ctx.Irc.Protocol.send_set_mode('+eee', channel_name=chan.name, params='~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users')
|
||||
|
||||
def __onload(self):
|
||||
|
||||
@@ -138,7 +146,7 @@ class Defender(IModule):
|
||||
if localscan:
|
||||
self.Schemas.DB_LOCALSCAN_USERS = localscan
|
||||
|
||||
def unload(self) -> None:
|
||||
async def unload(self) -> None:
|
||||
"""Cette methode sera executée a chaque désactivation ou
|
||||
rechargement de module
|
||||
"""
|
||||
@@ -158,6 +166,13 @@ class Defender(IModule):
|
||||
|
||||
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||
|
||||
if self.mod_config.reputation == 1:
|
||||
await self.ctx.Irc.Protocol.send_part_chan(self.ctx.Config.SERVICE_ID, self.ctx.Config.SALON_JAIL)
|
||||
for chan in self.ctx.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != self.ctx.Config.SALON_JAIL:
|
||||
await self.ctx.Irc.Protocol.send_set_mode('-b', channel_name=chan.name, params='~security-group:unknown-users')
|
||||
await self.ctx.Irc.Protocol.send_set_mode('-eee', channel_name=chan.name, params='~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users')
|
||||
|
||||
return None
|
||||
|
||||
async def insert_db_trusted(self, uid: str, nickname:str) -> None:
|
||||
@@ -411,22 +426,26 @@ class Defender(IModule):
|
||||
|
||||
if self.mod_config.reputation == 1:
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION{self.ctx.Config.COLORS.black} ] : Already activated", channel=dchanlog)
|
||||
return False
|
||||
return None
|
||||
|
||||
# self.update_db_configuration('reputation', 1)
|
||||
await self.update_configuration(key, 1)
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_apply_reputation_sanctions(self))
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {self.ctx.Config.COLORS.green}REPUTATION{self.ctx.Config.COLORS.black} ] : Activated by {fromuser}", channel=dchanlog)
|
||||
|
||||
await self.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname, channel=jail_chan)
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} +{dumodes} {dnickname}")
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {jail_chan} +{jail_chan_mode}")
|
||||
await self.ctx.Irc.Protocol.send_set_mode(f'+{jail_chan_mode}', channel_name=jail_chan)
|
||||
|
||||
if self.mod_config.reputation_sg == 1:
|
||||
for chan in self.ctx.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != jail_chan:
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users")
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
||||
await self.ctx.Irc.Protocol.send_set_mode('+b', channel_name=chan.name, params='~security-group:unknown-users')
|
||||
await self.ctx.Irc.Protocol.send_set_mode(
|
||||
'+eee',
|
||||
channel_name=chan.name,
|
||||
params='~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users'
|
||||
)
|
||||
|
||||
await self.ctx.Channel.db_query_channel('add', self.module_name, jail_chan)
|
||||
|
||||
@@ -441,20 +460,26 @@ class Defender(IModule):
|
||||
return False
|
||||
|
||||
await self.update_configuration(key, 0)
|
||||
self.reputationTimer_isRunning = False
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"[ {self.ctx.Config.COLORS.red}REPUTATION{self.ctx.Config.COLORS.black} ] : Deactivated by {fromuser}",
|
||||
channel=dchanlog
|
||||
)
|
||||
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} SAMODE {jail_chan} -{dumodes} {dnickname}")
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {jail_chan} -sS")
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} PART {jail_chan}")
|
||||
await self.ctx.Irc.Protocol.send_set_mode('-sS', channel_name=jail_chan)
|
||||
await self.ctx.Irc.Protocol.send_part_chan(service_id, jail_chan)
|
||||
|
||||
for chan in self.ctx.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != jail_chan:
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} -b ~security-group:unknown-users")
|
||||
await self.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {chan.name} -eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users")
|
||||
await self.ctx.Irc.Protocol.send_set_mode('-b', channel_name=chan.name, params='~security-group:unknown-users')
|
||||
await self.ctx.Irc.Protocol.send_set_mode(
|
||||
'-eee',
|
||||
channel_name=chan.name,
|
||||
params='~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users'
|
||||
)
|
||||
|
||||
await self.ctx.Channel.db_query_channel('del', self.module_name, jail_chan)
|
||||
|
||||
@@ -464,12 +489,17 @@ class Defender(IModule):
|
||||
match get_options:
|
||||
case 'release':
|
||||
# .reputation release [nick]
|
||||
p = await self.ctx.Irc.Protocol
|
||||
link = self.ctx.Config.SERVEUR_LINK
|
||||
jailed_salon = self.ctx.Config.SALON_JAIL
|
||||
welcome_salon = self.ctx.Config.SALON_LIBERER
|
||||
client_obj = self.ctx.User.get_user(str(cmd[2]))
|
||||
|
||||
if self.mod_config.reputation != 1:
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg="The reputation system is not activated!")
|
||||
return None
|
||||
|
||||
if client_obj is None:
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
@@ -658,6 +688,7 @@ class Defender(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog)
|
||||
return None
|
||||
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_local_scan(self))
|
||||
await self.update_configuration(option, 1)
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog)
|
||||
@@ -667,6 +698,7 @@ class Defender(IModule):
|
||||
return None
|
||||
|
||||
await self.update_configuration(option, 0)
|
||||
self.localscan_isRunning = False
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog)
|
||||
|
||||
@@ -676,6 +708,7 @@ class Defender(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog)
|
||||
return None
|
||||
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_psutil_scan(self))
|
||||
await self.update_configuration(option, 1)
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog)
|
||||
@@ -685,6 +718,7 @@ class Defender(IModule):
|
||||
return None
|
||||
|
||||
await self.update_configuration(option, 0)
|
||||
self.psutil_isRunning = False
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog)
|
||||
|
||||
@@ -694,6 +728,7 @@ class Defender(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog)
|
||||
return None
|
||||
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_abuseipdb_scan(self))
|
||||
await self.update_configuration(option, 1)
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog)
|
||||
@@ -703,6 +738,7 @@ class Defender(IModule):
|
||||
return None
|
||||
|
||||
await self.update_configuration(option, 0)
|
||||
self.abuseipdb_isRunning = False
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog)
|
||||
|
||||
@@ -712,6 +748,7 @@ class Defender(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog)
|
||||
return None
|
||||
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_freeipapi_scan(self))
|
||||
await self.update_configuration(option, 1)
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog)
|
||||
@@ -721,6 +758,7 @@ class Defender(IModule):
|
||||
return None
|
||||
|
||||
await self.update_configuration(option, 0)
|
||||
self.freeipapi_isRunning = False
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog)
|
||||
|
||||
@@ -730,6 +768,7 @@ class Defender(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Already activated", channel=dchanlog)
|
||||
return None
|
||||
|
||||
self.ctx.Base.create_asynctask(self.Threads.coro_cloudfilt_scan(self))
|
||||
await self.update_configuration(option, 1)
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_green}PROXY_SCAN {option.upper()}{color_black} ] : Activated by {fromuser}", channel=dchanlog)
|
||||
@@ -739,6 +778,7 @@ class Defender(IModule):
|
||||
return None
|
||||
|
||||
await self.update_configuration(option, 0)
|
||||
self.cloudfilt_isRunning = False
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"[ {color_red}PROXY_SCAN {option.upper()}{color_black} ] : Deactivated by {fromuser}", channel=dchanlog)
|
||||
|
||||
@@ -915,3 +955,6 @@ class Defender(IModule):
|
||||
await self.join_saved_channels()
|
||||
|
||||
return None
|
||||
|
||||
case _:
|
||||
pass
|
||||
@@ -28,9 +28,11 @@ class FloodUser(MainModel):
|
||||
nbr_msg: int = 0
|
||||
first_msg_time: int = 0
|
||||
|
||||
DB_FLOOD_USERS: list[FloodUser] = []
|
||||
DB_ABUSEIPDB_USERS: list[MUser] = []
|
||||
DB_FREEIPAPI_USERS: list[MUser] = []
|
||||
DB_CLOUDFILT_USERS: list[MUser] = []
|
||||
DB_PSUTIL_USERS: list[MUser] = []
|
||||
DB_LOCALSCAN_USERS: list[MUser] = []
|
||||
|
||||
class RepDB:
|
||||
DB_FLOOD_USERS: list[FloodUser] = []
|
||||
DB_ABUSEIPDB_USERS: list[MUser] = []
|
||||
DB_FREEIPAPI_USERS: list[MUser] = []
|
||||
DB_CLOUDFILT_USERS: list[MUser] = []
|
||||
DB_PSUTIL_USERS: list[MUser] = []
|
||||
DB_LOCALSCAN_USERS: list[MUser] = []
|
||||
@@ -1,89 +1,251 @@
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING
|
||||
from time import sleep
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mods.defender.mod_defender import Defender
|
||||
|
||||
async def coro_apply_reputation_sanctions(uplink: 'Defender'):
|
||||
uplink.reputationTimer_isRunning = True
|
||||
while uplink.reputationTimer_isRunning:
|
||||
await uplink.mod_utils.action_apply_reputation_santions(uplink)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
async def coro_cloudfilt_scan(uplink: 'Defender'):
|
||||
uplink.cloudfilt_isRunning = True
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
|
||||
while uplink.cloudfilt_isRunning:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_CLOUDFILT_USERS:
|
||||
await uplink.mod_utils.action_scan_client_with_cloudfilt(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
await asyncio.sleep(1)
|
||||
try:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_CLOUDFILT_USERS:
|
||||
if user.remote_ip not in uplink.ctx.Config.WHITELISTED_IP:
|
||||
result: Optional[dict] = await uplink.ctx.Base.create_thread_io(
|
||||
uplink.mod_utils.action_scan_client_with_cloudfilt,
|
||||
uplink, user
|
||||
)
|
||||
list_to_remove.append(user)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model)
|
||||
if not result:
|
||||
continue
|
||||
|
||||
await asyncio.sleep(1)
|
||||
remote_ip = user.remote_ip
|
||||
fullname = f'{user.nickname}!{user.username}@{user.hostname}'
|
||||
|
||||
r_host = result.get('host', None)
|
||||
r_countryiso = result.get('countryiso', None)
|
||||
r_listed = result.get('listed', False)
|
||||
r_listedby = result.get('listed_by', None)
|
||||
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {r_host} | country: {r_countryiso} | listed: {r_listed} | listed by : {r_listedby}",
|
||||
channel=service_chanlog)
|
||||
|
||||
uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({r_countryiso}), Listed: {r_listed}, by: {r_listedby}")
|
||||
|
||||
if r_listed:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} Your connexion is listed as dangerous {r_listed} {r_listedby} - detected by cloudfilt")
|
||||
uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({r_countryiso}) Listed: {r_listed}, by: {r_listedby}")
|
||||
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_CLOUDFILT_USERS.remove(user_model)
|
||||
|
||||
await asyncio.sleep(1.5)
|
||||
except ValueError as ve:
|
||||
uplink.ctx.Logs.debug(f"The value to remove is not in the list. {ve}")
|
||||
except TimeoutError as te:
|
||||
uplink.ctx.Logs.debug(f"Timeout Error {te}")
|
||||
|
||||
async def coro_freeipapi_scan(uplink: 'Defender'):
|
||||
uplink.freeipapi_isRunning = True
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
|
||||
while uplink.freeipapi_isRunning:
|
||||
try:
|
||||
list_to_remove: list = []
|
||||
for user in uplink.Schemas.DB_FREEIPAPI_USERS:
|
||||
if user.remote_ip not in uplink.ctx.Config.WHITELISTED_IP:
|
||||
result: Optional[dict] = await uplink.ctx.Base.create_thread_io(
|
||||
uplink.mod_utils.action_scan_client_with_freeipapi,
|
||||
uplink, user
|
||||
)
|
||||
|
||||
list_to_remove: list = []
|
||||
for user in uplink.Schemas.DB_FREEIPAPI_USERS:
|
||||
await uplink.mod_utils.action_scan_client_with_freeipapi(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
await asyncio.sleep(1)
|
||||
if not result:
|
||||
continue
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model)
|
||||
# pseudo!ident@host
|
||||
remote_ip = user.remote_ip
|
||||
fullname = f'{user.nickname}!{user.username}@{user.hostname}'
|
||||
|
||||
await asyncio.sleep(1)
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}",
|
||||
channel=service_chanlog)
|
||||
uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}")
|
||||
|
||||
if result['isProxy']:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
|
||||
uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}")
|
||||
|
||||
list_to_remove.append(user)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# remove users from the list
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_FREEIPAPI_USERS.remove(user_model)
|
||||
|
||||
await asyncio.sleep(1.5)
|
||||
except ValueError as ve:
|
||||
uplink.ctx.Logs.debug(f"The value to remove is not in the list. {ve}")
|
||||
except TimeoutError as te:
|
||||
uplink.ctx.Logs.debug(f"Timeout Error {te}")
|
||||
|
||||
async def coro_abuseipdb_scan(uplink: 'Defender'):
|
||||
|
||||
uplink.abuseipdb_isRunning = True
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
|
||||
while uplink.abuseipdb_isRunning:
|
||||
try:
|
||||
list_to_remove: list = []
|
||||
for user in uplink.Schemas.DB_ABUSEIPDB_USERS:
|
||||
if user.remote_ip not in uplink.ctx.Config.WHITELISTED_IP:
|
||||
|
||||
list_to_remove: list = []
|
||||
print(uplink.Schemas.DB_ABUSEIPDB_USERS)
|
||||
for user in uplink.Schemas.DB_ABUSEIPDB_USERS:
|
||||
await uplink.mod_utils.action_scan_client_with_abuseipdb(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
await asyncio.sleep(1)
|
||||
result: Optional[dict] = await uplink.ctx.Base.create_thread_io(
|
||||
uplink.mod_utils.action_scan_client_with_abuseipdb,
|
||||
uplink, user
|
||||
)
|
||||
list_to_remove.append(user)
|
||||
|
||||
print(list_to_remove)
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model)
|
||||
if not result:
|
||||
continue
|
||||
|
||||
await asyncio.sleep(1)
|
||||
remote_ip = user.remote_ip
|
||||
fullname = f'{user.nickname}!{user.username}@{user.hostname}'
|
||||
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}",
|
||||
channel=service_chanlog
|
||||
)
|
||||
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}")
|
||||
|
||||
if result['isTor']:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
|
||||
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}")
|
||||
elif result['score'] >= 95:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
|
||||
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}")
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_ABUSEIPDB_USERS.remove(user_model)
|
||||
|
||||
await asyncio.sleep(1.5)
|
||||
except ValueError as ve:
|
||||
uplink.ctx.Logs.debug(f"The value to remove is not in the list. {ve}", exc_info=True)
|
||||
except TimeoutError as te:
|
||||
uplink.ctx.Logs.debug(f"Timeout Error {te}", exc_info=True)
|
||||
|
||||
async def coro_local_scan(uplink: 'Defender'):
|
||||
uplink.localscan_isRunning = True
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
|
||||
while uplink.localscan_isRunning:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_LOCALSCAN_USERS:
|
||||
await uplink.mod_utils.action_scan_client_with_local_socket(uplink, user)
|
||||
list_to_remove.append(user)
|
||||
await asyncio.sleep(1)
|
||||
try:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_LOCALSCAN_USERS:
|
||||
if user.remote_ip not in uplink.ctx.Config.WHITELISTED_IP:
|
||||
list_to_remove.append(user)
|
||||
result = await uplink.ctx.Base.create_thread_io(
|
||||
uplink.mod_utils.action_scan_client_with_local_socket,
|
||||
uplink, user
|
||||
)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model)
|
||||
if not result:
|
||||
continue
|
||||
|
||||
await asyncio.sleep(1)
|
||||
fullname = f'{user.nickname}!{user.username}@{user.hostname}'
|
||||
opened_ports = result['opened_ports']
|
||||
closed_ports = result['closed_ports']
|
||||
if opened_ports:
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}LOCAL_SCAN{nogc} ] {fullname} ({user.remote_ip}) : The Port(s) {opened_ports} are opened on this remote ip [{user.remote_ip}]",
|
||||
channel=service_chanlog
|
||||
)
|
||||
if closed_ports:
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}LOCAL_SCAN{nogc} ] {fullname} ({user.remote_ip}) : The Port(s) {closed_ports} are closed on this remote ip [{user.remote_ip}]",
|
||||
channel=service_chanlog
|
||||
)
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_LOCALSCAN_USERS.remove(user_model)
|
||||
|
||||
await asyncio.sleep(1.5)
|
||||
except ValueError as ve:
|
||||
uplink.ctx.Logs.debug(f"The value to remove is not in the list. {ve}")
|
||||
except TimeoutError as te:
|
||||
uplink.ctx.Logs.debug(f"Timeout Error {te}")
|
||||
|
||||
async def coro_psutil_scan(uplink: 'Defender'):
|
||||
uplink.psutil_isRunning = True
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
|
||||
while uplink.psutil_isRunning:
|
||||
|
||||
while uplink.psutil_isRunning:
|
||||
try:
|
||||
list_to_remove:list = []
|
||||
for user in uplink.Schemas.DB_PSUTIL_USERS:
|
||||
await uplink.mod_utils.action_scan_client_with_psutil(uplink, user)
|
||||
result = await uplink.ctx.Base.create_thread_io(uplink.mod_utils.action_scan_client_with_psutil, uplink, user)
|
||||
list_to_remove.append(user)
|
||||
if not result:
|
||||
continue
|
||||
|
||||
fullname = f'{user.nickname}!{user.username}@{user.hostname}'
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}PSUTIL_SCAN{nogc} ] {fullname} ({user.remote_ip}) is using ports {result}",
|
||||
channel=service_chanlog
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
for user_model in list_to_remove:
|
||||
uplink.Schemas.DB_PSUTIL_USERS.remove(user_model)
|
||||
|
||||
await asyncio.sleep(1)
|
||||
await asyncio.sleep(1.5)
|
||||
except ValueError as ve:
|
||||
uplink.ctx.Logs.debug(f"The value to remove is not in the list. {ve}")
|
||||
except TimeoutError as te:
|
||||
uplink.ctx.Logs.debug(f"Timeout Error {te}")
|
||||
|
||||
async def coro_autolimit(uplink: 'Defender'):
|
||||
|
||||
@@ -104,7 +266,6 @@ async def coro_autolimit(uplink: 'Defender'):
|
||||
chan_list: list[str] = [c.name for c in uplink.ctx.Channel.UID_CHANNEL_DB]
|
||||
|
||||
while uplink.autolimit_isRunning:
|
||||
|
||||
if uplink.mod_config.autolimit == 0:
|
||||
uplink.ctx.Logs.debug("autolimit deactivated ... stopping the current thread")
|
||||
break
|
||||
@@ -112,7 +273,7 @@ async def coro_autolimit(uplink: 'Defender'):
|
||||
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||
for chan_copy in chanObj_copy:
|
||||
if chan_copy["name"] == chan.name and len(chan.uids) != chan_copy["uids_count"]:
|
||||
await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
|
||||
await p.send_set_mode('+l', channel_name=chan.name, params=len(chan.uids) + uplink.mod_config.autolimit_amount)
|
||||
chan_copy["uids_count"] = len(chan.uids)
|
||||
|
||||
if chan.name not in chan_list:
|
||||
@@ -128,13 +289,13 @@ async def coro_autolimit(uplink: 'Defender'):
|
||||
# Si c'est la premiere execution
|
||||
if INIT == 1:
|
||||
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||
await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
|
||||
await p.send_set_mode('+l', channel_name=chan.name, params=len(chan.uids) + uplink.mod_config.autolimit_amount)
|
||||
|
||||
# Si le nouveau amount est différent de l'initial
|
||||
if init_amount != uplink.mod_config.autolimit_amount:
|
||||
init_amount = uplink.mod_config.autolimit_amount
|
||||
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||
await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + uplink.mod_config.autolimit_amount}")
|
||||
await p.send_set_mode('+l', channel_name=chan.name, params=len(chan.uids) + uplink.mod_config.autolimit_amount)
|
||||
|
||||
INIT = 0
|
||||
|
||||
@@ -142,7 +303,6 @@ async def coro_autolimit(uplink: 'Defender'):
|
||||
await asyncio.sleep(uplink.mod_config.autolimit_interval)
|
||||
|
||||
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||
# await p.send2socket(f":{uplink.ctx.Config.SERVICE_ID} MODE {chan.name} -l")
|
||||
await p.send_set_mode('-l', channel_name=chan.name)
|
||||
|
||||
uplink.ctx.Irc.autolimit_started = False
|
||||
@@ -158,7 +318,6 @@ async def coro_release_mode_mute(uplink: 'Defender', action: str, channel: str):
|
||||
channel (str): The related channel
|
||||
|
||||
"""
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
timeout = uplink.mod_config.flood_timer
|
||||
await asyncio.sleep(timeout)
|
||||
|
||||
@@ -169,6 +328,6 @@ async def coro_release_mode_mute(uplink: 'Defender', action: str, channel: str):
|
||||
match action:
|
||||
case 'mode-m':
|
||||
# Action -m sur le salon
|
||||
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel} -m")
|
||||
await uplink.ctx.Irc.Protocol.send_set_mode('-m', channel_name=channel)
|
||||
case _:
|
||||
pass
|
||||
|
||||
@@ -267,6 +267,7 @@ async def handle_on_uid(uplink: 'Defender', srvmsg: list[str]):
|
||||
####################
|
||||
# [:<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
|
||||
|
||||
async def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
||||
|
||||
confmodel = uplink.mod_config
|
||||
@@ -316,17 +317,16 @@ async def action_on_flood(uplink: 'Defender', srvmsg: list[str]):
|
||||
fu.nbr_msg = 0
|
||||
get_diff_secondes = unixtime - fu.first_msg_time
|
||||
elif fu.nbr_msg > flood_message:
|
||||
uplink.ctx.Logs.info('system de flood detecté')
|
||||
await p.send_set_mode('+m', channel_name=channel)
|
||||
await p.send_priv_msg(
|
||||
nick_from=dnickname,
|
||||
msg=f"{color_red} {color_bold} Flood detected. Apply the +m mode (Ô_o)",
|
||||
channel=channel
|
||||
)
|
||||
await p.send2socket(f":{service_id} MODE {channel} +m")
|
||||
uplink.ctx.Logs.info(f'FLOOD Détecté sur {get_detected_nickname} mode +m appliqué sur le salon {channel}')
|
||||
uplink.ctx.Logs.debug(f'[FLOOD] {get_detected_nickname} triggered +m mode on the channel {channel}')
|
||||
fu.nbr_msg = 0
|
||||
fu.first_msg_time = unixtime
|
||||
uplink.ctx.Base.create_asynctask(dthreads.coro_release_mode_mute(uplink, 'mode-m', channel))
|
||||
uplink.ctx.Base.create_asynctask(uplink.Threads.coro_release_mode_mute(uplink, 'mode-m', channel))
|
||||
|
||||
async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
||||
|
||||
@@ -336,10 +336,14 @@ async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
||||
confmodel = uplink.mod_config
|
||||
|
||||
get_reputation = uplink.ctx.Reputation.get_reputation(jailed_uid)
|
||||
|
||||
if get_reputation is None:
|
||||
uplink.ctx.Logs.warning(f'UID {jailed_uid} has not been found')
|
||||
return
|
||||
return None
|
||||
|
||||
if get_reputation.isWebirc or get_reputation.isWebsocket:
|
||||
uplink.ctx.Logs.debug(f'This nickname is exampted from the reputation system (Webirc or Websocket). {get_reputation.nickname} ({get_reputation.uid})')
|
||||
uplink.ctx.Reputation.delete(get_reputation.uid)
|
||||
return None
|
||||
|
||||
salon_logs = gconfig.SERVICE_CHANLOG
|
||||
salon_jail = gconfig.SALON_JAIL
|
||||
@@ -360,7 +364,7 @@ async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
||||
# Si le user ne vient pas de webIrc
|
||||
await p.send_sajoin(nick_to_sajoin=jailed_nickname, channel_name=salon_jail)
|
||||
await p.send_priv_msg(nick_from=gconfig.SERVICE_NICKNAME,
|
||||
msg=f" [{color_red} REPUTATION {nogc}] : Connexion de {jailed_nickname} ({jailed_score}) ==> {salon_jail}",
|
||||
msg=f" [ {color_red}REPUTATION{nogc} ]: The nickname {jailed_nickname} has been sent to {salon_jail} because his reputation score is ({jailed_score})",
|
||||
channel=salon_logs
|
||||
)
|
||||
await p.send_notice(
|
||||
@@ -371,7 +375,7 @@ async def action_add_reputation_sanctions(uplink: 'Defender', jailed_uid: str ):
|
||||
if reputation_ban_all_chan == 1:
|
||||
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != salon_jail:
|
||||
await p.send2socket(f":{service_id} MODE {chan.name} +b {jailed_nickname}!*@*")
|
||||
await p.send_set_mode('+b', channel_name=chan.name, params=f'{jailed_nickname}!*@*')
|
||||
await p.send2socket(f":{service_id} KICK {chan.name} {jailed_nickname}")
|
||||
|
||||
uplink.ctx.Logs.info(f"[REPUTATION] {jailed_nickname} jailed (UID: {jailed_uid}, score: {jailed_score})")
|
||||
@@ -419,14 +423,14 @@ async def action_apply_reputation_santions(uplink: 'Defender') -> None:
|
||||
for chan in uplink.ctx.Channel.UID_CHANNEL_DB:
|
||||
if chan.name != salon_jail and ban_all_chan == 1:
|
||||
get_user_reputation = uplink.ctx.Reputation.get_reputation(uid)
|
||||
await p.send2socket(f":{service_id} MODE {chan.name} -b {get_user_reputation.nickname}!*@*")
|
||||
await p.send_set_mode('-b', channel_name=chan.name, params=f"{get_user_reputation.nickname}!*@*")
|
||||
|
||||
# Lorsqu'un utilisateur quitte, il doit être supprimé de {UID_DB}.
|
||||
uplink.ctx.Channel.delete_user_from_all_channel(uid)
|
||||
uplink.ctx.Reputation.delete(uid)
|
||||
uplink.ctx.User.delete(uid)
|
||||
|
||||
async def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""Analyse l'ip avec cloudfilt
|
||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||
Args:
|
||||
@@ -438,11 +442,6 @@ async def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUs
|
||||
"""
|
||||
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
|
||||
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.mod_config.cloudfilt_scan == 0:
|
||||
@@ -450,52 +449,28 @@ async def action_scan_client_with_cloudfilt(uplink: 'Defender', user_model: 'MUs
|
||||
if uplink.cloudfilt_key == '':
|
||||
return None
|
||||
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
|
||||
url = "https://developers18334.cloudfilt.com/"
|
||||
data = {'ip': remote_ip, 'key': uplink.cloudfilt_key}
|
||||
with requests.Session() as sess:
|
||||
response = sess.post(url=url, data=data)
|
||||
|
||||
data = {
|
||||
'ip': remote_ip,
|
||||
'key': uplink.cloudfilt_key
|
||||
}
|
||||
# Formatted output
|
||||
decoded_response: dict = loads(response.text)
|
||||
status_code = response.status_code
|
||||
if status_code != 200:
|
||||
uplink.ctx.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
|
||||
return
|
||||
|
||||
response = requests.post(url=url, data=data)
|
||||
# Formatted output
|
||||
decoded_response: dict = loads(response.text)
|
||||
status_code = response.status_code
|
||||
if status_code != 200:
|
||||
uplink.ctx.Logs.warning(f'Error connecting to cloudfilt API | Code: {str(status_code)}')
|
||||
return
|
||||
result = {
|
||||
'countryiso': decoded_response.get('countryiso', None),
|
||||
'listed': decoded_response.get('listed', False),
|
||||
'listed_by': decoded_response.get('listed_by', None),
|
||||
'host': decoded_response.get('host', None)
|
||||
}
|
||||
|
||||
result = {
|
||||
'countryiso': decoded_response.get('countryiso', None),
|
||||
'listed': decoded_response.get('listed', None),
|
||||
'listed_by': decoded_response.get('listed_by', None),
|
||||
'host': decoded_response.get('host', None)
|
||||
}
|
||||
return result
|
||||
|
||||
# pseudo!ident@host
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}CLOUDFILT_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Host: {str(result['host'])} | country: {str(result['countryiso'])} | listed: {str(result['listed'])} | listed by : {str(result['listed_by'])}",
|
||||
channel=service_chanlog)
|
||||
|
||||
uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN] ({fullname}) connected from ({result['countryiso']}), Listed: {result['listed']}, by: {result['listed_by']}")
|
||||
|
||||
if result['listed']:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} Your connexion is listed as dangerous {str(result['listed'])} {str(result['listed_by'])} - detected by cloudfilt")
|
||||
uplink.ctx.Logs.debug(f"[CLOUDFILT SCAN GLINE] Dangerous connection ({fullname}) from ({result['countryiso']}) Listed: {result['listed']}, by: {result['listed_by']}")
|
||||
|
||||
response.close()
|
||||
|
||||
return result
|
||||
|
||||
async def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""Analyse l'ip avec Freeipapi
|
||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||
Args:
|
||||
@@ -505,64 +480,35 @@ async def action_scan_client_with_freeipapi(uplink: 'Defender', user_model: 'MUs
|
||||
dict[str, any] | None: les informations du provider
|
||||
keys : 'countryCode', 'isProxy'
|
||||
"""
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
|
||||
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.mod_config.freeipapi_scan == 0:
|
||||
return None
|
||||
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
with requests.Session() as sess:
|
||||
url = f'https://freeipapi.com/api/json/{remote_ip}'
|
||||
headers = {'Accept': 'application/json'}
|
||||
response = sess.request(method='GET', url=url, headers=headers, timeout=uplink.timeout)
|
||||
|
||||
url = f'https://freeipapi.com/api/json/{remote_ip}'
|
||||
# Formatted output
|
||||
decoded_response: dict = loads(response.text)
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
}
|
||||
status_code = response.status_code
|
||||
if status_code == 429:
|
||||
uplink.ctx.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.')
|
||||
return None
|
||||
elif status_code != 200:
|
||||
uplink.ctx.Logs.warning(f'status code = {str(status_code)}')
|
||||
return None
|
||||
|
||||
response = requests.request(method='GET', url=url, headers=headers, timeout=uplink.timeout)
|
||||
result = {
|
||||
'countryCode': decoded_response.get('countryCode', None),
|
||||
'isProxy': decoded_response.get('isProxy', None)
|
||||
}
|
||||
return result
|
||||
|
||||
# Formatted output
|
||||
decoded_response: dict = loads(response.text)
|
||||
|
||||
status_code = response.status_code
|
||||
if status_code == 429:
|
||||
uplink.ctx.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.')
|
||||
return None
|
||||
elif status_code != 200:
|
||||
uplink.ctx.Logs.warning(f'status code = {str(status_code)}')
|
||||
return None
|
||||
|
||||
result = {
|
||||
'countryCode': decoded_response.get('countryCode', None),
|
||||
'isProxy': decoded_response.get('isProxy', None)
|
||||
}
|
||||
|
||||
# pseudo!ident@host
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}FREEIPAPI_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Proxy: {str(result['isProxy'])} | Country : {str(result['countryCode'])}",
|
||||
channel=service_chanlog)
|
||||
uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN] ({fullname}) connected from ({result['countryCode']}), Proxy: {result['isProxy']}")
|
||||
|
||||
if result['isProxy']:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow proxy connexions {str(result['isProxy'])} - detected by freeipapi")
|
||||
uplink.ctx.Logs.debug(f"[FREEIPAPI SCAN GLINE] Server do not allow proxy connexions {result['isProxy']}")
|
||||
|
||||
response.close()
|
||||
|
||||
return result
|
||||
|
||||
async def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""Analyse l'ip avec AbuseIpDB
|
||||
Cette methode devra etre lancer toujours via un thread ou un timer.
|
||||
Args:
|
||||
@@ -572,121 +518,81 @@ async def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUs
|
||||
Returns:
|
||||
dict[str, str] | None: les informations du provider
|
||||
"""
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
|
||||
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.mod_config.abuseipdb_scan == 0:
|
||||
return None
|
||||
|
||||
if uplink.abuseipdb_key == '':
|
||||
return None
|
||||
|
||||
url = 'https://api.abuseipdb.com/api/v2/check'
|
||||
querystring = {
|
||||
'ipAddress': remote_ip,
|
||||
'maxAgeInDays': '90'
|
||||
}
|
||||
with requests.Session() as sess:
|
||||
url = 'https://api.abuseipdb.com/api/v2/check'
|
||||
querystring = {'ipAddress': remote_ip, 'maxAgeInDays': '90'}
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
'Key': uplink.abuseipdb_key
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json',
|
||||
'Key': uplink.abuseipdb_key
|
||||
}
|
||||
response = sess.request(method='GET', url=url, headers=headers, params=querystring, timeout=uplink.timeout)
|
||||
|
||||
response = requests.request(method='GET', url=url, headers=headers, params=querystring, timeout=uplink.timeout)
|
||||
if response.status_code != 200:
|
||||
uplink.ctx.Logs.warning(f'status code = {str(response.status_code)}')
|
||||
return None
|
||||
|
||||
# Formatted output
|
||||
decoded_response: dict[str, dict] = loads(response.text)
|
||||
# Formatted output
|
||||
decoded_response: dict[str, dict] = loads(response.text)
|
||||
|
||||
if 'data' not in decoded_response:
|
||||
return None
|
||||
if 'data' not in decoded_response:
|
||||
return None
|
||||
|
||||
result = {
|
||||
'score': decoded_response.get('data', {}).get('abuseConfidenceScore', 0),
|
||||
'country': decoded_response.get('data', {}).get('countryCode', None),
|
||||
'isTor': decoded_response.get('data', {}).get('isTor', None),
|
||||
'totalReports': decoded_response.get('data', {}).get('totalReports', 0)
|
||||
}
|
||||
|
||||
service_id = uplink.ctx.Config.SERVICE_ID
|
||||
service_chanlog = uplink.ctx.Config.SERVICE_CHANLOG
|
||||
color_red = uplink.ctx.Config.COLORS.red
|
||||
nogc = uplink.ctx.Config.COLORS.nogc
|
||||
|
||||
# pseudo!ident@host
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
await p.send_priv_msg(
|
||||
nick_from=service_id,
|
||||
msg=f"[ {color_red}ABUSEIPDB_SCAN{nogc} ] : Connexion de {fullname} ({remote_ip}) ==> Score: {str(result['score'])} | Country : {result['country']} | Tor : {str(result['isTor'])} | Total Reports : {str(result['totalReports'])}",
|
||||
channel=service_chanlog
|
||||
)
|
||||
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN] ({fullname}) connected from ({result['country']}), Score: {result['score']}, Tor: {result['isTor']}")
|
||||
|
||||
if result['isTor']:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} This server do not allow Tor connexions {str(result['isTor'])} - Detected by Abuseipdb")
|
||||
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not allow Tor connections Tor: {result['isTor']}, Score: {result['score']}")
|
||||
elif result['score'] >= 95:
|
||||
await p.send2socket(f":{service_id} GLINE +*@{remote_ip} {uplink.ctx.Config.GLINE_DURATION} You were banned from this server because your abuse score is = {str(result['score'])} - Detected by Abuseipdb")
|
||||
uplink.ctx.Logs.debug(f"[ABUSEIPDB SCAN GLINE] Server do not high risk connections Country: {result['country']}, Score: {result['score']}")
|
||||
|
||||
response.close()
|
||||
result = {
|
||||
'score': decoded_response.get('data', {}).get('abuseConfidenceScore', 0),
|
||||
'country': decoded_response.get('data', {}).get('countryCode', None),
|
||||
'isTor': decoded_response.get('data', {}).get('isTor', None),
|
||||
'totalReports': decoded_response.get('data', {}).get('totalReports', 0)
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
async def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser'):
|
||||
def action_scan_client_with_local_socket(uplink: 'Defender', user_model: 'MUser') -> Optional[dict[str, str]]:
|
||||
"""local_scan
|
||||
|
||||
Args:
|
||||
uplink (Defender): Defender instance object
|
||||
user_model (MUser): l'objet User qui contient l'ip
|
||||
"""
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||
return None
|
||||
|
||||
result = {'opened_ports': [], 'closed_ports': []}
|
||||
|
||||
for port in uplink.ctx.Config.PORTS_TO_SCAN:
|
||||
try:
|
||||
newSocket = ''
|
||||
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK)
|
||||
newSocket.settimeout(0.5)
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM or socket.SOCK_NONBLOCK) as sock:
|
||||
try:
|
||||
sock.settimeout(0.5)
|
||||
connection = (remote_ip, uplink.ctx.Base.int_if_possible(port))
|
||||
sock.connect(connection)
|
||||
|
||||
connection = (remote_ip, uplink.ctx.Base.int_if_possible(port))
|
||||
newSocket.connect(connection)
|
||||
result['opened_ports'].append(port)
|
||||
uplink.ctx.Base.running_sockets.append(sock)
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
uplink.ctx.Base.running_sockets.remove(sock)
|
||||
return result
|
||||
|
||||
await p.send_priv_msg(
|
||||
nick_from=uplink.ctx.Config.SERVICE_NICKNAME,
|
||||
msg=f"[ {uplink.ctx.Config.COLORS.red}PROXY_SCAN{uplink.ctx.Config.COLORS.nogc} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]",
|
||||
channel=uplink.ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
# print(f"=======> Le port {str(port)} est ouvert !!")
|
||||
uplink.ctx.Base.running_sockets.append(newSocket)
|
||||
# print(newSocket)
|
||||
newSocket.shutdown(socket.SHUT_RDWR)
|
||||
newSocket.close()
|
||||
except (socket.timeout, ConnectionRefusedError):
|
||||
uplink.ctx.Logs.debug(f"[LOCAL SCAN] Port {remote_ip}:{str(port)} is close.")
|
||||
result['closed_ports'].append(port)
|
||||
except AttributeError as ae:
|
||||
uplink.ctx.Logs.warning(f"AttributeError ({remote_ip}): {ae}")
|
||||
except socket.gaierror as err:
|
||||
uplink.ctx.Logs.warning(f"Address Info Error ({remote_ip}): {err}")
|
||||
|
||||
except (socket.timeout, ConnectionRefusedError):
|
||||
uplink.ctx.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé")
|
||||
except AttributeError as ae:
|
||||
uplink.ctx.Logs.warning(f"AttributeError ({remote_ip}): {ae}")
|
||||
except socket.gaierror as err:
|
||||
uplink.ctx.Logs.warning(f"Address Info Error ({remote_ip}): {err}")
|
||||
finally:
|
||||
# newSocket.shutdown(socket.SHUT_RDWR)
|
||||
newSocket.close()
|
||||
uplink.ctx.Logs.info('=======> Fermeture de la socket')
|
||||
return result
|
||||
|
||||
async def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]:
|
||||
def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser') -> list[int]:
|
||||
"""psutil_scan for Linux (should be run on the same location as the unrealircd server)
|
||||
|
||||
Args:
|
||||
@@ -695,28 +601,16 @@ async def action_scan_client_with_psutil(uplink: 'Defender', user_model: 'MUser'
|
||||
Returns:
|
||||
list[int]: list of ports
|
||||
"""
|
||||
p = uplink.ctx.Irc.Protocol
|
||||
remote_ip = user_model.remote_ip
|
||||
username = user_model.username
|
||||
hostname = user_model.hostname
|
||||
nickname = user_model.nickname
|
||||
|
||||
if remote_ip in uplink.ctx.Config.WHITELISTED_IP:
|
||||
return None
|
||||
if uplink.mod_config.psutil_scan == 0:
|
||||
return None
|
||||
|
||||
try:
|
||||
connections = psutil.net_connections(kind='inet')
|
||||
fullname = f'{nickname}!{username}@{hostname}'
|
||||
|
||||
matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip]
|
||||
uplink.ctx.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}")
|
||||
|
||||
if matching_ports:
|
||||
await p.send_priv_msg(
|
||||
nick_from=uplink.ctx.Config.SERVICE_NICKNAME,
|
||||
msg=f"[ {uplink.ctx.Config.COLORS.red}PSUTIL_SCAN{uplink.ctx.Config.COLORS.black} ] {fullname} ({remote_ip}) : is using ports {matching_ports}",
|
||||
channel=uplink.ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
uplink.ctx.Logs.debug(f"Connexion of ({remote_ip}) using ports : {str(matching_ports)}")
|
||||
|
||||
return matching_ports
|
||||
|
||||
|
||||
@@ -91,9 +91,9 @@ class Jsonrpc(IModule):
|
||||
self.is_streaming = False
|
||||
|
||||
# Create module commands (Mandatory)
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'jrinstances', 'Get number of instances')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'jsonrpc', 'Activate the JSON RPC Live connection [ON|OFF]')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'jruser', 'Get Information about a user using JSON RPC')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'jrinstances', 'Get number of instances')
|
||||
|
||||
try:
|
||||
self.Rpc = ConnectionFactory(self.ctx.Config.DEBUG_LEVEL).get(self.ctx.Config.JSONRPC_METHOD)
|
||||
@@ -138,7 +138,6 @@ class Jsonrpc(IModule):
|
||||
channel=self.ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self.ctx.Base.create_asynctask(thds.thread_unsubscribe(self))
|
||||
# await self.update_configuration('jsonrpc', 0)
|
||||
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||
self.ctx.Logs.debug(f"Unloading {self.module_name}")
|
||||
return None
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
@@ -53,11 +53,11 @@ class Test(IModule):
|
||||
"""
|
||||
|
||||
# Create module commands (Mandatory)
|
||||
self.ctx.Irc.build_command(0, self.module_name, 'test-command', 'Execute a test command')
|
||||
self.ctx.Irc.build_command(0, self.module_name, 'asyncio', 'Create a new asynchron task!')
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command')
|
||||
self.ctx.Irc.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command')
|
||||
self.ctx.Irc.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command')
|
||||
self.ctx.Commands.build_command(0, self.module_name, 'test-command', 'Execute a test command')
|
||||
self.ctx.Commands.build_command(0, self.module_name, 'asyncio', 'Create a new asynchron task!')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'test_level_1', 'Execute a level 1 test command')
|
||||
self.ctx.Commands.build_command(2, self.module_name, 'test_level_2', 'Execute a level 2 test command')
|
||||
self.ctx.Commands.build_command(3, self.module_name, 'test_level_3', 'Execute a level 3 test command')
|
||||
|
||||
# Build the default configuration model (Mandatory)
|
||||
self._mod_config = self.ModConfModel(param_exemple1='str', param_exemple2=1)
|
||||
|
||||
@@ -88,7 +88,7 @@ class Votekick(IModule):
|
||||
self.VoteKickManager.VOTE_CHANNEL_DB = metadata
|
||||
|
||||
# Créer les nouvelles commandes du module
|
||||
self.ctx.Irc.build_command(1, self.module_name, 'vote', 'The kick vote module')
|
||||
self.ctx.Commands.build_command(1, self.module_name, 'vote', 'The kick vote module')
|
||||
|
||||
async def unload(self) -> None:
|
||||
try:
|
||||
|
||||
@@ -12,7 +12,7 @@ async def timer_vote_verdict(uplink: 'Votekick', channel: str) -> None:
|
||||
if not uplink.VoteKickManager.is_vote_ongoing(channel):
|
||||
return None
|
||||
|
||||
asyncio.sleep(60)
|
||||
await asyncio.sleep(60)
|
||||
|
||||
votec = uplink.VoteKickManager.get_vote_channel_model(channel)
|
||||
if votec:
|
||||
|
||||
Reference in New Issue
Block a user