diff --git a/core/Model.py b/core/Model.py index 946435c..f7b2dca 100644 --- a/core/Model.py +++ b/core/Model.py @@ -10,10 +10,12 @@ class User: uid: str nickname: str username: str + realname: str hostname: str umodes: str vhost: str isWebirc: bool + isWebsocket: bool remote_ip: str score_connexion: int connexion_datetime: datetime = field(default=datetime.now()) @@ -410,6 +412,8 @@ class Clones: alive: bool nickname: str username: str + realname: str + connected: bool = False UID_CLONE_DB: list[CloneModel] = [] diff --git a/core/connection.py b/core/connection.py index 0b403d4..23de602 100644 --- a/core/connection.py +++ b/core/connection.py @@ -7,13 +7,15 @@ from typing import Union class Connection: - def __init__(self, server_port: int, nickname: str, username: str, channels:list[str], CloneObject: Clones, ssl:bool = False) -> None: + def __init__(self, server_port: int, nickname: str, username: str, realname: str, channels:list[str], CloneObject: Clones, ssl:bool = False) -> None: self.Config = Config().ConfigObject self.Base = Base(self.Config) self.IrcSocket: Union[socket.socket, SSLSocket] = None self.nickname = nickname self.username = username + self.realname = realname + self.chanlog = '#clones' self.channels:list[str] = channels self.CHARSET = ['utf-8', 'iso-8859-1'] self.Clones = CloneObject @@ -97,10 +99,11 @@ class Connection: try: nickname = self.nickname username = self.username + realname = self.realname # Envoyer un message d'identification writer.send(f"USER {nickname} {username} {username} {nickname} {username} :{username}\r\n".encode('utf-8')) - writer.send(f"USER {username} {username} {username} :{username}\r\n".encode('utf-8')) + writer.send(f"USER {username} {username} {username} :{realname}\r\n".encode('utf-8')) writer.send(f"NICK {nickname}\r\n".encode('utf-8')) self.Base.logs.debug('Link information sent to the server') @@ -162,6 +165,7 @@ class Connection: for data in cmd: response = data.decode(self.CHARSET[0]).split() self.signal = self.currentCloneObject.alive + current_clone_nickname = self.currentCloneObject.nickname # print(response) match response[0]: @@ -176,6 +180,7 @@ class Connection: match response[1]: case '376': + self.currentCloneObject.connected = True for channel in self.channels: self.send2socket(f"JOIN {channel}") return None @@ -184,6 +189,14 @@ class Connection: self.Base.logs.debug(f'{self.currentCloneObject.nickname} - {self.currentCloneObject.alive}') fullname = str(response[0]).replace(':', '') nickname = fullname.split('!')[0].replace(':','') + + if response[2] == current_clone_nickname: + message = [] + for i in range(3, len(response)): + message.append(response[i]) + final_message = ' '.join(message) + self.send2socket(f"PRIVMSG {self.chanlog} :{fullname} => {final_message[1:]}") + if nickname == self.Config.SERVICE_NICKNAME: command = str(response[3]).replace(':','') diff --git a/core/irc.py b/core/irc.py index 2e7e80e..3703010 100644 --- a/core/irc.py +++ b/core/irc.py @@ -816,10 +816,9 @@ class Irc: # ['@s2s-md/geoip=cc=GB|cd=United\\sKingdom|asn=16276|asname=OVH\\sSAS;s2s-md/tls_cipher=TLSv1.3-TLS_CHACHA20_POLY1305_SHA256;s2s-md/creationtime=1721564601', # ':001', 'UID', 'albatros', '0', '1721564597', 'albatros', 'vps-91b2f28b.vps.ovh.net', # '001HB8G04', '0', '+iwxz', 'Clk-A62F1D18.vps.ovh.net', 'Clk-A62F1D18.vps.ovh.net', 'MyZBwg==', ':...'] - if 'webirc' in original_response[0]: - isWebirc = True - else: - isWebirc = False + + isWebirc = True if 'webirc' in original_response[0] else False + isWebsocket = True if 'websocket' in original_response[0] else False uid = str(original_response[8]) nickname = str(original_response[3]) @@ -832,6 +831,13 @@ class Irc: else: remote_ip = '127.0.0.1' + # extract realname + realname_list = [] + for i in range(14, len(original_response)): + realname_list.append(original_response[i]) + + realname = ' '.join(realname_list)[1:] + score_connexion = self.first_score self.User.insert( @@ -839,10 +845,12 @@ class Irc: uid=uid, nickname=nickname, username=username, + realname=realname, hostname=hostname, umodes=umodes, vhost=vhost, isWebirc=isWebirc, + isWebsocket=isWebsocket, remote_ip=remote_ip, score_connexion=score_connexion, connexion_datetime=datetime.now() @@ -1342,7 +1350,7 @@ class Irc: case 'show_users': for db_user in self.User.UID_DB: - self.send2socket(f":{dnickname} NOTICE {fromuser} :UID : {db_user.uid} - isWebirc: {db_user.isWebirc} - Nickname: {db_user.nickname} - Connection: {db_user.connexion_datetime}") + self.send2socket(f":{dnickname} NOTICE {fromuser} :UID : {db_user.uid} - isWebirc: {db_user.isWebirc} - isWebSocket: {db_user.isWebsocket} - Nickname: {db_user.nickname} - Connection: {db_user.connexion_datetime}") case 'show_admins': for db_admin in self.Admin.UID_ADMIN_DB: diff --git a/mods/mod_clone.py b/mods/mod_clone.py index 9da948f..8d265b8 100644 --- a/mods/mod_clone.py +++ b/mods/mod_clone.py @@ -122,9 +122,25 @@ class Clone(): return None - def thread_create_clones(self, nickname: str, username: str, channels: list, server_port: int, ssl: bool) -> None: + def thread_change_hostname(self): - Connection(server_port=server_port, nickname=nickname, username=username, channels=channels, CloneObject=self.Clone, ssl=ssl) + fake = faker.Faker('en_GB') + for clone in self.Clone.UID_CLONE_DB: + rand_1 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) + rand_2 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) + rand_3 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8) + + rand_ip = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP' + if clone.connected: + self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} CHGHOST {clone.nickname} {rand_ip}') + + while not clone.connected: + if clone.connected: + self.Irc.send2socket(f':{self.Config.SERVICE_NICKNAME} CHGHOST {clone.nickname} {rand_ip}') + + def thread_create_clones(self, nickname: str, username: str, realname: str, channels: list, server_port: int, ssl: bool) -> None: + + Connection(server_port=server_port, nickname=nickname, username=username, realname=realname, channels=channels, CloneObject=self.Clone, ssl=ssl) return None @@ -144,30 +160,34 @@ class Clone(): try: fake = faker.Faker('en_GB') nickname = fake.first_name() - username = fake.last_name() - hostname = fake.domain_name(3) + # username = fake.last_name() + + # Generate Username + chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + new_username = fake.random_sample(chaine, 9) + username = ''.join(new_username) + + # Create realname XX F|M Department + gender = fake.random_choices(['F','M'], 1) + gender = ''.join(gender) + age = random.randint(20, 60) + fake_fr = faker.Faker(['fr_FR', 'en_GB']) + department = fake_fr.department_name() + realname = f'{age} {gender} {department}' if self.Clone.exists(nickname=nickname): caracteres = '0123456789' randomize = ''.join(random.choice(caracteres) for _ in range(2)) nickname = nickname + str(randomize) self.Clone.insert( - self.Clone.CloneModel(alive=True, nickname=nickname, username=username) + self.Clone.CloneModel(alive=True, nickname=nickname, username=username, realname=realname) ) else: self.Clone.insert( - self.Clone.CloneModel(alive=True, nickname=nickname, username=username) + self.Clone.CloneModel(alive=True, nickname=nickname, username=username, realname=realname) ) - # if not nickname in self.ModConfig.clone_nicknames: - # self.ModConfig.clone_nicknames.append(nickname) - # else: - # caracteres = '0123456789' - # randomize = ''.join(random.choice(caracteres) for _ in range(2)) - # nickname = nickname + str(randomize) - # self.ModConfig.clone_nicknames.append(nickname) - - return (nickname, username, hostname) + return (nickname, username, realname) except AttributeError as ae: self.Logs.error(f'Attribute Error : {ae}') @@ -189,131 +209,129 @@ class Clone(): def _hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None: - command = str(cmd[0]).lower() - fromuser = user + try: + command = str(cmd[0]).lower() + fromuser = user - dnickname = self.Config.SERVICE_NICKNAME # Defender nickname + dnickname = self.Config.SERVICE_NICKNAME # Defender nickname - match command: + match command: - case 'clone': - option = str(cmd[1]).lower() + case 'clone': - if len(command) == 1: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone shadow') - - match option: - - case 'shadow': - try: - fake = faker.Faker('en_GB') - for clone in self.Clone.UID_CLONE_DB: - hostname = fake.domain_name(3) - self.Irc.send2socket(f':{dnickname} CHGHOST {clone.nickname} {hostname}') - - except Exception as err: - self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone shadow') - - case 'connect': - try: - number_of_clones = int(cmd[2]) - for i in range(number_of_clones): - nickname, username, hostname = self.generate_names() - self.Base.create_thread( - self.thread_create_clones, - (nickname, username, [], 6697, True) - ) - - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{str(number_of_clones)} clones joined the network') - - except Exception as err: - self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect [number of clone you want to connect]') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} clone connect 6') - - case 'kill': - try: - # clone kill [all | nickname] - clone_name = str(cmd[2]) - clone_to_kill: list[str] = [] - - if clone_name.lower() == 'all': - for clone in self.Clone.UID_CLONE_DB: - self.Irc.send2socket(f':{dnickname} PRIVMSG {clone.nickname} :KILL') - clone_to_kill.append(clone.nickname) - clone.alive = False - - for clone_nickname in clone_to_kill: - self.Clone.delete(clone_nickname) - - del clone_to_kill - - else: - if self.Clone.exists(clone_name): - self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :KILL') - self.Clone.kill(clone_name) - self.Clone.delete(clone_name) - - except Exception as err: - self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill all') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill clone_nickname') - - case 'join': - try: - # clone join [all | nickname] #channel - clone_name = str(cmd[2]) - clone_channel_to_join = str(cmd[3]) - - if clone_name.lower() == 'all': - self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2)) - else: - self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2, clone_name)) - - except Exception as err: - self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join all #channel') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join clone_nickname #channel') - - case 'list': - try: - for clone_name in self.Clone.UID_CLONE_DB: - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :>> {clone_name.nickname} | {clone_name.username}') - pass - except Exception as err: - self.Logs.error(f'{err}') - - case 'say': - try: - # clone say clone_nickname #channel message - clone_name = str(cmd[2]) - clone_channel = str(cmd[3]) if self.Base.Is_Channel(str(cmd[3])) else None - - message = [] - for i in range(4, len(cmd)): - message.append(cmd[i]) - final_message = ' '.join(message) - - if clone_channel is None or not self.Clone.exists(clone_name): - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message') - return None - - if self.Clone.exists(clone_name): - self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :SAY {clone_channel} {final_message}') - - except Exception as err: - self.Logs.error(f'{err}') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message') - - case _: + if len(cmd) == 1: self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel [message]') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list') - self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone shadow') + + option = str(cmd[1]).lower() + + match option: + + case 'connect': + try: + number_of_clones = int(cmd[2]) + for i in range(number_of_clones): + nickname, username, realname = self.generate_names() + self.Base.create_thread( + self.thread_create_clones, + (nickname, username, realname, ['#clones'], 6697, True) + ) + + self.Base.create_thread( + self.thread_change_hostname, + run_once=True + ) + + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :{str(number_of_clones)} clones joined the network') + + except Exception as err: + self.Logs.error(f'{err}') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect [number of clone you want to connect]') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :Exemple /msg {dnickname} clone connect 6') + + case 'kill': + try: + # clone kill [all | nickname] + clone_name = str(cmd[2]) + clone_to_kill: list[str] = [] + + if clone_name.lower() == 'all': + for clone in self.Clone.UID_CLONE_DB: + self.Irc.send2socket(f':{dnickname} PRIVMSG {clone.nickname} :KILL') + clone_to_kill.append(clone.nickname) + clone.alive = False + + for clone_nickname in clone_to_kill: + self.Clone.delete(clone_nickname) + + del clone_to_kill + + else: + if self.Clone.exists(clone_name): + self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :KILL') + self.Clone.kill(clone_name) + self.Clone.delete(clone_name) + + except Exception as err: + self.Logs.error(f'{err}') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill all') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill clone_nickname') + + case 'join': + try: + # clone join [all | nickname] #channel + clone_name = str(cmd[2]) + clone_channel_to_join = str(cmd[3]) + + if clone_name.lower() == 'all': + self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2)) + else: + self.Base.create_thread(self.thread_join_channels, (clone_channel_to_join, 2, clone_name)) + + except Exception as err: + self.Logs.error(f'{err}') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join all #channel') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join clone_nickname #channel') + + case 'list': + try: + for clone_name in self.Clone.UID_CLONE_DB: + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :>> {clone_name.nickname} | {clone_name.username}') + pass + except Exception as err: + self.Logs.error(f'{err}') + + case 'say': + try: + # clone say clone_nickname #channel message + clone_name = str(cmd[2]) + clone_channel = str(cmd[3]) if self.Base.Is_Channel(str(cmd[3])) else None + + message = [] + for i in range(4, len(cmd)): + message.append(cmd[i]) + final_message = ' '.join(message) + + if clone_channel is None or not self.Clone.exists(clone_name): + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message') + return None + + if self.Clone.exists(clone_name): + self.Irc.send2socket(f':{dnickname} PRIVMSG {clone_name} :SAY {clone_channel} {final_message}') + + except Exception as err: + self.Logs.error(f'{err}') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel message') + + case _: + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone connect 6') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone kill [all | nickname]') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone join [all | nickname] #channel') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone say [clone_nickname] #channel [message]') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} clone list') + except IndexError as ie: + self.Logs.error(f'Index Error: {ie}') + except Exception as err: + self.Logs.error(f'Index Error: {err}') diff --git a/mods/mod_defender.py b/mods/mod_defender.py index 06e5400..7abf92c 100644 --- a/mods/mod_defender.py +++ b/mods/mod_defender.py @@ -44,11 +44,13 @@ class Defender(): nickname: str username: str hostname: str + realname: str umodes: str vhost: str ip: str score: int isWebirc: bool + isWebsocket: bool secret_code: str connected_datetime: str updated_datetime: str @@ -611,13 +613,14 @@ class Defender(): """local_scan Args: - remote_ip (str): _description_ + userModel (UserModel): _description_ """ User = userModel remote_ip = User.remote_ip username = User.username hostname = User.hostname nickname = User.nickname + fullname = f'{nickname}!{username}@{hostname}' if remote_ip in self.Config.WHITELISTED_IP: return None @@ -631,14 +634,13 @@ class Defender(): connection = (remote_ip, self.Base.int_if_possible(port)) newSocket.connect(connection) - fullname = f'{nickname}!{username}@{hostname}' - self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.CONFIG_COLOR['rouge']}PROXY_SCAN{self.Config.CONFIG_COLOR['noire']} ] {fullname} ({remote_ip}) : Port [{str(port)}] ouvert sur l'adresse ip [{remote_ip}]") # print(f"=======> Le port {str(port)} est ouvert !!") self.Base.running_sockets.append(newSocket) # print(newSocket) newSocket.shutdown(socket.SHUT_RDWR) newSocket.close() + except (socket.timeout, ConnectionRefusedError): self.Logs.info(f"Le port {remote_ip}:{str(port)} est fermé") except AttributeError as ae: @@ -670,10 +672,10 @@ class Defender(): self.Logs.warning(f"thread_local_scan Error : {ve}") def get_ports_connexion(self, userModel: User.UserModel) -> list[int]: - """psutil_scan for Linux + """psutil_scan for Linux (should be run on the same location as the unrealircd server) Args: - remote_ip (str): The remote ip address + userModel (UserModel): The User Model Object Returns: list[int]: list of ports @@ -694,6 +696,9 @@ class Defender(): matching_ports = [conn.raddr.port for conn in connections if conn.raddr and conn.raddr.ip == remote_ip] self.Logs.info(f"Connexion of {fullname} ({remote_ip}) using ports : {str(matching_ports)}") + if matching_ports: + self.Irc.send2socket(f":{self.Config.SERVICE_NICKNAME} PRIVMSG {self.Config.SERVICE_CHANLOG} :[ {self.Config.CONFIG_COLOR['rouge']}PROXY_SCAN{self.Config.CONFIG_COLOR['noire']} ] {fullname} ({remote_ip}) : is using ports {matching_ports}") + return matching_ports except psutil.AccessDenied as ad: @@ -1061,9 +1066,9 @@ class Defender(): currentDateTime = self.Base.get_datetime() self.reputation_insert( self.ReputationModel( - uid=_User.uid, nickname=_User.nickname, username=_User.username, hostname=_User.hostname, - umodes=_User.umodes, vhost=_User.vhost, ip=_User.remote_ip, score=_User.score_connexion, - secret_code=self.Base.get_random(8), isWebirc=_User.isWebirc, connected_datetime=currentDateTime, + uid=_User.uid, nickname=_User.nickname, username=_User.username, realname=_User.realname, + hostname=_User.hostname, umodes=_User.umodes, vhost=_User.vhost, ip=_User.remote_ip, score=_User.score_connexion, + secret_code=self.Base.get_random(8), isWebirc=_User.isWebirc, isWebsocket=_User.isWebsocket, connected_datetime=currentDateTime, updated_datetime=currentDateTime ) ) @@ -1086,6 +1091,9 @@ class Defender(): get_reputation = self.reputation_get_Reputation(parsed_UID) + self.Irc.send2socket(f":{service_id} MODE {parsed_chan} +b ~security-group:unknown-users") + self.Irc.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: isWebirc = get_reputation.isWebirc @@ -1285,9 +1293,7 @@ class Defender(): for chan in self.Channel.UID_CHANNEL_DB: if chan.name != jail_chan: self.Irc.send2socket(f":{service_id} MODE {chan.name} +b ~security-group:unknown-users") - self.Irc.send2socket(f":{service_id} MODE {chan.name} +e ~security-group:webirc-users") - self.Irc.send2socket(f":{service_id} MODE {chan.name} +e ~security-group:known-users") - self.Irc.send2socket(f":{service_id} MODE {chan.name} +e ~security-group:websocket-users") + self.Irc.send2socket(f":{service_id} MODE {chan.name} +eee ~security-group:webirc-users ~security-group:known-users ~security-group:websocket-users") self.Base.db_query_channel('add', self.module_name, jail_chan) @@ -1623,10 +1629,12 @@ class Defender(): self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : UID : {UserObject.uid}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : NICKNAME : {UserObject.nickname}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : USERNAME : {UserObject.username}') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : REALNAME : {UserObject.realname}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : HOSTNAME : {UserObject.hostname}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : VHOST : {UserObject.vhost}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : IP : {UserObject.remote_ip}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : WebIrc : {UserObject.isWebirc}') + self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : WebWebsocket : {UserObject.isWebsocket}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : REPUTATION : {UserObject.score_connexion}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : MODES : {UserObject.umodes}') self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} : CONNECTION TIME : {UserObject.connexion_datetime}') diff --git a/version.json b/version.json index f4ad94a..dd07759 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "5.2.1" + "version": "5.2.2" } \ No newline at end of file