3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-03-15 05:41:51 +00:00

feat: add rate limits to import/export

This commit is contained in:
Dragory 2021-11-03 00:49:36 +02:00
parent 45941e47d6
commit fc4f106afb
No known key found for this signature in database
GPG key ID: 5F387BA66DF8AAC1
3 changed files with 32 additions and 2 deletions

View file

@ -5,6 +5,8 @@ import { clientError, ok } from "../responses";
import { GuildCases } from "../../data/GuildCases";
import { z } from "zod";
import { Case } from "../../data/entities/Case";
import { rateLimit } from "../rateLimits";
import { MINUTES } from "../../utils";
const caseHandlingModeSchema = z.union([
z.literal("replace"),
@ -62,6 +64,11 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) {
importExportRouter.post(
"/:guildId/import",
requireGuildPermission(ApiPermissions.ManageAccess),
rateLimit(
(req) => `import-${req.params.guildId}`,
5 * MINUTES,
"A single server can only import data once every 5 minutes",
),
async (req: Request, res: Response) => {
let data: TImportExportData;
try {
@ -119,6 +126,11 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) {
importExportRouter.post(
"/:guildId/export",
requireGuildPermission(ApiPermissions.ManageAccess),
rateLimit(
(req) => `export-${req.params.guildId}`,
5 * MINUTES,
"A single server can only export data once every 5 minutes",
),
async (req: Request, res: Response) => {
const guildCases = GuildCases.getGuildInstance(req.params.guildId);

View file

@ -0,0 +1,18 @@
import { Request, Response } from "express";
import { error } from "./responses";
const lastRequestsByKey: Map<string, number> = new Map();
export function rateLimit(getKey: (req: Request) => string, limitMs: number, message = "Rate limited") {
return async (req: Request, res: Response, next) => {
const key = getKey(req);
if (lastRequestsByKey.has(key)) {
if (lastRequestsByKey.get(key)! > Date.now() - limitMs) {
return error(res, message, 429);
}
}
lastRequestsByKey.set(key, Date.now());
next();
};
}

View file

@ -108,7 +108,7 @@ export default {
caseHandlingMode: this.importCaseMode,
});
} catch (err) {
this.importError = String(err);
this.importError = err.body?.error ?? String(err);
return;
} finally {
this.importing = false;
@ -134,7 +134,7 @@ export default {
guildId: this.$route.params.guildId,
});
} catch (err) {
this.exportError = String(err);
this.exportError = err.body?.error ?? String(err);
return;
} finally {
this.exporting = false;