From 44da01945cef02b64af0fa87cfb0eadd43db0f50 Mon Sep 17 00:00:00 2001 From: adator <85586985+adator85@users.noreply.github.com> Date: Mon, 11 Nov 2024 23:38:05 +0100 Subject: [PATCH] V6.0.1 --- core/base.py | 9 +- core/irc.py | 29 ++-- core/loader.py | 3 - mods/mod_command.py | 324 ++++++++++++++++++++++++++++--------------- mods/mod_defender.py | 100 ++++++------- mods/mod_jsonrpc.py | 13 +- version.json | 4 +- 7 files changed, 290 insertions(+), 192 deletions(-) diff --git a/core/base.py b/core/base.py index e71dafe..6eb2edd 100644 --- a/core/base.py +++ b/core/base.py @@ -194,14 +194,19 @@ class Base: file_hanlder = logging.FileHandler(f'logs{self.Config.OS_SEP}defender.log',encoding='UTF-8') file_hanlder.setLevel(self.Config.DEBUG_LEVEL) + stdout_handler = logging.StreamHandler() + stdout_handler.setLevel(50) + # Define log format formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(lineno)d - %(funcName)s - %(message)s') # Apply log format file_hanlder.setFormatter(formatter) + stdout_handler.setFormatter(formatter) # Add handler to logs self.logs.addHandler(file_hanlder) + self.logs.addHandler(stdout_handler) # Apply the filter self.logs.addFilter(self.replace_filter) @@ -217,8 +222,8 @@ class Base: filter: list[str] = ['PING', f":{self.Config.SERVICE_PREFIX}auth"] # record.msg = record.getMessage().replace("PING", "[REDACTED]") - if self.Settings.CONSOLE: - print(record.getMessage()) + # if self.Settings.CONSOLE: + # print(record.getMessage()) for f in filter: if f in record.getMessage(): diff --git a/core/irc.py b/core/irc.py index dae9065..6464db1 100644 --- a/core/irc.py +++ b/core/irc.py @@ -1184,6 +1184,10 @@ class Irc: case 'auth': # ['auth', 'adator', 'password'] + if len(cmd) != 3: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [password]") + return None + current_command = cmd[0] user_to_log = self.User.get_nickname(cmd[1]) password = cmd[2] @@ -1241,25 +1245,30 @@ class Irc: case 'editaccess': # .editaccess [USER] [PASSWORD] [LEVEL] try: - user_to_edit = cmd[1] - user_new_level = int(cmd[3]) - user_password = self.Base.crypt_password(cmd[2]) - - if len(cmd) < 4 or len(cmd) > 4: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{self.Config.SERVICE_PREFIX}editaccess [USER] [NEWPASSWORD] [NEWLEVEL]") + if len(cmd) < 3: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Right command : /msg {dnickname} editaccess [nickname] [NEWPASSWORD] [NEWLEVEL]") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"level: from 1 to 4") return None + user_to_edit = cmd[1] + user_password = self.Base.crypt_password(cmd[2]) + get_admin = self.Admin.get_Admin(fromuser) if get_admin is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" This user {fromuser} has no Admin access") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"This user {fromuser} has no Admin access") return None current_user = self.User.get_nickname(fromuser) current_uid = self.User.get_uid(fromuser) current_user_level = get_admin.level + user_new_level = int(cmd[3]) if len(cmd) == 4 else get_admin.level + + if current_user == fromuser: + user_new_level = get_admin.level + if user_new_level > 5: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" Maximum authorized level is 5") + 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. @@ -1271,9 +1280,9 @@ class Irc: if not isUserExist is None: if current_user_level < int(isUserExist[1]): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You are not allowed to edit this access") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You are not allowed to edit this access") return None - + if current_user_level == int(isUserExist[1]) and current_user != user_to_edit: self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" You can't edit access of a user with same level") return None diff --git a/core/loader.py b/core/loader.py index de4f4c3..759b49b 100644 --- a/core/loader.py +++ b/core/loader.py @@ -1,5 +1,4 @@ from core.classes import user, admin, channel, clone, reputation, settings -import utils import core.definition as df import core.base as baseModule import core.classes.config as confModule @@ -15,8 +14,6 @@ class Loader: self.BaseModule: baseModule = baseModule - self.Utils: utils - # Load Classes self.Settings: settings = settings.Settings() diff --git a/mods/mod_command.py b/mods/mod_command.py index 8e1a8ff..919c98e 100644 --- a/mods/mod_command.py +++ b/mods/mod_command.py @@ -1,10 +1,12 @@ -from typing import TYPE_CHECKING -from dataclasses import dataclass, fields +from typing import Union, TYPE_CHECKING +from dataclasses import dataclass + +from core.classes import user if TYPE_CHECKING: from core.irc import Irc -class Command(): +class Command: @dataclass class ModConfModel: @@ -20,6 +22,9 @@ class Command(): # Add Irc Object to the module (Mandatory) self.Irc = ircInstance + # Add Loader Object to the module (Mandatory) + self.Loader = ircInstance.Loader + # Add Protocol object to the module (Mandatory) self.Protocol = ircInstance.Protocol @@ -40,14 +45,14 @@ class Command(): # Create module commands (Mandatory) self.commands_level = { - 1: ['join', 'part','owner', 'deowner', 'protect', 'deprotect', 'op', + 1: ['join', 'part','owner', 'deowner', 'protect', 'deprotect', 'op', 'deop', 'halfop', 'dehalfop', 'voice','devoice', 'topic'], - 2: ['opall', 'deopall', 'devoiceall', 'voiceall', 'ban', - 'unban','kick', 'kickban', 'umode', 'mode', 'get_mode', 'svsjoin', 'svspart', 'svsnick', + 2: ['opall', 'deopall', 'devoiceall', 'voiceall', 'ban', 'automode', + 'unban', 'kick', 'kickban', 'umode', + 'mode', 'get_mode', 'svsjoin', 'svspart', 'svsnick', 'wallops', 'globops','gnotice','whois', 'names', 'invite', 'inviteme', - 'sajoin', 'sapart', - 'kill', 'gline', 'ungline', 'kline', 'unkline', 'shun', 'unshun', - 'glinelist', 'shunlist', 'klinelist'], + 'sajoin', 'sapart', 'kill', 'gline', 'ungline', 'kline', + 'unkline', 'shun', 'unshun', 'glinelist', 'shunlist', 'klinelist'], 3: ['map'] } @@ -74,7 +79,7 @@ class Command(): return None - def __set_commands(self, commands:dict[int, list[str]]) -> None: + def __set_commands(self, commands: dict[int, list[str]]) -> None: """### Rajoute les commandes du module au programme principal Args: @@ -82,7 +87,7 @@ class Command(): """ for level, com in commands.items(): for c in commands[level]: - if not c in self.Irc.commands: + if c not in self.Irc.commands: self.Irc.commands_level[level].append(c) self.Irc.commands.append(c) @@ -98,14 +103,17 @@ class Command(): None: Aucun retour n'es attendu """ - table_logs = '''CREATE TABLE IF NOT EXISTS test_logs ( + table_automode = '''CREATE TABLE IF NOT EXISTS command_automode ( id INTEGER PRIMARY KEY AUTOINCREMENT, - datetime TEXT, - server_msg TEXT + created_on TEXT, + updated_on TEXT, + nickname TEXT, + channel TEXT, + mode TEXT ) ''' - # self.Base.db_execute_query(table_logs) + self.Base.db_execute_query(table_automode) return None def __load_module_configuration(self) -> None: @@ -136,107 +144,203 @@ class Command(): return None - def cmd(self, data: list) -> None: + def cmd(self, data: list[str]) -> None: + try: + # service_id = self.Config.SERVICE_ID + dnickname = self.Config.SERVICE_NICKNAME + # dchanlog = self.Config.SERVICE_CHANLOG + red = self.Config.COLORS.red + green = self.Config.COLORS.green + bold = self.Config.COLORS.bold + nogc = self.Config.COLORS.nogc + cmd = list(data).copy() - service_id = self.Config.SERVICE_ID - dnickname = self.Config.SERVICE_NICKNAME - dchanlog = self.Config.SERVICE_CHANLOG - red = self.Config.COLORS.red - green = self.Config.COLORS.green - bold = self.Config.COLORS.bold - nogc = self.Config.COLORS.nogc - cmd = list(data).copy() + if len(cmd) < 2: + return None - if len(cmd) < 2: - return None + match cmd[1]: + # [':irc.deb.biz.st', '403', 'Dev-PyDefender', '#Z', ':No', 'such', 'channel'] + case '403' | '401': + try: + message = ' '.join(cmd[3:]) + self.Protocol.send_notice( + nick_from=dnickname, + nick_to=self.user_to_notice, + msg=f"[{red}ERROR MSG{nogc}] {message}" + ) + self.Logs.error(f"{cmd[1]} - {message}") + except KeyError as ke: + self.Logs.error(ke) + except Exception as err: + self.Logs.warning(f'Unknown Error: {str(err)}') - match cmd[1]: - # [':irc.deb.biz.st', '403', 'Dev-PyDefender', '#Z', ':No', 'such', 'channel'] - case '403' | '401': - try: - message = ' '.join(cmd[3:]) - self.Protocol.send_notice( - nick_from=dnickname, - nick_to=self.user_to_notice, - msg=f"[{red}ERROR MSG{nogc}] {message}" - ) - self.Logs.error(f"{cmd[1]} - {message}") - except KeyError as ke: - self.Logs.error(ke) - except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + case '006' | '018': + try: + # [':irc.deb.biz.st', '006', 'Dev-PyDefender', ':`-services.deb.biz.st', '------', '|', 'Users:', '9', '(47.37%)', '[00B]'] + # [':irc.deb.biz.st', '018', 'Dev-PyDefender', ':4', 'servers', 'and', '19', 'users,', 'average', '4.75', 'users', 'per', 'server'] + message = ' '.join(cmd[3:]) + self.Protocol.send_notice( + nick_from=dnickname, + nick_to=self.user_to_notice, + msg=f"[{green}SERVER MSG{nogc}] {message}" + ) + except KeyError as ke: + self.Logs.error(ke) + except Exception as err: + self.Logs.warning(f'Unknown Error: {str(err)}') - case '006' | '018': - try: - # [':irc.deb.biz.st', '006', 'Dev-PyDefender', ':`-services.deb.biz.st', '------', '|', 'Users:', '9', '(47.37%)', '[00B]'] - # [':irc.deb.biz.st', '018', 'Dev-PyDefender', ':4', 'servers', 'and', '19', 'users,', 'average', '4.75', 'users', 'per', 'server'] - message = ' '.join(cmd[3:]) - self.Protocol.send_notice( - nick_from=dnickname, - nick_to=self.user_to_notice, - msg=f"[{green}SERVER MSG{nogc}] {message}" - ) - except KeyError as ke: - self.Logs.error(ke) - except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + case '219': + try: + # [':irc.deb.biz.st', '219', 'Dev-PyDefender', 's', ':End', 'of', '/STATS', 'report'] + if not self.show_219: + # If there is a result in 223 then stop here + self.show_219 = True + return None - case '219': - try: - # [':irc.deb.biz.st', '219', 'Dev-PyDefender', 's', ':End', 'of', '/STATS', 'report'] - if not self.show_219: - # If there is a result in 223 then stop here - self.show_219 = True - return None + type_of_stats = str(cmd[3]) - type_of_stats = str(cmd[3]) + match type_of_stats: + case 's': + self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No shun") + case 'G': + self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No gline") + case 'k': + self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No kline") - match type_of_stats: - case 's': - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No shun") - case 'G': - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No gline") - case 'k': - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, msg="No kline") + except KeyError as ke: + self.Logs.error(ke) + except Exception as err: + self.Logs.warning(f'Unknown Error: {str(err)}') - except KeyError as ke: - self.Logs.error(ke) - except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + case '223': + try: + # [':irc.deb.biz.st', '223', 'Dev-PyDefender', 'G', '*@162.142.125.217', '67624', '18776', 'irc.deb.biz.st', ':Proxy/Drone', 'detected.', 'Check', 'https://dronebl.org/lookup?ip=162.142.125.217', 'for', 'details.'] + self.show_219 = False + host = str(cmd[4]) + author = str(cmd[7]) + reason = ' '.join(cmd[8:]) - case '223': - try: - # [':irc.deb.biz.st', '223', 'Dev-PyDefender', 'G', '*@162.142.125.217', '67624', '18776', 'irc.deb.biz.st', ':Proxy/Drone', 'detected.', 'Check', 'https://dronebl.org/lookup?ip=162.142.125.217', 'for', 'details.'] - self.show_219 = False - host = str(cmd[4]) - author = str(cmd[7]) - reason = ' '.join(cmd[8:]) + self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, + msg=f"{bold}Author{nogc}: {author} - {bold}Host{nogc}: {host} - {bold}Reason{nogc}: {reason}" + ) - self.Protocol.send_notice(nick_from=dnickname,nick_to=self.user_to_notice, - msg=f"{bold}Author{nogc}: {author} - {bold}Host{nogc}: {host} - {bold}Reason{nogc}: {reason}" - ) + except KeyError as ke: + self.Logs.error(ke) + except Exception as err: + self.Logs.warning(f'Unknown Error: {str(err)}') - except KeyError as ke: - self.Logs.error(ke) - except Exception as err: - self.Logs.warning(f'Unknown Error: {str(err)}') + case _: + pass - case _: - pass + if len(cmd) < 3: + return None - return None + match cmd[2]: - def _hcmds(self, user: str, channel: any, cmd: list, fullcmd: list = []) -> None: + case 'SJOIN': + # ['@msgid=yldTlbwAGbzCGUcCIHi3ku;time=2024-11-11T17:56:24.297Z', ':001', 'SJOIN', '1728815963', '#znc', ':001LQ0L0C'] + # Check if the user has an automode + try: + + if len(cmd) < 6: + return None + + user_uid = self.User.clean_uid(cmd[5]) + userObj = self.User.get_User(user_uid) + channel_name = cmd[4] if self.Channel.Is_Channel(cmd[4]) else None + + if userObj is None: + return None + + if 'r' not in userObj.umodes: + return None + + db_data = {"nickname": userObj.nickname, "channel": channel_name} + db_query = self.Base.db_execute_query("SELECT id, mode FROM command_automode WHERE nickname = :nickname AND channel = :channel", db_data) + db_result = db_query.fetchone() + if db_result is not None: + id, mode = db_result + self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {channel_name} {mode} {userObj.nickname}") + except KeyError as ke: + self.Logs.error(f"Key Error: {err}") + + + except Exception as err: + self.Logs.error(f"General Error: {err}") + + def _hcmds(self, uidornickname: str, channel_name: Union[str, None], cmd: list, fullcmd: list = []) -> None: command = str(cmd[0]).lower() dnickname = self.Config.SERVICE_NICKNAME service_id = self.Config.SERVICE_ID dchanlog = self.Config.SERVICE_CHANLOG - self.user_to_notice = user - fromuser = user - fromchannel = channel + self.user_to_notice = uidornickname + fromuser = uidornickname + fromchannel = channel_name match command: + case "automode": + # automode nickname +/-mode #channel + # automode adator +o #channel + try: + + allowed_modes = ['q','a','o','h','v'] + userObj = self.User.get_User(str(cmd[1])) + + if len(cmd) != 4: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}") + return None + + mode = str(cmd[2]) + flag_found: bool = False + if mode.startswith( ('+', '-') ): + flag_found = True + + if not flag_found: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You must provide the flag mode + or -") + return None + + mode = str(cmd[2]) + chan = cmd[3] if self.Channel.Is_Channel(cmd[3]) else None + + if mode.lstrip('+-') not in allowed_modes: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") + return None + + if chan is None: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You should use one of those modes {' / '.join(allowed_modes)}") + return None + + db_data: dict[str, str] = {"nickname": userObj.nickname, "channel": chan} + db_query = self.Base.db_execute_query(query="SELECT id FROM command_automode WHERE nickname = :nickname and channel = :channel", params=db_data) + db_result = db_query.fetchone() + + if db_result is not None: + db_data = {"updated_on": self.Base.get_datetime(), "nickname": userObj.nickname, "channel": chan, "mode": mode} + db_result = self.Base.db_execute_query(query="UPDATE command_automode SET mode = :mode, updated_on = :updated_on WHERE nickname = :nickname and channel = :channel", + params=db_data) + if db_result.rowcount > 0: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} edited for {userObj.nickname} in {chan}") + + return None + + # Instert a new automode + db_data = {"created_on": self.Base.get_datetime(), "updated_on": self.Base.get_datetime(), "nickname": userObj.nickname, "channel": chan, "mode": mode} + db_query = self.Base.db_execute_query( + query="INSERT INTO command_automode (created_on, updated_on, nickname, channel, mode) VALUES (:created_on, :updated_on, :nickname, :channel, :mode)", + params=db_data + ) + + if db_query.rowcount > 0: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Automode {mode} applied to {userObj.nickname} in {chan}") + self.Protocol.send2socket(f":{service_id} MODE {chan} {mode} {userObj.nickname}") + + except KeyError: + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} [nickname] [+/-mode] [#channel]") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"AutoModes available: {' / '.join(allowed_modes)}") + except Exception as err: + self.Logs.error(f"General Error: {err}") case 'deopall': try: @@ -679,7 +783,7 @@ class Command(): self.Protocol.send_part_chan(uidornickname=dnickname, channel=sent_channel) self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" {dnickname} LEFT {sent_channel}") - + self.Channel.db_query_channel('del', self.module_name, sent_channel) except IndexError as ie: @@ -696,7 +800,7 @@ class Command(): chan = str(cmd[1]) if not self.Channel.Is_Channel(chan): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The channel must start with #") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} TOPIC #channel THE_TOPIC_MESSAGE") return None @@ -705,7 +809,7 @@ class Command(): if topic_msg: self.Protocol.send2socket(f':{dnickname} TOPIC {chan} :{topic_msg}') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the topic") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the topic") except KeyError as ke: self.Logs.error(ke) @@ -723,7 +827,7 @@ class Command(): if wallops_msg: self.Protocol.send2socket(f':{dnickname} WALLOPS {wallops_msg} ({dnickname})') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the wallops message") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the wallops message") except KeyError as ke: self.Logs.error(ke) @@ -741,7 +845,7 @@ class Command(): if globops_msg: self.Protocol.send2socket(f':{dnickname} GLOBOPS {globops_msg} ({dnickname})') else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the globops message") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the globops message") except KeyError as ke: self.Logs.error(ke) @@ -759,7 +863,7 @@ class Command(): if gnotice_msg: self.Protocol.send_notice(nick_from=dnickname, nick_to='$*.*', msg=f"[{self.Config.COLORS.red}GLOBAL NOTICE{self.Config.COLORS.nogc}] {gnotice_msg}") else: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"You need to specify the global notice message") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="You need to specify the global notice message") except KeyError as ke: self.Logs.error(ke) @@ -776,7 +880,7 @@ class Command(): nickname = str(cmd[1]) if self.User.get_nickname(nickname) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nickname not found !") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nickname not found !") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME") return None @@ -796,7 +900,7 @@ class Command(): chan = str(cmd[1]) if not self.Channel.Is_Channel(chan): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The channel must start with #") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} #channel") return None @@ -817,12 +921,12 @@ class Command(): chan = str(cmd[2]) if not self.Channel.Is_Channel(chan): - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"The channel must start with #") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="The channel must start with #") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") return None if self.User.get_nickname(nickname) is None: - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"Nickname not found !") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg="Nickname not found !") self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {str(cmd[0]).upper()} NICKNAME #CHANNEL") return None @@ -906,8 +1010,10 @@ class Command(): self.Logs.warning(f'Unknown Error: {str(err)}') case 'get_mode': - - self.Protocol.send2socket(f'MODE {channel}') + try: + self.Protocol.send2socket(f'MODE {fromchannel}') + except Exception as err: + self.Logs.error(f"General Error {err}") case 'svsjoin': try: @@ -927,7 +1033,7 @@ class Command(): case 'svspart': try: - # .svspart nickname #channel + # svspart nickname #channel nickname = str(cmd[1]) channel = str(cmd[2]) if len(cmd) != 3: @@ -1191,4 +1297,4 @@ class Command(): self.Logs.warning(f'Unknown Error: {str(err)}') case _: - pass \ No newline at end of file + pass diff --git a/mods/mod_defender.py b/mods/mod_defender.py index 5a41961..a0bd33d 100644 --- a/mods/mod_defender.py +++ b/mods/mod_defender.py @@ -4,10 +4,9 @@ import time import re import psutil import requests -from dataclasses import dataclass, fields, field +from dataclasses import dataclass from datetime import datetime from typing import Union, TYPE_CHECKING -from sys import exit import core.definition as df # Le module crée devra réspecter quelques conditions @@ -141,7 +140,9 @@ class Defender(): self.Base.create_thread(func=self.thread_local_scan) self.Base.create_thread(func=self.thread_psutil_scan) self.Base.create_thread(func=self.thread_reputation_timer) - self.Base.create_thread(func=self.thread_autolimit) + + if self.ModConfig.autolimit == 1: + self.Base.create_thread(func=self.thread_autolimit) if self.ModConfig.reputation == 1: self.Protocol.sjoin(self.Config.SALON_JAIL) @@ -149,7 +150,7 @@ class Defender(): return None - def __set_commands(self, commands:dict[int, list[str]]) -> None: + def __set_commands(self, commands: dict[int, list[str]]) -> None: """### Rajoute les commandes du module au programme principal Args: @@ -157,7 +158,7 @@ class Defender(): """ for level, com in commands.items(): for c in commands[level]: - if not c in self.Irc.commands: + if c not in self.Irc.commands: self.Irc.commands_level[level].append(c) self.Irc.commands.append(c) @@ -173,31 +174,15 @@ class Defender(): None: Aucun retour n'es attendu """ - table_channel = '''CREATE TABLE IF NOT EXISTS def_channels ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - datetime TEXT, - channel TEXT - ) - ''' + # table_autoop = '''CREATE TABLE IF NOT EXISTS defender_autoop ( + # id INTEGER PRIMARY KEY AUTOINCREMENT, + # datetime TEXT, + # nickname TEXT, + # channel TEXT + # ) + # ''' - table_config = '''CREATE TABLE IF NOT EXISTS def_config ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - datetime TEXT, - parameter TEXT, - value TEXT - ) - ''' - - table_trusted = '''CREATE TABLE IF NOT EXISTS def_trusted ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - datetime TEXT, - user TEXT, - host TEXT, - vhost TEXT - ) - ''' - - # self.Base.db_execute_query(table_channel) + # self.Base.db_execute_query(table_autoop) # self.Base.db_execute_query(table_config) # self.Base.db_execute_query(table_trusted) return None @@ -255,7 +240,7 @@ class Defender(): exec_query = self.Base.db_execute_query(query, {"user": nickname}) response = exec_query.fetchone() - if not response is None: + if response is not None: q_insert = "INSERT INTO def_trusted (datetime, user, host, vhost) VALUES (?, ?, ?, ?)" mes_donnees = {'datetime': self.Base.get_datetime(), 'user': nickname, 'host': '*', 'vhost': '*'} exec_query = self.Base.db_execute_query(q_insert, mes_donnees) @@ -301,7 +286,8 @@ class Defender(): # Convertir la date enregistrée dans UID_DB en un objet {datetime} connected_time_string = get_user.connexion_datetime - if type(connected_time_string) == datetime: + + if isinstance(connected_time_string, datetime): connected_time = connected_time_string else: connected_time = datetime.strptime(connected_time_string, "%Y-%m-%d %H:%M:%S.%f") @@ -386,7 +372,6 @@ class Defender(): service_id = self.Config.SERVICE_ID dchanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red - color_black = self.Config.COLORS.black nogc = self.Config.COLORS.nogc salon_jail = self.Config.SALON_JAIL @@ -480,7 +465,7 @@ class Defender(): unixtime = self.Base.get_unixtime() get_diff_secondes = 0 - if not get_detected_uid in self.flood_system: + if get_detected_uid not in self.flood_system: self.flood_system[get_detected_uid] = { 'nbr_msg': 0, 'first_msg_time': unixtime @@ -694,7 +679,7 @@ class Defender(): # Formatted output decodedResponse = json.loads(response.text) - if not 'data' in decodedResponse: + if 'data' not in decodedResponse: return None result = { @@ -707,7 +692,6 @@ class Defender(): service_id = self.Config.SERVICE_ID service_chanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red - color_black = self.Config.COLORS.black nogc = self.Config.COLORS.nogc # pseudo!ident@host @@ -780,7 +764,6 @@ class Defender(): service_id = self.Config.SERVICE_ID service_chanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red - color_black = self.Config.COLORS.black nogc = self.Config.COLORS.nogc url = f'https://freeipapi.com/api/json/{remote_ip}' @@ -797,7 +780,7 @@ class Defender(): status_code = response.status_code if status_code == 429: - self.Logs.warning(f'Too Many Requests - The rate limit for the API has been exceeded.') + self.Logs.warning('Too Many Requests - The rate limit for the API has been exceeded.') return None elif status_code != 200: self.Logs.warning(f'status code = {str(status_code)}') @@ -873,10 +856,9 @@ class Defender(): service_id = self.Config.SERVICE_ID service_chanlog = self.Config.SERVICE_CHANLOG color_red = self.Config.COLORS.red - color_black = self.Config.COLORS.black nogc = self.Config.COLORS.nogc - url = f"https://developers18334.cloudfilt.com/" + url = "https://developers18334.cloudfilt.com/" data = { 'ip': remote_ip, @@ -941,7 +923,7 @@ class Defender(): def thread_autolimit(self) -> None: if self.ModConfig.autolimit == 0: - self.Logs.debug(f"autolimit deactivated ... canceling the thread") + self.Logs.debug("autolimit deactivated ... canceling the thread") return None while self.Irc.autolimit_started: @@ -958,7 +940,7 @@ class Defender(): while self.autolimit_isRunning: if self.ModConfig.autolimit == 0: - self.Logs.debug(f"autolimit deactivated ... stopping the current thread") + self.Logs.debug("autolimit deactivated ... stopping the current thread") break for chan in self.Channel.UID_CHANNEL_DB: @@ -967,14 +949,14 @@ class Defender(): self.Protocol.send2socket(f":{self.Config.SERVICE_ID} MODE {chan.name} +l {len(chan.uids) + self.ModConfig.autolimit_amount}") chan_copy["uids_count"] = len(chan.uids) - if not chan.name in chan_list: + if chan.name not in chan_list: chan_list.append(chan.name) chanObj_copy.append({"name": chan.name, "uids_count": 0}) # Verifier si un salon a été vidé current_chan_in_list = [d.name for d in self.Channel.UID_CHANNEL_DB] for c in chan_list: - if not c in current_chan_in_list: + if c not in current_chan_in_list: chan_list.remove(c) # Si c'est la premiere execution @@ -1059,12 +1041,12 @@ class Defender(): _User = self.User.get_User(str(cmd[7])) # If user is not service or IrcOp then scan them - if not re.match(fr'^.*[S|o?].*$', _User.umodes): - self.abuseipdb_UserModel.append(_User) if self.ModConfig.abuseipdb_scan == 1 and not _User.remote_ip in self.Config.WHITELISTED_IP else None - self.freeipapi_UserModel.append(_User) if self.ModConfig.freeipapi_scan == 1 and not _User.remote_ip in self.Config.WHITELISTED_IP else None - self.cloudfilt_UserModel.append(_User) if self.ModConfig.cloudfilt_scan == 1 and not _User.remote_ip in self.Config.WHITELISTED_IP else None - self.psutil_UserModel.append(_User) if self.ModConfig.psutil_scan == 1 and not _User.remote_ip in self.Config.WHITELISTED_IP else None - self.localscan_UserModel.append(_User) if self.ModConfig.local_scan == 1 and not _User.remote_ip in self.Config.WHITELISTED_IP else None + if not re.match(r'^.*[S|o?].*$', _User.umodes): + self.abuseipdb_UserModel.append(_User) if self.ModConfig.abuseipdb_scan == 1 and _User.remote_ip not in self.Config.WHITELISTED_IP else None + self.freeipapi_UserModel.append(_User) if self.ModConfig.freeipapi_scan == 1 and _User.remote_ip not in self.Config.WHITELISTED_IP else None + self.cloudfilt_UserModel.append(_User) if self.ModConfig.cloudfilt_scan == 1 and _User.remote_ip not in self.Config.WHITELISTED_IP else None + self.psutil_UserModel.append(_User) if self.ModConfig.psutil_scan == 1 and _User.remote_ip not in self.Config.WHITELISTED_IP else None + self.localscan_UserModel.append(_User) if self.ModConfig.local_scan == 1 and _User.remote_ip not in self.Config.WHITELISTED_IP else None if _User is None: self.Logs.critical(f'This UID: [{cmd[7]}] is not available please check why') @@ -1075,9 +1057,9 @@ class Defender(): if self.Config.DEFENDER_INIT == 0: # Si le user n'es pas un service ni un IrcOP - if not re.match(fr'^.*[S|o?].*$', _User.umodes): + if not re.match(r'^.*[S|o?].*$', _User.umodes): if reputation_flag == 1 and _User.score_connexion <= reputation_seuil: - currentDateTime = self.Base.get_datetime() + # currentDateTime = self.Base.get_datetime() self.Reputation.insert( self.Loader.Definition.MReputation( **_User.__dict__, @@ -1107,7 +1089,7 @@ class Defender(): self.Protocol.send2socket(f":{service_id} MODE {parsed_chan} +b ~security-group:unknown-users") self.Protocol.send2socket(f":{service_id} MODE {parsed_chan} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") - if not get_reputation is None: + if get_reputation is not None: isWebirc = get_reputation.isWebirc if not isWebirc: @@ -1187,7 +1169,7 @@ class Defender(): get_user_reputation = self.Reputation.get_Reputation(final_UID) - if not get_user_reputation is None: + if get_user_reputation is not None: final_nickname = get_user_reputation.nickname for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_salon and ban_all_chan == 1: @@ -1522,7 +1504,7 @@ class Defender(): except ValueError as ve: self.Logs.warning(f'{ve}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f" La valeur devrait etre un entier >= 0") + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=" La valeur devrait etre un entier >= 0") case 'proxy_scan': @@ -1729,14 +1711,14 @@ class Defender(): self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_after_release ==> {self.ModConfig.reputation_score_after_release}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_ban_all_chan ==> {self.ModConfig.reputation_ban_all_chan}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' reputation_timer ==> {self.ModConfig.reputation_timer}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [Proxy_scan]') + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' [Proxy_scan]') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.local_scan == 1 else color_red}local_scan{nogc} ==> {self.ModConfig.local_scan}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.psutil_scan == 1 else color_red}psutil_scan{nogc} ==> {self.ModConfig.psutil_scan}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.abuseipdb_scan == 1 else color_red}abuseipdb_scan{nogc} ==> {self.ModConfig.abuseipdb_scan}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.freeipapi_scan == 1 else color_red}freeipapi_scan{nogc} ==> {self.ModConfig.freeipapi_scan}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' {color_green if self.ModConfig.cloudfilt_scan == 1 else color_red}cloudfilt_scan{nogc} ==> {self.ModConfig.cloudfilt_scan}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' [{color_green if self.ModConfig.flood == 1 else color_red}Flood{nogc}] ==> {self.ModConfig.flood}') - self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_action ==> Coming soon') + self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=' flood_action ==> Coming soon') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_message ==> {self.ModConfig.flood_message}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_time ==> {self.ModConfig.flood_time}') self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f' flood_timer ==> {self.ModConfig.flood_timer}') @@ -1748,7 +1730,7 @@ class Defender(): nickoruid = cmd[1] UserObject = self.User.get_User(nickoruid) - if not UserObject is None: + if UserObject is not None: channels: list = [] for chan in self.Channel.UID_CHANNEL_DB: for uid_in_chan in chan.uids: @@ -1784,10 +1766,10 @@ class Defender(): if activation == 'on': for chan in self.Channel.UID_CHANNEL_DB: - if not chan.name in channel_to_dont_quit: + if chan.name not in channel_to_dont_quit: self.Protocol.send_join_chan(uidornickname=dnickname, channel=chan.name) if activation == 'off': for chan in self.Channel.UID_CHANNEL_DB: - if not chan.name in channel_to_dont_quit: + if chan.name not in channel_to_dont_quit: self.Protocol.part(uidornickname=dnickname, channel=chan.name) self.join_saved_channels() diff --git a/mods/mod_jsonrpc.py b/mods/mod_jsonrpc.py index fe008f3..1a1d660 100644 --- a/mods/mod_jsonrpc.py +++ b/mods/mod_jsonrpc.py @@ -57,6 +57,7 @@ class Jsonrpc(): # Insert module commands into the core one (Mandatory) self.__set_commands(self.commands_level) logging.getLogger('websockets').setLevel(logging.WARNING) + logging.getLogger('unrealircd-rpc-py').setLevel(logging.CRITICAL) # Create you own tables (Mandatory) # self.__create_tables() @@ -65,13 +66,6 @@ class Jsonrpc(): self.__load_module_configuration() # End of mandatory methods you can start your customization # - # self.UnrealIrcdRpcLive: Live = Live( - # req_method='unixsocket', - # path_to_socket_file=self.Config.JSONRPC_PATH_TO_SOCKET_FILE, - # callback_object_instance=self, - # callback_method_name='callback_sent_to_irc' - # ) - self.UnrealIrcdRpcLive: Live = Live( req_method='websocket', url=self.Config.JSONRPC_URL, @@ -235,6 +229,11 @@ class Jsonrpc(): match option: case 'on': + + # for logger_name, logger in logging.root.manager.loggerDict.items(): + # if isinstance(logger, logging.Logger): + # self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"{logger_name} - {logger.level}") + for thread in self.Base.running_threads: if thread.getName() == 'thread_start_jsonrpc': if thread.is_alive(): diff --git a/version.json b/version.json index 98162f5..30e9a11 100644 --- a/version.json +++ b/version.json @@ -1,9 +1,9 @@ { - "version": "6.0.0", + "version": "6.0.1", "requests": "2.32.3", "psutil": "6.0.0", - "unrealircd_rpc_py": "1.0.6", + "unrealircd_rpc_py": "1.0.7", "sqlalchemy": "2.0.35", "faker": "30.1.0" } \ No newline at end of file