From 07a32b63e5dbc207ea3f3b0fde93ea7981ebb94e Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 1 Feb 2022 18:38:48 +0100 Subject: [PATCH] using asynchandlerwrapper removed try catches removed old, unused functions --- backend/api/controllers/result.js | 574 ++++++++++++++---------------- backend/api/routes/result.js | 16 +- 2 files changed, 273 insertions(+), 317 deletions(-) diff --git a/backend/api/controllers/result.js b/backend/api/controllers/result.js index 64c1f34a4..853b5a699 100644 --- a/backend/api/controllers/result.js +++ b/backend/api/controllers/result.js @@ -32,347 +32,299 @@ try { } class ResultController { - static async getResults(req, res, next) { - try { - const { uid } = req.decodedToken; - const results = await ResultDAO.getResults(uid); - return res.status(200).json(results); - } catch (e) { - next(e); - } + static async getResults(req, res) { + const { uid } = req.decodedToken; + const results = await ResultDAO.getResults(uid); + return res.status(200).json(results); } - static async deleteAll(req, res, next) { - try { - const { uid } = req.decodedToken; - await ResultDAO.deleteAll(uid); - Logger.log("user_results_deleted", "", uid); - return res.sendStatus(200); - } catch (e) { - next(e); - } + static async deleteAll(req, res) { + const { uid } = req.decodedToken; + await ResultDAO.deleteAll(uid); + Logger.log("user_results_deleted", "", uid); + return res.sendStatus(200); } - static async updateTags(req, res, next) { - try { - const { uid } = req.decodedToken; - const { tags, resultid } = req.body; - await ResultDAO.updateTags(uid, resultid, tags); - return res.sendStatus(200); - } catch (e) { - next(e); - } + static async updateTags(req, res) { + const { uid } = req.decodedToken; + const { tags, resultid } = req.body; + await ResultDAO.updateTags(uid, resultid, tags); + return res.sendStatus(200); } - static async addResult(req, res, next) { - try { - const { uid } = req.decodedToken; - const { result } = req.body; - result.uid = uid; - if (validateObjectValues(result) > 0) - return res.status(400).json({ message: "Bad input" }); - if ( - result.wpm <= 0 || - result.wpm > 350 || - result.acc < 75 || - result.acc > 100 || - result.consistency > 100 - ) { - return res.status(400).json({ message: "Bad input" }); - } - if (result.wpm == result.raw && result.acc != 100) { - return res.status(400).json({ message: "Bad input" }); - } - if ( - (result.mode === "time" && result.mode2 < 15 && result.mode2 > 0) || - (result.mode === "time" && - result.mode2 == 0 && - result.testDuration < 15) || - (result.mode === "words" && result.mode2 < 10 && result.mode2 > 0) || - (result.mode === "words" && - result.mode2 == 0 && - result.testDuration < 15) || - (result.mode === "custom" && - result.customText !== undefined && - !result.customText.isWordRandom && - !result.customText.isTimeRandom && - result.customText.textLen < 10) || - (result.mode === "custom" && - result.customText !== undefined && - result.customText.isWordRandom && - !result.customText.isTimeRandom && - result.customText.word < 10) || - (result.mode === "custom" && - result.customText !== undefined && - !result.customText.isWordRandom && - result.customText.isTimeRandom && - result.customText.time < 15) - ) { - return res.status(400).json({ message: "Test too short" }); - } + static async addResult(req, res) { + const { uid } = req.decodedToken; + const { result } = req.body; + result.uid = uid; + if (validateObjectValues(result) > 0) + return res.status(400).json({ message: "Bad input" }); + if ( + result.wpm <= 0 || + result.wpm > 350 || + result.acc < 75 || + result.acc > 100 || + result.consistency > 100 + ) { + return res.status(400).json({ message: "Bad input" }); + } + if (result.wpm == result.raw && result.acc != 100) { + return res.status(400).json({ message: "Bad input" }); + } + if ( + (result.mode === "time" && result.mode2 < 15 && result.mode2 > 0) || + (result.mode === "time" && + result.mode2 == 0 && + result.testDuration < 15) || + (result.mode === "words" && result.mode2 < 10 && result.mode2 > 0) || + (result.mode === "words" && + result.mode2 == 0 && + result.testDuration < 15) || + (result.mode === "custom" && + result.customText !== undefined && + !result.customText.isWordRandom && + !result.customText.isTimeRandom && + result.customText.textLen < 10) || + (result.mode === "custom" && + result.customText !== undefined && + result.customText.isWordRandom && + !result.customText.isTimeRandom && + result.customText.word < 10) || + (result.mode === "custom" && + result.customText !== undefined && + !result.customText.isWordRandom && + result.customText.isTimeRandom && + result.customText.time < 15) + ) { + return res.status(400).json({ message: "Test too short" }); + } - let resulthash = result.hash; - delete result.hash; - if (req.context.configuration.resultObjectHashCheck.enabled) { - const serverhash = objecthash(result); - if (serverhash !== resulthash) { - Logger.log( - "incorrect_result_hash", - { - serverhash, - resulthash, - result, - }, - uid - ); - return res.status(400).json({ message: "Incorrect result hash" }); - } - } - - if (validateResult) { - if (!validateResult(result)) { - return res - .status(400) - .json({ message: "Result data doesn't make sense" }); - } - } else { - if (process.env.MODE === "dev") { - console.error( - "No anticheat module found. Continuing in dev mode, results will not be validated." - ); - } else { - throw new Error("No anticheat module found"); - } - } - - result.timestamp = Math.round(result.timestamp / 1000) * 1000; - - //dont use - result timestamp is unreliable, can be changed by system time and stuff - // if (result.timestamp > Math.round(Date.now() / 1000) * 1000 + 10) { - // Logger.log( - // "time_traveler", - // { - // resultTimestamp: result.timestamp, - // serverTimestamp: Math.round(Date.now() / 1000) * 1000 + 10, - // }, - // uid - // ); - // return res.status(400).json({ message: "Time traveler detected" }); - - // this probably wont work if we replace the timestamp with the server time later - // let timestampres = await ResultDAO.getResultByTimestamp( - // uid, - // result.timestamp - // ); - // if (timestampres) { - // return res.status(400).json({ message: "Duplicate result" }); - // } - - //convert result test duration to miliseconds - const testDurationMilis = result.testDuration * 1000; - //get latest result ordered by timestamp - let lastResultTimestamp; - try { - lastResultTimestamp = - (await ResultDAO.getLastResult(uid)).timestamp - 1000; - } catch (e) { - lastResultTimestamp = null; - } - - result.timestamp = Math.round(Date.now() / 1000) * 1000; - - //check if its greater than server time - milis or result time - milis - if ( - lastResultTimestamp && - (lastResultTimestamp + testDurationMilis > result.timestamp || - lastResultTimestamp + testDurationMilis > - Math.round(Date.now() / 1000) * 1000) - ) { + let resulthash = result.hash; + delete result.hash; + if (req.context.configuration.resultObjectHashCheck.enabled) { + const serverhash = objecthash(result); + if (serverhash !== resulthash) { Logger.log( - "invalid_result_spacing", + "incorrect_result_hash", { - lastTimestamp: lastResultTimestamp, - resultTime: result.timestamp, - difference: - lastResultTimestamp + testDurationMilis - result.timestamp, + serverhash, + resulthash, + result, }, uid ); - return res.status(400).json({ message: "Invalid result spacing" }); + return res.status(400).json({ message: "Incorrect result hash" }); } + } - try { - result.keySpacingStats = { - average: - result.keySpacing.reduce( - (previous, current) => (current += previous) - ) / result.keySpacing.length, - sd: stdDev(result.keySpacing), - }; - } catch (e) { - // + if (validateResult) { + if (!validateResult(result)) { + return res + .status(400) + .json({ message: "Result data doesn't make sense" }); } - try { - result.keyDurationStats = { - average: - result.keyDuration.reduce( - (previous, current) => (current += previous) - ) / result.keyDuration.length, - sd: stdDev(result.keyDuration), - }; - } catch (e) { - // + } else { + if (process.env.MODE === "dev") { + console.error( + "No anticheat module found. Continuing in dev mode, results will not be validated." + ); + } else { + throw new Error("No anticheat module found"); } + } - const user = await UserDAO.getUser(uid); - // result.name = user.name; + result.timestamp = Math.round(result.timestamp / 1000) * 1000; - //check keyspacing and duration here for bots - if ( - result.mode === "time" && - result.wpm > 130 && - result.testDuration < 122 - ) { - if (user.verified === false || user.verified === undefined) { - if ( - result.keySpacingStats !== null && - result.keyDurationStats !== null - ) { - if (validateKeys) { - if (!validateKeys(result, uid)) { - return res - .status(400) - .json({ message: "Possible bot detected" }); - } - } else { - if (process.env.MODE === "dev") { - console.error( - "No anticheat module found. Continuing in dev mode, results will not be validated." - ); - } else { - throw new Error("No anticheat module found"); - } + //dont use - result timestamp is unreliable, can be changed by system time and stuff + // if (result.timestamp > Math.round(Date.now() / 1000) * 1000 + 10) { + // Logger.log( + // "time_traveler", + // { + // resultTimestamp: result.timestamp, + // serverTimestamp: Math.round(Date.now() / 1000) * 1000 + 10, + // }, + // uid + // ); + // return res.status(400).json({ message: "Time traveler detected" }); + + // this probably wont work if we replace the timestamp with the server time later + // let timestampres = await ResultDAO.getResultByTimestamp( + // uid, + // result.timestamp + // ); + // if (timestampres) { + // return res.status(400).json({ message: "Duplicate result" }); + // } + + //convert result test duration to miliseconds + const testDurationMilis = result.testDuration * 1000; + //get latest result ordered by timestamp + let lastResultTimestamp; + try { + lastResultTimestamp = + (await ResultDAO.getLastResult(uid)).timestamp - 1000; + } catch (e) { + lastResultTimestamp = null; + } + + result.timestamp = Math.round(Date.now() / 1000) * 1000; + + //check if its greater than server time - milis or result time - milis + if ( + lastResultTimestamp && + (lastResultTimestamp + testDurationMilis > result.timestamp || + lastResultTimestamp + testDurationMilis > + Math.round(Date.now() / 1000) * 1000) + ) { + Logger.log( + "invalid_result_spacing", + { + lastTimestamp: lastResultTimestamp, + resultTime: result.timestamp, + difference: + lastResultTimestamp + testDurationMilis - result.timestamp, + }, + uid + ); + return res.status(400).json({ message: "Invalid result spacing" }); + } + + try { + result.keySpacingStats = { + average: + result.keySpacing.reduce( + (previous, current) => (current += previous) + ) / result.keySpacing.length, + sd: stdDev(result.keySpacing), + }; + } catch (e) { + // + } + try { + result.keyDurationStats = { + average: + result.keyDuration.reduce( + (previous, current) => (current += previous) + ) / result.keyDuration.length, + sd: stdDev(result.keyDuration), + }; + } catch (e) { + // + } + + const user = await UserDAO.getUser(uid); + + //check keyspacing and duration here for bots + if ( + result.mode === "time" && + result.wpm > 130 && + result.testDuration < 122 + ) { + if (user.verified === false || user.verified === undefined) { + if ( + result.keySpacingStats !== null && + result.keyDurationStats !== null + ) { + if (validateKeys) { + if (!validateKeys(result, uid)) { + return res.status(400).json({ message: "Possible bot detected" }); } } else { - return res.status(400).json({ message: "Missing key data" }); + if (process.env.MODE === "dev") { + console.error( + "No anticheat module found. Continuing in dev mode, results will not be validated." + ); + } else { + throw new Error("No anticheat module found"); + } } + } else { + return res.status(400).json({ message: "Missing key data" }); } } - - delete result.keySpacing; - delete result.keyDuration; - delete result.smoothConsistency; - delete result.wpmConsistency; - - try { - result.keyDurationStats.average = roundTo2( - result.keyDurationStats.average - ); - result.keyDurationStats.sd = roundTo2(result.keyDurationStats.sd); - result.keySpacingStats.average = roundTo2( - result.keySpacingStats.average - ); - result.keySpacingStats.sd = roundTo2(result.keySpacingStats.sd); - } catch (e) { - // - } - - let isPb = false; - let tagPbs = []; - - if (!result.bailedOut) { - isPb = await UserDAO.checkIfPb(uid, result); - tagPbs = await UserDAO.checkIfTagPb(uid, result); - } - - if (isPb) { - result.isPb = true; - } - - if (result.mode === "time" && String(result.mode2) === "60") { - UserDAO.incrementBananas(uid, result.wpm); - if (isPb && user.discordId) { - BotDAO.updateDiscordRole(user.discordId, result.wpm); - } - } - - if (result.challenge && user.discordId) { - BotDAO.awardChallenge(user.discordId, result.challenge); - } else { - delete result.challenge; - } - - let tt = 0; - let afk = result.afkDuration; - if (afk == undefined) { - afk = 0; - } - tt = result.testDuration + result.incompleteTestSeconds - afk; - - await UserDAO.updateTypingStats(uid, result.restartCount, tt); - - await PublicStatsDAO.updateStats(result.restartCount, tt); - - if (result.bailedOut === false) delete result.bailedOut; - if (result.blindMode === false) delete result.blindMode; - if (result.lazyMode === false) delete result.lazyMode; - if (result.difficulty === "normal") delete result.difficulty; - if (result.funbox === "none") delete result.funbox; - if (result.language === "english") delete result.language; - if (result.numbers === false) delete result.numbers; - if (result.punctuation === false) delete result.punctuation; - - if (result.mode !== "custom") delete result.customText; - - let addedResult = await ResultDAO.addResult(uid, result); - - if (isPb) { - Logger.log( - "user_new_pb", - `${result.mode + " " + result.mode2} ${result.wpm} ${result.acc}% ${ - result.rawWpm - } ${result.consistency}% (${addedResult.insertedId})`, - uid - ); - } - - return res.status(200).json({ - message: "Result saved", - isPb, - name: result.name, - tagPbs, - insertedId: addedResult.insertedId, - }); - } catch (e) { - next(e); } - } - static async getLeaderboard(req, res, next) { + delete result.keySpacing; + delete result.keyDuration; + delete result.smoothConsistency; + delete result.wpmConsistency; + try { - // const { type, mode, mode2 } = req.params; - // const results = await ResultDAO.getLeaderboard(type, mode, mode2); - // return res.status(200).json(results); - return res - .status(503) - .json({ message: "Leaderboard temporarily disabled" }); + result.keyDurationStats.average = roundTo2( + result.keyDurationStats.average + ); + result.keyDurationStats.sd = roundTo2(result.keyDurationStats.sd); + result.keySpacingStats.average = roundTo2(result.keySpacingStats.average); + result.keySpacingStats.sd = roundTo2(result.keySpacingStats.sd); } catch (e) { - next(e); + // } - } - static async checkLeaderboardQualification(req, res, next) { - try { - // const { uid } = req.decodedToken; - // const { result } = req.body; - // const data = await ResultDAO.checkLeaderboardQualification(uid, result); - // return res.status(200).json(data); - return res - .status(503) - .json({ message: "Leaderboard temporarily disabled" }); - } catch (e) { - next(e); + let isPb = false; + let tagPbs = []; + + if (!result.bailedOut) { + isPb = await UserDAO.checkIfPb(uid, result); + tagPbs = await UserDAO.checkIfTagPb(uid, result); } + + if (isPb) { + result.isPb = true; + } + + if (result.mode === "time" && String(result.mode2) === "60") { + UserDAO.incrementBananas(uid, result.wpm); + if (isPb && user.discordId) { + BotDAO.updateDiscordRole(user.discordId, result.wpm); + } + } + + if (result.challenge && user.discordId) { + BotDAO.awardChallenge(user.discordId, result.challenge); + } else { + delete result.challenge; + } + + let tt = 0; + let afk = result.afkDuration; + if (afk == undefined) { + afk = 0; + } + tt = result.testDuration + result.incompleteTestSeconds - afk; + + await UserDAO.updateTypingStats(uid, result.restartCount, tt); + + await PublicStatsDAO.updateStats(result.restartCount, tt); + + if (result.bailedOut === false) delete result.bailedOut; + if (result.blindMode === false) delete result.blindMode; + if (result.lazyMode === false) delete result.lazyMode; + if (result.difficulty === "normal") delete result.difficulty; + if (result.funbox === "none") delete result.funbox; + if (result.language === "english") delete result.language; + if (result.numbers === false) delete result.numbers; + if (result.punctuation === false) delete result.punctuation; + + if (result.mode !== "custom") delete result.customText; + + let addedResult = await ResultDAO.addResult(uid, result); + + if (isPb) { + Logger.log( + "user_new_pb", + `${result.mode + " " + result.mode2} ${result.wpm} ${result.acc}% ${ + result.rawWpm + } ${result.consistency}% (${addedResult.insertedId})`, + uid + ); + } + + return res.status(200).json({ + message: "Result saved", + isPb, + name: result.name, + tagPbs, + insertedId: addedResult.insertedId, + }); } } diff --git a/backend/api/routes/result.js b/backend/api/routes/result.js index 6f26701d0..ee4b6f25b 100644 --- a/backend/api/routes/result.js +++ b/backend/api/routes/result.js @@ -2,6 +2,10 @@ const { authenticateRequest } = require("../../middlewares/auth"); const { Router } = require("express"); const ResultController = require("../controllers/result"); const RateLimit = require("../../middlewares/rate-limit"); +const { + asyncHandlerWrapper, + requestValidation, +} = require("../../middlewares/api-utils"); const router = Router(); @@ -9,41 +13,41 @@ router.get( "/", RateLimit.resultsGet, authenticateRequest, - ResultController.getResults + asyncHandlerWrapper(ResultController.getResults) ); router.post( "/add", RateLimit.resultsAdd, authenticateRequest, - ResultController.addResult + asyncHandlerWrapper(ResultController.addResult) ); router.post( "/updateTags", RateLimit.resultsTagsUpdate, authenticateRequest, - ResultController.updateTags + asyncHandlerWrapper(ResultController.updateTags) ); router.post( "/deleteAll", RateLimit.resultsDeleteAll, authenticateRequest, - ResultController.deleteAll + asyncHandlerWrapper(ResultController.deleteAll) ); router.get( "/getLeaderboard/:type/:mode/:mode2", RateLimit.resultsLeaderboardGet, - ResultController.getLeaderboard + asyncHandlerWrapper(ResultController.getLeaderboard) ); router.post( "/checkLeaderboardQualification", RateLimit.resultsLeaderboardQualificationGet, authenticateRequest, - ResultController.checkLeaderboardQualification + asyncHandlerWrapper(ResultController.checkLeaderboardQualification) ); module.exports = router;