app.post("/testCompleted", authenticateToken, (req, res) => { User.findOne({ uid: req.uid }, (err, user) => { if (err) res.status(500).send({ error: err }); request = req.body; if (request === undefined) { res.status(200).send({ resultCode: -999 }); return; } try { if (req.uid === undefined || request.obj === undefined) { console.error(`error saving result for - missing input`); res.status(200).send({ resultCode: -999 }); return; } let obj = request.obj; function verifyValue(val) { let errCount = 0; if (val === null || val === undefined) { } else if (Array.isArray(val)) { //array val.forEach((val2) => { errCount += verifyValue(val2); }); } else if (typeof val === "object" && !Array.isArray(val)) { //object Object.keys(val).forEach((valkey) => { errCount += verifyValue(val[valkey]); }); } else { if (!/^[0-9a-zA-Z._\-\+]+$/.test(val)) errCount++; } return errCount; } let errCount = verifyValue(obj); if (errCount > 0) { console.error( `error saving result for ${ req.uid } error count ${errCount} - bad input - ${JSON.stringify( request.obj )}` ); res.status(200).send({ resultCode: -1 }); return; } if ( obj.wpm <= 0 || obj.wpm > 350 || obj.acc < 50 || obj.acc > 100 || obj.consistency > 100 ) { res.status(200).send({ resultCode: -1 }); return; } if ( (obj.mode === "time" && obj.mode2 < 15 && obj.mode2 > 0) || (obj.mode === "time" && obj.mode2 == 0 && obj.testDuration < 15) || (obj.mode === "words" && obj.mode2 < 10 && obj.mode2 > 0) || (obj.mode === "words" && obj.mode2 == 0 && obj.testDuration < 15) || (obj.mode === "custom" && obj.customText !== undefined && !obj.customText.isWordRandom && !obj.customText.isTimeRandom && obj.customText.textLen < 10) || (obj.mode === "custom" && obj.customText !== undefined && obj.customText.isWordRandom && !obj.customText.isTimeRandom && obj.customText.word < 10) || (obj.mode === "custom" && obj.customText !== undefined && !obj.customText.isWordRandom && obj.customText.isTimeRandom && obj.customText.time < 15) ) { res.status(200).send({ resultCode: -5, message: "Test too short" }); return; } if (!validateResult(obj)) { if ( obj.bailedOut && ((obj.mode === "time" && obj.mode2 >= 3600) || (obj.mode === "words" && obj.mode2 >= 5000) || obj.mode === "custom") ) { //dont give an error } else { res.status(200).send({ resultCode: -4 }); return; } } let keySpacing = null; let keyDuration = null; try { keySpacing = { average: obj.keySpacing.reduce( (previous, current) => (current += previous) ) / obj.keySpacing.length, sd: stdDev(obj.keySpacing), }; keyDuration = { average: obj.keyDuration.reduce( (previous, current) => (current += previous) ) / obj.keyDuration.length, sd: stdDev(obj.keyDuration), }; } catch (e) { console.error( `cant verify key spacing or duration for user ${req.uid}! - ${e} - ${obj.keySpacing} ${obj.keyDuration}` ); } obj.keySpacingStats = keySpacing; obj.keyDurationStats = keyDuration; if (obj.mode == "time" && (obj.mode2 == 15 || obj.mode2 == 60)) { } else { obj.keySpacing = "removed"; obj.keyDuration = "removed"; } // emailVerified = await admin // .auth() // .getUser(req.uid) // .then((user) => { // return user.emailVerified; // }); // emailVerified = true; // if (obj.funbox === "nospace") { // res.status(200).send({ data: { resultCode: -1 } }); // return; // } //user.results.push() let userdata = user; let name = userdata.name === undefined ? false : userdata.name; let banned = userdata.banned === undefined ? false : userdata.banned; let verified = userdata.verified; request.obj.name = name; //check keyspacing and duration here if (obj.mode === "time" && obj.wpm > 130 && obj.testDuration < 122) { if (verified === false || verified === undefined) { if (keySpacing !== null && keyDuration !== null) { if ( keySpacing.sd <= 15 || keyDuration.sd <= 10 || keyDuration.average < 15 || (obj.wpm > 200 && obj.consistency < 70) ) { console.error( `possible bot detected by user (${obj.wpm} ${obj.rawWpm} ${ obj.acc }) ${req.name} ${name} - spacing ${JSON.stringify( keySpacing )} duration ${JSON.stringify(keyDuration)}` ); res.status(200).send({ resultCode: -2 }); return; } if ( (keySpacing.sd > 15 && keySpacing.sd <= 25) || (keyDuration.sd > 10 && keyDuration.sd <= 15) || (keyDuration.average > 15 && keyDuration.average <= 20) ) { console.error( `very close to bot detected threshold by user (${obj.wpm} ${ obj.rawWpm } ${obj.acc}) ${req.uid} ${name} - spacing ${JSON.stringify( keySpacing )} duration ${JSON.stringify(keyDuration)}` ); } } else { res.status(200).send({ resultCode: -3 }); return; } } } //yeet the key data obj.keySpacing = null; obj.keyDuration = null; try { obj.keyDurationStats.average = roundTo2(obj.keyDurationStats.average); obj.keyDurationStats.sd = roundTo2(obj.keyDurationStats.sd); obj.keySpacingStats.average = roundTo2(obj.keySpacingStats.average); obj.keySpacingStats.sd = roundTo2(obj.keySpacingStats.sd); } catch (e) {} // return db // .collection(`users/${req.uid}/results`) // .add(obj) // .then((e) => { // let createdDocId = e.id; return Promise.all([ // checkLeaderboards( // request.obj, // "global", // banned, // name, // verified, // emailVerified // ), // checkLeaderboards( // request.obj, // "daily", // banned, // name, // verified, // emailVerified // ), checkIfPB(request.obj, userdata), checkIfTagPB(request.obj, userdata), ]) .then(async (values) => { // let globallb = values[0].insertedAt; // let dailylb = values[1].insertedAt; let ispb = values[0]; let tagPbs = values[1]; // console.log(values); if (obj.mode === "time" && String(obj.mode2) === "60") { incrementT60Bananas(req.uid, obj, userdata); } await incrementUserGlobalTypingStats(userdata, obj); //equivalent to getIncrementedTypingStats let returnobj = { resultCode: null, // globalLeaderboard: globallb, // dailyLeaderboard: dailylb, // lbBanned: banned, name: name, needsToVerify: values[0].needsToVerify, needsToVerifyEmail: values[0].needsToVerifyEmail, tagPbs: tagPbs, }; if (ispb) { let logobj = request.obj; logobj.keySpacing = "removed"; logobj.keyDuration = "removed"; console.log( `saved result for ${req.uid} (new PB) - ${JSON.stringify(logobj)}` ); /* User.findOne({ name: userdata.name }, (err, user2) => { console.log(user2.results[user2.results.length-1]) console.log(user2.results[user2.results.length-1]).isPb user2.results[user2.results.length-1].isPb = true; user2.save(); }) */ request.obj.isPb = true; if ( obj.mode === "time" && String(obj.mode2) === "60" && userdata.discordId !== null && userdata.discordId !== undefined ) { if (verified !== false) { console.log( `sending command to the bot to update the role for user ${req.uid} with wpm ${obj.wpm}` ); updateDiscordRole(userdata.discordId, Math.round(obj.wpm)); } } returnobj.resultCode = 2; } else { let logobj = request.obj; logobj.keySpacing = "removed"; logobj.keyDuration = "removed"; request.obj.isPb = false; console.log( `saved result for ${req.uid} - ${JSON.stringify(logobj)}` ); returnobj.resultCode = 1; } stripAndSave(req.uid, request.obj); res.status(200).send(returnobj); }) .catch((e) => { console.error( `error saving result when checking for PB / checking leaderboards for ${req.uid} - ${e.message}` ); res .status(200) .send({ data: { resultCode: -999, message: e.message } }); }); } catch (e) { console.error( `error saving result for ${req.uid} - ${JSON.stringify( request.obj )} - ${e}` ); res.status(200).send({ resultCode: -999, message: e.message }); } }); }); app.post("/updateResultTags", authenticateToken, (req, res) => { try { let validTags = true; req.body.tags.forEach((tag) => { if (!/^[0-9a-zA-Z]+$/.test(tag)) validTags = false; }); if (validTags) { User.findOne({ uid: req.uid }, (err, user) => { for (let i = 0; i < user.results.length; i++) { if (user.results[i]._id.toString() === req.body.resultid.toString()) { user.results[i].tags = req.body.tags; user.save(); console.log( `user ${request.uid} updated tags for result ${request.resultid}` ); res.send({ resultCode: 1 }); return; } } console.error( `error while updating tags for result by user ${req.uid}: ${e.message}` ); res.send({ resultCode: -999 }); }); } else { console.error(`invalid tags for user ${req.uid}: ${req.body.tags}`); res.send({ resultCode: -1 }); } } catch (e) { console.error(`error updating tags by ${req.uid} - ${e}`); res.send({ resultCode: -999, message: e }); } });