From 7f283d9aa2dd59d46fff4d6682459577007ba216 Mon Sep 17 00:00:00 2001 From: Giuseppe Guerra Date: Sat, 4 Aug 2018 19:16:40 +0200 Subject: [PATCH] Forbid #spect_ and #multi_ manual join from game clients --- events/tournamentJoinMatchChannelEvent.py | 2 +- events/tournamentLeaveMatchChannelEvent.py | 2 +- helpers/chatHelper.py | 25 ++++++++++++++++++---- objects/channel.py | 21 +++++++++++------- objects/osuToken.py | 12 +++++------ 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/events/tournamentJoinMatchChannelEvent.py b/events/tournamentJoinMatchChannelEvent.py index f9bcca1..bfe4c13 100644 --- a/events/tournamentJoinMatchChannelEvent.py +++ b/events/tournamentJoinMatchChannelEvent.py @@ -8,4 +8,4 @@ def handle(userToken, packetData): if matchID not in glob.matches.matches or not userToken.tournament: return userToken.matchID = matchID - chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID)) \ No newline at end of file + chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID), force=True) \ No newline at end of file diff --git a/events/tournamentLeaveMatchChannelEvent.py b/events/tournamentLeaveMatchChannelEvent.py index 981f2bb..f5c3bd3 100644 --- a/events/tournamentLeaveMatchChannelEvent.py +++ b/events/tournamentLeaveMatchChannelEvent.py @@ -7,5 +7,5 @@ def handle(userToken, packetData): matchID = packetData["matchID"] if matchID not in glob.matches.matches or not userToken.tournament: return - chat.partChannel(token=userToken, channel="#multi_{}".format(matchID)) + chat.partChannel(token=userToken, channel="#multi_{}".format(matchID), force=True) userToken.matchID = 0 \ No newline at end of file diff --git a/helpers/chatHelper.py b/helpers/chatHelper.py index 1850709..dd52ae5 100644 --- a/helpers/chatHelper.py +++ b/helpers/chatHelper.py @@ -8,7 +8,7 @@ from objects import fokabot from objects import glob -def joinChannel(userID = 0, channel = "", token = None, toIRC = True): +def joinChannel(userID = 0, channel = "", token = None, toIRC = True, force=False): """ Join a channel @@ -16,6 +16,7 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True): :param token: user token object of user that joins the channel. Optional. userID can be used instead. :param channel: channel name :param toIRC: if True, send this channel join event to IRC. Must be true if joining from bancho. Default: True + :param force: whether to allow game clients to join #spect_ and #multi_ channels :return: 0 if joined or other IRC code in case of error. Needed only on IRC-side """ try: @@ -33,8 +34,13 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True): if channel not in glob.channels.channels: raise exceptions.channelUnknownException() + # Make sure a game client is not trying to join a #multi_ or #spect_ channel manually + channelObject = glob.channels.channels[channel] + if channelObject.isSpecial and not token.irc and not force: + raise exceptions.channelUnknownException() + # Add the channel to our joined channel - token.joinChannel(glob.channels.channels[channel]) + token.joinChannel(channelObject) # Send channel joined (IRC) if glob.irc == True and toIRC == True: @@ -58,7 +64,7 @@ def joinChannel(userID = 0, channel = "", token = None, toIRC = True): log.warning("User not connected to IRC/Bancho") return 403 # idk -def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = False): +def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = False, force=False): """ Part a channel @@ -67,6 +73,7 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal :param channel: channel name :param toIRC: if True, send this channel join event to IRC. Must be true if joining from bancho. Optional. Default: True :param kick: if True, channel tab will be closed on client. Used when leaving lobby. Optional. Default: False + :param force: whether to allow game clients to part #spect_ and #multi_ channels :return: 0 if joined or other IRC code in case of error. Needed only on IRC-side """ try: @@ -103,12 +110,16 @@ def partChannel(userID = 0, channel = "", token = None, toIRC = True, kick = Fal if channel not in glob.channels.channels: raise exceptions.channelUnknownException() + # Make sure a game client is not trying to join a #multi_ or #spect_ channel manually + channelObject = glob.channels.channels[channel] + if channelObject.isSpecial and not token.irc and not force: + raise exceptions.channelUnknownException() + # Make sure the user is in the channel if channel not in token.joinedChannels: raise exceptions.userNotInChannelException() # Part channel (token-side and channel-side) - channelObject = glob.channels.channels[channel] token.partChannel(channelObject) # Delete temporary channel if everyone left @@ -220,6 +231,12 @@ def sendMessage(fro = "", to = "", message = "", token = None, toIRC = True): if glob.channels.channels[to].moderated == True and token.admin == False: raise exceptions.channelModeratedException() + # Make sure we are in the channel + if to not in token.joinedChannels: + # I'm too lazy to put and test the correct IRC error code here... + # but IRC is not strict at all so who cares + raise exceptions.channelNoPermissionsException() + # Make sure we have write permissions if glob.channels.channels[to].publicWrite == False and token.admin == False: raise exceptions.channelNoPermissionsException() diff --git a/objects/channel.py b/objects/channel.py index 2d68162..1b8a4e6 100644 --- a/objects/channel.py +++ b/objects/channel.py @@ -20,14 +20,19 @@ class channel: self.temp = temp self.hidden = hidden - # Client name (#spectator/#multiplayer) - self.clientName = self.name - if self.name.startswith("#spect_"): - self.clientName = "#spectator" - elif self.name.startswith("#multi_"): - self.clientName = "#multiplayer" - # Make Foka join the channel fokaToken = glob.tokens.getTokenFromUserID(999) if fokaToken is not None: - fokaToken.joinChannel(self) \ No newline at end of file + fokaToken.joinChannel(self) + + @property + def isSpecial(self): + return any(self.name.startswith(x) for x in ("#spect_", "#multi_")) + + @property + def clientName(self): + if self.name.startswith("#spect_"): + return "#spectator" + elif self.name.startswith("#multi_"): + return "#multiplayer" + return self.name \ No newline at end of file diff --git a/objects/osuToken.py b/objects/osuToken.py index a4b0a43..c8e8131 100644 --- a/objects/osuToken.py +++ b/objects/osuToken.py @@ -212,10 +212,10 @@ class token: # Create and join #spectator (#spect_userid) channel glob.channels.addTempChannel("#spect_{}".format(host.userID)) - chat.joinChannel(token=self, channel="#spect_{}".format(host.userID)) + chat.joinChannel(token=self, channel="#spect_{}".format(host.userID), force=True) if len(host.spectators) == 1: # First spectator, send #spectator join to host too - chat.joinChannel(token=host, channel="#spect_{}".format(host.userID)) + chat.joinChannel(token=host, channel="#spect_{}".format(host.userID), force=True) # Send fellow spectator join to all clients glob.streams.broadcast(streamName, serverPackets.fellowSpectatorJoined(self.userID)) @@ -265,14 +265,14 @@ class token: # If nobody is spectating the host anymore, close #spectator channel # and remove host from spect stream too if len(hostToken.spectators) == 0: - chat.partChannel(token=hostToken, channel="#spect_{}".format(hostToken.userID), kick=True) + chat.partChannel(token=hostToken, channel="#spect_{}".format(hostToken.userID), kick=True, force=True) hostToken.leaveStream(streamName) # Console output log.info("{} is no longer spectating {}. Current spectators: {}".format(self.username, self.spectatingUserID, hostToken.spectators)) # Part #spectator channel - chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True) + chat.partChannel(token=self, channel="#spect_{}".format(self.spectatingUserID), kick=True, force=True) # Set our spectating user to 0 self.spectating = None @@ -318,7 +318,7 @@ class token: # Set matchID, join stream, channel and send packet self.matchID = matchID self.joinStream(match.streamName) - chat.joinChannel(token=self, channel="#multi_{}".format(self.matchID)) + chat.joinChannel(token=self, channel="#multi_{}".format(self.matchID), force=True) self.enqueue(serverPackets.matchJoinSuccess(matchID)) if match.isTourney: @@ -339,7 +339,7 @@ class token: return # Part #multiplayer channel and streams (/ and /playing) - chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True) + chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True, force=True) self.leaveStream("multi/{}".format(self.matchID)) self.leaveStream("multi/{}/playing".format(self.matchID)) # optional