def asyncGet(self): statusCode = 400 data = {"message": "unknown error"} try: # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["b"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get beatmap ID and make sure it's a valid number beatmapID = self.get_argument("b") if not beatmapID.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get mods if "m" in self.request.arguments: modsEnum = self.get_argument("m") if not modsEnum.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) modsEnum = int(modsEnum) else: modsEnum = 0 # Get game mode if "g" in self.request.arguments: gameMode = self.get_argument("g") if not gameMode.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) gameMode = int(gameMode) else: gameMode = 0 # Get acc if "a" in self.request.arguments: accuracy = self.get_argument("a") try: accuracy = float(accuracy) except ValueError: raise exceptions.invalidArgumentsException(MODULE_NAME) else: accuracy = None # Print message log.info("Requested pp for beatmap {}".format(beatmapID)) # Get beatmap md5 from osuapi # TODO: Move this to beatmap object osuapiData = osuapiHelper.osuApiRequest("get_beatmaps", "b={}".format(beatmapID)) if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData: raise exceptions.invalidBeatmapException(MODULE_NAME) beatmapMd5 = osuapiData["file_md5"] beatmapSetID = osuapiData["beatmapset_id"] # Create beatmap object bmap = beatmap.beatmap(beatmapMd5, beatmapSetID) # Check beatmap length if bmap.hitLength > 900: raise exceptions.beatmapTooLongException(MODULE_NAME) if gameMode == gameModes.STD and bmap.starsStd == 0: # Mode Specific beatmap, auto detect game mode if bmap.starsTaiko > 0: gameMode = gameModes.TAIKO if bmap.starsCtb > 0: gameMode = gameModes.CTB if bmap.starsMania > 0: gameMode = gameModes.MANIA # Calculate pp if gameMode in (gameModes.STD, gameModes.TAIKO): # osu!standard and osu!taiko oppai = ez.Ez(bmap, mods_=modsEnum, tillerino=accuracy is None, acc=accuracy, gameMode=gameMode) bmap.starsStd = oppai.stars returnPP = oppai.pp elif gameMode == gameModes.CTB: # osu!catch ciccio = cicciobello.Cicciobello(bmap, mods_=modsEnum, tillerino=accuracy is None, accuracy=accuracy) bmap.starsStd = ciccio.stars returnPP = ciccio.pp else: raise exceptions.unsupportedGameModeException() # Data to return data = { "song_name": bmap.songName, "pp": [x for x in returnPP] if type(returnPP) is list else returnPP, "game_mode": gameMode, "length": bmap.hitLength, "stars": bmap.starsStd, "ar": bmap.AR, "bpm": bmap.bpm, } # Set status code and message statusCode = 200 data["message"] = "ok" except exceptions.invalidArgumentsException: # Set error and message statusCode = 400 data["message"] = "missing required arguments" except exceptions.invalidBeatmapException: statusCode = 400 data["message"] = "beatmap not found" except exceptions.beatmapTooLongException: statusCode = 400 data["message"] = "requested beatmap is too long" except exceptions.unsupportedGameModeException: statusCode = 400 data["message"] = "Unsupported gamemode" finally: # Add status code to data data["status"] = statusCode # Debug output log.debug(str(data)) # Send response self.write(json.dumps(data)) self.set_header("Content-Type", "application/json") self.set_status(statusCode)
def asyncGet(self): output = "" try: if not requestsManager.checkArguments(self.request.arguments, ["u", "h"]): raise exceptions.invalidArgumentsException(MODULE_NAME) username = self.get_argument("u", "") password = self.get_argument("h", "") userID = userUtils.getID(username) if not userUtils.checkLogin(userID, password): self.write("error:pass") return gameMode = self.get_argument("m", "-1") rankedStatus = self.get_argument("r", "-1") query = self.get_argument("q", "") page = int(self.get_argument("p", "0")) glob.db = connectToDB(1) query = query.lower() whereClause = [] #stars filter regexp = r"stars[<>=]\d+(\*\d*)?" for match in re.finditer(regexp, query): matchStr = match.group(0) query = query.replace(matchStr, "") num = float(matchStr[6:]) whereClause.append("difficulty_std " + matchStr[5] + " " + str(num)) #ar filter regexp = r"ar[<>=]\d+(\*\d*)?" for match in re.finditer(regexp, query): matchStr = match.group(0) query = query.replace(matchStr, "") num = float(matchStr[3:]) whereClause.append("ar " + matchStr[2] + " " + str(num)) #cs filter regexp = r"cs[<>=]\d+(\*\d*)?" for match in re.finditer(regexp, query): matchStr = match.group(0) query = query.replace(matchStr, "") num = float(matchStr[3:]) whereClause.append("cs " + matchStr[2] + " " + str(num)) #max_combo regexp = r"combo[<>=]\d+" for match in re.finditer(regexp, query): matchStr = match.group(0) query = query.replace(matchStr, "") num = int(matchStr[6:]) whereClause.append("max_combo " + matchStr[5] + " " + str(num)) #length filter regexp = r"length[<>=]\d+" for match in re.finditer(regexp, query): matchStr = match.group(0) query = query.replace(matchStr, "") num = int(matchStr[7:]) whereClause.append("hit_length " + matchStr[6] + " " + str(num)) #bpm filter regexp = r"bpm[<>=]\d+" for match in re.finditer(regexp, query): matchStr = match.group(0) query = query.replace(matchStr, "") num = int(matchStr[4:]) whereClause.append("bpm " + matchStr[3] + " " + str(num)) if query.lower() in ["newest", "top rated", "most played"]: query = "" #get response from API response = requests.get( "https://osu.gatari.pw/api/v1/beatmaps/search?r={0}&q={1}&m={2}&p={3}" .format(rankedStatus, query, gameMode, page)) if len(whereClause ) > 0 and userUtils.getPrivileges(userID) & 4 > 0: #join with Database bs_ids = parseBeatmapsetIdsFromDirect(response.text) if len(bs_ids) == 0: return whereClause.append("beatmapset_id IN (" + ",".join(bs_ids) + ")") pandasResult = pandasQuery( "select DISTINCT beatmapset_id from beatmaps WHERE " + " AND ".join(whereClause)) if len(pandasResult) == 0: return filtered_bs_ids = np.array(pandasResult["beatmapset_id"]) response_rows = response.text.split("\n")[1:-1] new_rows = [ row for row in response_rows if row.split('|')[7] in list(map(str, filtered_bs_ids)) ] result = str(len(new_rows)) + "\n" + "\n".join(new_rows) + "\n" output += result else: output += response.text finally: self.write(output)
def asyncGet(self): statusCode = 400 data = {"message": "unknown error"} try: # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["b"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get beatmap ID and make sure it's a valid number beatmapID = self.get_argument("b") if not beatmapID.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get mods if "m" in self.request.arguments: modsEnum = self.get_argument("m") if not modsEnum.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) modsEnum = int(modsEnum) else: modsEnum = 0 # Get game mode if "g" in self.request.arguments: gameMode = self.get_argument("g") if not gameMode.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) gameMode = int(gameMode) else: gameMode = 0 # Get acc if "a" in self.request.arguments: accuracy = self.get_argument("a") try: accuracy = float(accuracy) except ValueError: raise exceptions.invalidArgumentsException(MODULE_NAME) else: accuracy = -1.0 # Print message log.info("Requested pp for beatmap {}".format(beatmapID)) """ Peppy >:( # Get beatmap md5 from osuapi # TODO: Move this to beatmap object osuapiData = osuapiHelper.osuApiRequest("get_beatmaps", "b={}".format(beatmapID)) if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData: raise exceptions.invalidBeatmapException(MODULE_NAME) beatmapMd5 = osuapiData["file_md5"] beatmapSetID = osuapiData["beatmapset_id"] """ dbData = glob.db.fetch("SELECT beatmap_md5, beatmapset_id FROM beatmaps WHERE beatmap_id = {}".format(beatmapID)) if dbData is None: raise exceptions.invalidBeatmapException(MODULE_NAME) beatmapMd5 = dbData["beatmap_md5"] beatmapSetID = dbData["beatmapset_id"] # Create beatmap object bmap = beatmap.beatmap(beatmapMd5, beatmapSetID) # Check beatmap length if bmap.hitLength > 900: raise exceptions.beatmapTooLongException(MODULE_NAME) returnPP = [] if gameMode == gameModes.STD and bmap.starsStd == 0: # Mode Specific beatmap, auto detect game mode if bmap.starsTaiko > 0: gameMode = gameModes.TAIKO if bmap.starsCtb > 0: gameMode = gameModes.CTB if bmap.starsMania > 0: gameMode = gameModes.MANIA # Calculate pp if accuracy < 0 and modsEnum == 0: # Generic acc # Get cached pp values cachedPP = bmap.getCachedTillerinoPP() if (modsEnum&mods.RELAX or modsEnum&mods.RELAX2): cachedPP = [0,0,0,0] if cachedPP != [0,0,0,0]: log.debug("Got cached pp.") returnPP = cachedPP else: log.debug("Cached pp not found. Calculating pp with oppai...") # Cached pp not found, calculate them peace = ez_peace.EzPeace(bmap, mods_=modsEnum, tillerino=True) returnPP = peace.pp bmap.starsStd = peace.stars if not (modsEnum&mods.RELAX or modsEnum&mods.RELAX2): # Cache values in DB log.debug("Saving cached pp...") if type(returnPP) == list and len(returnPP) == 4: bmap.saveCachedTillerinoPP(returnPP) else: # Specific accuracy, calculate # Create peace instance log.debug("Specific request ({}%/{}). Calculating pp with peace...".format(accuracy, modsEnum)) peace = ez_peace.EzPeace(bmap, mods_=modsEnum, tillerino=True) bmap.starsStd = peace.stars if accuracy > 0: returnPP.append(calculatePPFromAcc(peace, accuracy)) else: returnPP = peace.pp # Data to return data = { "song_name": bmap.songName, "pp": [round(x, 2) for x in returnPP] if type(returnPP) == list else round(returnPP, 2), "length": bmap.hitLength, "stars": bmap.starsStd, "ar": bmap.AR, "bpm": bmap.bpm, } # Set status code and message statusCode = 200 data["message"] = "ok" except exceptions.invalidArgumentsException: # Set error and message statusCode = 400 data["message"] = "missing required arguments" except exceptions.invalidBeatmapException: statusCode = 400 data["message"] = "beatmap not found" except exceptions.beatmapTooLongException: statusCode = 400 data["message"] = "requested beatmap is too long" except exceptions.unsupportedGameModeException: statusCode = 400 data["message"] = "Unsupported gamemode" finally: # Add status code to data data["status"] = statusCode # Debug output log.debug(str(data)) # Send response #self.clear() self.write(json.dumps(data)) self.set_header("Content-Type", "application/json") self.set_status(statusCode)
def asyncGet(self): try: # Get request ip ip = self.getRequestIP() # Argument check if not requestsManager.checkArguments(self.request.arguments, ["u", "h"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get user ID username = self.get_argument("u") userID = userUtils.getID(username) if userID is None: self.write("error: pass\n") return # Check login log.info("{} ({}) wants to connect".format(username, userID)) if not userUtils.checkLogin(userID, self.get_argument("h"), ip): self.write("error: pass\n") return # Ban check if userUtils.isBanned(userID): return # Lock check if userUtils.isLocked(userID): return # 2FA check if userUtils.check2FA(userID, ip): self.write("error: verify\n") # Update latest activity userUtils.updateLatestActivity(userID) if "x" in self.request.arguments: if len(self.get_argument("x")) > 4: ''' When "x" is found in the arguments, it means two things, 1. "Monitor" has just been triggered (desktop screenshot """"""anticheat"""""") 2. Files named "LL" (used by *a certain cheat website* for login data) have been found on the users computer. This should *NEVER* happen, but just incase it does, i'll send a notification to the discord. ''' webhook = Webhook( glob.conf.config["discord"] ["ahook"], #send shit to discord hq color=0xc32c74, footer="stupid anticheat") if glob.conf.config["discord"]["enable"]: webhook.set_title( title=f"Catched some cheater {username} ({userID})" ) webhook.set_desc( f'They just tried to send bancho_monitor and they have LL files!' ) webhook.set_footer(text="peppycode anticheat") webhook.post() # Get country and output it country = glob.db.fetch( "SELECT country FROM users_stats WHERE id = %s", [userID])["country"] self.write(country) except exceptions.invalidArgumentsException: pass except exceptions.loginFailedException: self.write("error: pass\n") except exceptions.userBannedException: pass except exceptions.userLockedException: pass except exceptions.need2FAException: self.write("error: verify\n")
def asyncGet(self): try: # Get request ip ip = self.getRequestIP() # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["c", "u", "h"]): raise exceptions.invalidArgumentsException(self.MODULE_NAME) # Get arguments username = self.get_argument("u") password = self.get_argument("h") replayID = self.get_argument("c") # Login check userID = userUtils.getID(username) if userID == 0: raise exceptions.loginFailedException(self.MODULE_NAME, userID) if not userUtils.checkLogin(userID, password, ip): raise exceptions.loginFailedException(self.MODULE_NAME, username) if userUtils.check2FA(userID, ip): raise exceptions.need2FAException(self.MODULE_NAME, username, ip) # Get user ID replayData = glob.db.fetch( "SELECT osu_scores.*, phpbb_users.username AS uname FROM osu_scores LEFT JOIN phpbb_users ON osu_scores.user_id = phpbb_users.user_id WHERE osu_scores.score_id = %s", [replayID]) # Increment 'replays watched by others' if needed if replayData is not None: if username != replayData["uname"]: userUtils.incrementReplaysWatched(replayData["userid"], replayData["play_mode"]) # Serve replay log.info("Serving replay_{}.osr".format(replayID)) r = "" replayID = int(replayID) try: r = replayHelper.getRawReplayS3(replayID) except timeout_decorator.TimeoutError: log.warning("S3 timed out") sentry.captureMessage("S3 timeout while fetching replay.") glob.stats["replay_download_failures"].labels( type="raw_s3_timeout").inc() except FileNotFoundError: log.warning("Replay {} doesn't exist".format(replayID)) except: glob.stats["replay_download_failures"].labels( type="raw_other").inc() raise finally: self.write(r) except exceptions.invalidArgumentsException: pass except exceptions.need2FAException: pass except exceptions.loginFailedException: pass
def asyncGet(self): try: # OOF UsingRelax = False UsingAuto = False # Get request ip ip = self.getRequestIP() # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["c", "u", "h"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get arguments username = self.get_argument("u") password = self.get_argument("h") replayID = self.get_argument("c") # Login check userID = userUtils.getID(username) if userID == 0: raise exceptions.loginFailedException(MODULE_NAME, userID) if not userUtils.checkLogin(userID, password, ip): raise exceptions.loginFailedException(MODULE_NAME, username) if userUtils.check2FA(userID, ip): raise exceptions.need2FAException(MODULE_NAME, username, ip) # Get user ID current_gamemode_redis = "lets:user_current_gamemode:{}".format( userID) cgamemode = int(glob.redis.get(current_gamemode_redis)) replayData = glob.db.fetch( "SELECT scores.*, users.username AS uname FROM scores LEFT JOIN users ON scores.userid = users.id WHERE scores.id = %s", [replayID]) if cgamemode == 3: log.debug("autopilot") UsingRelax = False usingAuto = True fileName = "{}_ap/replay_{}.osr".format( glob.conf.config["server"]["replayspath"], replayID) if cgamemode == 2: log.debug("relax") fileName = "{}_relax/replay_{}.osr".format( glob.conf.config["server"]["replayspath"], replayID) UsingRelax = True UsingAuto = False if cgamemode == 1: log.debug("std") UsingRelax = False UsingAuto = False fileName = "{}/replay_{}.osr".format( glob.conf.config["server"]["replayspath"], replayID) # Increment 'replays watched by others' if needed if replayData is not None: if username != replayData["uname"]: userUtils.incrementReplaysWatched(replayData["userid"], replayData["play_mode"]) Play = "VANILLA" if UsingRelax: Play = "RELAX" if UsingAuto: Play = "AUTOPILOT" # Serve replay log.info("[{}] Serving replay_{}.osr".format(Play, replayID)) if os.path.isfile(fileName): with open(fileName, "rb") as f: fileContent = f.read() self.write(fileContent) else: log.info("Replay {} doesn't exist".format(replayID)) self.write("") except exceptions.invalidArgumentsException: pass except exceptions.need2FAException: pass except exceptions.loginFailedException: pass
def asyncPost(self): try: if glob.debug: requestsManager.printArguments(self) # Make sure screenshot file was passed if "ss" not in self.request.files: raise exceptions.invalidArgumentsException(MODULE_NAME) # Check user auth because of sneaky people if not requestsManager.checkArguments(self.request.arguments, ["u", "p"]): raise exceptions.invalidArgumentsException(MODULE_NAME) username = self.get_argument("u") password = self.get_argument("p") ip = self.getRequestIP() userID = userUtils.getID(username) if not userUtils.checkLogin(userID, password): raise exceptions.loginFailedException(MODULE_NAME, username) if userUtils.check2FA(userID, ip): raise exceptions.need2FAException(MODULE_NAME, username, ip) # Rate limit if glob.redis.get("lets:screenshot:{}".format(userID)) is not None: self.write("no") return glob.redis.set("lets:screenshot:{}".format(userID), 1, 60) #check if user folder exist screenshotID = generalUtils.randomString(8) if not os.path.isdir("{}/{}/".format( glob.conf.config["server"]["storagepath"], userID)): os.mkdir("{}/{}/".format( glob.conf.config["server"]["storagepath"], userID)) # Get a random screenshot id found = False screenshotID = "" while not found: screenshotID = generalUtils.randomString(8) if not os.path.isfile("{}/{}/{}.jpg".format( glob.conf.config["server"]["storagepath"], userID, screenshotID)): found = True # Write screenshot file to screenshots folder with open( "{}/{}/{}.jpg".format( glob.conf.config["server"]["storagepath"], userID, screenshotID), "wb") as f: f.write(self.request.files["ss"][0]["body"]) # Output log.info("New screenshot ({})".format(screenshotID)) # Return screenshot link self.write("https://storage.aeris-dev.pw/get/{}/{}.jpg".format( userID, screenshotID)) except exceptions.need2FAException: pass except exceptions.invalidArgumentsException: pass except exceptions.loginFailedException: pass
def asyncGet(self): output = "" try: if not requestsManager.checkArguments(self.request.arguments, ["c", "u", "p"]): raise exceptions.invalidArgumentsException(MODULE_NAME) ip = self.getRequestIP() username = self.get_argument("u").strip() password = self.get_argument("p").strip() user_id = userUtils.getID(username) checksum = self.get_argument("c").strip() if not user_id: raise exceptions.loginFailedException(MODULE_NAME, user_id) if not userUtils.checkLogin(user_id, password, ip): raise exceptions.loginFailedException(MODULE_NAME, username) if userUtils.check2FA(user_id, ip): raise exceptions.need2FAException(MODULE_NAME, user_id, ip) ranked = glob.db.fetch( "SELECT ranked FROM beatmaps WHERE beatmap_md5 = %s LIMIT 1", (checksum, )) if ranked is None: output = "no exist" return if ranked["ranked"] < rankedStatuses.RANKED: output = "not ranked" return rating = glob.db.fetch( "SELECT rating FROM beatmaps WHERE beatmap_md5 = %s LIMIT 1", (checksum, )) has_voted = glob.db.fetch( "SELECT id FROM beatmaps_rating WHERE user_id = %s AND beatmap_md5 = %s LIMIT 1", (user_id, checksum)) if has_voted != None: output = f"alreadyvoted\n{rating['rating']:.2f}" return vote = self.get_argument("v", default=None) if vote is None: output = "ok" return try: vote = int(vote) except ValueError: raise exceptions.invalidArgumentsException(MODULE_NAME) if vote < 0 or vote > 10: output = "out of range" return glob.db.execute( "REPLACE INTO beatmaps_rating (beatmap_md5, user_id, rating) VALUES (%s, %s, %s)", (checksum, user_id, vote)) glob.db.execute( "UPDATE beatmaps SET rating = (SELECT SUM(rating)/COUNT(rating) FROM beatmaps_rating " "WHERE beatmap_md5 = %(md5)s) WHERE beatmap_md5 = %(md5)s LIMIT 1", {"md5": checksum}) rating = glob.db.fetch( "SELECT rating FROM beatmaps WHERE beatmap_md5 = %s LIMIT 1", (checksum, )) output = f"{rating['rating']:.2f}" except exceptions.loginFailedException: output = "auth failed" except exceptions.invalidArgumentsException: output = "no" finally: self.write(output)
def asyncPost(self): try: if glob.conf["DEBUG"]: requestsManager.printArguments(self) # Make sure screenshot file was passed if "ss" not in self.request.files: raise exceptions.invalidArgumentsException(MODULE_NAME) # Check user auth because of sneaky people if not requestsManager.checkArguments(self.request.arguments, ["u", "p"]): raise exceptions.invalidArgumentsException(MODULE_NAME) username = self.get_argument("u") password = self.get_argument("p") ip = self.getRequestIP() userID = userUtils.getID(username) if not userUtils.checkLogin(userID, password): raise exceptions.loginFailedException(MODULE_NAME, username) if userUtils.check2FA(userID, ip): raise exceptions.need2FAException(MODULE_NAME, username, ip) # Rate limit if glob.redis.get("lets:screenshot:{}".format(userID)) is not None: self.write("no") return glob.redis.set("lets:screenshot:{}".format(userID), 1, 60) # Get a random screenshot id hasS3 = bool(glob.conf["S3_SCREENSHOTS_BUCKET"]) \ and bool(glob.conf["S3_SCREENSHOTS_REGION"]) \ and bool(glob.conf["S3_SCREENSHOTS_ENDPOINT_URL"]) found = False screenshotID = "" while not found: screenshotID = generalUtils.randomString(8) if hasS3: try: glob.threadScope.s3Screenshots.head_object( Bucket=glob.conf["S3_SCREENSHOTS_BUCKET"], Key=f"{screenshotID}.jpg") found = False except botocore.errorfactory.ClientError: found = True else: found = not os.path.isfile("{}/{}.jpg".format( glob.conf["SCREENSHOTS_FOLDER"], screenshotID)) # Output log.info("New screenshot ({})".format(screenshotID)) # Write screenshot file to .data folder if hasS3: with io.BytesIO(self.request.files["ss"][0]["body"]) as f: glob.threadScope.s3Screenshots.upload_fileobj( f, glob.conf["S3_SCREENSHOTS_BUCKET"], f"{screenshotID}.jpg", ExtraArgs={"ACL": "public-read"}) else: with open( "{}/{}.jpg".format(glob.conf["SCREENSHOTS_FOLDER"], screenshotID), "wb") as f: f.write(self.request.files["ss"][0]["body"]) # Return screenshot link self.write("{}/ss/{}.jpg".format(glob.conf["SERVER_URL"], screenshotID)) except exceptions.need2FAException: pass except exceptions.invalidArgumentsException: pass except exceptions.loginFailedException: pass
def asyncPost(self): try: if not requestsManager.checkArguments(self.request.arguments, [ "user[username]", "user[user_email]", "user[password]", "check" ]): return self.write("what are you doing here?") username = self.get_argument("user[username]") email = self.get_argument("user[user_email]") password = self.get_argument("user[password]") # Raw password accountCreated = self.get_argument("check") if accountCreated == "1": return self.write( '{"form_error":{"user":{"check":["Account already created."]}}}' ) emailCheck = glob.db.fetch("SELECT 1 FROM users WHERE email = %s", [email]) usernameCheck = glob.db.fetch( "SELECT 1 FROM users WHERE username = %s", [username]) if emailCheck != None: return self.write( '{"form_error":{"user":{"user_email":["Email address already used."]}}}' ) if usernameCheck != None or username.lower() in [ "peppy", "rrtyui", "cookiezi", "azer", "loctav", "banchobot", "happystick", "doomsday", "sharingan33", "andrea", "cptnxn", "reimu-desu", "hvick225", "_index", "my aim sucks", "kynan", "rafis", "sayonara-bye", "thelewa", "wubwoofwolf", "millhioref", "tom94", "tillerino", "clsw", "spectator", "exgon", "axarious", "angelsim", "recia", "nara", "emperorpenguin83", "bikko", "xilver", "vettel", "kuu01", "_yu68", "tasuke912", "dusk", "ttobas", "velperk", "jakads", "jhlee0133", "abcdullah", "yuko-", "entozer", "hdhr", "ekoro", "snowwhite", "osuplayer111", "musty", "nero", "elysion", "ztrot", "koreapenguin", "fort", "asphyxia", "niko", "shigetora" ]: return self.write( '{"form_error":{"user":{"username":["Username already used or it is forbidden."]}}}' ) if len(password) < 8 or len(password) > 32: return self.write( '{"form_error":{"user":{"password":["Password too short or long! (Password length must be more than 8 and less than 32)"]}}}' ) if "_" in username and " " in username: self.write( '{"form_error":{"user":{"username":["An username can not contain both underscores and spaces."]}}}' ) userID = int( glob.db.execute( "INSERT INTO users(username, username_safe, password_md5, salt, email, register_datetime, privileges, password_version) VALUES (%s, %s, %s, '', %s, %s, 1048576, 2)", [ username, userUtils.safeUsername(username), passwordUtils.genBcrypt( hashlib.md5(password.encode('utf-8')).hexdigest()), email, int(time.time()) ])) glob.db.execute( "INSERT INTO users_stats(id, username, user_color, user_style, ranked_score_std, playcount_std, total_score_std, ranked_score_taiko, playcount_taiko, total_score_taiko, ranked_score_ctb, playcount_ctb, total_score_ctb, ranked_score_mania, playcount_mania, total_score_mania) VALUES (%s, %s, 'black', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)", [userID, username]) glob.db.execute( "INSERT INTO rx_stats(id, username, user_color, user_style, ranked_score_std, playcount_std, total_score_std, ranked_score_taiko, playcount_taiko, total_score_taiko, ranked_score_ctb, playcount_ctb, total_score_ctb, ranked_score_mania, playcount_mania, total_score_mania) VALUES (%s, %s, 'black', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)", [userID, username]) log.info( "{} created their account using ingame registration.".format( username)) except Exception as e: log.error(e)
def asyncGet(self): statusCode = 400 response = {"message": "unknow error"} try: # Check args if not requestsManager.checkArguments(self.request.arguments, ['k', 'command', 'matchID']): response['message'] = 'missing params' raise exceptions.invalidArgumentsException() # Check secret key key = self.get_argument('k') if key is None or key != glob.conf.config['server']['cikey']: response['message'] = 'bad secret key. you are not allowed to access to this api' raise exceptions.invalidArgumentsException() command = self.get_argument('command') matchID = self.get_argument('matchID') channel = '%23multi_{}'.format(matchID) available_commands = { 'invite': '!mp invite ', 'move': '!mp move ', 'lock': '!mp lock', 'unlock': '!mp unlock', 'map': '!mp map ', 'mods': '!mp mods ', 'scorev': '!mp scorev ', 'set': '!mp set ', 'team': '!mp team ', 'kick': '!mp kick ', 'start': '!mp start', 'abort': '!mp abort', 'close': '!mp close' } # Main msg for Fokabot msg = available_commands.get(command, None) # LOL if msg is None: response['message'] = 'Bad command' raise exceptions.invalidArgumentsException() elif command == 'invite': user = self.get_argument('user') if user is None: response['message'] = 'Missing username' raise exceptions.invalidArgumentsException() else: msg = msg + user elif command == 'move': user = self.get_argument('user') slot = self.get_argument('slot') if user is None: response['message'] = 'Missing username' raise exceptions.invalidArgumentsException() elif slot is None: response['message'] = 'Missing slot position' raise exceptions.invalidArgumentsException() else: msg = msg + user + ' ' + slot elif command == 'map': beatmapID = self.get_argument('beatmapID') if beatmapID is None: response['message'] = 'Missing beatmapID' raise exceptions.invalidArgumentsException() else: msg = msg + beatmapID elif command == 'mods': mods = self.get_arguments('mod') if mods is None: response['message'] = 'Missing mod' raise exceptions.invalidArgumentsException() else: for mod in mods: msg = msg + mod + ' ' elif command == 'scorev': scorev = self.get_argument('scorev') if scorev is None: response['message'] = 'Missing score version (scorev)' raise exceptions.invalidArgumentsException() else: msg = msg + scorev elif command == 'set': gameMode = self.get_argument('mode') if gameMode is None: response['message'] = 'Missing game type. Only support h2h and teamvs' raise exceptions.invalidArgumentsException() elif gameMode == 'h2h': msg = msg + '0' elif gameMode == 'teamvs': msg = msg + '2' else: response['message'] = 'Not supported game type' raise exceptions.invalidArgumentsException() elif command == 'team': user = self.get_argument('user') teamColor = self.get_argument('teamColor') if user is None: response['message'] = 'Missing username' raise exceptions.invalidArgumentsException() elif teamColor is None: response['message'] = 'Missing team color' raise exceptions.invalidArgumentsException() elif teamColor == 'red': msg = msg + user + ' red' elif teamColor == 'blue': msg = msg + user + ' blue' else: response['message'] = 'Bad team color. Only support red and blue' raise exceptions.invalidArgumentsException() elif command == 'kick': user = self.get_argument('user') if user is None: response['message'] = 'Missing username' raise exceptions.invalidArgumentsException() with urlopen('http://localhost:5001/api/v1/fokabotMessage?k={}&to=%23multi_{}&msg={}'.format(glob.conf.config['server']['cikey'], matchID, msg.replace('!', '%21').replace(' ', '%20'))) as req: req = req.read() #chatHelper.sendMessage(glob.BOT_NAME, channel.encode().decode("ASCII", "ignore"), msg.encode().decode("ASCII", "ignore")) statusCode = 200 response = req.decode('ASCII') except exceptions.invalidArgumentsException: statusCode = 400 finally: self.write(json.dumps(response)) self.set_status(statusCode)
def asyncGet(self): statusCode = 400 data = {"message": "unknown error"} try: # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["b"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get beatmap ID and make sure it's a valid number beatmapID = self.get_argument("b") if not beatmapID.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get mods if "m" in self.request.arguments: modsEnum = self.get_argument("m") if not modsEnum.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) modsEnum = int(modsEnum) else: modsEnum = 0 # Get game mode if "g" in self.request.arguments: gameMode = self.get_argument("g") if not gameMode.isdigit(): raise exceptions.invalidArgumentsException(MODULE_NAME) gameMode = int(gameMode) else: gameMode = 0 # Get acc if "a" in self.request.arguments: accuracy = self.get_argument("a") try: accuracy = float(accuracy) except ValueError: raise exceptions.invalidArgumentsException(MODULE_NAME) else: accuracy = None # Max combo if "max_combo" in self.request.arguments: try: max_combo = int(self.get_argument("max_combo")) except ValueError: raise exceptions.invalidArgumentsException(MODULE_NAME) else: max_combo = -1 # Print message log.info("Requested pp for beatmap {}".format(beatmapID)) # Get beatmap md5 from osuapi # TODO: Move this to beatmap object osuapiData = osuapiHelper.osuApiRequest("get_beatmaps", "b={}".format(beatmapID)) if int(beatmapID) > 100000000: raise exceptions.ppCustomBeatmap(MODULE_NAME) if osuapiData is None or "file_md5" not in osuapiData or "beatmapset_id" not in osuapiData: raise exceptions.invalidBeatmapException(MODULE_NAME) beatmapMd5 = osuapiData["file_md5"] beatmapSetID = osuapiData["beatmapset_id"] # Create beatmap object bmap = beatmap.beatmap(beatmapMd5, beatmapSetID) # Check beatmap length if bmap.hitLength > 1500: raise exceptions.beatmapTooLongException(MODULE_NAME) returnPP = [] if gameMode == gameModes.STD and bmap.starsStd == 0: # Mode Specific beatmap, auto detect game mode if bmap.starsTaiko > 0: gameMode = gameModes.TAIKO if bmap.starsCtb > 0: gameMode = gameModes.CTB if bmap.starsMania > 0: gameMode = gameModes.MANIA # Calculate pp if gameMode in (gameModes.STD, gameModes.TAIKO): # Std pp if accuracy is None and max_combo == -1 and modsEnum == 0: # Generic acc/nomod # Get cached pp values cachedPP = bmap.getCachedTillerinoPP() if (modsEnum & mods.RELAX): cachedPP = [0, 0, 0, 0] if (modsEnum & mods.RELAX2): cachedPP = [0, 0, 0, 0] if cachedPP != [0, 0, 0, 0]: log.debug("Got cached pp.") returnPP = cachedPP else: log.debug( "Cached pp not found. Calculating pp with oppai..." ) # Cached pp not found, calculate them if gameMode == gameModes.STD and (modsEnum & mods.RELAX): oppai = relaxoppai.oppai(bmap, mods=modsEnum, tillerino=True) elif gameMode == gameModes.STD and (modsEnum & mods.RELAX2): oppai = autoppai.oppai(bmap, mods=modsEnum, tillerino=True) else: oppai = rippoppai.oppai(bmap, mods=modsEnum, tillerino=True) returnPP = oppai.pp bmap.starsStd = oppai.stars if not (modsEnum & mods.RELAX) or (modsEnum & mods.RELAX2): # Cache values in DB log.debug("Saving cached pp...") if type(returnPP) == list and len(returnPP) == 4: bmap.saveCachedTillerinoPP(returnPP) else: # Specific accuracy/mods, calculate pp # Create oppai instance log.debug( "Specific request ({}%/{}). Calculating pp with oppai..." .format(accuracy, modsEnum)) til_enable = accuracy is None if gameMode == gameModes.STD and (modsEnum & mods.RELAX): oppai = relaxoppai.oppai(bmap, mods=modsEnum, tillerino=til_enable, combo=max_combo) elif gameMode == gameModes.STD and (modsEnum & mods.RELAX2): oppai = autoppai.oppai(bmap, mods=modsEnum, tillerino=til_enable, combo=max_combo) else: oppai = rippoppai.oppai(bmap, mods=modsEnum, tillerino=til_enable, combo=max_combo) bmap.starsStd = oppai.stars if not til_enable: returnPP = [calculatePPFromAcc(oppai, accuracy)] else: returnPP = oppai.pp else: raise exceptions.unsupportedGameModeException() # Data to return data = { "song_name": bmap.songName, "pp": returnPP, "length": bmap.hitLength, "stars": bmap.starsStd, "ar": bmap.AR, "bpm": bmap.bpm, } # Set status code and message statusCode = 200 data["message"] = "ok" except exceptions.invalidArgumentsException: # Set error and message statusCode = 400 data["message"] = "missing required arguments" except exceptions.ppCustomBeatmap: statusCode = 400 data[ "message"] = "Custom map does not supported pp calculating yet" except exceptions.invalidBeatmapException: statusCode = 400 data["message"] = "beatmap not found" except exceptions.beatmapTooLongException: statusCode = 400 data["message"] = "requested beatmap is too long" except exceptions.unsupportedGameModeException: statusCode = 400 data["message"] = "Unsupported gamemode" finally: # Add status code to data data["status"] = statusCode # Debug output log.debug(str(data)) # Send response #self.clear() self.write(json.dumps(data)) self.set_header("Content-Type", "application/json") self.set_status(statusCode)
def asyncGet(self): try: # Get request ip ip = self.getRequestIP() # Check arguments if not requestsManager.checkArguments(self.request.arguments, ["c", "u", "h"]): raise exceptions.invalidArgumentsException(MODULE_NAME) # Get arguments username = self.get_argument("u") password = self.get_argument("h") replayID = self.get_argument("c") s = rxscore.score() # Login check userID = userUtils.getID(username) if userID == 0: raise exceptions.loginFailedException(MODULE_NAME, userID) if not userUtils.checkLogin(userID, password, ip): raise exceptions.loginFailedException(MODULE_NAME, username) if userUtils.check2FA(userID, ip): raise exceptions.need2FAException(MODULE_NAME, username, ip) # Get user ID if bool(s.mods & 128): # Relax replayData = glob.db.fetch( "SELECT scores_relax.*, users.username AS uname FROM scores_relax LEFT JOIN users ON scores_relax.userid = users.id WHERE scores_relax.id = %s", [replayID]) # Increment 'replays watched by others' if needed if replayData is not None: if username != replayData["uname"]: userUtils.incrementReplaysWatched( replayData["userid"], replayData["play_mode"], s.mods) else: replayData = glob.db.fetch( "SELECT scores.*, users.username AS uname FROM scores LEFT JOIN users ON scores.userid = users.id WHERE scores.id = %s", [replayID]) # Increment 'replays watched by others' if needed if replayData is not None: if username != replayData["uname"]: userUtils.incrementReplaysWatched( replayData["userid"], replayData["play_mode"], s.mods) log.info("Serving replay_{}.osr".format(replayID)) fileName = ".data/replays/replay_{}.osr".format(replayID) if os.path.isfile(fileName): with open(fileName, "rb") as f: fileContent = f.read() self.write(fileContent) else: self.write("") log.warning("Replay {} doesn't exist.".format(replayID)) except exceptions.invalidArgumentsException: pass except exceptions.need2FAException: pass except exceptions.loginFailedException: pass
def asyncPost(self): try: if glob.debug: requestsManager.printArguments(self) # Make sure screenshot file was passed if "ss" not in self.request.files: raise exceptions.invalidArgumentsException(MODULE_NAME) # Check user auth because of sneaky people if not requestsManager.checkArguments(self.request.arguments, ["u", "p"]): raise exceptions.invalidArgumentsException(MODULE_NAME) username = self.get_argument("u") password = self.get_argument("p") ip = self.getRequestIP() userID = userUtils.getID(username) if not userUtils.checkLogin(userID, password): raise exceptions.loginFailedException(MODULE_NAME, username) if userUtils.check2FA(userID, ip): raise exceptions.need2FAException(MODULE_NAME, username, ip) # Rate limit if glob.redis.get("lets:screenshot:{}".format(userID)) is not None: self.write("no") return glob.redis.set("lets:screenshot:{}".format(userID), 1, 60) # Get a random screenshot id found = False screenshotID = "" while not found: screenshotID = generalUtils.randomString(8) if not os.path.isfile("/home/ss/{}.png".format(screenshotID)): found = True # Write screenshot file to .data folder with open("/home/ss/{}.png".format(screenshotID), "wb") as f: f.write(self.request.files["ss"][0]["body"]) # Add Akatsuki's watermark base_screenshot = Image.open( '/home/ss/{}.png'.format(screenshotID)) watermark = Image.open('constants/watermark.png') width, height = base_screenshot.size position = (width - 330, height - 200) transparent = Image.new('RGBA', (width, height), (0, 0, 0, 0)) transparent.paste(base_screenshot, (0, 0)) transparent.paste(watermark, position, mask=watermark) transparent.show() transparent.save('/home/ss/{}.png'.format(screenshotID)) # Output log.info("New screenshot ({})".format(screenshotID)) # Return screenshot link self.write("{}/ss/{}.png".format( glob.conf.config["server"]["servername"], screenshotID)) except exceptions.need2FAException: pass except exceptions.invalidArgumentsException: pass except exceptions.loginFailedException: pass