mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-02-04 21:09:18 +08:00
345 lines
No EOL
11 KiB
JavaScript
345 lines
No EOL
11 KiB
JavaScript
|
|
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 });
|
|
}
|
|
}); |