feat: add rate limits to import/export
This commit is contained in:
parent
45941e47d6
commit
fc4f106afb
3 changed files with 32 additions and 2 deletions
|
@ -5,6 +5,8 @@ import { clientError, ok } from "../responses";
|
||||||
import { GuildCases } from "../../data/GuildCases";
|
import { GuildCases } from "../../data/GuildCases";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Case } from "../../data/entities/Case";
|
import { Case } from "../../data/entities/Case";
|
||||||
|
import { rateLimit } from "../rateLimits";
|
||||||
|
import { MINUTES } from "../../utils";
|
||||||
|
|
||||||
const caseHandlingModeSchema = z.union([
|
const caseHandlingModeSchema = z.union([
|
||||||
z.literal("replace"),
|
z.literal("replace"),
|
||||||
|
@ -62,6 +64,11 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) {
|
||||||
importExportRouter.post(
|
importExportRouter.post(
|
||||||
"/:guildId/import",
|
"/:guildId/import",
|
||||||
requireGuildPermission(ApiPermissions.ManageAccess),
|
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) => {
|
async (req: Request, res: Response) => {
|
||||||
let data: TImportExportData;
|
let data: TImportExportData;
|
||||||
try {
|
try {
|
||||||
|
@ -119,6 +126,11 @@ export function initGuildsImportExportAPI(guildRouter: express.Router) {
|
||||||
importExportRouter.post(
|
importExportRouter.post(
|
||||||
"/:guildId/export",
|
"/:guildId/export",
|
||||||
requireGuildPermission(ApiPermissions.ManageAccess),
|
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) => {
|
async (req: Request, res: Response) => {
|
||||||
const guildCases = GuildCases.getGuildInstance(req.params.guildId);
|
const guildCases = GuildCases.getGuildInstance(req.params.guildId);
|
||||||
|
|
||||||
|
|
18
backend/src/api/rateLimits.ts
Normal file
18
backend/src/api/rateLimits.ts
Normal 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();
|
||||||
|
};
|
||||||
|
}
|
|
@ -108,7 +108,7 @@ export default {
|
||||||
caseHandlingMode: this.importCaseMode,
|
caseHandlingMode: this.importCaseMode,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.importError = String(err);
|
this.importError = err.body?.error ?? String(err);
|
||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
this.importing = false;
|
this.importing = false;
|
||||||
|
@ -134,7 +134,7 @@ export default {
|
||||||
guildId: this.$route.params.guildId,
|
guildId: this.$route.params.guildId,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.exportError = String(err);
|
this.exportError = err.body?.error ?? String(err);
|
||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
this.exporting = false;
|
this.exporting = false;
|
||||||
|
|
Loading…
Add table
Reference in a new issue