mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 19:24:23 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3002313697 | ||
|
|
735553549f | ||
|
|
4d4d0db102 | ||
|
|
6f6e6d6c22 | ||
|
|
91210f96ec | ||
|
|
54ea946da0 | ||
|
|
26364f854a | ||
|
|
bfd434eca4 | ||
|
|
1d7a31ec20 | ||
|
|
f2323f7a3c | ||
|
|
fe96d2e906 | ||
|
|
6c797b8efb | ||
|
|
8bc417abf9 | ||
|
|
9cd338ecf8 | ||
|
|
ab4df40a4c | ||
|
|
d989dcd762 |
@@ -23,9 +23,28 @@ configuration:
|
||||
OWNER: "TON_NICK_NAME"
|
||||
PASSWORD: "TON_PASSWORD"
|
||||
|
||||
JSONRPC_URL: "https://your.domaine.com:8600/api"
|
||||
JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket"
|
||||
##########################################
|
||||
# Defender JSON-RPC Configuration #
|
||||
##########################################
|
||||
RPC_HOST: "0.0.0.0"
|
||||
RPC_PORT: 5000
|
||||
RPC_USERS:
|
||||
- USERNAME: "RPC_USER_1"
|
||||
PASSWORD: "RPC_USER_1_PASSWORD"
|
||||
- USERNAME: "RPC_USER_2"
|
||||
PASSWORD: "RPC_USER_2_PASSWORD"
|
||||
|
||||
##########################################
|
||||
# UnrealIRCD JSON-RPC Configuration #
|
||||
##########################################
|
||||
# unixsocket or http
|
||||
JSONRPC_METHOD: "unixsocket"
|
||||
|
||||
# If the method is unixsocket you don't need URL, USER or PASSWORD
|
||||
JSONRPC_PATH_TO_SOCKET_FILE: "/PATH/TO/YOUR/IRCD/data/rpc.socket"
|
||||
|
||||
# If METHOD is http
|
||||
JSONRPC_URL: "https://your.domaine.com:8600/api"
|
||||
JSONRPC_USER: "YOUR_RPC_USER"
|
||||
JSONRPC_PASSWORD: "YOUR_RPC_PASSWORD"
|
||||
|
||||
|
||||
35
core/base.py
35
core/base.py
@@ -378,7 +378,7 @@ class Base:
|
||||
|
||||
if run_once:
|
||||
for task in asyncio.all_tasks():
|
||||
if task.get_name().lower() == async_name.lower():
|
||||
if task.get_name().lower() == name.lower():
|
||||
return None
|
||||
|
||||
task = asyncio.create_task(func, name=name)
|
||||
@@ -431,23 +431,27 @@ class Base:
|
||||
self.running_iothreads.remove(id_obj)
|
||||
return result
|
||||
|
||||
def asynctask_done(self, task: Union[asyncio.Task, asyncio.Future]):
|
||||
def asynctask_done(self, task: Union[asyncio.Task, asyncio.Future], context: Optional[dict[str, Any]] = None):
|
||||
"""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"
|
||||
|
||||
if context:
|
||||
print(context)
|
||||
|
||||
task_name = "Future" if isinstance(task, asyncio.Future) else task.get_name()
|
||||
task_or_future = "Task"
|
||||
try:
|
||||
if task.exception():
|
||||
self.logs.error(f"[ASYNCIO] {task_or_future} {name} failed with exception: {task.exception()}")
|
||||
self.logs.error(f"[ASYNCIO] {task_or_future} {task_name} failed with exception: {task.exception()}")
|
||||
else:
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {name} completed successfully.")
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {task_name} completed successfully.")
|
||||
except asyncio.CancelledError as ce:
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {name} terminated with cancelled error. {ce}")
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {task_name} terminated with cancelled error. {ce}")
|
||||
except asyncio.InvalidStateError as ie:
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {name} terminated with invalid state error. {ie}")
|
||||
self.logs.debug(f"[ASYNCIO] {task_or_future} {task_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.
|
||||
@@ -611,25 +615,10 @@ class Base:
|
||||
)
|
||||
'''
|
||||
|
||||
table_core_client = f'''CREATE TABLE IF NOT EXISTS {self.Config.TABLE_CLIENT} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
createdOn TEXT,
|
||||
account TEXT,
|
||||
nickname TEXT,
|
||||
hostname TEXT,
|
||||
vhost TEXT,
|
||||
realname TEXT,
|
||||
email TEXT,
|
||||
password TEXT,
|
||||
level INTEGER
|
||||
)
|
||||
'''
|
||||
|
||||
await self.db_execute_query(table_core_log)
|
||||
await self.db_execute_query(table_core_log_command)
|
||||
await self.db_execute_query(table_core_module)
|
||||
await self.db_execute_query(table_core_admin)
|
||||
await self.db_execute_query(table_core_client)
|
||||
await self.db_execute_query(table_core_channel)
|
||||
await self.db_execute_query(table_core_config)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class IModule(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def create_tables(self) -> None:
|
||||
async def create_tables(self) -> None:
|
||||
"""Method that will create the database if it does not exist.
|
||||
A single Session for this class will be created, which will be used within this class/module.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import Optional, TYPE_CHECKING
|
||||
from core.classes.protocols.command_handler import CommandHandler
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MClient, MSasl, MUser, MChannel
|
||||
from core.definition import MSasl, MUser, MChannel
|
||||
from core.loader import Loader
|
||||
|
||||
class IProtocol(ABC):
|
||||
@@ -224,11 +224,8 @@ class IProtocol(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
async def send_svslogout(self, client_obj: 'MClient') -> None:
|
||||
async def send_svslogout(self) -> None:
|
||||
"""Logout a client from his account
|
||||
|
||||
Args:
|
||||
client_obj (MClient): The Client UID
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@@ -244,7 +241,7 @@ class IProtocol(ABC):
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
async def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None:
|
||||
async def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str, vhost: str, remote_ip: str, realname: str, geoip: str, print_log: bool = True) -> None:
|
||||
"""Send UID to the server
|
||||
- Insert User to User Object
|
||||
Args:
|
||||
@@ -256,6 +253,7 @@ class IProtocol(ABC):
|
||||
vhost (str): vhost of the client you want to create
|
||||
remote_ip (str): remote_ip of the client you want to create
|
||||
realname (str): realname of the client you want to create
|
||||
geoip (str): The country code of the client you want to create
|
||||
print_log (bool, optional): print logs if true. Defaults to True.
|
||||
"""
|
||||
|
||||
|
||||
@@ -67,15 +67,14 @@ class Admin:
|
||||
Returns:
|
||||
bool: True if the admin level has been updated
|
||||
"""
|
||||
|
||||
for record in self.UID_ADMIN_DB:
|
||||
if record.nickname == nickname:
|
||||
admin_obj = self.get_admin(nickname)
|
||||
if admin_obj:
|
||||
# If the admin exist, update and do not go further
|
||||
record.level = new_admin_level
|
||||
self._ctx.Logs.debug(f'Admin ({record.nickname}) has been updated with new level {new_admin_level}')
|
||||
admin_obj.level = new_admin_level
|
||||
self._ctx.Logs.debug(f'Admin ({admin_obj.nickname}) has been updated with new level {new_admin_level}')
|
||||
return True
|
||||
|
||||
self._ctx.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 in local variable, nickname = {nickname} is not logged in')
|
||||
|
||||
return False
|
||||
|
||||
@@ -94,7 +93,7 @@ class Admin:
|
||||
self._ctx.Logs.debug(f'UID ({admin_obj.uid}) has been deleted')
|
||||
return True
|
||||
|
||||
self._ctx.Logs.debug(f'The UID {uidornickname} was not deleted')
|
||||
self._ctx.Logs.debug(f'The UID {uidornickname} was not deleted from the local variable (admin not connected)')
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
from re import sub
|
||||
from typing import Any, Optional, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
from core.definition import MClient
|
||||
|
||||
class Client:
|
||||
|
||||
CLIENT_DB: list['MClient'] = []
|
||||
|
||||
def __init__(self, loader: 'Loader'):
|
||||
"""
|
||||
|
||||
Args:
|
||||
loader (Loader): The Loader instance.
|
||||
"""
|
||||
self._ctx = loader
|
||||
|
||||
def insert(self, new_client: 'MClient') -> bool:
|
||||
"""Insert a new User object
|
||||
|
||||
Args:
|
||||
new_client (MClient): New Client object
|
||||
|
||||
Returns:
|
||||
bool: True if inserted
|
||||
"""
|
||||
|
||||
client_obj = self.get_client(new_client.uid)
|
||||
|
||||
if not client_obj is None:
|
||||
# User already created return False
|
||||
return False
|
||||
|
||||
self.CLIENT_DB.append(new_client)
|
||||
|
||||
return True
|
||||
|
||||
def update_nickname(self, uid: str, new_nickname: str) -> bool:
|
||||
"""Update the nickname starting from the UID
|
||||
|
||||
Args:
|
||||
uid (str): UID of the user
|
||||
new_nickname (str): New nickname
|
||||
|
||||
Returns:
|
||||
bool: True if updated
|
||||
"""
|
||||
user_obj = self.get_client(uidornickname=uid)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
user_obj.nickname = new_nickname
|
||||
|
||||
return True
|
||||
|
||||
def update_mode(self, uidornickname: str, modes: str) -> bool:
|
||||
"""Updating user mode
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or Nickname of the user
|
||||
modes (str): new modes to update
|
||||
|
||||
Returns:
|
||||
bool: True if user mode has been updaed
|
||||
"""
|
||||
response = True
|
||||
user_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
action = modes[0]
|
||||
new_modes = modes[1:]
|
||||
|
||||
existing_umodes = user_obj.umodes
|
||||
umodes = user_obj.umodes
|
||||
|
||||
if action == '+':
|
||||
|
||||
for nm in new_modes:
|
||||
if nm not in existing_umodes:
|
||||
umodes += nm
|
||||
|
||||
elif action == '-':
|
||||
for nm in new_modes:
|
||||
if nm in existing_umodes:
|
||||
umodes = umodes.replace(nm, '')
|
||||
else:
|
||||
return False
|
||||
|
||||
liste_umodes = list(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}"
|
||||
|
||||
return response
|
||||
|
||||
def delete(self, uid: str) -> bool:
|
||||
"""Delete the User starting from the UID
|
||||
|
||||
Args:
|
||||
uid (str): UID of the user
|
||||
|
||||
Returns:
|
||||
bool: True if deleted
|
||||
"""
|
||||
|
||||
user_obj = self.get_client(uidornickname=uid)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
self.CLIENT_DB.remove(user_obj)
|
||||
|
||||
return True
|
||||
|
||||
def get_client(self, uidornickname: str) -> Optional['MClient']:
|
||||
"""Get The Client Object model
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or Nickname
|
||||
|
||||
Returns:
|
||||
UserModel|None: The UserModel Object | None
|
||||
"""
|
||||
for record in self.CLIENT_DB:
|
||||
if record.uid == uidornickname:
|
||||
return record
|
||||
elif record.nickname == uidornickname:
|
||||
return record
|
||||
|
||||
return None
|
||||
|
||||
def get_uid(self, uidornickname:str) -> Optional[str]:
|
||||
"""Get the UID of the user starting from the UID or the Nickname
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or Nickname
|
||||
|
||||
Returns:
|
||||
str|None: Return the UID
|
||||
"""
|
||||
|
||||
client_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return client_obj.uid
|
||||
|
||||
def get_nickname(self, uidornickname:str) -> Union[str, None]:
|
||||
"""Get the Nickname starting from UID or the nickname
|
||||
|
||||
Args:
|
||||
uidornickname (str): UID or Nickname of the user
|
||||
|
||||
Returns:
|
||||
str|None: the nickname
|
||||
"""
|
||||
client_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if client_obj is None:
|
||||
return None
|
||||
|
||||
return client_obj.nickname
|
||||
|
||||
def is_exist(self, uidornickname: str) -> bool:
|
||||
"""Check if the UID or the nickname exist in the USER DB
|
||||
|
||||
Args:
|
||||
uidornickname (str): The UID or the NICKNAME
|
||||
|
||||
Returns:
|
||||
bool: True if exist
|
||||
"""
|
||||
user_obj = self.get_client(uidornickname=uidornickname)
|
||||
|
||||
if user_obj is None:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
async def db_is_account_exist(self, account: str) -> bool:
|
||||
"""Check if the account exist in the database
|
||||
|
||||
Args:
|
||||
account (str): The account to check
|
||||
|
||||
Returns:
|
||||
bool: True if exist
|
||||
"""
|
||||
|
||||
table_client = self._ctx.Base.Config.TABLE_CLIENT
|
||||
account_to_check = {'account': account.lower()}
|
||||
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._ctx.Logs.error(f"Account ({account}) already exist")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def clean_uid(self, uid: str) -> Union[str, None]:
|
||||
"""Clean UID by removing @ / % / + / ~ / * / :
|
||||
|
||||
Args:
|
||||
uid (str): The UID to clean
|
||||
|
||||
Returns:
|
||||
str: Clean UID without any sign
|
||||
"""
|
||||
|
||||
pattern = fr'[:|@|%|\+|~|\*]*'
|
||||
parsed_uid = sub(pattern, '', uid)
|
||||
|
||||
if not parsed_uid:
|
||||
return None
|
||||
|
||||
return parsed_uid
|
||||
@@ -1,9 +1,11 @@
|
||||
import asyncio
|
||||
import importlib
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
from typing import TYPE_CHECKING
|
||||
import socket
|
||||
import core.module as module_mod
|
||||
from core.classes.modules import user, admin, channel, reputation, sasl
|
||||
from core.utils import tr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.loader import Loader
|
||||
@@ -12,9 +14,15 @@ if TYPE_CHECKING:
|
||||
REHASH_MODULES = [
|
||||
'core.definition',
|
||||
'core.utils',
|
||||
'core.classes.modules.config',
|
||||
'core.base',
|
||||
'core.module',
|
||||
'core.classes.modules.config',
|
||||
'core.classes.modules.commands',
|
||||
'core.classes.modules.user',
|
||||
'core.classes.modules.admin',
|
||||
'core.classes.modules.channel',
|
||||
'core.classes.modules.reputation',
|
||||
'core.classes.modules.sasl',
|
||||
'core.classes.modules.rpc.rpc_channel',
|
||||
'core.classes.modules.rpc.rpc_command',
|
||||
'core.classes.modules.rpc.rpc_user',
|
||||
@@ -54,33 +62,35 @@ async def restart_service(uplink: 'Loader', reason: str = "Restarting with no re
|
||||
uplink.ModuleUtils.model_clear() # Clear loaded modules.
|
||||
uplink.User.UID_DB.clear() # Clear User Object
|
||||
uplink.Channel.UID_CHANNEL_DB.clear() # Clear Channel Object
|
||||
uplink.Client.CLIENT_DB.clear() # Clear Client object
|
||||
uplink.Irc.Protocol.Handler.DB_IRCDCOMMS.clear()
|
||||
|
||||
# Reload Service modules
|
||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||
await uplink.ModuleUtils.reload_one_module(module.module_name, uplink.Settings.current_admin)
|
||||
|
||||
uplink.Irc.signal = True
|
||||
await uplink.Irc.run()
|
||||
uplink.Config.DEFENDER_RESTART = 0
|
||||
|
||||
async def rehash_service(uplink: 'Loader', nickname: str) -> None:
|
||||
need_a_restart = ["SERVEUR_ID"]
|
||||
uplink.Settings.set_cache('db_commands', uplink.Commands.DB_COMMANDS)
|
||||
uplink.Settings.set_cache('commands', uplink.Commands.DB_COMMANDS)
|
||||
uplink.Settings.set_cache('users', uplink.User.UID_DB)
|
||||
uplink.Settings.set_cache('admins', uplink.Admin.UID_ADMIN_DB)
|
||||
uplink.Settings.set_cache('reputations', uplink.Reputation.UID_REPUTATION_DB)
|
||||
uplink.Settings.set_cache('channels', uplink.Channel.UID_CHANNEL_DB)
|
||||
uplink.Settings.set_cache('sasl', uplink.Sasl.DB_SASL)
|
||||
uplink.Settings.set_cache('modules', uplink.ModuleUtils.DB_MODULES)
|
||||
uplink.Settings.set_cache('module_headers', uplink.ModuleUtils.DB_MODULE_HEADERS)
|
||||
|
||||
await uplink.RpcServer.stop_rpc_server()
|
||||
|
||||
restart_flag = False
|
||||
config_model_bakcup = uplink.Config
|
||||
mods = REHASH_MODULES
|
||||
_count_reloaded_modules = len(mods)
|
||||
for mod in mods:
|
||||
importlib.reload(sys.modules[mod])
|
||||
await uplink.Irc.Protocol.send_priv_msg(
|
||||
nick_from=uplink.Config.SERVICE_NICKNAME,
|
||||
msg=f'[REHASH] Module [{mod}] reloaded',
|
||||
channel=uplink.Config.SERVICE_CHANLOG
|
||||
)
|
||||
|
||||
uplink.Utils = sys.modules['core.utils']
|
||||
uplink.Config = uplink.ConfModule.Configuration(uplink).configuration_model
|
||||
uplink.Config.HSID = config_model_bakcup.HSID
|
||||
@@ -115,9 +125,25 @@ async def rehash_service(uplink: 'Loader', nickname: str) -> None:
|
||||
|
||||
# Reload Main Commands Module
|
||||
uplink.Commands = uplink.CommandModule.Command(uplink)
|
||||
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('db_commands')
|
||||
|
||||
uplink.Commands.DB_COMMANDS = uplink.Settings.get_cache('commands')
|
||||
uplink.Base = uplink.BaseModule.Base(uplink)
|
||||
|
||||
uplink.User = user.User(uplink)
|
||||
uplink.Admin = admin.Admin(uplink)
|
||||
uplink.Channel = channel.Channel(uplink)
|
||||
uplink.Reputation = reputation.Reputation(uplink)
|
||||
uplink.ModuleUtils = module_mod.Module(uplink)
|
||||
uplink.Sasl = sasl.Sasl(uplink)
|
||||
|
||||
# Backup data
|
||||
uplink.User.UID_DB = uplink.Settings.get_cache('users')
|
||||
uplink.Admin.UID_ADMIN_DB = uplink.Settings.get_cache('admins')
|
||||
uplink.Channel.UID_CHANNEL_DB = uplink.Settings.get_cache('channels')
|
||||
uplink.Reputation.UID_REPUTATION_DB = uplink.Settings.get_cache('reputations')
|
||||
uplink.Sasl.DB_SASL = uplink.Settings.get_cache('sasl')
|
||||
uplink.ModuleUtils.DB_MODULE_HEADERS = uplink.Settings.get_cache('module_headers')
|
||||
uplink.ModuleUtils.DB_MODULES = uplink.Settings.get_cache('modules')
|
||||
|
||||
uplink.Irc.Protocol = uplink.PFactory.get()
|
||||
uplink.Irc.Protocol.register_command()
|
||||
|
||||
@@ -128,6 +154,15 @@ async def rehash_service(uplink: 'Loader', nickname: str) -> None:
|
||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||
await uplink.ModuleUtils.reload_one_module(module.module_name, nickname)
|
||||
|
||||
color_green = uplink.Config.COLORS.green
|
||||
color_reset = uplink.Config.COLORS.nogc
|
||||
|
||||
await uplink.Irc.Protocol.send_priv_msg(
|
||||
uplink.Config.SERVICE_NICKNAME,
|
||||
tr("[ %sREHASH INFO%s ] Rehash completed! %s modules reloaded.", color_green, color_reset, _count_reloaded_modules),
|
||||
uplink.Config.SERVICE_CHANLOG
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
async def shutdown(uplink: 'Loader') -> None:
|
||||
@@ -141,6 +176,14 @@ async def shutdown(uplink: 'Loader') -> None:
|
||||
for module in uplink.ModuleUtils.model_get_loaded_modules().copy():
|
||||
await uplink.ModuleUtils.unload_one_module(module.module_name)
|
||||
|
||||
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())}")
|
||||
|
||||
# Nettoyage des timers
|
||||
uplink.Logs.debug(f"=======> Closing all timers!")
|
||||
for timer in uplink.Base.running_timers:
|
||||
@@ -158,25 +201,37 @@ async def shutdown(uplink: 'Loader') -> None:
|
||||
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]
|
||||
[th.thread_event.clear() for th in uplink.Base.running_iothreads if isinstance(th.thread_event, threading.Event)]
|
||||
|
||||
uplink.Logs.debug(f"=======> Closing all IO TASKS!")
|
||||
t = None
|
||||
for task in uplink.Base.running_iotasks:
|
||||
if 'force_shutdown' == task.get_name():
|
||||
t = task
|
||||
if t:
|
||||
uplink.Base.running_iotasks.remove(t)
|
||||
|
||||
task_already_canceled: list = []
|
||||
for task in uplink.Base.running_iotasks:
|
||||
try:
|
||||
await asyncio.wait_for(asyncio.gather(*uplink.Base.running_iotasks), timeout=5)
|
||||
if not task.cancel():
|
||||
print(task.get_name())
|
||||
task_already_canceled.append(task)
|
||||
except asyncio.exceptions.CancelledError as cerr:
|
||||
uplink.Logs.debug(f"Asyncio CancelledError reached! {task}")
|
||||
|
||||
for task in task_already_canceled:
|
||||
uplink.Base.running_iotasks.remove(task)
|
||||
|
||||
for task in uplink.Base.running_iotasks:
|
||||
try:
|
||||
await asyncio.wait_for(asyncio.gather(task), timeout=5)
|
||||
except asyncio.exceptions.TimeoutError as te:
|
||||
uplink.Logs.debug(f"Asyncio Timeout reached! {te}")
|
||||
uplink.Logs.debug(f"Asyncio Timeout reached! {te} {task}")
|
||||
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.Logs.debug(f"Asyncio CancelledError reached! {cerr} {task}")
|
||||
|
||||
uplink.Base.running_timers.clear()
|
||||
uplink.Base.running_threads.clear()
|
||||
@@ -187,3 +242,9 @@ async def shutdown(uplink: 'Loader') -> None:
|
||||
uplink.Base.db_close()
|
||||
|
||||
return None
|
||||
|
||||
async def force_shutdown(uplink: 'Loader') -> None:
|
||||
await asyncio.sleep(10)
|
||||
uplink.Logs.critical("The system has been killed because something is blocking the loop")
|
||||
uplink.Logs.critical(asyncio.all_tasks())
|
||||
sys.exit('The system has been killed')
|
||||
@@ -8,7 +8,7 @@ from core.classes.interfaces.iprotocol import IProtocol
|
||||
from core.utils import tr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MSasl, MClient, MUser, MChannel
|
||||
from core.definition import MSasl, MUser, MChannel
|
||||
|
||||
class Inspircd(IProtocol):
|
||||
|
||||
@@ -562,7 +562,6 @@ class Inspircd(IProtocol):
|
||||
uid = str(scopy[0]).replace(':','')
|
||||
newnickname = scopy[2]
|
||||
self._ctx.User.update_nickname(uid, newnickname)
|
||||
self._ctx.Client.update_nickname(uid, newnickname)
|
||||
self._ctx.Admin.update_nickname(uid, newnickname)
|
||||
|
||||
return None
|
||||
@@ -1334,15 +1333,12 @@ class Inspircd(IProtocol):
|
||||
client_uid (str): Client UID
|
||||
user_account (str): The account of the user
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
async def send_svslogout(self, client_obj: 'MClient') -> None:
|
||||
async def send_svslogout(self) -> None:
|
||||
"""Logout a client from his account
|
||||
|
||||
Args:
|
||||
client_obj (MClient): The Client Object Model
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
async def send_svsmode(self, nickname: str, user_mode: str) -> None:
|
||||
"""_summary_
|
||||
|
||||
@@ -7,7 +7,7 @@ from core.classes.interfaces.iprotocol import IProtocol
|
||||
from core.utils import is_coroutinefunction, tr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MClient, MSasl, MUser, MChannel
|
||||
from core.definition import MSasl, MUser, MChannel
|
||||
|
||||
class Unrealircd6(IProtocol):
|
||||
|
||||
@@ -469,18 +469,13 @@ class Unrealircd6(IProtocol):
|
||||
except Exception as err:
|
||||
self._ctx.Logs.error(f'General Error: {err}')
|
||||
|
||||
async def send_svslogout(self, client_obj: 'MClient') -> None:
|
||||
async def send_svslogout(self) -> None:
|
||||
"""Logout a client from his account
|
||||
|
||||
Args:
|
||||
client_obj (MClient): The Client object
|
||||
"""
|
||||
try:
|
||||
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")
|
||||
await self.send_svs2mode(c_nickname, '-r')
|
||||
|
||||
# await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SVSLOGIN {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {c_uid} 0")
|
||||
# await self.send_svs2mode(c_nickname, '-r')
|
||||
pass
|
||||
except Exception as err:
|
||||
self._ctx.Logs.error(f'General Error: {err}')
|
||||
|
||||
@@ -510,7 +505,7 @@ class Unrealircd6(IProtocol):
|
||||
return None
|
||||
|
||||
async def send_uid(self, nickname:str, username: str, hostname: str, uid:str, umodes: str,
|
||||
vhost: str, remote_ip: str, realname: str, print_log: bool = True) -> None:
|
||||
vhost: str, remote_ip: str, realname: str, geoip: str, print_log: bool = True) -> None:
|
||||
"""Send UID to the server
|
||||
- Insert User to User Object
|
||||
Args:
|
||||
@@ -535,7 +530,7 @@ class Unrealircd6(IProtocol):
|
||||
self._ctx.Definition.MUser(
|
||||
uid=uid, nickname=nickname, username=username,
|
||||
realname=realname,hostname=hostname, umodes=umodes,
|
||||
vhost=vhost, remote_ip=remote_ip
|
||||
vhost=vhost, remote_ip=remote_ip, geoip=geoip
|
||||
)
|
||||
)
|
||||
|
||||
@@ -795,7 +790,6 @@ class Unrealircd6(IProtocol):
|
||||
|
||||
self._ctx.Channel.delete_user_from_all_channel(uid_who_quit)
|
||||
self._ctx.User.delete(uid_who_quit)
|
||||
self._ctx.Client.delete(uid_who_quit)
|
||||
self._ctx.Reputation.delete(uid_who_quit)
|
||||
self._ctx.Admin.delete(uid_who_quit)
|
||||
|
||||
@@ -879,7 +873,6 @@ class Unrealircd6(IProtocol):
|
||||
uid = str(server_msg[1]).lstrip(':')
|
||||
newnickname = server_msg[3]
|
||||
self._ctx.User.update_nickname(uid, newnickname)
|
||||
self._ctx.Client.update_nickname(uid, newnickname)
|
||||
self._ctx.Admin.update_nickname(uid, newnickname)
|
||||
self._ctx.Reputation.update(uid, newnickname)
|
||||
|
||||
@@ -1472,7 +1465,7 @@ class Unrealircd6(IProtocol):
|
||||
sasl_obj.fingerprint = str(scopy[6])
|
||||
await self.send2socket(f":{self._ctx.Config.SERVEUR_LINK} SASL {self._ctx.Settings.MAIN_SERVER_HOSTNAME} {sasl_obj.client_uid} C +")
|
||||
|
||||
self.on_sasl_authentication_process(sasl_obj)
|
||||
await self.on_sasl_authentication_process(sasl_obj)
|
||||
return sasl_obj
|
||||
|
||||
case 'C':
|
||||
|
||||
@@ -28,26 +28,6 @@ class MainModel:
|
||||
"""Return a list of attributes name"""
|
||||
return [f.name for f in fields(self)]
|
||||
|
||||
@dataclass
|
||||
class MClient(MainModel):
|
||||
"""Model Client for registred nickname"""
|
||||
uid: str = None
|
||||
account: str = None
|
||||
nickname: str = None
|
||||
username: str = None
|
||||
realname: str = None
|
||||
hostname: str = None
|
||||
umodes: str = None
|
||||
vhost: str = None
|
||||
fingerprint: str = None
|
||||
tls_cipher: str = None
|
||||
isWebirc: bool = False
|
||||
isWebsocket: bool = False
|
||||
remote_ip: str = None
|
||||
score_connexion: int = 0
|
||||
geoip: str = None
|
||||
connexion_datetime: datetime = field(default=datetime.now())
|
||||
|
||||
@dataclass
|
||||
class MUser(MainModel):
|
||||
"""Model User"""
|
||||
@@ -283,9 +263,6 @@ class MConfig(MainModel):
|
||||
LOGGING_NAME: str = "defender"
|
||||
"""The name of the Logging instance"""
|
||||
|
||||
TABLE_CLIENT: str = "core_client"
|
||||
"""Core Client table"""
|
||||
|
||||
TABLE_ADMIN: str = "core_admin"
|
||||
"""Core Admin table"""
|
||||
|
||||
|
||||
278
core/irc.py
278
core/irc.py
@@ -2,14 +2,12 @@ import asyncio
|
||||
import re
|
||||
import ssl
|
||||
import threading
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
from core.classes.modules import rehash
|
||||
from core.classes.interfaces.iprotocol import IProtocol
|
||||
from core.utils import tr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.definition import MSasl
|
||||
from core.loader import Loader
|
||||
|
||||
class Irc:
|
||||
@@ -66,36 +64,32 @@ class Irc:
|
||||
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', 'quit', 'Disconnect the bot or user from the server.')
|
||||
self.ctx.Commands.build_command(4, 'core', 'rehash', 'Reload the configuration file without restarting')
|
||||
self.ctx.Commands.build_command(4, 'core', 'restart', 'Restart the bot or service.')
|
||||
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', 'show_timers', 'Display active timers')
|
||||
self.ctx.Commands.build_command(4, 'core', 'show_threads', 'Display active threads in the system')
|
||||
self.ctx.Commands.build_command(4, 'core', 'show_asyncio', 'Display active asyncio')
|
||||
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.ctx.Commands.build_command(4, 'core', 'load', 'Load an existing module')
|
||||
self.ctx.Commands.build_command(4, 'core', 'unload', 'Unload a module')
|
||||
self.ctx.Commands.build_command(4, 'core', 'reload', 'Reload a module')
|
||||
|
||||
##############################################
|
||||
# CONNEXION IRC #
|
||||
@@ -103,6 +97,7 @@ class Irc:
|
||||
|
||||
async def run(self):
|
||||
try:
|
||||
self.signal = True
|
||||
await self.connect()
|
||||
await self.listen()
|
||||
except asyncio.exceptions.IncompleteReadError as ie:
|
||||
@@ -137,6 +132,7 @@ class Irc:
|
||||
data = await self.reader.readuntil(b'\r\n')
|
||||
await self.send_response(data.splitlines())
|
||||
|
||||
|
||||
async def send_response(self, responses:list[bytes]) -> None:
|
||||
try:
|
||||
for data in responses:
|
||||
@@ -206,65 +202,6 @@ class Irc:
|
||||
|
||||
return None
|
||||
|
||||
async def on_sasl_authentication_process(self, sasl_model: 'MSasl') -> bool:
|
||||
s = sasl_model
|
||||
if sasl_model:
|
||||
async def db_get_admin_info(*, username: Optional[str] = None, password: Optional[str] = None, fingerprint: Optional[str] = None) -> Optional[dict[str, Any]]:
|
||||
if fingerprint:
|
||||
mes_donnees = {'fingerprint': fingerprint}
|
||||
query = f"SELECT user, level, language FROM {self.ctx.Config.TABLE_ADMIN} WHERE fingerprint = :fingerprint"
|
||||
else:
|
||||
mes_donnees = {'user': username, 'password': self.ctx.Utils.hash_password(password)}
|
||||
query = f"SELECT user, level, language FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user AND password = :password"
|
||||
|
||||
result = await self.ctx.Base.db_execute_query(query, mes_donnees)
|
||||
user_from_db = result.fetchone()
|
||||
if user_from_db:
|
||||
return {'user': user_from_db[0], 'level': user_from_db[1], 'language': user_from_db[2]}
|
||||
else:
|
||||
return None
|
||||
|
||||
if s.message_type == 'C' and s.mechanisme == 'PLAIN':
|
||||
# Connection via PLAIN
|
||||
admin_info = await db_get_admin_info(username=s.username, password=s.password)
|
||||
if admin_info is not None:
|
||||
s.auth_success = True
|
||||
s.level = admin_info.get('level', 0)
|
||||
s.language = admin_info.get('language', 'EN')
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
||||
else:
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F")
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed")
|
||||
|
||||
elif s.message_type == 'S' and s.mechanisme == 'EXTERNAL':
|
||||
# Connection using fingerprints
|
||||
admin_info = await db_get_admin_info(fingerprint=s.fingerprint)
|
||||
|
||||
if admin_info is not None:
|
||||
s.auth_success = True
|
||||
s.level = admin_info.get('level', 0)
|
||||
s.username = admin_info.get('user', None)
|
||||
s.language = admin_info.get('language', 'EN')
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D S")
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 903 {s.username} :SASL authentication successful")
|
||||
else:
|
||||
# "904 <nick> :SASL authentication failed"
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} SASL {self.ctx.Settings.MAIN_SERVER_HOSTNAME} {s.client_uid} D F")
|
||||
await self.Protocol.send2socket(f":{self.ctx.Config.SERVEUR_LINK} 904 {s.username} :SASL authentication failed")
|
||||
|
||||
def get_defender_uptime(self) -> str:
|
||||
"""Savoir depuis quand Defender est connecté
|
||||
|
||||
Returns:
|
||||
str: L'écart entre la date du jour et celle de la connexion de Defender
|
||||
"""
|
||||
current_datetime = datetime.now()
|
||||
diff_date = current_datetime - self.defender_connexion_datetime
|
||||
uptime = timedelta(days=diff_date.days, seconds=diff_date.seconds)
|
||||
|
||||
return uptime
|
||||
|
||||
def insert_db_admin(self, uid: str, account: str, level: int, language: str) -> None:
|
||||
user_obj = self.ctx.User.get_user(uid)
|
||||
|
||||
@@ -330,7 +267,7 @@ class Irc:
|
||||
spassword = self.ctx.Utils.hash_password(password)
|
||||
|
||||
# Check if the user already exist
|
||||
if not self.ctx.Admin.db_is_admin_exist(nickname):
|
||||
if not await self.ctx.Admin.db_is_admin_exist(nickname):
|
||||
mes_donnees = {'datetime': self.ctx.Utils.get_sdatetime(), 'user': nickname, 'password': spassword, 'hostname': hostname, 'vhost': vhost, 'level': level, 'language': self.ctx.Config.LANG}
|
||||
await self.ctx.Base.db_execute_query(f'''INSERT INTO {self.ctx.Config.TABLE_ADMIN}
|
||||
(createdOn, user, password, hostname, vhost, level, language) VALUES
|
||||
@@ -347,7 +284,7 @@ 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(
|
||||
response = await self.ctx.Base.create_asynctask(
|
||||
self.ctx.Base.create_thread_io(
|
||||
self.ctx.Base.check_for_new_version, True
|
||||
)
|
||||
@@ -405,9 +342,6 @@ class Irc:
|
||||
if u is None:
|
||||
return None
|
||||
|
||||
c = self.ctx.Client.get_client(u.uid)
|
||||
"""The Client Object"""
|
||||
|
||||
fromuser = u.nickname
|
||||
uid = u.uid
|
||||
self.ctx.Settings.current_admin = self.ctx.Admin.get_admin(user) # set Current admin if any.
|
||||
@@ -609,10 +543,19 @@ class Irc:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4")
|
||||
return None
|
||||
|
||||
if len(cmd) == 4:
|
||||
user_new_level = int(cmd[3])
|
||||
if user_new_level > 5:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Maximum authorized level is 5")
|
||||
return None
|
||||
if user_new_level == 0:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide a valid level [1 to 4]")
|
||||
return None
|
||||
|
||||
user_to_edit = cmd[1]
|
||||
user_password = self.ctx.Utils.hash_password(cmd[2])
|
||||
|
||||
get_admin = self.ctx.Admin.get_admin(fromuser)
|
||||
|
||||
if get_admin is None:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no Admin access")
|
||||
return None
|
||||
@@ -621,15 +564,9 @@ class Irc:
|
||||
current_uid = uid
|
||||
current_user_level = get_admin.level
|
||||
|
||||
user_new_level = int(cmd[3]) if len(cmd) == 4 else get_admin.level
|
||||
|
||||
if current_user == fromuser:
|
||||
if current_user == user_to_edit:
|
||||
user_new_level = get_admin.level
|
||||
|
||||
if user_new_level > 5:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Maximum authorized level is 5")
|
||||
return None
|
||||
|
||||
# Rechercher le user dans la base de données.
|
||||
mes_donnees = {'user': user_to_edit}
|
||||
query = f"SELECT user, level FROM {self.ctx.Config.TABLE_ADMIN} WHERE user = :user"
|
||||
@@ -664,6 +601,10 @@ class Irc:
|
||||
|
||||
case 'delaccess':
|
||||
# .delaccess [USER] [CONFIRMUSER]
|
||||
if len(cmd) < 3:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} delaccess [nickname] [CONFIRMNICKNAME]")
|
||||
return None
|
||||
|
||||
user_to_del = cmd[1]
|
||||
user_confirmation = cmd[2]
|
||||
|
||||
@@ -672,10 +613,6 @@ class Irc:
|
||||
self.ctx.Logs.warning(f':{dnickname} NOTICE {fromuser} : Les user ne sont pas les mêmes, tu dois confirmer le user que tu veux supprimer')
|
||||
return None
|
||||
|
||||
if len(cmd) < 3:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.ctx.Config.SERVICE_PREFIX}delaccess [USER] [CONFIRMUSER]")
|
||||
return None
|
||||
|
||||
get_admin = self.ctx.Admin.get_admin(fromuser)
|
||||
|
||||
if get_admin is None:
|
||||
@@ -747,147 +684,6 @@ class Irc:
|
||||
except Exception as e:
|
||||
self.ctx.Logs.error(e)
|
||||
|
||||
case 'register':
|
||||
# Syntax. Register PASSWORD EMAIL
|
||||
try:
|
||||
|
||||
if len(cmd) < 3:
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f'/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} <PASSWORD> <EMAIL>'
|
||||
)
|
||||
return None
|
||||
|
||||
password = cmd[1]
|
||||
email = cmd[2]
|
||||
|
||||
if not self.ctx.Base.is_valid_email(email_to_control=email):
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg='The email is not valid. You must provide a valid email address (first.name@email.extension)'
|
||||
)
|
||||
return None
|
||||
|
||||
user_obj = u
|
||||
|
||||
if user_obj is None:
|
||||
self.ctx.Logs.error(f"Nickname ({fromuser}) doesn't exist, it is impossible to register this nickname")
|
||||
return None
|
||||
|
||||
# If the account already exist.
|
||||
if self.ctx.Client.db_is_account_exist(fromuser):
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f"Your account already exist, please try to login instead /msg {self.ctx.Config.SERVICE_NICKNAME} IDENTIFY <account> <password>"
|
||||
)
|
||||
return None
|
||||
|
||||
# If the account doesn't exist then insert into database
|
||||
data_to_record = {
|
||||
'createdOn': self.ctx.Utils.get_sdatetime(), 'account': fromuser,
|
||||
'nickname': user_obj.nickname, 'hostname': user_obj.hostname, 'vhost': user_obj.vhost, 'realname': user_obj.realname, 'email': email,
|
||||
'password': self.ctx.Utils.hash_password(password=password), 'level': 0
|
||||
}
|
||||
|
||||
insert_to_db = await self.ctx.Base.db_execute_query(f"""
|
||||
INSERT INTO {self.ctx.Config.TABLE_CLIENT}
|
||||
(createdOn, account, nickname, hostname, vhost, realname, email, password, level)
|
||||
VALUES
|
||||
(:createdOn, :account, :nickname, :hostname, :vhost, :realname, :email, :password, :level)
|
||||
""", data_to_record)
|
||||
|
||||
if insert_to_db.rowcount > 0:
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f"You have register your nickname successfully"
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
except ValueError as ve:
|
||||
self.ctx.Logs.error(f"Value Error : {ve}")
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {self.ctx.Config.SERVICE_PREFIX}{command.upper()} <PASSWORD> <EMAIL>")
|
||||
|
||||
case 'identify':
|
||||
# Identify ACCOUNT PASSWORD
|
||||
try:
|
||||
if len(cmd) < 3:
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f'/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} <ACCOUNT> <PASSWORD>'
|
||||
)
|
||||
return None
|
||||
|
||||
account = str(cmd[1]) # account
|
||||
encrypted_password = self.ctx.Utils.hash_password(cmd[2])
|
||||
user_obj = u
|
||||
client_obj = c
|
||||
|
||||
if client_obj is not None:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are already logged in")
|
||||
return None
|
||||
|
||||
db_query = f"SELECT account FROM {self.ctx.Config.TABLE_CLIENT} WHERE account = :account AND password = :password"
|
||||
db_param = {'account': account, 'password': encrypted_password}
|
||||
exec_query = await self.ctx.Base.db_execute_query(db_query, db_param)
|
||||
result_query = exec_query.fetchone()
|
||||
if result_query:
|
||||
account = result_query[0]
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You are now logged in")
|
||||
client = self.ctx.Definition.MClient(**user_obj.to_dict(), account=account)
|
||||
self.ctx.Client.insert(client)
|
||||
await self.Protocol.send_svslogin(user_obj.uid, account)
|
||||
await self.Protocol.send_svs2mode(nickname=fromuser, user_mode='+r')
|
||||
else:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Wrong password or account")
|
||||
|
||||
return None
|
||||
|
||||
except ValueError as ve:
|
||||
self.ctx.Logs.error(f"Value Error: {ve}")
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f'/msg {self.ctx.Config.SERVICE_NICKNAME} {command.upper()} <ACCOUNT> <PASSWORD>'
|
||||
)
|
||||
|
||||
except Exception as err:
|
||||
self.ctx.Logs.error(f"General Error: {err}")
|
||||
|
||||
case 'logout':
|
||||
try:
|
||||
# LOGOUT <account>
|
||||
if len(cmd) < 2:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} <account>")
|
||||
return None
|
||||
|
||||
user_obj = u
|
||||
if user_obj is None:
|
||||
self.ctx.Logs.error(f"The User [{fromuser}] is not available in the database")
|
||||
return None
|
||||
|
||||
client_obj = c
|
||||
|
||||
if client_obj is None:
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nothing to logout. please login first")
|
||||
return None
|
||||
|
||||
await self.Protocol.send_svslogout(client_obj)
|
||||
self.ctx.Client.delete(user_obj.uid)
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You have been logged out successfully")
|
||||
|
||||
except ValueError as ve:
|
||||
self.ctx.Logs.error(f"Value Error: {ve}")
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} <account>")
|
||||
except Exception as err:
|
||||
self.ctx.Logs.error(f"General Error: {err}")
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} <account>")
|
||||
|
||||
case 'help':
|
||||
# Syntax. !help [module_name]
|
||||
module_name = str(cmd[1]) if len(cmd) == 2 else None
|
||||
@@ -946,15 +742,13 @@ class Irc:
|
||||
try:
|
||||
final_reason = ' '.join(cmd[1:])
|
||||
self.hb_active = False
|
||||
self.ctx.Base.create_asynctask(rehash.force_shutdown(self.ctx), run_once=True)
|
||||
await rehash.shutdown(self.ctx)
|
||||
self.ctx.Base.execute_periodic_action()
|
||||
|
||||
for chan_name in self.ctx.Channel.UID_CHANNEL_DB:
|
||||
await self.Protocol.send_set_mode('-l', channel_name=chan_name.name)
|
||||
|
||||
for client in self.ctx.Client.CLIENT_DB:
|
||||
await self.Protocol.send_svslogout(client)
|
||||
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
@@ -1088,17 +882,6 @@ class Irc:
|
||||
)
|
||||
return None
|
||||
|
||||
case 'show_clients':
|
||||
count_users = len(self.ctx.Client.CLIENT_DB)
|
||||
await self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Total Connected Clients: {count_users}")
|
||||
for db_client in self.ctx.Client.CLIENT_DB:
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
msg=f"UID : {db_client.uid} - isWebirc: {db_client.isWebirc} - isWebSocket: {db_client.isWebsocket} - Nickname: {db_client.nickname} - Account: {db_client.account} - Connection: {db_client.connexion_datetime}"
|
||||
)
|
||||
return None
|
||||
|
||||
case 'show_admins':
|
||||
for db_admin in self.ctx.Admin.UID_ADMIN_DB:
|
||||
await self.Protocol.send_notice(
|
||||
@@ -1135,7 +918,7 @@ class Irc:
|
||||
return None
|
||||
|
||||
case 'uptime':
|
||||
uptime = self.get_defender_uptime()
|
||||
uptime = self.ctx.Utils.get_defender_uptime(self.ctx)
|
||||
await self.Protocol.send_notice(
|
||||
nick_from=dnickname,
|
||||
nick_to=fromuser,
|
||||
@@ -1187,4 +970,3 @@ class Irc:
|
||||
|
||||
case _:
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
traduction:
|
||||
# Message help
|
||||
|
||||
# Message help
|
||||
- orig: "Access denied!"
|
||||
trad: "Accès refusé."
|
||||
- orig: "Wrong password!"
|
||||
@@ -11,11 +12,34 @@ traduction:
|
||||
- orig: "cmd method is not available in the module (%s)"
|
||||
trad: "La méthode cmd n'est pas disponible dans le module (%s)"
|
||||
- orig: "[%sMODULE ERROR%s] Module %s is facing issues! %s"
|
||||
trad: "[%sMODULE ERREUR%s] Le module %s a rencontré une erreur! %s"
|
||||
trad: "[%sERREUR MODULE%s] Le module %s a rencontré une erreur! %s"
|
||||
- orig: "%s - %sNot Loaded%s"
|
||||
trad: "%s - %sNon chargé%s"
|
||||
- orig: "Successfuly connected to %s"
|
||||
trad: "Connecter a %s avec succés"
|
||||
trad: "Connecté à %s avec succés"
|
||||
- orig: "[ %sINFORMATION%s ] >> %s is ready!"
|
||||
trad: "[ %sINFORMATION%s ] >> %s est prêt!"
|
||||
|
||||
# core/irc.py
|
||||
- orig: "[ %s%s%s ] - %s has been disconnected from %s"
|
||||
trad: "[ %s%s%s ] - %s a été déconnecté de %s"
|
||||
- orig: "You can't use this command anymore ! Please use [%sauth] instead"
|
||||
trad: "Vous ne pouvez plus utiliser cette commande ! Utilisez [%auth] à la place."
|
||||
- orig: "The nickname sent [%s] is different than the one set in the configuration file!"
|
||||
trad: "Le pseudo transmis, [%s], ne correspond pas à celui renseigné dans le fichier de configuration !"
|
||||
- orig: "[%s %s %s] - %s is now connected to %s"
|
||||
trad: "[%s %s %s] - %s est désormais connecté à %s"
|
||||
- orig: "[ %s %s %s ] - %s provided a wrong password!"
|
||||
trad: "[ %s %s %s ] - %s a donné un mauvais mot de passe !"
|
||||
- orig: "%s - %sNot Loaded%s"
|
||||
trad: "%s - Non chargé%s"
|
||||
|
||||
# core/classe/protocols/unreal6.py & core/classe/protocols/inspircd.py
|
||||
- orig: "[ %sINFORMATION%s ] >> %s is ready!"
|
||||
trad: "[ %sINFORMATION%s ] >> %s est prêt !"
|
||||
- orig: "[ %sSASL AUTH%s ] - %s (%s) is now connected successfuly to %s"
|
||||
trad: "[ %sSASL AUTH%s ] - %s (%s) s'est connecté avec succès à %s"
|
||||
- orig: "[ %sSASL AUTH%s ] - %s provided a wrong password for this username %s"
|
||||
trad: "[ %sSASL AUTH%s ] - %s : Mauvais certificat fourni avec le compte %s"
|
||||
- orig: "[ %sFINGERPRINT AUTH%s ] - %s (%s) is now connected successfuly to %s"
|
||||
trad: "[ %sFINGERPRINT AUTH%s ] - %s (%s) est maintenant authentifié sur %s !"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from logging import Logger
|
||||
from core.classes.modules.settings import global_settings
|
||||
from core.classes.modules import translation, user, admin, client, channel, reputation, settings, sasl
|
||||
from core.classes.modules import translation, user, admin, channel, reputation, settings, sasl
|
||||
import core.logs as logs
|
||||
import core.definition as df
|
||||
import core.utils as utils
|
||||
@@ -63,8 +63,6 @@ class Loader:
|
||||
|
||||
self.Settings.global_user = self.User
|
||||
|
||||
self.Client: client.Client = client.Client(self)
|
||||
|
||||
self.Admin: admin.Admin = admin.Admin(self)
|
||||
|
||||
self.Channel: channel.Channel = channel.Channel(self)
|
||||
|
||||
@@ -22,6 +22,25 @@ class Module:
|
||||
def __init__(self, loader: 'Loader') -> None:
|
||||
self._ctx = loader
|
||||
|
||||
def is_module_compliant(self, obj: object) -> bool:
|
||||
class_name = obj.__name__
|
||||
is_compliant = True
|
||||
attributs = {'MOD_HEADER', 'mod_config'}
|
||||
methods = {'load', 'unload', 'create_tables', 'cmd', 'hcmds', 'ModConfModel'}
|
||||
|
||||
obj_attributs: set = set([attribut for attribut in dir(obj) if not callable(getattr(obj, attribut)) and not attribut.startswith('__')])
|
||||
obj_methods: set = set([method for method in dir(obj) if callable(getattr(obj, method)) and not method.startswith('__')])
|
||||
|
||||
if not attributs.issubset(obj_attributs):
|
||||
self._ctx.Logs.error(f'[{class_name}] Your module is not valid make sure you have implemented required attributes {attributs}')
|
||||
raise AttributeError(f'[{class_name}] Your module is not valid make sure you have implemented required attributes {attributs}')
|
||||
|
||||
if not methods.issubset(obj_methods):
|
||||
self._ctx.Logs.error(f'[{class_name}] Your module is not valid make sure you have implemented required methods {methods}')
|
||||
raise AttributeError(f'[{class_name}] Your module is not valid make sure you have implemented required methods {methods}')
|
||||
|
||||
return is_compliant
|
||||
|
||||
def get_all_available_modules(self) -> list[str]:
|
||||
"""Get list of all main modules
|
||||
using this pattern mod_*.py
|
||||
@@ -100,13 +119,14 @@ class Module:
|
||||
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
return False
|
||||
|
||||
return self.reload_one_module(module_name, nickname)
|
||||
reload_mod = await self.reload_one_module(module_name, nickname)
|
||||
return reload_mod
|
||||
|
||||
# Charger le module
|
||||
try:
|
||||
loaded_module = importlib.import_module(f'mods.{module_folder}.{module_name}')
|
||||
my_class = getattr(loaded_module, class_name, None) # Récuperer le nom de classe
|
||||
self.is_module_compliant(my_class)
|
||||
create_instance_of_the_class: 'IModule' = my_class(self._ctx) # Créer une nouvelle instance de la classe
|
||||
await create_instance_of_the_class.load() if self._ctx.Utils.is_coroutinefunction(create_instance_of_the_class.load) else create_instance_of_the_class.load()
|
||||
self.create_module_header(create_instance_of_the_class.MOD_HEADER)
|
||||
@@ -118,17 +138,9 @@ class Module:
|
||||
msg=tr("[%sMODULE ERROR%s] Module %s is facing issues! %s", red, nogc, module_name, attr),
|
||||
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self._ctx.Logs.error(msg=attr, exc_info=True)
|
||||
return False
|
||||
|
||||
if not hasattr(create_instance_of_the_class, 'cmd'):
|
||||
await self._ctx.Irc.Protocol.send_priv_msg(
|
||||
nick_from=self._ctx.Config.SERVICE_NICKNAME,
|
||||
msg=tr("cmd method is not available in the module (%s)", module_name),
|
||||
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self._ctx.Logs.critical(f"The Module {module_name} has not been loaded because cmd method is not available")
|
||||
self.drop_module_from_sys_modules(module_name)
|
||||
await self.db_delete_module(module_name)
|
||||
self._ctx.Logs.error(msg=attr, exc_info=True)
|
||||
return False
|
||||
|
||||
# Charger la nouvelle class dans la variable globale
|
||||
@@ -184,6 +196,7 @@ class Module:
|
||||
the_module = sys.modules[f'mods.{module_folder}.{module_name}']
|
||||
importlib.reload(the_module)
|
||||
my_class = getattr(the_module, class_name, None)
|
||||
self.is_module_compliant(my_class)
|
||||
new_instance: 'IModule' = my_class(self._ctx)
|
||||
await new_instance.load() if self._ctx.Utils.is_coroutinefunction(new_instance.load) else new_instance.load()
|
||||
self.create_module_header(new_instance.MOD_HEADER)
|
||||
@@ -215,7 +228,9 @@ class Module:
|
||||
msg=f"[RELOAD MODULE ERROR]: {err}",
|
||||
channel=self._ctx.Config.SERVICE_CHANLOG
|
||||
)
|
||||
self.drop_module_from_sys_modules(module_name)
|
||||
await self.db_delete_module(module_name)
|
||||
return False
|
||||
|
||||
def reload_all_modules(self) -> bool:
|
||||
...
|
||||
@@ -323,6 +338,24 @@ class Module:
|
||||
self._ctx.Logs.debug(f"[SYS MODULE] (mods.{module_folder}.{module_name}) not found in sys.modules")
|
||||
return False
|
||||
|
||||
def drop_module_from_sys_modules(self, module_name: str) -> bool:
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
module_name (str): _description_
|
||||
|
||||
Returns:
|
||||
bool: _description_
|
||||
"""
|
||||
module_folder, module_name, class_name = self.get_module_information(module_name)
|
||||
full_module_name = "mods." + module_folder + "." + module_name
|
||||
del sys.modules[full_module_name]
|
||||
|
||||
if not self.is_module_exist_in_sys_module(module_name):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
'''
|
||||
ALL METHODS RELATED TO THE MModule MODEL DATACLASS
|
||||
'''
|
||||
@@ -343,6 +376,22 @@ class Module:
|
||||
self._ctx.Logs.debug(f"[MODEL MODULE GET] The module {module_name} not found in the model DB_MODULES")
|
||||
return None
|
||||
|
||||
def model_drop_module(self, module_name: str) -> bool:
|
||||
"""Drop a module model object from DB_MODULES
|
||||
|
||||
Args:
|
||||
module_name (str): The module name you want to drop
|
||||
|
||||
Returns:
|
||||
bool: True if the model has been dropped
|
||||
"""
|
||||
module = self.model_get_module(module_name)
|
||||
if module:
|
||||
self.DB_MODULES.remove(module)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def model_get_loaded_modules(self) -> list[MModule]:
|
||||
"""Get the instance of DB_MODULES.
|
||||
Warning: You should use a copy if you want to loop through the list!
|
||||
|
||||
@@ -5,9 +5,8 @@ import gc
|
||||
import ssl
|
||||
from pathlib import Path
|
||||
from re import match, sub
|
||||
import threading
|
||||
from typing import Literal, Optional, Any, TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from time import time, sleep
|
||||
from random import choice
|
||||
from hashlib import md5, sha3_512
|
||||
@@ -115,6 +114,18 @@ def get_ssl_context() -> ssl.SSLContext:
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
return ctx
|
||||
|
||||
def get_defender_uptime(loader: 'Loader') -> str:
|
||||
"""Savoir depuis quand Defender est connecté
|
||||
|
||||
Returns:
|
||||
str: L'écart entre la date du jour et celle de la connexion de Defender
|
||||
"""
|
||||
current_datetime = datetime.now()
|
||||
diff_date = current_datetime - loader.Irc.defender_connexion_datetime
|
||||
uptime = timedelta(days=diff_date.days, seconds=diff_date.seconds)
|
||||
|
||||
return uptime
|
||||
|
||||
def run_python_garbage_collector() -> int:
|
||||
"""Run Python garbage collector
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ from core import install
|
||||
#############################################
|
||||
|
||||
async def main():
|
||||
install.update_packages()
|
||||
# install.update_packages()
|
||||
from core.loader import Loader
|
||||
loader = Loader()
|
||||
await loader.start()
|
||||
|
||||
@@ -17,6 +17,7 @@ class MClone(MainModel):
|
||||
hostname: str = 'localhost'
|
||||
umodes: str = None
|
||||
remote_ip: str = '127.0.0.1'
|
||||
group: str = 'Default'
|
||||
group: str = 'Default',
|
||||
geoip: str = 'XX'
|
||||
|
||||
# DB_CLONES: list[MClone] = []
|
||||
@@ -28,7 +28,7 @@ async def coro_connect_clones(uplink: 'Clone',
|
||||
break
|
||||
|
||||
if not clone.connected:
|
||||
await uplink.ctx.Irc.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
||||
await uplink.ctx.Irc.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, clone.geoip, print_log=False)
|
||||
await uplink.ctx.Irc.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.ctx.Config.CLONE_CHANNEL, password=uplink.ctx.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
||||
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
@@ -103,6 +103,17 @@ def generate_ipv4_for_clone(faker_instance: 'Faker', auto: bool = True) -> str:
|
||||
"""
|
||||
return faker_instance.ipv4_private() if auto else '127.0.0.1'
|
||||
|
||||
def generate_country_code_for_clone(faker_instance: 'Faker') -> str:
|
||||
"""Generate the alpha-2 country code for clone
|
||||
|
||||
Args:
|
||||
faker_instance (Faker): The Faker Instance
|
||||
|
||||
Returns:
|
||||
str: The Country Code
|
||||
"""
|
||||
return faker_instance.country_code('alpha-2')
|
||||
|
||||
def generate_hostname_for_clone(faker_instance: 'Faker') -> str:
|
||||
"""Generate hostname for clone
|
||||
|
||||
@@ -143,6 +154,8 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
|
||||
hostname = generate_hostname_for_clone(faker)
|
||||
vhost = generate_vhost_for_clone(faker)
|
||||
|
||||
geoip = generate_country_code_for_clone(faker)
|
||||
|
||||
checkNickname = uplink.Clone.nickname_exists(nickname)
|
||||
checkUid = uplink.Clone.uid_exists(uid=uid)
|
||||
|
||||
@@ -167,7 +180,8 @@ def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Def
|
||||
remote_ip=decoded_ip,
|
||||
vhost=vhost,
|
||||
group=group,
|
||||
channels=[]
|
||||
channels=[],
|
||||
geoip=geoip
|
||||
)
|
||||
|
||||
uplink.Clone.insert(clone)
|
||||
|
||||
@@ -31,7 +31,7 @@ class Command(IModule):
|
||||
def mod_config(self) -> ModConfModel:
|
||||
return self._mod_config
|
||||
|
||||
def create_tables(self) -> None:
|
||||
async def create_tables(self) -> None:
|
||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||
Args:
|
||||
@@ -51,10 +51,14 @@ class Command(IModule):
|
||||
)
|
||||
'''
|
||||
|
||||
self.ctx.Base.db_execute_query(table_automode)
|
||||
await self.ctx.Base.db_execute_query(table_automode)
|
||||
return None
|
||||
|
||||
def load(self) -> None:
|
||||
async def load(self) -> None:
|
||||
|
||||
# Create the database
|
||||
await self.create_tables()
|
||||
|
||||
# Module Utils
|
||||
self.mod_utils = utils
|
||||
self.user_to_notice: str = ''
|
||||
@@ -66,9 +70,7 @@ class Command(IModule):
|
||||
self.ctx.Irc.Protocol.known_protocol.add(c)
|
||||
|
||||
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')
|
||||
@@ -214,16 +216,12 @@ 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)
|
||||
nickname = userObj.nickname if userObj is not None else None
|
||||
|
||||
if client_obj is not None:
|
||||
nickname = client_obj.account
|
||||
|
||||
if userObj is None:
|
||||
return None
|
||||
|
||||
if 'r' not in userObj.umodes and 'o' not in userObj.umodes and not self.ctx.Client.is_exist(userObj.uid):
|
||||
if 'r' not in userObj.umodes and 'o' not in userObj.umodes:
|
||||
return None
|
||||
|
||||
db_data: dict[str, str] = {"nickname": nickname.lower(), "channel": channel_name.lower()}
|
||||
@@ -412,7 +410,7 @@ class Command(IModule):
|
||||
except Exception as err:
|
||||
self.ctx.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'join' | 'assign':
|
||||
case 'join':
|
||||
try:
|
||||
await self.mod_utils.set_assign_channel_to_service(self, cmd, fromuser)
|
||||
except IndexError as ie:
|
||||
@@ -421,7 +419,7 @@ class Command(IModule):
|
||||
except Exception as err:
|
||||
self.ctx.Logs.warning(f'Unknown Error: {str(err)}')
|
||||
|
||||
case 'part' | 'unassign':
|
||||
case 'part':
|
||||
try:
|
||||
# Syntax. !part #channel
|
||||
await self.mod_utils.set_unassign_channel_to_service(self, cmd, fromuser)
|
||||
|
||||
@@ -115,9 +115,11 @@ async def set_mode_to_all(uplink: 'Command', channel_name: str, action: Literal[
|
||||
users:str = ''
|
||||
uids_split = [chan_info.uids[i:i + 6] for i in range(0, len(chan_info.uids), 6)]
|
||||
|
||||
await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}")
|
||||
# await uplink.ctx.Irc.Protocol.send2socket(f":{service_id} MODE {channel_name} {action}{set_mode} {dnickname}")
|
||||
for uid in uids_split:
|
||||
for i in range(0, len(uid)):
|
||||
if uplink.ctx.Utils.clean_uid(uid[i]) == uplink.ctx.Config.SERVICE_ID:
|
||||
continue
|
||||
mode += set_mode
|
||||
users += f'{uplink.ctx.User.get_nickname(uplink.ctx.Utils.clean_uid(uid[i]))} '
|
||||
if i == len(uid) - 1:
|
||||
|
||||
@@ -288,10 +288,19 @@ class Defender(IModule):
|
||||
jail_chan = self.ctx.Config.SALON_JAIL # Salon pot de miel
|
||||
jail_chan_mode = self.ctx.Config.SALON_JAIL_MODES # Mode du salon "pot de miel"
|
||||
|
||||
color_green = self.ctx.Config.COLORS.green
|
||||
color_red = self.ctx.Config.COLORS.red
|
||||
color_black = self.ctx.Config.COLORS.black
|
||||
color_nogc = self.ctx.Config.COLORS.nogc
|
||||
|
||||
match command:
|
||||
|
||||
case 'show_reputation':
|
||||
|
||||
if self.mod_config.reputation == 0:
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Reputation system if off!")
|
||||
return None
|
||||
|
||||
if not self.ctx.Reputation.UID_REPUTATION_DB:
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="No one is suspected")
|
||||
|
||||
@@ -664,9 +673,6 @@ class Defender(IModule):
|
||||
# .proxy_scan set psutil_scan on/off --> Active les informations de connexion a la machine locale
|
||||
# .proxy_scan set abuseipdb_scan on/off --> Active le scan via l'api abuseipdb
|
||||
len_cmd = len(cmd)
|
||||
color_green = self.ctx.Config.COLORS.green
|
||||
color_red = self.ctx.Config.COLORS.red
|
||||
color_black = self.ctx.Config.COLORS.black
|
||||
|
||||
if len_cmd == 4:
|
||||
set_key = str(cmd[1]).lower()
|
||||
@@ -901,7 +907,7 @@ class Defender(IModule):
|
||||
UserObject = self.ctx.User.get_user(nickoruid)
|
||||
|
||||
if UserObject is not None:
|
||||
channels: list = [chan.name for chan in self.ctx.Channel.UID_CHANNEL_DB for uid_in_chan in chan.uids if self.ctx.mod_utils.clean_uid(uid_in_chan) == UserObject.uid]
|
||||
channels: list = [chan.name for chan in self.ctx.Channel.UID_CHANNEL_DB for uid_in_chan in chan.uids if self.ctx.User.clean_uid(uid_in_chan) == UserObject.uid]
|
||||
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' UID : {UserObject.uid}')
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' NICKNAME : {UserObject.nickname}')
|
||||
@@ -925,6 +931,10 @@ class Defender(IModule):
|
||||
|
||||
case 'sentinel':
|
||||
# .sentinel on
|
||||
if len(cmd) < 2:
|
||||
await self.ctx.Irc.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Syntax. /msg {dnickname} sentinel [ON | OFF]")
|
||||
return None
|
||||
|
||||
activation = str(cmd[1]).lower()
|
||||
channel_to_dont_quit = [self.ctx.Config.SALON_JAIL, self.ctx.Config.SERVICE_CHANLOG]
|
||||
|
||||
@@ -939,6 +949,7 @@ class Defender(IModule):
|
||||
if chan.name not in channel_to_dont_quit:
|
||||
await self.ctx.Irc.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name)
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(dnickname, f"Sentinel mode activated on {channel}", channel=chan.name)
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(dnickname, f"[ {color_green}SENTINEL{color_nogc} ] Activated by {fromuser}", channel=self.ctx.Config.SERVICE_CHANLOG)
|
||||
return None
|
||||
|
||||
if activation == 'off':
|
||||
@@ -953,7 +964,7 @@ class Defender(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(dnickname, f"Sentinel mode deactivated on {channel}", channel=chan.name)
|
||||
|
||||
await self.join_saved_channels()
|
||||
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(dnickname, f"[ {color_red}SENTINEL{color_nogc} ] Deactivated by {fromuser}", channel=self.ctx.Config.SERVICE_CHANLOG)
|
||||
return None
|
||||
|
||||
case _:
|
||||
|
||||
@@ -227,6 +227,7 @@ async def coro_psutil_scan(uplink: 'Defender'):
|
||||
for user in uplink.Schemas.DB_PSUTIL_USERS:
|
||||
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
|
||||
|
||||
|
||||
@@ -534,8 +534,14 @@ def action_scan_client_with_abuseipdb(uplink: 'Defender', user_model: 'MUser') -
|
||||
'Accept': 'application/json',
|
||||
'Key': uplink.abuseipdb_key
|
||||
}
|
||||
|
||||
try:
|
||||
response = sess.request(method='GET', url=url, headers=headers, params=querystring, timeout=uplink.timeout)
|
||||
except (requests.exceptions.ReadTimeout, requests.exceptions.ConnectTimeout) as err:
|
||||
uplink.ctx.Logs.error(f"Time-out Error: {err}")
|
||||
return None
|
||||
except Exception as e:
|
||||
uplink.ctx.Logs.error(f"Time-out Error: {e}")
|
||||
return None
|
||||
|
||||
if response.status_code != 200:
|
||||
uplink.ctx.Logs.warning(f'status code = {str(response.status_code)}')
|
||||
|
||||
@@ -26,11 +26,15 @@ class Test(IModule):
|
||||
}
|
||||
"""Module Header (Mandatory)"""
|
||||
|
||||
@property
|
||||
def mod_config(self) -> ModConfModel:
|
||||
return self._mod_config
|
||||
|
||||
def __init__(self, uplink: 'Loader'):
|
||||
super().__init__(uplink)
|
||||
self._mod_config: Optional[Test.ModConfModel] = None
|
||||
|
||||
def create_tables(self) -> None:
|
||||
async def create_tables(self) -> None:
|
||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||
|
||||
@@ -45,12 +49,14 @@ class Test(IModule):
|
||||
)
|
||||
'''
|
||||
|
||||
# self.ctx.Base.db_execute_query(table_logs)
|
||||
# await self.ctx.Base.db_execute_query(table_logs)
|
||||
return None
|
||||
|
||||
async def load(self) -> None:
|
||||
"""### Load Module Configuration (Mandatory)
|
||||
"""
|
||||
# Create tables if any (Mandatory)
|
||||
await self.create_tables()
|
||||
|
||||
# Create module commands (Mandatory)
|
||||
self.ctx.Commands.build_command(0, self.module_name, 'test-command', 'Execute a test command')
|
||||
@@ -68,15 +74,16 @@ class Test(IModule):
|
||||
if self.mod_config.param_exemple2 == 1:
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(self.ctx.Config.SERVICE_NICKNAME, "Param activated", self.ctx.Config.SERVICE_CHANLOG)
|
||||
|
||||
@property
|
||||
def mod_config(self) -> ModConfModel:
|
||||
return self._mod_config
|
||||
|
||||
def unload(self) -> None:
|
||||
"""### This method is called when you unload, or you reload the module (Mandatory)"""
|
||||
self.ctx.Commands.drop_command_by_module(self.module_name)
|
||||
return None
|
||||
|
||||
async def asyncio_func(self) -> None:
|
||||
self.ctx.Logs.debug(f"Starting async method in a task: {self.__class__.__name__}")
|
||||
await asyncio.sleep(2)
|
||||
self.ctx.Logs.debug(f"End of the task: {self.__class__.__name__}")
|
||||
|
||||
def cmd(self, data: list[str]) -> None:
|
||||
"""All messages coming from the IRCD server will be handled using this method (Mandatory)
|
||||
|
||||
@@ -89,11 +96,6 @@ class Test(IModule):
|
||||
except Exception as err:
|
||||
self.ctx.Logs.error(f"General Error: {err}")
|
||||
|
||||
async def asyncio_func(self) -> None:
|
||||
self.ctx.Logs.debug(f"Starting async method in a task: {self.__class__.__name__}")
|
||||
await asyncio.sleep(2)
|
||||
self.ctx.Logs.debug(f"End of the task: {self.__class__.__name__}")
|
||||
|
||||
async def hcmds(self, user: str, channel: Any, cmd: list, fullcmd: Optional[list] = None) -> None:
|
||||
"""All messages coming from the user commands (Mandatory)
|
||||
|
||||
@@ -126,8 +128,8 @@ class Test(IModule):
|
||||
await self.ctx.Irc.Protocol.send_priv_msg(nick_from=dnickname, msg=f"This is private message to the sender ...", channel=c.name)
|
||||
|
||||
# How to update your module configuration
|
||||
self.update_configuration('param_exemple2', 7)
|
||||
self.update_configuration('param_exemple1', 'my_value')
|
||||
await self.update_configuration('param_exemple2', 7)
|
||||
await self.update_configuration('param_exemple1', 'my_value')
|
||||
|
||||
# Log if you want the result
|
||||
self.ctx.Logs.debug(f"Test logs ready")
|
||||
|
||||
@@ -43,7 +43,7 @@ class Votekick(IModule):
|
||||
def mod_config(self) -> ModConfModel:
|
||||
return self._mod_config
|
||||
|
||||
def create_tables(self) -> None:
|
||||
async def create_tables(self) -> None:
|
||||
"""Methode qui va créer la base de donnée si elle n'existe pas.
|
||||
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
|
||||
|
||||
@@ -65,12 +65,15 @@ class Votekick(IModule):
|
||||
)
|
||||
'''
|
||||
|
||||
self.ctx.Base.db_execute_query(table_logs)
|
||||
self.ctx.Base.db_execute_query(table_vote)
|
||||
await self.ctx.Base.db_execute_query(table_logs)
|
||||
await self.ctx.Base.db_execute_query(table_vote)
|
||||
return None
|
||||
|
||||
async def load(self) -> None:
|
||||
|
||||
# Create tables.
|
||||
await self.create_tables()
|
||||
|
||||
self._mod_config = self.ModConfModel()
|
||||
await self.sync_db()
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ class VotekickManager:
|
||||
votec = self.get_vote_channel_model(channel_name)
|
||||
|
||||
if votec:
|
||||
client_obj = self.uplink.User.get_user(votec.target_user)
|
||||
client_obj = self.uplink.ctx.User.get_user(votec.target_user)
|
||||
client_to_punish = votec.target_user if client_obj is None else client_obj.nickname
|
||||
if nickname in votec.voter_users:
|
||||
self.Logs.debug(f"[VOTEKICK MANAGER] This nickname ({nickname}) has already voted for ({client_to_punish})")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "6.4.0",
|
||||
"version": "6.4.1",
|
||||
|
||||
"requests": "2.32.5",
|
||||
"psutil": "7.1.2",
|
||||
|
||||
Reference in New Issue
Block a user