diff --git a/constants/exceptions.py b/constants/exceptions.py
index e9967af..e353197 100644
--- a/constants/exceptions.py
+++ b/constants/exceptions.py
@@ -77,3 +77,6 @@ class need2FAException(Exception):
class userRestrictedException(Exception):
pass
+
+class haxException(Exception):
+ pass
diff --git a/constants/fokabotCommands.py b/constants/fokabotCommands.py
index 398b024..3fb1216 100644
--- a/constants/fokabotCommands.py
+++ b/constants/fokabotCommands.py
@@ -127,7 +127,7 @@ def kick(fro, chan, message):
def fokabotReconnect(fro, chan, message):
# Check if fokabot is already connected
if glob.tokens.getTokenFromUserID(999) != None:
- return"Fokabot is already connected to Bancho"
+ return "Fokabot is already connected to Bancho"
# Fokabot is not connected, connect it
fokabot.connect()
diff --git a/constants/serverPackets.py b/constants/serverPackets.py
index b1e0a0e..13ac0cf 100644
--- a/constants/serverPackets.py
+++ b/constants/serverPackets.py
@@ -130,16 +130,9 @@ def userStats(userID, force = False):
# Get userID's token from tokens list
userToken = glob.tokens.getTokenFromUserID(userID)
if userToken == None:
- return bytes() # NOTE: ???
- if userToken.restricted == True and force == False:
return bytes()
- # Stats are cached in token object
- #rankedScore = userHelper.getRankedScore(userID, userToken.gameMode)
- #accuracy = userHelper.getAccuracy(userID, userToken.gameMode)/100
- #playcount = userHelper.getPlaycount(userID, userToken.gameMode)
- #totalScore = userHelper.getTotalScore(userID, userToken.gameMode)
- #gameRank = userHelper.getGameRank(userID, userToken.gameMode)
- #pp = int(userHelper.getPP(userID, userToken.gameMode))
+ if (userToken.restricted == True or userToken.irc == True) and force == False:
+ return bytes()
return packetHelper.buildPacket(packetIDs.server_userStats,
[
[userID, dataTypes.uInt32],
diff --git a/events/changeActionEvent.py b/events/changeActionEvent.py
index 1c1dde0..dbf5e47 100644
--- a/events/changeActionEvent.py
+++ b/events/changeActionEvent.py
@@ -4,6 +4,7 @@ from constants import serverPackets
from helpers import userHelper
from helpers import logHelper as log
from constants import actions
+from helpers import chatHelper as chat
def handle(userToken, packetData):
# Get usertoken data
@@ -58,7 +59,7 @@ def handle(userToken, packetData):
# NOTE: Remove this when osu!direct will be fixed
if userToken.actionID == actions.osuDirect and userToken.osuDirectAlert == False:
userToken.osuDirectAlert = True
- userToken.enqueue(serverPackets.sendMessage("FokaBot", userToken.username, "Sup! osu!direct works, but you'll need to update the switcher to have the Download button working. If you didn't update the switcher yet, please do!"))
+ chat.sendMessage("FokaBot", userToken.username, "Sup! osu!direct works, but you'll need to update the switcher to have the Download button working. If you didn't update the switcher yet, please do!")
# Console output
diff --git a/events/channelJoinEvent.py b/events/channelJoinEvent.py
index fc14b4c..a0a2053 100644
--- a/events/channelJoinEvent.py
+++ b/events/channelJoinEvent.py
@@ -1,56 +1,7 @@
-"""
-Event called when someone joins a channel
-"""
-
from constants import clientPackets
-from helpers import consoleHelper
-from constants import bcolors
-from constants import serverPackets
-from objects import glob
-from constants import exceptions
-from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(userToken, packetData):
# Channel join packet
packetData = clientPackets.channelJoin(packetData)
- joinChannel(userToken, packetData["channel"])
-
-def joinChannel(userToken, channelName):
- '''
- Join a channel
-
- userToken -- user token object of user that joins the chanlle
- channelName -- name of channel
- '''
- try:
- # Get usertoken data
- username = userToken.username
- userID = userToken.userID
-
- # Check spectator channel
- # If it's spectator channel, skip checks and list stuff
- if channelName != "#spectator" and channelName != "#multiplayer":
- # Normal channel, do check stuff
- # Make sure the channel exists
- if channelName not in glob.channels.channels:
- raise exceptions.channelUnknownException
-
- # Check channel permissions
- if glob.channels.channels[channelName].publicRead == False and userToken.admin == False:
- raise exceptions.channelNoPermissionsException
-
- # Add our userID to users in that channel
- glob.channels.channels[channelName].userJoin(userID)
-
- # Add the channel to our joined channel
- userToken.joinChannel(channelName)
-
- # Send channel joined
- userToken.enqueue(serverPackets.channelJoinSuccess(userID, channelName))
-
- # Console output
- log.info("{} joined channel {}".format(username, channelName))
- except exceptions.channelNoPermissionsException:
- log.warning("{} attempted to join channel {}, but they have no read permissions".format(username, channelName))
- except exceptions.channelUnknownException:
- log.warning("{} attempted to join an unknown channel ({})".format(username, channelName))
+ chat.joinChannel(token=userToken, channel=packetData["channel"])
diff --git a/events/channelPartEvent.py b/events/channelPartEvent.py
index 11d1ad3..845ed01 100644
--- a/events/channelPartEvent.py
+++ b/events/channelPartEvent.py
@@ -8,13 +8,14 @@ from objects import glob
from constants import clientPackets
from constants import serverPackets
from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(userToken, packetData):
- # Channel part packet
+ # Channel join packet
packetData = clientPackets.channelPart(packetData)
- partChannel(userToken, packetData["channel"])
+ chat.partChannel(token=userToken, channel=packetData["channel"])
-def partChannel(userToken, channelName, kick = False):
+"""def partChannel(userToken, channelName, kick = False):
# Get usertoken data
username = userToken.username
userID = userToken.userID
@@ -34,4 +35,4 @@ def partChannel(userToken, channelName, kick = False):
userToken.enqueue(serverPackets.channelKicked(channelName))
# Console output
- log.info("{} parted channel {}".format(username, channelName))
+ log.info("{} parted channel {}".format(username, channelName))"""
diff --git a/events/joinMatchEvent.py b/events/joinMatchEvent.py
index 4ff0e42..6f75519 100644
--- a/events/joinMatchEvent.py
+++ b/events/joinMatchEvent.py
@@ -3,6 +3,7 @@ from constants import serverPackets
from objects import glob
from constants import exceptions
from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(userToken, packetData):
# read packet data
@@ -44,8 +45,7 @@ def joinMatch(userToken, matchID, password):
# Send packets
userToken.enqueue(serverPackets.matchJoinSuccess(matchID))
- userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#multiplayer"))
- #userToken.enqueue(serverPackets.sendMessage("FokaBot", "#multiplayer", "Hi {}, and welcome to Ripple's multiplayer mode! This feature is still WIP and might have some issues. If you find any bugs, please report them (by clicking here)[https://ripple.moe/index.php?p=22].".format(username)))
+ chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID))
except exceptions.matchNotFoundException:
userToken.enqueue(serverPackets.matchJoinFail())
log.warning("{} has tried to join a mp room, but it doesn't exist".format(userToken.username))
diff --git a/events/loginEvent.py b/events/loginEvent.py
index 7d83253..7115a52 100644
--- a/events/loginEvent.py
+++ b/events/loginEvent.py
@@ -8,12 +8,12 @@ from helpers import locationHelper
from helpers import countryHelper
import time
from helpers import generalFunctions
-from events import channelJoinEvent
import sys
import traceback
from helpers import requestHelper
from helpers import discordBotHelper
from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(tornadoRequest):
# Data to return
@@ -30,6 +30,10 @@ def handle(tornadoRequest):
# If true, print error to console
err = False
+ # Make sure loginData is valid
+ if len(loginData) < 3:
+ raise exceptions.haxException()
+
# Try to get the ID from username
username = str(loginData[0])
userID = userHelper.getID(username)
@@ -59,6 +63,9 @@ def handle(tornadoRequest):
responseToken = glob.tokens.addToken(userID, requestIP)
responseTokenString = responseToken.token
+ # Check restricted mode (and eventually send message)
+ responseToken.checkRestricted()
+
# Set silence end UNIX time in token
responseToken.silenceEndTime = userHelper.getSilenceEnd(userID)
@@ -101,12 +108,12 @@ def handle(tornadoRequest):
responseToken.enqueue(serverPackets.channelInfoEnd())
# Default opened channels
# TODO: Configurable default channels
- channelJoinEvent.joinChannel(responseToken, "#osu")
- channelJoinEvent.joinChannel(responseToken, "#announce")
+ chat.joinChannel(token=responseToken, channel="#osu")
+ chat.joinChannel(token=responseToken, channel="#announce")
# Join admin channel if we are an admin
if responseToken.admin == True:
- channelJoinEvent.joinChannel(responseToken, "#admin")
+ chat.joinChannel(token=responseToken, channel="#admin")
# Output channels info
for key, value in glob.channels.channels.items():
@@ -156,6 +163,12 @@ def handle(tornadoRequest):
# (we don't use enqueue because we don't have a token since login has failed)
err = True
responseData += serverPackets.loginFailed()
+ except exceptions.haxException:
+ # Invalid POST data
+ # (we don't use enqueue because we don't have a token since login has failed)
+ err = True
+ responseData += serverPackets.loginFailed()
+ responseData += serverPackets.notification("I see what you're doing...")
except exceptions.loginBannedException:
# Login banned error packet
err = True
@@ -172,9 +185,14 @@ def handle(tornadoRequest):
except exceptions.need2FAException:
# User tried to log in from unknown IP
responseData += serverPackets.needVerification()
+ except:
+ log.error("Unknown error!\n```\n{}\n{}```".format(sys.exc_info(), traceback.format_exc()))
finally:
# Console and discord log
- msg = "Bancho login request from {} for user {} ({})".format(requestIP, loginData[0], "failed" if err == True else "success")
+ if len(loginData) < 3:
+ msg = "Invalid bancho login request from **{}** (insufficient POST data)".format(requestIP)
+ else:
+ msg = "Bancho login request from **{}** for user **{}** ({}) **({})**".format(requestIP, loginData[0], loginData[2], "failed" if err == True else "success")
log.info(msg, True)
# Return token string and data
diff --git a/events/logoutEvent.py b/events/logoutEvent.py
index ef71beb..2666f57 100644
--- a/events/logoutEvent.py
+++ b/events/logoutEvent.py
@@ -4,8 +4,9 @@ from constants import bcolors
from constants import serverPackets
import time
from helpers import logHelper as log
+from helpers import chatHelper as chat
-def handle(userToken, _):
+def handle(userToken, _=None):
# get usertoken data
userID = userToken.userID
username = userToken.username
@@ -15,8 +16,9 @@ def handle(userToken, _):
# the old logout packet will still be in the queue and will be sent to
# the server, so we accept logout packets sent at least 5 seconds after login
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
- if int(time.time()-userToken.loginTime) >= 5:
+ if int(time.time()-userToken.loginTime) >= 5 or userToken.irc == True:
# Stop spectating if needed
+ # TODO: Call stopSpectatingEvent!!!!!!!!!
if userToken.spectating != 0:
# The user was spectating someone
spectatorHostToken = glob.tokens.getTokenFromUserID(userToken.spectating)
@@ -26,13 +28,17 @@ def handle(userToken, _):
# Part all joined channels
for i in userToken.joinedChannels:
- glob.channels.channels[i].userPart(userID)
+ chat.partChannel(token=userToken, channel=i)
# TODO: Lobby left if joined
# Enqueue our disconnection to everyone else
glob.tokens.enqueueAll(serverPackets.userLogout(userID))
+ # Disconnect from IRC if needed
+ if userToken.irc == True and glob.irc == True:
+ glob.ircServer.forceDisconnection(userToken.username)
+
# Delete token
glob.tokens.deleteToken(requestToken)
diff --git a/events/partLobbyEvent.py b/events/partLobbyEvent.py
index 768f32c..e66224e 100644
--- a/events/partLobbyEvent.py
+++ b/events/partLobbyEvent.py
@@ -1,6 +1,7 @@
from objects import glob
from events import channelPartEvent
from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(userToken, _):
# Get usertoken data
@@ -11,7 +12,7 @@ def handle(userToken, _):
glob.matches.lobbyUserPart(userID)
# Part lobby channel
- channelPartEvent.partChannel(userToken, "#lobby", True)
+ chat.partChannel(channel="#lobby", token=userToken, kick=True)
# Console output
log.info("{} has left multiplayer lobby".format(username))
diff --git a/events/partMatchEvent.py b/events/partMatchEvent.py
index e02036b..933c7ba 100644
--- a/events/partMatchEvent.py
+++ b/events/partMatchEvent.py
@@ -1,4 +1,5 @@
from objects import glob
+from helpers import chatHelper as chat
from constants import serverPackets
def handle(userToken, _):
@@ -22,6 +23,8 @@ def handle(userToken, _):
# Set slot to free
match.userLeft(userID)
+ # Part #multiplayer channel
+ chat.partChannel(token=userToken, channel="#multi_{}".format(matchID))
+
# Set usertoken match to -1
userToken.partMatch()
- userToken.enqueue(serverPackets.channelKicked("#multiplayer"))
diff --git a/events/sendPrivateMessageEvent.py b/events/sendPrivateMessageEvent.py
index 3e34a3e..98eee35 100644
--- a/events/sendPrivateMessageEvent.py
+++ b/events/sendPrivateMessageEvent.py
@@ -1,79 +1,7 @@
-from helpers import consoleHelper
-from constants import bcolors
from constants import clientPackets
-from constants import serverPackets
-from objects import glob
-from objects import fokabot
-from constants import exceptions
-from constants import messageTemplates
-from helpers import generalFunctions
-from helpers import userHelper
-from helpers import logHelper as log
-import time
+from helpers import chatHelper as chat
def handle(userToken, packetData):
- """
- Event called when someone sends a private message
-
- userToken -- request user token
- packetData -- request data bytes
- """
-
- try:
- # Get usertoken username
- username = userToken.username
- userID = userToken.userID
-
- # Make sure the user is not in restricted mode
- if userToken.restricted == True:
- raise exceptions.userRestrictedException
-
- # Private message packet
- packetData = clientPackets.sendPrivateMessage(packetData)
-
- # Make sure the user is not silenced
- if userToken.isSilenced() == True:
- raise exceptions.userSilencedException
-
- # Check message length
- packetData["message"] = packetData["message"][:2048]+"..." if len(packetData["message"]) > 2048 else packetData["message"]
-
- if packetData["to"] == "FokaBot":
- # FokaBot command check
- fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"])
- if fokaMessage != False:
- userToken.enqueue(serverPackets.sendMessage("FokaBot", username, fokaMessage))
- log.pm("FokaBot -> {}: {}".format(packetData["to"], str(fokaMessage.encode("UTF-8"))))
- else:
- # Send packet message to target if it exists
- token = glob.tokens.getTokenFromUsername(packetData["to"])
- if token == None:
- raise exceptions.tokenNotFoundException()
-
- # Check message templates (mods/admins only)
- if packetData["message"] in messageTemplates.templates and userToken.admin == True:
- packetData["message"] = messageTemplates.templates[packetData["message"]]
-
- # Send message to target
- token.enqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]))
-
- # Send away message to sender if needed
- if token.awayMessage != "":
- userToken.enqueue(serverPackets.sendMessage(packetData["to"], username, "This user is away: {}".format(token.awayMessage)))
-
- # Spam protection
- userToken.spamProtection()
-
- # Console and file output
- log.pm("{} -> {}: {}".format(username, packetData["to"], packetData["message"]))
- except exceptions.userSilencedException:
- userToken.enqueue(serverPackets.silenceEndTime(userToken.getSilenceSecondsLeft()))
- log.warning("{} tried to send a message during silence".format(username))
- except exceptions.tokenNotFoundException:
- # Token not found, user disconnected
- log.warning("{} tried to send a message to {}, but their token couldn't be found".format(username, packetData["to"]))
- except exceptions.messageTooLongException:
- # Message > 256 silence
- userToken.silence(2*3600, "Sending messages longer than 256 characters")
- except exceptions.userRestrictedException:
- pass
+ # Send private message packet
+ packetData = clientPackets.sendPrivateMessage(packetData)
+ chat.sendMessage(token=userToken, to=packetData["to"], message=packetData["message"])
diff --git a/events/sendPublicMessageEvent.py b/events/sendPublicMessageEvent.py
index 926c1bd..86956dd 100644
--- a/events/sendPublicMessageEvent.py
+++ b/events/sendPublicMessageEvent.py
@@ -1,135 +1,7 @@
-from constants import exceptions
from constants import clientPackets
-from objects import glob
-from objects import fokabot
-from constants import serverPackets
-from helpers import discordBotHelper
-from helpers import logHelper as log
-from helpers import userHelper
-import time
+from helpers import chatHelper as chat
def handle(userToken, packetData):
- """
- Event called when someone sends a public message
-
- userToken -- request user token
- packetData -- request data bytes
- """
-
- try:
- # Get userToken data
- userID = userToken.userID
- username = userToken.username
-
- # Make sure the user is not in restricted mode
- if userToken.restricted == True:
- raise exceptions.userRestrictedException
-
- # Public chat packet
- packetData = clientPackets.sendPublicMessage(packetData)
-
- # Receivers
- who = []
-
- # Make sure the user is not silenced
- if userToken.isSilenced() == True:
- raise exceptions.userSilencedException
-
- # Check message length
- packetData["message"] = packetData["message"][:2048]+"..." if len(packetData["message"]) > 2048 else packetData["message"]
-
- # Get receivers list
- # Check #spectator
- if packetData["to"] == "#spectator":
- # Spectator channel
- # Send this packet to every spectator and host
- if userToken.spectating == 0:
- # We have sent to send a message to our #spectator channel
- targetToken = userToken
- who = targetToken.spectators[:]
- # No need to remove us because we are the host so we are not in spectators list
- else:
- # We have sent a message to someone else's #spectator
- targetToken = glob.tokens.getTokenFromUserID(userToken.spectating)
- who = targetToken.spectators[:]
-
- # Remove us
- if userID in who:
- who.remove(userID)
-
- # Add host
- who.append(targetToken.userID)
- elif packetData["to"] == "#multiplayer":
- # Multiplayer Channel
- # Get match ID and match object
- matchID = userToken.matchID
-
- # Make sure we are in a match
- if matchID == -1:
- return
-
- # Make sure the match exists
- if matchID not in glob.matches.matches:
- return
-
- # The match exists, get object
- match = glob.matches.matches[matchID]
-
- # Create targets list
- who = []
- for i in range(0,16):
- uid = match.slots[i]["userID"]
- if uid > -1 and uid != userID:
- who.append(uid)
- else:
- # Standard channel
- # Make sure the channel exists
- if packetData["to"] not in glob.channels.channels:
- raise exceptions.channelUnknownException
-
- # Make sure the channel is not in moderated mode
- if glob.channels.channels[packetData["to"]].moderated == True and userToken.admin == False:
- raise exceptions.channelModeratedException
-
- # Make sure we have write permissions
- if glob.channels.channels[packetData["to"]].publicWrite == False and userToken.admin == False:
- raise exceptions.channelNoPermissionsException
-
- # Send this packet to everyone in that channel except us
- who = glob.channels.channels[packetData["to"]].getConnectedUsers()[:]
- if userID in who:
- who.remove(userID)
-
- # We have receivers
- # Send packet to required users
- glob.tokens.multipleEnqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]), who, False)
-
- # Fokabot command check
- fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"])
- if fokaMessage != False:
- who.append(userID)
- glob.tokens.multipleEnqueue(serverPackets.sendMessage("FokaBot", packetData["to"], fokaMessage), who, False)
- log.chat("FokaBot @ {}: {}".format(packetData["to"], str(fokaMessage.encode("UTF-8"))))
-
- # Spam protection
- userToken.spamProtection()
-
- # Console and file log
- log.chat("{fro} @ {to}: {message}".format(fro=username, to=packetData["to"], message=str(packetData["message"].encode("utf-8"))))
-
- # Discord log
- discordBotHelper.sendChatlog("**{fro} @ {to}:** {message}".format(fro=username, to=packetData["to"], message=str(packetData["message"].encode("utf-8"))[2:-1]))
- except exceptions.userSilencedException:
- userToken.enqueue(serverPackets.silenceEndTime(userToken.getSilenceSecondsLeft()))
- log.warning("{} tried to send a message during silence".format(username))
- except exceptions.channelModeratedException:
- log.warning("{} tried to send a message to a channel that is in moderated mode ({})".format(username, packetData["to"]))
- except exceptions.channelUnknownException:
- log.warning("{} tried to send a message to an unknown channel ({})".format(username, packetData["to"]))
- except exceptions.channelNoPermissionsException:
- log.warning("{} tried to send a message to channel {}, but they have no write permissions".format(username, packetData["to"]))
- except exceptions.messageTooLongException:
- # Message > 256 silence
- userToken.silence(2*3600, "Sending messages longer than 256 characters")
- except exceptions.userRestrictedException:
- pass
+ # Send public message packet
+ packetData = clientPackets.sendPublicMessage(packetData)
+ chat.sendMessage(token=userToken, to=packetData["to"], message=packetData["message"])
diff --git a/events/startSpectatingEvent.py b/events/startSpectatingEvent.py
index 2eeec23..9bbddcb 100644
--- a/events/startSpectatingEvent.py
+++ b/events/startSpectatingEvent.py
@@ -4,6 +4,7 @@ from constants import exceptions
from objects import glob
from helpers import userHelper
from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(userToken, packetData):
try:
@@ -34,12 +35,12 @@ def handle(userToken, packetData):
# Send spectator join packet to host
targetToken.enqueue(serverPackets.addSpectator(userID))
- # Join #spectator channel
- userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))
-
+ # Create and join #spectator (#spect_userid) channel
+ glob.channels.addTempChannel("#spect_{}".format(targetToken.userID))
+ chat.joinChannel(token=userToken, channel="#spect_{}".format(targetToken.userID))
if len(targetToken.spectators) == 1:
# First spectator, send #spectator join to host too
- targetToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))
+ chat.joinChannel(token=targetToken, channel="#spect_{}".format(targetToken.userID))
# send fellowSpectatorJoined to all spectators
for spec in targetToken.spectators:
diff --git a/events/stopSpectatingEvent.py b/events/stopSpectatingEvent.py
index 9161714..1332425 100644
--- a/events/stopSpectatingEvent.py
+++ b/events/stopSpectatingEvent.py
@@ -2,6 +2,7 @@ from objects import glob
from constants import serverPackets
from constants import exceptions
from helpers import logHelper as log
+from helpers import chatHelper as chat
def handle(userToken, _):
try:
@@ -16,6 +17,9 @@ def handle(userToken, _):
raise exceptions.tokenNotFoundException
targetToken.removeSpectator(userID)
+ # Part #spectator channel
+ chat.partChannel(token=userToken, channel="#spect_{}".format(target))
+
# Send the spectator left packet to host
targetToken.enqueue(serverPackets.removeSpectator(userID))
for c in targetToken.spectators:
@@ -25,8 +29,7 @@ def handle(userToken, _):
#targetToken.enqueue(serverPackets.fellowSpectatorLeft(userID))
# Console output
- # TODO: Move messages in stop spectating
- log.info("{} are no longer spectating whoever they were spectating".format(username))
+ log.info("{} are no longer spectating {}".format(username, target))
except exceptions.tokenNotFoundException:
log.warning("Spectator stop: token not found")
finally:
diff --git a/handlers/mainHandler.py b/handlers/mainHandler.py
index f02aa8b..0c6853b 100644
--- a/handlers/mainHandler.py
+++ b/handlers/mainHandler.py
@@ -1,5 +1,7 @@
import datetime
import gzip
+import time
+from helpers import generalFunctions
from helpers import requestHelper
from objects import glob
from helpers import consoleHelper
@@ -257,7 +259,7 @@ class handler(SentryMixin, requestHelper.asyncRequestHandler):
html += " \\\"\"\"\"\"\"\"\"\"\"\"\"\"\"/
"
html += " \\ . .. .. . /
"
html += "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"
- html += "
reverse engineering a protocol impossible to reverse engineer since always
we are actually reverse engineering bancho successfully. for the third time.