monkeytype/backend/handlers/result.js

345 lines
11 KiB
JavaScript
Raw Normal View History

2021-06-07 21:29:51 +08:00
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 });
}
});