Beispiel #1
0
def userPanel(userID):
	# Get user data
	userToken = glob.tokens.getTokenFromUserID(userID)
	username = userHelper.getUserUsername(userID)
	timezone = 24	# TODO: Timezone
	country = userToken.getCountry()
	gameRank = userHelper.getUserGameRank(userID, userToken.gameMode)
	latitude = userToken.getLatitude()
	longitude = userToken.getLongitude()

	# Get username color according to rank
	# Only admins and normal users are currently supported
	rank = userHelper.getUserRank(userID)
	if (username == "FokaBot"):
		usernameColor = usernameColors.mod
	elif (rank == 4):
		usernameColor = usernameColors.admin
	else:
		usernameColor = usernameColors.normal


	return packetHelper.buildPacket(packetIDs.server_userPanel,
	[
		[userID, dataTypes.sInt32],
		[username, dataTypes.string],
		[timezone, dataTypes.byte],
		[country, dataTypes.byte],
		[usernameColor, dataTypes.byte],
		[longitude, dataTypes.ffloat],
		[latitude, dataTypes.ffloat],
		[gameRank, dataTypes.uInt32]
	])
Beispiel #2
0
def userPanel(userID):
    # Get user data
    userToken = glob.tokens.getTokenFromUserID(userID)
    username = userHelper.getUserUsername(userID)
    timezone = 24  # TODO: Timezone
    country = userToken.getCountry()
    gameRank = userHelper.getUserGameRank(userID, userToken.gameMode)
    latitude = userToken.getLatitude()
    longitude = userToken.getLongitude()

    # Get username color according to rank
    # Only admins and normal users are currently supported
    rank = userHelper.getUserRank(userID)
    if (username == "FokaBot"):
        userRank = userRanks.MOD
    elif (rank == 4):
        userRank = userRanks.ADMIN
    elif (rank == 3):
        userRank = userRank.MOD
    elif (rank == 2):
        userRank = userRanks.SUPPORTER
    else:
        userRank = userRanks.NORMAL

    return packetHelper.buildPacket(
        packetIDs.server_userPanel,
        [[userID, dataTypes.sInt32], [username, dataTypes.string],
         [timezone, dataTypes.byte], [country, dataTypes.byte],
         [userRank, dataTypes.byte], [longitude, dataTypes.ffloat],
         [latitude, dataTypes.ffloat], [gameRank, dataTypes.uInt32]])
Beispiel #3
0
	def __init__(self, __userID, __token = None):
		"""
		Create a token object and set userID and token

		__userID -- user associated to this token
		__token -- 	if passed, set token to that value
					if not passed, token will be generated
		"""

		# Set stuff
		self.userID = __userID
		self.username = userHelper.getUserUsername(self.userID)
		self.rank = userHelper.getUserRank(self.userID)
		self.loginTime = int(time.time())
		self.pingTime = self.loginTime

		# Default variables
		self.spectators = []
		self.spectating = 0
		self.location = [0,0]
		self.joinedChannels = []
		self.actionID = actions.idle
		self.actionText = ""
		self.actionMods = 0
		self.gameMode = gameModes.std
		self.awayMessage = ""
		self.matchID = -1

		# Generate/set token
		if (__token != None):
			self.token = __token
		else:
			self.token = str(uuid.uuid4())
Beispiel #4
0
    def __init__(self, __userID, __token=None):
        """
		Create a token object and set userID and token

		__userID -- user associated to this token
		__token -- 	if passed, set token to that value
					if not passed, token will be generated
		"""

        # Set stuff
        self.userID = __userID
        self.username = userHelper.getUserUsername(self.userID)
        self.rank = userHelper.getUserRank(self.userID)
        self.loginTime = int(time.time())
        self.pingTime = self.loginTime

        # Default variables
        self.spectators = []
        self.spectating = 0
        self.location = [0, 0]
        self.joinedChannels = []
        self.actionID = actions.idle
        self.actionText = ""
        self.actionMods = 0
        self.gameMode = gameModes.std
        self.awayMessage = ""
        self.matchID = -1

        # Generate/set token
        if (__token != None):
            self.token = __token
        else:
            self.token = str(uuid.uuid4())
Beispiel #5
0
	def __init__(self, __userID, __token = None):
		"""
		Create a token object and set userID and token

		__userID -- user associated to this token
		__token -- 	if passed, set token to that value
					if not passed, token will be generated
		"""

		# Set stuff
		self.userID = __userID
		self.username = userHelper.getUserUsername(self.userID)
		self.rank = userHelper.getUserRank(self.userID)
		self.loginTime = int(time.time())

		# Generate/set token
		if (__token != None):
			self.token = __token
		else:
			self.token = str(uuid.uuid4())
Beispiel #6
0
def handle(flaskRequest):
	# Data to return
	responseTokenString = "ayy"
	responseData = bytes()

	# Get IP from flask request
	requestIP = flaskRequest.headers.get('X-Real-IP')
	if (requestIP == None):
		requestIP = flaskRequest.remote_addr

	# Console output
	print("> Accepting connection from {}...".format(requestIP))

	# Split POST body so we can get username/password/hardware data
	# 2:-3 thing is because requestData has some escape stuff that we don't need
	loginData = str(flaskRequest.data)[2:-3].split("\\n")

	# Process login
	print("> Processing login request for {}...".format(loginData[0]))
	try:
		# If true, print error to console
		err = False

		# Try to get the ID from username
		userID = userHelper.getUserID(str(loginData[0]))

		if (userID == False):
			# Invalid username
			raise exceptions.loginFailedException()
		if (userHelper.checkLogin(userID, loginData[1]) == False):
			# Invalid password
			raise exceptions.loginFailedException()

		# Make sure we are not banned
		userAllowed = userHelper.getUserAllowed(userID)
		if (userAllowed == 0):
			# Banned
			raise exceptions.loginBannedException()

		# No login errors!
		# Delete old tokens for that user and generate a new one
		glob.tokens.deleteOldTokens(userID)
		responseToken = glob.tokens.addToken(userID)
		responseTokenString = responseToken.token

		# Get silence end
		userSilenceEnd = max(0, userHelper.getUserSilenceEnd(userID)-int(time.time()))

		# Get supporter/GMT
		userRank = userHelper.getUserRank(userID)
		userGMT = False
		userSupporter = True
		if (userRank >= 3):
			userGMT = True

		# Maintenance check
		if (glob.banchoConf.config["banchoMaintenance"] == True):
			if (userGMT == False):
				# We are not mod/admin, delete token, send notification and logout
				glob.tokens.deleteToken(responseTokenString)
				raise exceptions.banchoMaintenanceException()
			else:
				# We are mod/admin, send warning notification and continue
				responseToken.enqueue(serverPackets.notification("Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode."))

		# Send all needed login packets
		responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd))
		responseToken.enqueue(serverPackets.userID(userID))
		responseToken.enqueue(serverPackets.protocolVersion())
		responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT))
		responseToken.enqueue(serverPackets.userPanel(userID))
		responseToken.enqueue(serverPackets.userStats(userID))

		# Channel info end (before starting!?! wtf bancho?)
		responseToken.enqueue(serverPackets.channelInfoEnd())

		# Default opened channels
		# TODO: Configurable default channels
		channelJoinEvent.joinChannel(responseToken, "#osu")
		channelJoinEvent.joinChannel(responseToken, "#announce")
		if (userRank >= 3):
			# Join admin chanenl if we are mod/admin
			# TODO: Separate channels for mods and admins
			channelJoinEvent.joinChannel(responseToken, "#admin")

		# Output channels info
		for key, value in glob.channels.channels.items():
			responseToken.enqueue(serverPackets.channelInfo(key))

		responseToken.enqueue(serverPackets.friendList(userID))

		# Send main menu icon and login notification if needed
		if (glob.banchoConf.config["menuIcon"] != ""):
			responseToken.enqueue(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))

		if (glob.banchoConf.config["loginNotification"] != ""):
			responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"]))

		# Get everyone else userpanel
		# TODO: Better online users handling
		for key, value in glob.tokens.tokens.items():
			responseToken.enqueue(serverPackets.userPanel(value.userID))
			responseToken.enqueue(serverPackets.userStats(value.userID))

		# Send online users IDs array
		responseToken.enqueue(serverPackets.onlineUsers())
		
		# Get location and country from ip.zxq.co or database
		if (generalFunctions.stringToBool(glob.conf.config["server"]["localizeusers"])):
			# Get location and country from IP
			location = locationHelper.getLocation(requestIP)
			country = countryHelper.getCountryID(locationHelper.getCountry(requestIP))
		else:
			# Set location to 0,0 and get country from db
			print("[!] Location skipped")
			location = [0,0]
			country = countryHelper.getCountryID(userHelper.getCountry(userID))

		# Set location and country
		responseToken.setLocation(location)
		responseToken.setCountry(country)

		# Send to everyone our userpanel and userStats (so they now we have logged in)
		glob.tokens.enqueueAll(serverPackets.userPanel(userID))
		glob.tokens.enqueueAll(serverPackets.userStats(userID))

		# Set reponse data to right value and reset our queue
		responseData = responseToken.queue
		responseToken.resetQueue()

		# Print logged in message
		consoleHelper.printColored("> {} logged in ({})".format(loginData[0], responseToken.token), bcolors.GREEN)
	except exceptions.loginFailedException:
		# Login failed error packet
		# (we don't use enqueue because we don't have a token since login has failed)
		err = True
		responseData += serverPackets.loginFailed()
	except exceptions.loginBannedException:
		# Login banned error packet
		err = True
		responseData += serverPackets.loginBanned()
	except exceptions.banchoMaintenanceException:
		# Bancho is in maintenance mode
		responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.")
		responseData += serverPackets.loginError()
	finally:
		# Print login failed message to console if needed
		if (err == True):
			consoleHelper.printColored("> {}'s login failed".format(loginData[0]), bcolors.YELLOW)

		return (responseTokenString, responseData)
Beispiel #7
0
def fokabotResponse(fro, chan, message):
    """
	Check if a message has triggered fokabot (and return its response)

	fro -- sender username (for permissions stuff with admin commands)
	chan -- channel name
	message -- message

	return -- fokabot's response string or False
	"""

    if "!roll" in message:
        maxPoints = 100
        message = message.split(" ")

        # Get max number if needed
        if (len(message) >= 2):
            if (message[1].isdigit() == True and int(message[1]) > 0):
                maxPoints = int(message[1])

        points = random.randrange(0, maxPoints)
        return fro + " rolls " + str(points) + " points!"
    elif "!faq rules" in message:
        return "Please make sure to check (Ripple's rules)[http://ripple.moe/?p=23]."
    elif "!faq swearing" in message:
        return "Please don't abuse swearing"
    elif "!faq spam" in message:
        return "Please don't spam"
    elif "!faq offend" in message:
        return "Please offend other players"
    elif "!help" in message:
        return "Click (here)[https://ripple.moe/index.php?p=16&id=4] for full FokaBot's command list"
    elif "!report" in message:
        return "Report command is not here yet :("

    # Admin commands
    elif "!moderated" in message:
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Make sure we are in a channel and not PM
            if (chan.startswith("#") == False):
                raise exceptions.moderatedPMException

            # Split message and default value
            message = message.lower().split(" ")
            enable = True

            # Get on/off
            if (len(message) >= 2):
                if (message[1] == "off"):
                    enable = False

            # Turn on/off moderated mode
            glob.channels.channels[chan].moderated = enable

            return "This channel is {} in moderated mode!".format(
                "now" if enable else "no longer")
        except exceptions.noAdminException:
            consoleHelper.printColored(
                "[!] " + fro + " has tried to put " + chan +
                " in moderated mode, but he is not an admin.", bcolors.RED)
            return False
        except exceptions.moderatedPMException:
            consoleHelper.printColored(
                "[!] " + fro +
                " has tried to put a PM chat in moderated mode.", bcolors.RED)
            return "Are you trying to put a private chat in moderated mode? Are you serious?!? You're fired."
    elif "!system" in message:
        # System commands
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Split message
            message = message.lower().split(" ")

            # Get parameters
            if (len(message) >= 2):
                if (message[1] == "restart"):
                    msg = "We are performing some maintenance. Bancho will restart in 5 seconds. Thank you for your patience."
                    systemHelper.scheduleShutdown(5, True, msg)
                    return msg
                elif (message[1] == "status"):
                    # Print some server info
                    data = systemHelper.getSystemInfo()

                    # Final message
                    msg = "=== PEP.PY STATS ===\n"
                    msg += "Running pep.py server\n"
                    msg += "Webserver: " + data["webServer"] + "\n"
                    msg += "\n"
                    msg += "=== BANCHO STATS ===\n"
                    msg += "Connected users: " + str(
                        data["connectedUsers"]) + "\n"
                    msg += "\n"
                    msg += "=== SYSTEM STATS ===\n"
                    msg += "CPU: " + str(data["cpuUsage"]) + "%\n"
                    msg += "RAM: " + str(data["usedMemory"]) + "GB/" + str(
                        data["totalMemory"]) + "GB\n"
                    if (data["unix"] == True):
                        msg += "Load average: " + str(
                            data["loadAverage"][0]) + "/" + str(
                                data["loadAverage"][1]) + "/" + str(
                                    data["loadAverage"][2]) + "\n"

                    return msg
                elif (message[1] == "reload"):
                    #Reload settings from bancho_settings
                    glob.banchoConf.loadSettings()
                    return "Bancho settings reloaded!"
                elif (message[1] == "maintenance"):
                    # Turn on/off bancho maintenance
                    maintenance = True

                    # Get on/off
                    if (len(message) >= 2):
                        if (message[2] == "off"):
                            maintenance = False

                    # Set new maintenance value in bancho_settings table
                    glob.banchoConf.setMaintenance(maintenance)

                    if (maintenance == True):
                        # We have turned on maintenance mode
                        # Users that will be disconnected
                        who = []

                        # Disconnect everyone but mod/admins
                        for key, value in glob.tokens.tokens.items():
                            if (value.rank <= 2):
                                who.append(value.userID)

                        glob.tokens.enqueueAll(
                            serverPackets.notification(
                                "Our bancho server is in maintenance mode. Please try to login again later."
                            ))
                        glob.tokens.multipleEnqueue(serverPackets.loginError(),
                                                    who)
                        msg = "The server is now in maintenance mode!"
                    else:
                        # We have turned off maintenance mode
                        # Send message if we have turned off maintenance mode
                        msg = "The server is no longer in maintenance mode!"

                    # Chat output
                    return msg
            else:
                raise exceptions.commandSyntaxException

        except exceptions.noAdminException:
            consoleHelper.printColored(
                "[!] " + fro +
                " has tried to run a system command, but he is not an admin.",
                bcolors.RED)
            return False
        except exceptions.commandSyntaxException:
            consoleHelper.printColored("[!] Fokabot command syntax error",
                                       bcolors.RED)
            return False
    elif "!scareall" in message:
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Get parameters
            message = message.lower().split(" ")
            if (len(message) < 2):
                raise exceptions.commandSyntaxException
            scaryMessage = ' '.join(message[1:])

            # Send packet to everyone
            consoleHelper.printColored(
                "> {} is turning osu! into an horror game ({})".format(
                    fro, scaryMessage), bcolors.PINK)
            glob.tokens.enqueueAll(serverPackets.jumpscare(scaryMessage))

        except exceptions.noAdminException:
            pass
        except exceptions.commandSyntaxException:
            return "Wrong syntax. !scareall <message>"
        finally:
            # No respobnse
            return False
    elif "!scare" in message:
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Get parameters
            message = message.lower().split(" ")
            if (len(message) < 3):
                raise exceptions.commandSyntaxException
            target = message[1]
            scaryMessage = ' '.join(message[2:])

            # Get target token and make sure is connected
            targetToken = glob.tokens.getTokenFromUsername(target)
            if (targetToken == None):
                raise exceptions.tokenNotFoundException

            # Send packet to target
            consoleHelper.printColored(
                "> Rip {}'s heart ({}). ~ <3, {}".format(
                    target, scaryMessage, fro), bcolors.PINK)
            targetToken.enqueue(serverPackets.jumpscare(scaryMessage))

            # No response
            return False
        except exceptions.noAdminException:
            return False
        except exceptions.tokenNotFoundException:
            return "{} is not online".format(message[1])
        except exceptions.commandSyntaxException:
            return "Wrong syntax. !scare <target> <message>"
    elif "!kick" in message:
        try:
            # Admin check
            # TODO: God this sucks
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Get parameters
            message = message.lower().split(" ")
            if (len(message) < 2):
                raise exceptions.commandSyntaxException
            target = message[1]

            # Get target token and make sure is connected
            targetToken = glob.tokens.getTokenFromUsername(target)
            if (targetToken == None):
                raise exceptions.tokenNotFoundException

            # Send packet to target
            consoleHelper.printColored(
                "> {} has been disconnected. (kick)".format(target),
                bcolors.YELLOW)
            targetToken.enqueue(
                serverPackets.notification(
                    "You have been kicked from the server. Please login again."
                ))
            targetToken.enqueue(serverPackets.loginFailed())

            # Bot response
            return "{} has been kicked from the server.".format(message[1])
        except exceptions.noAdminException:
            return False
        except exceptions.tokenNotFoundException:
            return "{} is not online.".format(message[1])
        except exceptions.commandSyntaxException:
            return "Wrong syntax. !kick <target>"
    elif "!silence" in message:
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Get parameters
            message = message.lower().split(" ")
            if (len(message) < 4):
                raise exceptions.commandSyntaxException
            target = message[1]
            amount = message[2]
            unit = message[3]
            reason = ' '.join(message[4:])

            # Get target user ID
            targetUserID = userHelper.getUserID(target)

            # Make sure the user exists
            if (targetUserID == False):
                raise exceptions.userNotFoundException

            # Calculate silence seconds
            if (unit == 's'):
                silenceTime = int(amount)
            elif (unit == 'm'):
                silenceTime = int(amount) * 60
            elif (unit == 'h'):
                silenceTime = int(amount) * 3600
            elif (unit == 'd'):
                silenceTime = int(amount) * 86400
            else:
                raise exceptions.commandSyntaxException

            # Max silence time is 7 days
            if (silenceTime > 604800):
                raise exceptions.commandSyntaxException

            # Calculate silence end time
            endTime = int(time.time()) + silenceTime

            # Update silence end in db
            userHelper.silenceUser(targetUserID, endTime, reason)

            # Check if target is connected
            targetToken = glob.tokens.getTokenFromUsername(target)
            if (targetToken == None):
                tokenFound = False
            else:
                tokenFound = True

            # Send silence packets if user is online
            if (tokenFound == True):
                targetToken.enqueue(serverPackets.silenceEndTime(silenceTime))

            consoleHelper.printColored(
                "{} has been silenced for {} seconds the following reason: {}".
                format(target, silenceTime, reason), bcolors.PINK)

            # Bot response
            return "{} has been silenced for the following reason: {}".format(
                target, reason)
        except exceptions.userNotFoundException:
            return "{}: user not found".format(message[1])
        except exceptions.noAdminException:
            return False
        except exceptions.commandSyntaxException:
            return "Wrong syntax. !silence <target> <amount> <unit (s/m/h/d)> <reason>. Max silence time is 7 days."
    elif "!removesilence" in message or "!resetsilence" in message:
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Get parameters
            message = message.lower().split(" ")
            if (len(message) < 2):
                raise exceptions.commandSyntaxException
            target = message[1]

            # Make sure the user exists
            targetUserID = userHelper.getUserID(target)
            if (targetUserID == False):
                raise exceptions.userNotFoundException

            # Reset user silence time and reason in db
            userHelper.silenceUser(targetUserID, 0, "")

            # Send new silence end packet to user if he's online
            targetToken = glob.tokens.getTokenFromUsername(target)
            if (targetToken != None):
                targetToken.enqueue(serverPackets.silenceEndTime(0))

            return "{}'s silence reset".format(target)
        except exceptions.commandSyntaxException:
            return "Wrong syntax. !removesilence <target>"
        except exceptions.noAdminException:
            return False
        except exceptions.userNotFoundException:
            return "{}: user not found".format(message[1])
    elif "!fokabot reconnect" in message:
        try:
            # Admin check
            if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
                raise exceptions.noAdminException

            # Check if fokabot is already connected
            if (glob.tokens.getTokenFromUserID(999) != None):
                raise exceptions.alreadyConnectedException

            # Fokabot is not connected, connect it
            connect()
            return False
        except exceptions.noAdminException:
            return False
        except exceptions.alreadyConnectedException:
            return "Fokabot is already connected to Bancho"
    else:
        return False
Beispiel #8
0
def banchoServer():
	if (flask.request.method == 'POST'):
		# Client's token
		requestToken = flask.request.headers.get('osu-token')

		# Client's request data
		# We remove the first two and last three characters because they are
		# some escape stuff that we don't need
		requestData = flask.request.data

		# Client's IP
		requestIP = flask.request.headers.get('X-Real-IP')
		if (requestIP == None):
			requestIP = flask.request.remote_addr

		# Server's response data
		responseData = bytes()

		# Server's response token string
		responseTokenString = "ayy";

		if (requestToken == None):
			# We don't have a token, this is the first packet aka login
			print("> Accepting connection from "+requestIP+"...")

			# Split POST body so we can get username/password/hardware data
			loginData = str(requestData)[2:-3].split("\\n")

			# Process login
			print("> Processing login request for "+loginData[0]+"...")
			try:
				# If true, print error to console
				err = False

				# Try to get the ID from username
				userID = userHelper.getUserID(str(loginData[0]))

				if (userID == False):
					# Invalid username
					raise exceptions.loginFailedException()
				if (userHelper.checkLogin(userID, loginData[1]) == False):
					# Invalid password
					raise exceptions.loginFailedException()

				# Make sure we are not banned
				userAllowed = userHelper.getUserAllowed(userID)
				if (userAllowed == 0):
					# Banned
					raise exceptions.loginBannedException()

				# No login errors!
				# Delete old tokens for that user and generate a new one
				glob.tokens.deleteOldTokens(userID)
				responseToken = glob.tokens.addToken(userID)
				responseTokenString = responseToken.token

				# Print logged in message
				consoleHelper.printColored("> "+loginData[0]+" logged in ("+responseToken.token+")", bcolors.GREEN)

				# Get silence end
				userSilenceEnd = max(0, userHelper.getUserSilenceEnd(userID)-int(time.time()))

				# Get supporter/GMT
				userRank = userHelper.getUserRank(userID)
				userGMT = False
				userSupporter = True
				if (userRank >= 3):
					userGMT = True

				# Maintenance check
				if (glob.banchoConf.config["banchoMaintenance"] == True):
					if (userGMT == False):
						# We are not mod/admin, delete token, send notification and logout
						glob.tokens.deleteToken(responseTokenString)
						raise exceptions.banchoMaintenanceException()
					else:
						# We are mod/admin, send warning notification and continue
						responseToken.enqueue(serverPackets.notification("Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode."))

				# Send all needed login packets
				responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd))
				responseToken.enqueue(serverPackets.userID(userID))
				responseToken.enqueue(serverPackets.protocolVersion())
				responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT))
				responseToken.enqueue(serverPackets.userPanel(userID))
				responseToken.enqueue(serverPackets.userStats(userID))

				# Channel info end (before starting!?! wtf bancho?)
				responseToken.enqueue(serverPackets.channelInfoEnd())

				# TODO: Configurable default channels
				# Default opened channels
				glob.channels.channels["#osu"].userJoin(userID)
				responseToken.joinChannel("#osu")
				glob.channels.channels["#announce"].userJoin(userID)
				responseToken.joinChannel("#announce")

				responseToken.enqueue(serverPackets.channelJoinSuccess(userID, "#osu"))
				responseToken.enqueue(serverPackets.channelJoinSuccess(userID, "#announce"))

				# Output channels info
				for key, value in glob.channels.channels.items():
					responseToken.enqueue(serverPackets.channelInfo(key))

				responseToken.enqueue(serverPackets.friendList(userID))

				# Send main menu icon and login notification if needed
				if (glob.banchoConf.config["menuIcon"] != ""):
					responseToken.enqueue(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))

				if (glob.banchoConf.config["loginNotification"] != ""):
					responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"]))

				# Get everyone else userpanel
				# TODO: Better online users handling
				for key, value in glob.tokens.tokens.items():
					responseToken.enqueue(serverPackets.userPanel(value.userID))
					responseToken.enqueue(serverPackets.userStats(value.userID))

				# Send online users IDs array
				responseToken.enqueue(serverPackets.onlineUsers())

				# Send to everyone our userpanel and userStats (so they now we have logged in)
				glob.tokens.enqueueAll(serverPackets.userPanel(userID))
				glob.tokens.enqueueAll(serverPackets.userStats(userID))

				# Set position and country
				responseToken.setLocation(locationHelper.getLocation(requestIP))
				responseToken.setCountry(countryHelper.getCountryID(locationHelper.getCountry(requestIP)))

				# Set reponse data to right value and reset our queue
				responseData = responseToken.queue
				responseToken.resetQueue()
			except exceptions.loginFailedException:
				# Login failed error packet
				# (we don't use enqueue because we don't have a token since login has failed)
				err = True
				responseData += serverPackets.loginFailed()
			except exceptions.loginBannedException:
				# Login banned error packet
				err = True
				responseData += serverPackets.loginBanned()
			except exceptions.banchoMaintenanceException:
				# Bancho is in maintenance mode
				responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.")
				responseData += serverPackets.loginError()
			finally:
				# Print login failed message to console if needed
				if (err == True):
					consoleHelper.printColored("> "+loginData[0]+"'s login failed", bcolors.YELLOW)
		else:
			try:
				# This is not the first packet, send response based on client's request
				# Packet start position, used to read stacked packets
				pos = 0

				# Make sure the token exists
				if (requestToken not in glob.tokens.tokens):
					raise exceptions.tokenNotFoundException()

				# Token exists, get its object
				userToken = glob.tokens.tokens[requestToken]

				# Get userID and username from token
				userID = userToken.userID
				username = userToken.username
				userRank = userToken.rank

				# Keep reading packets until everything has been read
				while pos < len(requestData):
					# Get packet from stack starting from new packet
					leftData = requestData[pos:]

					# Get packet ID, data length and data
					packetID = packetHelper.readPacketID(leftData)
					dataLength = packetHelper.readPacketLength(leftData)
					packetData = requestData[pos:(pos+dataLength+7)]

					# Console output if needed
					if (serverOutputPackets == True and packetID != 4):
						consoleHelper.printColored("Incoming packet ("+requestToken+")("+username+"):", bcolors.GREEN)
						consoleHelper.printColored("Packet code: "+str(packetID)+"\nPacket length: "+str(dataLength)+"\nSingle packet data: "+str(packetData)+"\n", bcolors.YELLOW)

					# Packet switch
					if (packetID == packetIDs.client_pong):
						# Ping packet, nothing to do
						# New packets are automatically taken from the queue
						pass
					elif (packetID == packetIDs.client_sendPublicMessage):
						try:
							# Public chat packet
							packetData = clientPackets.sendPublicMessage(packetData)

							# Receivers
							who = []

							# Check #spectator
							if (packetData["to"] != "#spectator"):
								# 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 userRank < 2):
									raise exceptions.channelModeratedException

								# Make sure we have write permissions
								if (glob.channels.channels[packetData["to"]].publicWrite == False and userRank < 2):
									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)
							else:
								# 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)

							# 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)
								consoleHelper.printColored("> FokaBot@"+packetData["to"]+": "+str(fokaMessage.encode("UTF-8")), bcolors.PINK)

							# Console output
							consoleHelper.printColored("> "+username+"@"+packetData["to"]+": "+str(packetData["message"].encode("UTF-8")), bcolors.PINK)
						except exceptions.channelModeratedException:
							consoleHelper.printColored("[!] "+username+" has attempted to send a message to a channel that is in moderated mode ("+packetData["to"]+")", bcolors.RED)
						except exceptions.channelUnknownException:
							consoleHelper.printColored("[!] "+username+" has attempted to send a message to an unknown channel ("+packetData["to"]+")", bcolors.RED)
						except exceptions.channelNoPermissionsException:
							consoleHelper.printColored("[!] "+username+" has attempted to send a message to channel "+packetData["to"]+", but he has no write permissions", bcolors.RED)

					elif (packetID == packetIDs.client_sendPrivateMessage):
						try:
							# Private message packet
							packetData = clientPackets.sendPrivateMessage(packetData)

							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))
									consoleHelper.printColored("> FokaBot>"+packetData["to"]+": "+str(fokaMessage.encode("UTF-8")), bcolors.PINK)
							else:
								# Send packet message to target if it exists
								token = glob.tokens.getTokenFromUsername(packetData["to"])
								if (token == None):
									raise exceptions.tokenNotFoundException()
								token.enqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]))

							# Console output
							consoleHelper.printColored("> "+username+">"+packetData["to"]+": "+packetData["message"], bcolors.PINK)
						except exceptions.tokenNotFoundException:
							# Token not found, user disconnected
							consoleHelper.printColored("[!] "+username+" has tried to send a message to "+packetData["to"]+", but its token couldn't be found", bcolors.RED)
					elif (packetID == packetIDs.client_channelJoin):
						try:
							# Channel join packet
							packetData = clientPackets.channelJoin(packetData)

							# Check spectator channel
							# If it's spectator channel, skip checks and list stuff
							if (packetData["channel"] != "#spectator"):
								# Normal channel, do check stuff
								# Make sure the channel exists
								if (packetData["channel"] not in glob.channels.channels):
									raise exceptions.channelUnknownException

								# Check channel permissions
								if ((glob.channels.channels[packetData["channel"]].publicWrite == False or glob.channels.channels[packetData["channel"]].moderated == True) and userRank < 2):
									raise exceptions.channelNoPermissionsException

								# Add our userID to users in that channel
								glob.channels.channels[packetData["channel"]].userJoin(userID)

								# Add the channel to our joined channel
								userToken.joinChannel(packetData["channel"])

							# Send channel joined
							userToken.enqueue(serverPackets.channelJoinSuccess(userID, packetData["channel"]))

							# Console output
							consoleHelper.printColored("> "+username+" has joined channel "+packetData["channel"], bcolors.GREEN)
						except exceptions.channelNoPermissionsException:
							consoleHelper.printColored("[!] "+username+" has attempted to join channel "+packetData["channel"]+", but he has no read permissions", bcolors.RED)
						except exceptions.channelUnknownException:
							consoleHelper.printColored("[!] "+username+" has attempted to join an unknown channel ("+packetData["channel"]+")", bcolors.RED)
					elif (packetID == packetIDs.client_channelPart):
						# Channel part packet
						packetData = clientPackets.channelPart(packetData)

						# Remove us from joined users and joined channels
						if packetData["channel"] in glob.channels.channels:
							userToken.partChannel(packetData["channel"])
							glob.channels.channels[packetData["channel"]].userPart(userID)

							# Console output
							consoleHelper.printColored("> "+username+" has parted channel "+packetData["channel"], bcolors.YELLOW)
					elif (packetID == packetIDs.client_changeAction):
						# Change action packet
						packetData = clientPackets.userActionChange(packetData)

						# Update our action id, text and md5
						userToken.actionID = packetData["actionID"]
						userToken.actionText = packetData["actionText"]
						userToken.actionMd5 = packetData["actionMd5"]
						userToken.actionMods = packetData["actionMods"]
						userToken.gameMode = packetData["gameMode"]

						# Enqueue our new user panel and stats to everyone
						glob.tokens.enqueueAll(serverPackets.userPanel(userID))
						glob.tokens.enqueueAll(serverPackets.userStats(userID))

						# Console output
						print("> "+username+" has changed action: "+str(userToken.actionID)+" ["+userToken.actionText+"]["+userToken.actionMd5+"]")
					elif (packetID == packetIDs.client_startSpectating):
						try:
							# Start spectating packet
							packetData = clientPackets.startSpectating(packetData)

							# Stop spectating old user if needed
							if (userToken.spectating != 0):
								oldTargetToken = glob.tokens.getTokenFromUserID(userToken.spectating)
								oldTargetToken.enqueue(serverPackets.removeSpectator(userID))
								userToken.stopSpectating()

							# Start spectating new user
							userToken.startSpectating(packetData["userID"])

							# Get host token
							targetToken = glob.tokens.getTokenFromUserID(packetData["userID"])
							if (targetToken == None):
								raise exceptions.tokenNotFoundException

							# Add us to host's spectators
							targetToken.addSpectator(userID)

							# Send spectator join packet to host
							targetToken.enqueue(serverPackets.addSpectator(userID))

							# Join #spectator channel
							userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))

							if (len(targetToken.spectators) == 1):
								# First spectator, send #spectator join to host too
								targetToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))

							# Console output
							consoleHelper.printColored("> "+username+" is spectating "+userHelper.getUserUsername(packetData["userID"]), bcolors.PINK)
							consoleHelper.printColored("> {}'s spectators: {}".format(str(packetData["userID"]), str(targetToken.spectators)), bcolors.BLUE)
						except exceptions.tokenNotFoundException:
							# Stop spectating if token not found
							consoleHelper.printColored("[!] Spectator start: token not found", bcolors.RED)
							userToken.stopSpectating()
					elif (packetID == packetIDs.client_stopSpectating):
						try:
							# Stop spectating packet, has no parameters

							# Remove our userID from host's spectators
							target = userToken.spectating
							targetToken = glob.tokens.getTokenFromUserID(target)
							if (targetToken == None):
								raise exceptions.tokenNotFoundException
							targetToken.removeSpectator(userID)

							# Send the spectator left packet to host
							targetToken.enqueue(serverPackets.removeSpectator(userID))

							# Console output
							# TODO: Move messages in stop spectating
							consoleHelper.printColored("> "+username+" is no longer spectating whoever he was spectating", bcolors.PINK)
							consoleHelper.printColored("> {}'s spectators: {}".format(str(target), str(targetToken.spectators)), bcolors.BLUE)
						except exceptions.tokenNotFoundException:
							consoleHelper.printColored("[!] Spectator stop: token not found", bcolors.RED)
						finally:
							# Set our spectating user to 0
							userToken.stopSpectating()
					elif (packetID == packetIDs.client_cantSpectate):
						try:
							# We don't have the beatmap, we can't spectate
							target = userToken.spectating
							targetToken = glob.tokens.getTokenFromUserID(target)

							# Send the packet to host
							targetToken.enqueue(serverPackets.noSongSpectator(userID))
						except exceptions.tokenNotFoundException:
							# Stop spectating if token not found
							consoleHelper.printColored("[!] Spectator can't spectate: token not found", bcolors.RED)
							userToken.stopSpectating()
					elif (packetID == packetIDs.client_spectateFrames):
						# Client spectate frames
						# Send spectator frames to every spectator
						consoleHelper.printColored("> {}'s spectators: {}".format(str(userID), str(userToken.spectators)), bcolors.BLUE)
						for i in userToken.spectators:
							if (i != userID):
								# TODO: Check that spectators are spectating us
								# Send to every spectator but us (host)
								spectatorToken = glob.tokens.getTokenFromUserID(i)
								if (spectatorToken != None):
									# Token found, send frames
									spectatorToken.enqueue(serverPackets.spectatorFrames(packetData[7:]))
								else:
									# Token not found, remove it
									userToken.removeSpectator(i)
									userToken.enqueue(serverPackets.removeSpectator(i))
					elif (packetID == packetIDs.client_friendAdd):
						# Friend add packet
						packetData = clientPackets.addRemoveFriend(packetData)
						userHelper.addFriend(userID, packetData["friendID"])

						# Console output
						print("> "+username+" has added "+str(packetData["friendID"])+" to his friends")
					elif (packetID == packetIDs.client_friendRemove):
						# Friend remove packet
						packetData = clientPackets.addRemoveFriend(packetData)
						userHelper.removeFriend(userID, packetData["friendID"])

						# Console output
						print("> "+username+" has removed "+str(packetData["friendID"])+" from his friends")
					elif (packetID == packetIDs.client_logout):
						# Logout packet, no parameters to read

						# Big client meme here. If someone logs out and logs in right after,
						# 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 (int(time.time()-userToken.loginTime) >= 5):
							# TODO: Channel part at logout
							# TODO: Stop spectating at logout
							# TODO: Stop spectating at timeout
							# Enqueue our disconnection to everyone else
							glob.tokens.enqueueAll(serverPackets.userLogout(userID))

							# Delete token
							glob.tokens.deleteToken(requestToken)

							consoleHelper.printColored("> "+username+" has been disconnected (logout)", bcolors.YELLOW)

					# Set reponse data and tokenstring to right value and reset our queue

					# Update pos so we can read the next stacked packet
					pos += dataLength+7	# add packet ID bytes, unused byte and data length bytes
				# WHILE END

				# Token queue built, send it
				# TODO: Move somewhere else
				responseTokenString = userToken.token
				responseData = userToken.queue
				userToken.resetQueue()

				# Update ping time for timeout
				userToken.updatePingTime()
			except exceptions.tokenNotFoundException:
				# Token not found. Disconnect that user
				responseData = serverPackets.loginError()
				responseData += serverPackets.notification("Whoops! Something went wrong, please login again.")
				consoleHelper.printColored("[!] Received packet from unknown token ("+requestToken+").", bcolors.RED)
				consoleHelper.printColored("> "+requestToken+" has been disconnected (invalid token)", bcolors.YELLOW)

		# Send server's response to client
		# We don't use token object because we might not have a token (failed login)
		return responseHelper.generateResponse(responseTokenString, responseData)
	else:
		# Not a POST request, send html page
		# TODO: Fix this crap
		return responseHelper.HTMLResponse()
Beispiel #9
0
def fokabotResponse(fro, chan, message):
	"""
	Check if a message has triggered fokabot (and return its response)

	fro -- sender username (for permissions stuff with admin commands)
	chan -- channel name
	message -- message

	return -- fokabot's response string or False
	"""

	if "!roll" in message:
		maxPoints = 100
		message = message.split(" ")

		# Get max number if needed
		if (len(message) >= 2):
			if (message[1].isdigit() == True and int(message[1]) > 0):
				maxPoints = int(message[1])

		points = random.randrange(0,maxPoints)
		return fro+" rolls "+str(points)+" points!"
	elif "!faq rules" in message:
		return "Please make sure to check (Ripple's rules)[http://ripple.moe/?p=23]."
	elif "!faq swearing" in message:
		return "Please don't abuse swearing"
	elif "!faq spam" in message:
		return "Please don't spam"
	elif "!faq offend" in message:
		return "Please offend other players"
	elif "!help" in message:
		return "Click (here)[https://ripple.moe/index.php?p=16&id=4] for full FokaBot's command list"
	elif "!report" in message:
		return "Report command is not here yet :("

	# Admin commands
	elif "!moderated" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Make sure we are in a channel and not PM
			if (chan.startswith("#") == False):
				raise exceptions.moderatedPMException

			# Split message and default value
			message = message.lower().split(" ")
			enable = True

			# Get on/off
			if (len(message) >= 2):
				if (message[1] == "off"):
					enable = False

			# Turn on/off moderated mode
			glob.channels.channels[chan].moderated = enable

			return "This channel is {} in moderated mode!".format("now" if enable else "no longer")
		except exceptions.noAdminException:
			consoleHelper.printColored("[!] "+fro+" has tried to put "+chan+" in moderated mode, but he is not an admin.", bcolors.RED)
			return False
		except exceptions.moderatedPMException:
			consoleHelper.printColored("[!] "+fro+" has tried to put a PM chat in moderated mode.", bcolors.RED)
			return "Are you trying to put a private chat in moderated mode? Are you serious?!? You're fired."
	elif "!system" in message:
		# System commands
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Split message
			message = message.lower().split(" ")

			# Get parameters
			if (len(message) >= 2):
				if (message[1] == "restart"):
					msg = "We are performing some maintenance. Bancho will restart in 5 seconds. Thank you for your patience."
					systemHelper.scheduleShutdown(5, True, msg)
					return msg
				elif (message[1] == "status"):
					# Print some server info
					data = systemHelper.getSystemInfo()

					# Final message
					msg =  "=== PEP.PY STATS ===\n"
					msg += "Running pep.py server\n"
					msg += "Webserver: "+data["webServer"]+"\n"
					msg += "\n"
					msg += "=== BANCHO STATS ===\n"
					msg += "Connected users: "+str(data["connectedUsers"])+"\n"
					msg += "\n"
					msg += "=== SYSTEM STATS ===\n"
					msg += "CPU: "+str(data["cpuUsage"])+"%\n"
					msg += "RAM: "+str(data["usedMemory"])+"GB/"+str(data["totalMemory"])+"GB\n"
					if (data["unix"] == True):
						msg += "Load average: "+str(data["loadAverage"][0])+"/"+str(data["loadAverage"][1])+"/"+str(data["loadAverage"][2])+"\n"

					return msg
				elif (message[1] == "reload"):
					#Reload settings from bancho_settings
					glob.banchoConf.loadSettings()
					return "Bancho settings reloaded!"
				elif (message[1] == "maintenance"):
					# Turn on/off bancho maintenance
					maintenance = True

					# Get on/off
					if (len(message) >= 2):
						if (message[2] == "off"):
							maintenance = False

					# Set new maintenance value in bancho_settings table
					glob.banchoConf.setMaintenance(maintenance)

					if (maintenance == True):
						# We have turned on maintenance mode
						# Users that will be disconnected
						who = []

						# Disconnect everyone but mod/admins
						for key,value in glob.tokens.tokens.items():
							if (value.rank <= 2):
								who.append(value.userID)

						glob.tokens.enqueueAll(serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later."))
						glob.tokens.multipleEnqueue(serverPackets.loginError(), who)
						msg = "The server is now in maintenance mode!"
					else:
						# We have turned off maintenance mode
						# Send message if we have turned off maintenance mode
						msg = "The server is no longer in maintenance mode!"

					# Chat output
					return msg
			else:
				raise exceptions.commandSyntaxException

		except exceptions.noAdminException:
			consoleHelper.printColored("[!] "+fro+" has tried to run a system command, but he is not an admin.", bcolors.RED)
			return False
		except exceptions.commandSyntaxException:
			consoleHelper.printColored("[!] Fokabot command syntax error", bcolors.RED)
			return False
	elif "!scareall" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException
			scaryMessage = ' '.join(message[1:])

			# Send packet to everyone
			consoleHelper.printColored("> {} is turning osu! into an horror game ({})".format(fro, scaryMessage), bcolors.PINK)
			glob.tokens.enqueueAll(serverPackets.jumpscare(scaryMessage))

		except exceptions.noAdminException:
			pass
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !scareall <message>"
		finally:
			# No respobnse
			return False
	elif "!scare" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 3):
				raise exceptions.commandSyntaxException
			target = message[1]
			scaryMessage = ' '.join(message[2:])

			# Get target token and make sure is connected
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken == None):
				raise exceptions.tokenNotFoundException

			# Send packet to target
			consoleHelper.printColored("> Rip {}'s heart ({}). ~ <3, {}".format(target, scaryMessage, fro), bcolors.PINK)
			targetToken.enqueue(serverPackets.jumpscare(scaryMessage))

			# No response
			return False
		except exceptions.noAdminException:
			return False
		except exceptions.tokenNotFoundException:
			return "{} is not online".format(message[1])
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !scare <target> <message>"
	elif "!kick" in message:
		try:
			# Admin check
			# TODO: God this sucks
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException
			target = message[1]

			# Get target token and make sure is connected
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken == None):
				raise exceptions.tokenNotFoundException

			# Send packet to target
			consoleHelper.printColored("> {} has been disconnected. (kick)".format(target), bcolors.YELLOW)
			targetToken.enqueue(serverPackets.notification("You have been kicked from the server. Please login again."))
			targetToken.enqueue(serverPackets.loginFailed())

			# Bot response
			return "{} has been kicked from the server.".format(message[1])
		except exceptions.noAdminException:
			return False
		except exceptions.tokenNotFoundException:
			return "{} is not online.".format(message[1])
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !kick <target>"
	elif "!silence" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 4):
				raise exceptions.commandSyntaxException
			target = message[1]
			amount = message[2]
			unit = message[3]
			reason = ' '.join(message[4:])

			# Get target user ID
			targetUserID = userHelper.getUserID(target)

			# Make sure the user exists
			if (targetUserID == False):
				raise exceptions.userNotFoundException

			# Calculate silence seconds
			if (unit == 's'):
				silenceTime = int(amount)
			elif (unit == 'm'):
				silenceTime = int(amount)*60
			elif (unit == 'h'):
				silenceTime = int(amount)*3600
			elif (unit == 'd'):
				silenceTime = int(amount)*86400
			else:
				raise exceptions.commandSyntaxException

			# Max silence time is 7 days
			if (silenceTime > 604800):
				raise exceptions.commandSyntaxException

			# Calculate silence end time
			endTime = int(time.time())+silenceTime

			# Update silence end in db
			userHelper.silenceUser(targetUserID, endTime, reason)

			# Check if target is connected
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken == None):
				tokenFound = False
			else:
				tokenFound = True

			# Send silence packets if user is online
			if (tokenFound == True):
				targetToken.enqueue(serverPackets.silenceEndTime(silenceTime))

			consoleHelper.printColored("{} has been silenced for {} seconds the following reason: {}".format(target, silenceTime, reason), bcolors.PINK)

			# Bot response
			return "{} has been silenced for the following reason: {}".format(target, reason)
		except exceptions.userNotFoundException:
			return "{}: user not found".format(message[1])
		except exceptions.noAdminException:
			return False
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !silence <target> <amount> <unit (s/m/h/d)> <reason>. Max silence time is 7 days."
	elif "!removesilence" in message or "!resetsilence" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException
			target = message[1]

			# Make sure the user exists
			targetUserID = userHelper.getUserID(target)
			if (targetUserID == False):
				raise exceptions.userNotFoundException

			# Reset user silence time and reason in db
			userHelper.silenceUser(targetUserID, 0, "")

			# Send new silence end packet to user if he's online
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken != None):
				targetToken.enqueue(serverPackets.silenceEndTime(0))

			return "{}'s silence reset".format(target)
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !removesilence <target>"
		except exceptions.noAdminException:
			return False
		except exceptions.userNotFoundException:
			return "{}: user not found".format(message[1])
	elif "!fokabot reconnect" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Check if fokabot is already connected
			if (glob.tokens.getTokenFromUserID(999) != None):
				raise exceptions.alreadyConnectedException

			# Fokabot is not connected, connect it
			connect()
			return False
		except exceptions.noAdminException:
			return False
		except exceptions.alreadyConnectedException:
			return "Fokabot is already connected to Bancho"
	else:
		return False
Beispiel #10
0
def handle(flaskRequest):
    # Data to return
    responseTokenString = "ayy"
    responseData = bytes()

    # Get IP from flask request
    requestIP = flaskRequest.headers.get('X-Real-IP')
    if (requestIP == None):
        requestIP = flaskRequest.remote_addr

    # Console output
    print("> Accepting connection from {}...".format(requestIP))

    # Split POST body so we can get username/password/hardware data
    # 2:-3 thing is because requestData has some escape stuff that we don't need
    loginData = str(flaskRequest.data)[2:-3].split("\\n")

    # Process login
    print("> Processing login request for {}...".format(loginData[0]))
    try:
        # If true, print error to console
        err = False

        # Try to get the ID from username
        userID = userHelper.getUserID(str(loginData[0]))

        if (userID == False):
            # Invalid username
            raise exceptions.loginFailedException()
        if (userHelper.checkLogin(userID, loginData[1]) == False):
            # Invalid password
            raise exceptions.loginFailedException()

        # Make sure we are not banned
        userAllowed = userHelper.getUserAllowed(userID)
        if (userAllowed == 0):
            # Banned
            raise exceptions.loginBannedException()

        # No login errors!
        # Delete old tokens for that user and generate a new one
        glob.tokens.deleteOldTokens(userID)
        responseToken = glob.tokens.addToken(userID)
        responseTokenString = responseToken.token

        # Get silence end
        userSilenceEnd = max(
            0,
            userHelper.getUserSilenceEnd(userID) - int(time.time()))

        # Get supporter/GMT
        userRank = userHelper.getUserRank(userID)
        userGMT = False
        userSupporter = True
        if (userRank >= 3):
            userGMT = True

        # Maintenance check
        if (glob.banchoConf.config["banchoMaintenance"] == True):
            if (userGMT == False):
                # We are not mod/admin, delete token, send notification and logout
                glob.tokens.deleteToken(responseTokenString)
                raise exceptions.banchoMaintenanceException()
            else:
                # We are mod/admin, send warning notification and continue
                responseToken.enqueue(
                    serverPackets.notification(
                        "Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode."
                    ))

        # Send all needed login packets
        responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd))
        responseToken.enqueue(serverPackets.userID(userID))
        responseToken.enqueue(serverPackets.protocolVersion())
        responseToken.enqueue(
            serverPackets.userSupporterGMT(userSupporter, userGMT))
        responseToken.enqueue(serverPackets.userPanel(userID))
        responseToken.enqueue(serverPackets.userStats(userID))

        # Channel info end (before starting!?! wtf bancho?)
        responseToken.enqueue(serverPackets.channelInfoEnd())

        # Default opened channels
        # TODO: Configurable default channels
        channelJoinEvent.joinChannel(responseToken, "#osu")
        channelJoinEvent.joinChannel(responseToken, "#announce")
        if (userRank >= 3):
            # Join admin chanenl if we are mod/admin
            # TODO: Separate channels for mods and admins
            channelJoinEvent.joinChannel(responseToken, "#admin")

        # Output channels info
        for key, value in glob.channels.channels.items():
            responseToken.enqueue(serverPackets.channelInfo(key))

        responseToken.enqueue(serverPackets.friendList(userID))

        # Send main menu icon and login notification if needed
        if (glob.banchoConf.config["menuIcon"] != ""):
            responseToken.enqueue(
                serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))

        if (glob.banchoConf.config["loginNotification"] != ""):
            responseToken.enqueue(
                serverPackets.notification(
                    glob.banchoConf.config["loginNotification"]))

        # Get everyone else userpanel
        # TODO: Better online users handling
        for key, value in glob.tokens.tokens.items():
            responseToken.enqueue(serverPackets.userPanel(value.userID))
            responseToken.enqueue(serverPackets.userStats(value.userID))

        # Send online users IDs array
        responseToken.enqueue(serverPackets.onlineUsers())

        # Get location and country from ip.zxq.co or database
        if (generalFunctions.stringToBool(
                glob.conf.config["server"]["localizeusers"])):
            # Get location and country from IP
            location = locationHelper.getLocation(requestIP)
            country = countryHelper.getCountryID(
                locationHelper.getCountry(requestIP))
        else:
            # Set location to 0,0 and get country from db
            print("[!] Location skipped")
            location = [0, 0]
            country = countryHelper.getCountryID(userHelper.getCountry(userID))

        # Set location and country
        responseToken.setLocation(location)
        responseToken.setCountry(country)

        # Send to everyone our userpanel and userStats (so they now we have logged in)
        glob.tokens.enqueueAll(serverPackets.userPanel(userID))
        glob.tokens.enqueueAll(serverPackets.userStats(userID))

        # Set reponse data to right value and reset our queue
        responseData = responseToken.queue
        responseToken.resetQueue()

        # Print logged in message
        consoleHelper.printColored(
            "> {} logged in ({})".format(loginData[0], responseToken.token),
            bcolors.GREEN)
    except exceptions.loginFailedException:
        # Login failed error packet
        # (we don't use enqueue because we don't have a token since login has failed)
        err = True
        responseData += serverPackets.loginFailed()
    except exceptions.loginBannedException:
        # Login banned error packet
        err = True
        responseData += serverPackets.loginBanned()
    except exceptions.banchoMaintenanceException:
        # Bancho is in maintenance mode
        responseData += serverPackets.notification(
            "Our bancho server is in maintenance mode. Please try to login again later."
        )
        responseData += serverPackets.loginError()
    finally:
        # Print login failed message to console if needed
        if (err == True):
            consoleHelper.printColored(
                "> {}'s login failed".format(loginData[0]), bcolors.YELLOW)

        return (responseTokenString, responseData)
Beispiel #11
0
def fokabotResponse(fro, chan, message):
	"""
	Check if a message has triggered fokabot (and return its response)

	fro -- sender username (for permissions stuff with admin commands)
	chan -- channel name
	message -- message

	return -- fokabot's response string or False
	"""

	if "!roll" in message:
		maxPoints = 100
		message = message.split(" ")

		# Get max number if needed
		if (len(message) >= 2):
			if (message[1].isdigit() == True and int(message[1]) > 0):
				maxPoints = int(message[1])

		points = random.randrange(0,maxPoints)
		return "{} rolls {} points!".format(fro, str(points))
	elif "!faq rules" in message:
		return "Please make sure to check (Ripple's rules)[http://ripple.moe/?p=23]."
	elif "!faq swearing" in message:
		return "Please don't abuse swearing"
	elif "!faq spam" in message:
		return "Please don't spam"
	elif "!faq offend" in message:
		return "Please don't offend other players"
	elif "!help" in message:
		return "Click (here)[https://ripple.moe/index.php?p=16&id=4] for FokaBot's full command list"
	elif "!report" in message:
		return "Report command is not here, yet :("
	elif "!faq github" in message:
		return "(Ripple's Github page!)[https://github.com/osuripple/ripple]"
	elif "!faq discord" in message:
		return "(Join Ripple's Discord!)[https://discord.gg/0rJcZruIsA6rXuIx]"
	elif "!faq blog" in message:
		return "You can find the latest Ripple news on the (blog)[https://ripple.moe/blog/]!"
	elif "!faq changelog" in message:
		return "Check the (changelog)[https://ripple.moe/index.php?p=17] !"
	elif "!ask" in message:
		if (len(message.split(" ")) >= 2):
			return "{}: {}".format(fro, random.choice(["Yes", "No", "Maybe"]))
		else:
			return False


	# Admin commands
	elif "!moderated" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Make sure we are in a channel and not PM
			if (chan.startswith("#") == False):
				raise exceptions.moderatedPMException

			# Split message and default value
			message = message.lower().split(" ")
			enable = True

			# Get on/off
			if (len(message) >= 2):
				if (message[1] == "off"):
					enable = False

			# Turn on/off moderated mode
			glob.channels.channels[chan].moderated = enable

			return "This channel is {} in moderated mode!".format("now" if enable else "no longer")
		except exceptions.noAdminException:
			consoleHelper.printColored("[!] {} tried to put {} in moderated mode, but they are not an admin.".format(fro, chan), bcolors.RED)
			return False
		except exceptions.moderatedPMException:
			consoleHelper.printColored("[!] {} tried to put a PM chat in moderated mode.".format(fro), bcolors.RED)
			return "You are trying to put a private chat in moderated mode. Are you serious?!? You're fired."
	elif "!system" in message:
		# System commands
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Split message
			message = message.lower().split(" ")

			# Get parameters
			if (len(message) >= 2):
				if (message[1] == "restart" or message[1] == "shutdown"):
					restart = message[1] == "restart"
					msg = "We are performing some maintenance. Bancho will {} in 5 seconds. Thank you for your patience.".format("restart" if restart else "shutdown")
					systemHelper.scheduleShutdown(5, restart, msg)
					return msg
				elif (message[1] == "status"):
					# Print some server info
					data = systemHelper.getSystemInfo()

					# Final message
					msg =  "=== PEP.PY STATS ===\n"
					msg += "Running pep.py server\n"
					msg += "Webserver: {}\n".format(data["webServer"])
					msg += "\n"
					msg += "=== BANCHO STATS ===\n"
					msg += "Connected users: {}\n".format(str(data["connectedUsers"]))
					msg += "\n"
					msg += "=== SYSTEM STATS ===\n"
					msg += "CPU: {}%\n".format(str(data["cpuUsage"]))
					msg += "RAM: {}GB/{}GB\n".format(str(data["usedMemory"]), str(data["totalMemory"]))
					if (data["unix"] == True):
						msg += "Load average: {}/{}/{}\n".format(str(data["loadAverage"][0]), str(data["loadAverage"][1]), str(data["loadAverage"][2]))

					return msg
				elif (message[1] == "reload"):
					#Reload settings from bancho_settings
					glob.banchoConf.loadSettings()

					# Reload channels too
					glob.channels.loadChannels()

					# Send new channels and new bottom icon to everyone
					glob.tokens.enqueueAll(serverPackets.channelInfoEnd())
					for key, value in glob.channels.channels.items():
						glob.tokens.enqueueAll(serverPackets.channelInfo(key))

					glob.tokens.enqueueAll(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))

					return "Bancho settings reloaded!"
				elif (message[1] == "maintenance"):
					# Turn on/off bancho maintenance
					maintenance = True

					# Get on/off
					if (len(message) >= 2):
						if (message[2] == "off"):
							maintenance = False

					# Set new maintenance value in bancho_settings table
					glob.banchoConf.setMaintenance(maintenance)

					if (maintenance == True):
						# We have turned on maintenance mode
						# Users that will be disconnected
						who = []

						# Disconnect everyone but mod/admins
						for _, value in glob.tokens.tokens.items():
							if (value.rank <= 2):
								who.append(value.userID)

						glob.tokens.enqueueAll(serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later."))
						glob.tokens.multipleEnqueue(serverPackets.loginError(), who)
						msg = "The server is now in maintenance mode!"
					else:
						# We have turned off maintenance mode
						# Send message if we have turned off maintenance mode
						msg = "The server is no longer in maintenance mode!"

					# Chat output
					return msg
				else:
					# Command not found
					return False
			else:
				raise exceptions.commandSyntaxException

		except exceptions.noAdminException:
			consoleHelper.printColored("[!] {} tried to run a system command, but they are not an admin.".format(fro), bcolors.RED)
			return False
		except exceptions.commandSyntaxException:
			consoleHelper.printColored("[!] Fokabot command syntax error", bcolors.RED)
			return False
	elif "!scareall" in message:
		return False	# !scareall is currently disabled. Remove this line to activate it.
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException
			scaryMessage = ' '.join(message[1:])

			# Send packet to everyone
			consoleHelper.printColored("> {} is turning osu! into an horror game ({})".format(fro, scaryMessage), bcolors.PINK)
			glob.tokens.enqueueAll(serverPackets.jumpscare(scaryMessage))

		except exceptions.noAdminException:
			pass
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !scareall <message>"
		finally:
			# No respobnse
			return False
	elif "!scare" in message:
		return False	# !scare is currently disabled. Remove this line to activate it.
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 3):
				raise exceptions.commandSyntaxException
			target = message[1].replace("_", " ")
			scaryMessage = ' '.join(message[2:])

			# Get target token and make sure is connected
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken == None):
				raise exceptions.tokenNotFoundException

			# Send packet to target
			consoleHelper.printColored("> Rip {}'s heart ({}). ~ <3, {}".format(target, scaryMessage, fro), bcolors.PINK)
			targetToken.enqueue(serverPackets.jumpscare(scaryMessage))

			# No response
			return False
		except exceptions.noAdminException:
			return False
		except exceptions.tokenNotFoundException:
			return "{} is not online".format(message[1])
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !scare <target> <message>"
	elif "!kickall" in message:
		try:
			# Check admin
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Kick everyone but mods/admins
			toKick = []
			for key, value in glob.tokens.tokens.items():
				if (value.rank < 3):
					toKick.append(key)

			# Loop though users to kick (we can't change dictionary size while iterating)
			for i in toKick:
				if (i in glob.tokens.tokens):
					glob.tokens.tokens[i].kick()

			return "Whoops! Rip everyone."
		except exceptions.noAdminException:
			return False
	elif "!kick" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException
			target = message[1].replace("_", " ")

			# Get target token and make sure is connected
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken == None):
				raise exceptions.tokenNotFoundException

			# Kick user
			targetToken.kick()

			# Bot response
			return "{} has been kicked from the server.".format(message[1])
		except exceptions.noAdminException:
			return False
		except exceptions.tokenNotFoundException:
			return "{} is not online.".format(message[1])
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !kick <target>"
	elif "!silence" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 4):
				raise exceptions.commandSyntaxException
			target = message[1].replace("_", " ")
			amount = message[2]
			unit = message[3]
			reason = ' '.join(message[4:])

			# Get target user ID
			targetUserID = userHelper.getUserID(target)

			# Make sure the user exists
			if (targetUserID == False):
				raise exceptions.userNotFoundException

			# Calculate silence seconds
			if (unit == 's'):
				silenceTime = int(amount)
			elif (unit == 'm'):
				silenceTime = int(amount)*60
			elif (unit == 'h'):
				silenceTime = int(amount)*3600
			elif (unit == 'd'):
				silenceTime = int(amount)*86400
			else:
				raise exceptions.commandSyntaxException

			# Max silence time is 7 days
			if (silenceTime > 604800):
				raise exceptions.commandSyntaxException

			# Calculate silence end time
			endTime = int(time.time())+silenceTime

			# Update silence end in db
			userHelper.silenceUser(targetUserID, endTime, reason)

			# Check if target is connected
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken == None):
				tokenFound = False
			else:
				tokenFound = True

			# Send silence packets if user is online
			if (tokenFound == True):
				targetToken.enqueue(serverPackets.silenceEndTime(silenceTime))

			consoleHelper.printColored("{} has been silenced for {} seconds the following reason: {}".format(target, silenceTime, reason), bcolors.PINK)

			# Bot response
			return "{} has been silenced for the following reason: {}".format(target, reason)
		except exceptions.userNotFoundException:
			return "{}: user not found".format(message[1])
		except exceptions.noAdminException:
			return False
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !silence <target> <amount> <unit (s/m/h/d)> <reason>. Max silence time is 7 days."
	elif "!removesilence" in message or "!resetsilence" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Get parameters
			message = message.lower().split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException
			target = message[1].replace("_", " ")

			# Make sure the user exists
			targetUserID = userHelper.getUserID(target)
			if (targetUserID == False):
				raise exceptions.userNotFoundException

			# Reset user silence time and reason in db
			userHelper.silenceUser(targetUserID, 0, "")

			# Send new silence end packet to user if he's online
			targetToken = glob.tokens.getTokenFromUsername(target)
			if (targetToken != None):
				targetToken.enqueue(serverPackets.silenceEndTime(0))

			return "{}'s silence reset".format(target)
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !removesilence <target>"
		except exceptions.noAdminException:
			return False
		except exceptions.userNotFoundException:
			return "{}: user not found".format(message[1])
	elif "!fokabot reconnect" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Check if fokabot is already connected
			if (glob.tokens.getTokenFromUserID(999) != None):
				raise exceptions.alreadyConnectedException

			# Fokabot is not connected, connect it
			connect()
			return False
		except exceptions.noAdminException:
			return False
		except exceptions.alreadyConnectedException:
			return "Fokabot is already connected to Bancho"
	elif "!alert" in message:
		try:
			# Admin check
			if (userHelper.getUserRank(userHelper.getUserID(fro)) <= 1):
				raise exceptions.noAdminException

			# Syntax check
			message = message.split(" ")
			if (len(message) < 2):
				raise exceptions.commandSyntaxException

			# Send alert to everyone
			glob.tokens.enqueueAll(serverPackets.notification(' '.join(message[1:])))

			return False
		except exceptions.noAdminException:
			return False
		except exceptions.commandSyntaxException:
			return "Wrong syntax. !alert <message>"
	else:
		return False