fix: endpoints share the same rate limit (#2136) by CameronCT

* fix: cleaned rate limiter

* chore: separated ratelimits per request

* fix: bug where leaderboards would crash
This commit is contained in:
Cameron 2021-11-29 16:49:05 -08:00 committed by GitHub
parent 8ae20c5626
commit e56d534f33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 275 additions and 113 deletions

View file

@ -7,14 +7,14 @@ const router = Router();
router.get(
"/",
RateLimit.limit60perhour,
RateLimit.configGet,
authenticateRequest,
ConfigController.getConfig
);
router.post(
"/save",
RateLimit.limit500perhour,
RateLimit.configUpdate,
authenticateRequest,
ConfigController.saveConfig
);

View file

@ -6,20 +6,13 @@ const { Router } = require("express");
const router = Router();
router.get("/", RateLimit.limit1persec, LeaderboardsController.get);
router.get("/", RateLimit.leaderboardsGet, LeaderboardsController.get);
router.get(
"/rank",
RateLimit.limit1persec,
RateLimit.leaderboardsGet,
authenticateRequest,
LeaderboardsController.getRank
);
router.post(
"/update",
RateLimit.limit60perhour,
authenticateRequest,
LeaderboardsController.update
);
module.exports = router;

View file

@ -7,28 +7,28 @@ const router = Router();
router.get(
"/get",
RateLimit.limit500perhour,
RateLimit.newQuotesGet,
authenticateRequest,
NewQuotesController.getQuotes
);
router.post(
"/add",
RateLimit.limit60perhour,
RateLimit.newQuotesAdd,
authenticateRequest,
NewQuotesController.addQuote
);
router.post(
"/approve",
RateLimit.limit500perhour,
RateLimit.newQuotesAction,
authenticateRequest,
NewQuotesController.approve
);
router.post(
"/refuse",
RateLimit.limit500perhour,
RateLimit.newQuotesAction,
authenticateRequest,
NewQuotesController.refuse
);

View file

@ -8,28 +8,28 @@ const router = Router();
router.get(
"/",
RateLimit.limit60perhour,
RateLimit.presetsGet,
authenticateRequest,
PresetController.getPresets
);
router.post(
"/add",
RateLimit.limit60perhour,
RateLimit.presetsAdd,
authenticateRequest,
PresetController.addPreset
);
router.post(
"/edit",
RateLimit.limit60perhour,
RateLimit.presetsEdit,
authenticateRequest,
PresetController.editPreset
);
router.post(
"/remove",
RateLimit.limit60perhour,
RateLimit.presetsRemove,
authenticateRequest,
PresetController.removePreset
);

View file

@ -6,6 +6,6 @@ const { Router } = require("express");
const router = Router();
router.get("/", RateLimit.limit1persec, PsaController.get);
router.get("/", RateLimit.psaGet, PsaController.get);
module.exports = router;

View file

@ -7,14 +7,14 @@ const router = Router();
router.get(
"/get",
RateLimit.limit500perhour,
RateLimit.quoteRatingsGet,
authenticateRequest,
QuoteRatingsController.getRating
);
router.post(
"/submit",
RateLimit.limit500perhour,
RateLimit.quoteRatingsSubmit,
authenticateRequest,
QuoteRatingsController.submitRating
);

View file

@ -7,41 +7,41 @@ const router = Router();
router.get(
"/",
RateLimit.limit60perhour,
RateLimit.resultsGet,
authenticateRequest,
ResultController.getResults
);
router.post(
"/add",
RateLimit.limit500perhour,
RateLimit.resultsAdd,
authenticateRequest,
ResultController.addResult
);
router.post(
"/updateTags",
RateLimit.limit500perhour,
RateLimit.resultsTagsUpdate,
authenticateRequest,
ResultController.updateTags
);
router.post(
"/deleteAll",
RateLimit.limit60perhour,
RateLimit.resultsDeleteAll,
authenticateRequest,
ResultController.deleteAll
);
router.get(
"/getLeaderboard/:type/:mode/:mode2",
RateLimit.limit60perhour,
RateLimit.resultsLeaderboardGet,
ResultController.getLeaderboard
);
router.post(
"/checkLeaderboardQualification",
RateLimit.limit60perhour,
RateLimit.resultsLeaderboardQualificationGet,
authenticateRequest,
ResultController.checkLeaderboardQualification
);

View file

@ -7,100 +7,100 @@ const router = Router();
router.get(
"/",
RateLimit.limit120perhour,
RateLimit.userGet,
authenticateRequest,
UserController.getUser
);
router.post(
"/signup",
RateLimit.limit3perday,
RateLimit.userSignup,
authenticateRequest,
UserController.createNewUser
);
router.post("/checkName", RateLimit.limit1persec, UserController.checkName);
router.post("/checkName", RateLimit.userCheckName, UserController.checkName);
router.post(
"/delete",
RateLimit.limit3perday,
RateLimit.userDelete,
authenticateRequest,
UserController.deleteUser
);
router.post(
"/updateName",
RateLimit.limit3perday,
RateLimit.userUpdateName,
authenticateRequest,
UserController.updateName
);
router.post(
"/updateLbMemory",
RateLimit.limit1persec,
RateLimit.userUpdateLBMemory,
authenticateRequest,
UserController.updateLbMemory
);
router.post(
"/updateEmail",
RateLimit.limit60perhour,
RateLimit.userUpdateEmail,
authenticateRequest,
UserController.updateEmail
);
router.post(
"/clearPb",
RateLimit.limit60perhour,
RateLimit.userClearPB,
authenticateRequest,
UserController.clearPb
);
router.post(
"/tags/add",
RateLimit.limit60perhour,
RateLimit.userTagsAdd,
authenticateRequest,
UserController.addTag
);
router.get(
"/tags",
RateLimit.limit60perhour,
RateLimit.userTagsGet,
authenticateRequest,
UserController.getTags
);
router.post(
"/tags/clearPb",
RateLimit.limit60perhour,
RateLimit.userTagsClearPB,
authenticateRequest,
UserController.clearTagPb
);
router.post(
"/tags/remove",
RateLimit.limit60perhour,
RateLimit.userTagsRemove,
authenticateRequest,
UserController.removeTag
);
router.post(
"/tags/edit",
RateLimit.limit60perhour,
RateLimit.userTagsEdit,
authenticateRequest,
UserController.editTag
);
router.post(
"/discord/link",
RateLimit.limit60perhour,
RateLimit.userDiscordLink,
authenticateRequest,
UserController.linkDiscord
);
router.post(
"/discord/unlink",
RateLimit.limit60perhour,
RateLimit.userDiscordUnlink,
authenticateRequest,
UserController.unlinkDiscord
);

View file

@ -90,9 +90,10 @@ class LeaderboardsDAO {
.collection(`leaderboards.${language}.${mode}.${mode2}`)
.drop();
} catch (e) {}
await mongoDB()
.collection(`leaderboards.${language}.${mode}.${mode2}`)
.insertMany(lb);
if (lb && lb.length !== 0)
await mongoDB()
.collection(`leaderboards.${language}.${mode}.${mode2}`)
.insertMany(lb);
let end3 = performance.now();
let start4 = performance.now();

View file

@ -1,83 +1,251 @@
const rateLimit = require("express-rate-limit");
let multiplier = process.env.MODE === "dev" ? 100 : 1;
const getAddress = (req) => req.headers["cf-connecting-ip"] || req.headers["x-forwarded-for"] || req.ip || "255.255.255.255";
const message = "Too many requests, please try again later";
const multiplier = process.env.MODE === "dev" ? 100 : 1;
exports.limit60perhour = rateLimit({
// Config Routing
exports.configUpdate = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message: {
message: "Too many requests, please try again later",
},
keyGenerator: (req) => {
return `${
req.headers["cf-connecting-ip"] ||
req.headers["x-forwarded-for"] ||
req.ip ||
"255.255.255.255"
}`;
},
max: 500 * multiplier,
message,
keyGenerator: getAddress
});
exports.limit120perhour = rateLimit({
exports.configGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 120 * multiplier,
message: {
message: "Too many requests, please try again later",
},
keyGenerator: (req) => {
return `${
req.headers["cf-connecting-ip"] ||
req.headers["x-forwarded-for"] ||
req.ip ||
"255.255.255.255"
}`;
},
message,
keyGenerator: getAddress
});
exports.limit3perday = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 1 day
max: 3 * multiplier,
message: {
message: "Too many requests, please try again later",
},
keyGenerator: (req) => {
return `${
req.headers["cf-connecting-ip"] ||
req.headers["x-forwarded-for"] ||
req.ip ||
"255.255.255.255"
}`;
},
});
exports.limit1persec = rateLimit({
windowMs: 60 * 1000,
// Leaderboards Routing
exports.leaderboardsGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message: {
message: "Too many requests, please try again later",
},
keyGenerator: (req) => {
return `${
req.headers["cf-connecting-ip"] ||
req.headers["x-forwarded-for"] ||
req.ip ||
"255.255.255.255"
}`;
},
message,
keyGenerator: getAddress
});
exports.limit500perhour = rateLimit({
// New Quotes Routing
exports.newQuotesGet = rateLimit({
windowMs: 60 * 60 * 1000,
max: 500 * multiplier,
message: {
message: "Too many requests, please try again later",
},
keyGenerator: (req) => {
return `${
req.headers["cf-connecting-ip"] ||
req.headers["x-forwarded-for"] ||
req.ip ||
"255.255.255.255"
}`;
},
message,
keyGenerator: getAddress
});
exports.newQuotesAdd = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.newQuotesAction = rateLimit({
windowMs: 60 * 60 * 1000,
max: 500 * multiplier,
message,
keyGenerator: getAddress
});
// Quote Ratings Routing
exports.quoteRatingsGet = rateLimit({
windowMs: 60 * 60 * 1000,
max: 500 * multiplier,
message,
keyGenerator: getAddress
});
exports.quoteRatingsSubmit = rateLimit({
windowMs: 60 * 60 * 1000,
max: 500 * multiplier,
message,
keyGenerator: getAddress
});
// Presets Routing
exports.presetsGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.presetsAdd = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.presetsRemove = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.presetsEdit = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
// PSA (Public Service Announcement) Routing
exports.psaGet = rateLimit({
windowMs: 60 * 1000,
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
// Results Routing
exports.resultsGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.resultsAdd = rateLimit({
windowMs: 60 * 60 * 1000,
max: 500 * multiplier,
message,
keyGenerator: getAddress
});
exports.resultsTagsUpdate = rateLimit({
windowMs: 60 * 60 * 1000,
max: 30 * multiplier,
message,
keyGenerator: getAddress
});
exports.resultsDeleteAll = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 10 * multiplier,
message,
keyGenerator: getAddress
});
exports.resultsLeaderboardGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.resultsLeaderboardQualificationGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
// Users Routing
exports.userGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 1 * multiplier,
message,
keyGenerator: getAddress
});
exports.userSignup = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 1 day
max: 3 * multiplier,
message,
keyGenerator: getAddress
});
exports.userDelete = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 1 day
max: 3 * multiplier,
message,
keyGenerator: getAddress
});
exports.userCheckName = rateLimit({
windowMs: 60 * 1000,
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.userUpdateName = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 1 day
max: 3 * multiplier,
message,
keyGenerator: getAddress
});
exports.userUpdateLBMemory = rateLimit({
windowMs: 60 * 1000,
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.userUpdateEmail = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.userClearPB = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.userTagsGet = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.userTagsRemove = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 30 * multiplier,
message,
keyGenerator: getAddress
});
exports.userTagsClearPB = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 60 * multiplier,
message,
keyGenerator: getAddress
});
exports.userTagsEdit = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 30 * multiplier,
message,
keyGenerator: getAddress
});
exports.userTagsAdd = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 30 * multiplier,
message,
keyGenerator: getAddress
});
exports.userDiscordLink = exports.usersTagsEdit = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 15 * multiplier,
message,
keyGenerator: getAddress
});
exports.userDiscordUnlink = exports.usersTagsEdit = rateLimit({
windowMs: 60 * 60 * 1000, // 60 min
max: 15 * multiplier,
message,
keyGenerator: getAddress
});