diff --git a/core/classes/admin.py b/core/classes/admin.py index 83444dd..aa4da1c 100644 --- a/core/classes/admin.py +++ b/core/classes/admin.py @@ -10,6 +10,11 @@ class Admin: def __init__(self, loader: 'Loader') -> None: self.Logs = loader.Logs + self.Base = loader.Base + self.Setting = loader.Settings + self.Config = loader.Config + self.User = loader.User + self.Definition = loader.Definition def insert(self, new_admin: MAdmin) -> bool: """Insert a new admin object model @@ -168,4 +173,31 @@ class Admin: if admin is None: return None - return admin.language \ No newline at end of file + return admin.language + + def db_auth_admin_via_fingerprint(self, fp: str, uidornickname: str) -> bool: + """Check the fingerprint + + Args: + fp (str): The unique fingerprint of the user + uidornickname (str): The UID or the Nickname of the user + + Returns: + bool: True if found + """ + query = f"SELECT user, level, language FROM {self.Config.TABLE_ADMIN} WHERE fingerprint = :fp" + data = {'fp': fp} + exe = self.Base.db_execute_query(query, data) + result = exe.fetchone() + if result: + account = result[0] + level = result[1] + language = result[2] + user_obj = self.User.get_user(uidornickname) + if user_obj: + admin_obj = self.Definition.MAdmin(**user_obj.to_dict(),account=account, level=level, language=language) + if self.insert(admin_obj): + self.Setting.current_admin = admin_obj + return True + + return False diff --git a/core/classes/protocols/unreal6.py b/core/classes/protocols/unreal6.py index 04068ea..14c7542 100644 --- a/core/classes/protocols/unreal6.py +++ b/core/classes/protocols/unreal6.py @@ -4,6 +4,8 @@ from datetime import datetime from typing import TYPE_CHECKING, Optional from ssl import SSLEOFError, SSLError +from core.utils import tr + if TYPE_CHECKING: from core.irc import Irc from core.classes.sasl import Sasl @@ -25,7 +27,7 @@ class Unrealircd6: self.known_protocol: set[str] = {'SJOIN', 'UID', 'MD', 'QUIT', 'SQUIT', 'EOS', 'PRIVMSG', 'MODE', 'UMODE2', 'VERSION', 'REPUTATION', 'SVS2MODE', - 'SLOG', 'NICK', 'PART', 'PONG', 'SASL', + 'SLOG', 'NICK', 'PART', 'PONG', 'SASL', 'PING', 'PROTOCTL', 'SERVER', 'SMOD', 'TKL', 'NETINFO', '006', '007', '018'} @@ -567,6 +569,7 @@ class Unrealircd6: def on_svs2mode(self, serverMsg: list[str]) -> None: """Handle svs2mode coming from a server + >>> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] Args: serverMsg (list[str]): Original server message @@ -604,6 +607,7 @@ class Unrealircd6: def on_umode2(self, serverMsg: list[str]) -> None: """Handle umode2 coming from a server + >>> [':adator_', 'UMODE2', '-i'] Args: serverMsg (list[str]): Original server message @@ -860,7 +864,7 @@ class Unrealircd6: # Initialisation terminé aprés le premier PING self.send_priv_msg( nick_from=self.__Config.SERVICE_NICKNAME, - msg=f"[{self.__Config.COLORS.green}INFORMATION{self.__Config.COLORS.nogc}] >> Defender is ready", + msg=tr("[ %sINFORMATION%s ] >> %s is ready!", self.__Config.COLORS.green, self.__Config.COLORS.nogc, self.__Config.SERVICE_NICKNAME), channel=self.__Config.SERVICE_CHANLOG ) self.__Config.DEFENDER_INIT = 0 @@ -946,6 +950,11 @@ class Unrealircd6: fp_match = match(pattern, serverMsg[0]) fingerprint = fp_match.group(1) if fp_match else None + # Extract tls_cipher information + pattern = r'^.*tls_cipher=([^;]+).*$' + tlsc_match = match(pattern, serverMsg[0]) + tls_cipher = tlsc_match.group(1) if tlsc_match else None + if geoip_match: geoip = geoip_match.group(1) else: @@ -963,6 +972,7 @@ class Unrealircd6: umodes=umodes, vhost=vhost, fingerprint=fingerprint, + tls_cipher=tls_cipher, isWebirc=isWebirc, isWebsocket=isWebsocket, remote_ip=remote_ip, @@ -971,6 +981,21 @@ class Unrealircd6: connexion_datetime=datetime.now() ) ) + + # Auto Auth admin via fingerprint + dnickname = self.__Config.SERVICE_NICKNAME + dchanlog = self.__Config.SERVICE_CHANLOG + GREEN = self.__Config.COLORS.green + NOGC = self.__Config.COLORS.nogc + + if self.__Irc.Admin.db_auth_admin_via_fingerprint(fingerprint, uid): + admin = self.__Irc.Admin.get_admin(uid) + account = admin.account if admin else '' + self.send_priv_msg(nick_from=dnickname, + msg=tr("[ %sSASL AUTO AUTH%s ] - %s (%s) is now connected successfuly to %s", GREEN, NOGC, nickname, account, dnickname), + channel=dchanlog) + self.send_notice(nick_from=dnickname, nick_to=nickname, msg=tr("Successfuly connected to %s", dnickname)) + return None except IndexError as ie: self.__Logs.error(f"{__name__} - Index Error: {ie}") @@ -1302,3 +1327,33 @@ class Unrealircd6: except Exception as err: self.__Logs.error(f'General Error: {err}', exc_info=True) + + def on_md(self, serverMsg: list[str]) -> None: + """Handle MD responses + [':001', 'MD', 'client', '001MYIZ03', 'certfp', ':d1235648...'] + Args: + serverMsg (list[str]): The server reply + """ + try: + scopy = serverMsg.copy() + available_vars = ['creationtime', 'certfp', 'tls_cipher'] + + uid = str(scopy[3]) + var = str(scopy[4]).lower() + value = str(scopy[5]).replace(':', '') + + user_obj = self.__Irc.User.get_user(uid) + if user_obj is None: + return None + + match var: + case 'certfp': + user_obj.fingerprint = value + case 'tls_cipher': + user_obj.tls_cipher = value + case _: + return None + + ... + except Exception as e: + self.__Logs.error(f"General Error: {e}") \ No newline at end of file diff --git a/core/definition.py b/core/definition.py index 657a01f..5e826af 100644 --- a/core/definition.py +++ b/core/definition.py @@ -31,6 +31,7 @@ class MClient(MainModel): umodes: str = None vhost: str = None fingerprint: str = None + tls_cipher: str = None isWebirc: bool = False isWebsocket: bool = False remote_ip: str = None @@ -50,6 +51,7 @@ class MUser(MainModel): umodes: str = None vhost: str = None fingerprint: str = None + tls_cipher: str = None isWebirc: bool = False isWebsocket: bool = False remote_ip: str = None @@ -70,6 +72,7 @@ class MAdmin(MainModel): umodes: str = None vhost: str = None fingerprint: str = None + tls_cipher: str = None isWebirc: bool = False isWebsocket: bool = False remote_ip: str = None diff --git a/core/irc.py b/core/irc.py index ad3c9fd..957d7aa 100644 --- a/core/irc.py +++ b/core/irc.py @@ -489,7 +489,8 @@ class Irc: return None self.Logs.debug(f">> {self.Utils.hide_sensitive_data(original_response)}") - parsed_protocol = self.Protocol.parse_server_msg(original_response.copy()) + # parsed_protocol = self.Protocol.parse_server_msg(original_response.copy()) + pos, parsed_protocol = self.Protocol.get_ircd_protocol_poisition(cmd=original_response) match parsed_protocol: case 'PING': @@ -544,7 +545,6 @@ class Irc: self.Protocol.on_protoctl(serverMsg=original_response) case 'SVS2MODE': - # >> [':00BAAAAAG', 'SVS2MODE', '001U01R03', '-r'] self.Protocol.on_svs2mode(serverMsg=original_response) case 'SQUIT': @@ -557,7 +557,6 @@ class Irc: self.Protocol.on_version_msg(serverMsg=original_response) case 'UMODE2': - # [':adator_', 'UMODE2', '-i'] self.Protocol.on_umode2(serverMsg=original_response) case 'NICK': @@ -573,15 +572,15 @@ class Irc: sasl_response = self.Protocol.on_sasl(original_response, self.Sasl) self.on_sasl_authentication_process(sasl_response) - case 'SLOG': # TODO - self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}") - - case 'MD': # TODO - self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}") + case 'MD': + self.Protocol.on_md(serverMsg=original_response) case 'PRIVMSG': self.Protocol.on_privmsg(serverMsg=original_response) + case 'SLOG': # TODO + self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}") + case 'PONG': # TODO self.Logs.debug(f"[!] TO HANDLE: {parsed_protocol}") diff --git a/core/language/fr/core-fr.yaml b/core/language/fr/core-fr.yaml index fdb01a8..d879cfb 100644 --- a/core/language/fr/core-fr.yaml +++ b/core/language/fr/core-fr.yaml @@ -6,3 +6,8 @@ traduction: trad: "%s - %sChargé%s par %s le %s" - orig: "%s - %sNot Loaded%s" trad: "%s - %sNon chargé%s" + - orig: "Successfuly connected to %s" + trad: "Connecter a %s avec succés" + - orig: "[ %sINFORMATION%s ] >> %s is ready!" + trad: "[ %sINFORMATION%s ] >> %s est prêt!" +