diff --git a/src/middlewares/GlobalRateLimit.ts b/src/middlewares/GlobalRateLimit.ts
new file mode 100644
index 00000000..5c5f690a
--- /dev/null
+++ b/src/middlewares/GlobalRateLimit.ts
@@ -0,0 +1,43 @@
+import { NextFunction, Request, Response } from "express";
+import Config from "../util/Config";
+import db from "../util/Database";
+
+export async function GlobalRateLimit(req: Request, res: Response, next: NextFunction) {
+ if (!Config.get().server.ipRateLimit.enabled) return next();
+
+ const ip = getIpAdress(req);
+ let limit = (await db.data.ratelimit.global[ip].get()) || { start: Date.now(), count: 0 };
+ if (limit.start < Date.now() - Config.get().server.ipRateLimit.timespan) {
+ limit.start = Date.now();
+ limit.count = 0;
+ }
+
+ if (limit.count > Config.get().server.ipRateLimit.count) {
+ const timespan = Date.now() - limit.start;
+
+ return res
+ .set("Retry-After", `${timespan.toFixed(0)}`)
+ .set("X-RateLimit-Global", "true")
+ .status(429)
+ .json({
+ message: "You are being rate limited.",
+ retry_after: timespan,
+ global: true,
+ });
+ }
+
+ res.once("close", async () => {
+ if (res.statusCode >= 400) {
+ limit.count++;
+ await db.data.ratelimit.global[ip].set(limit);
+ }
+ });
+
+ return next();
+}
+
+export function getIpAdress(req: Request): string {
+ const { forwadedFor } = Config.get().server;
+ const ip = forwadedFor ? <string>req.headers[forwadedFor] : req.ip;
+ return ip.replaceAll(".", "_").replaceAll(":", "_");
+}
diff --git a/src/middlewares/RateLimit.ts b/src/middlewares/RateLimit.ts
new file mode 100644
index 00000000..abfc1c3d
--- /dev/null
+++ b/src/middlewares/RateLimit.ts
@@ -0,0 +1,40 @@
+import { NextFunction, Request, Response } from "express";
+import db from "../util/Database";
+import { getIpAdress } from "./GlobalRateLimit";
+
+export function RateLimit({ count = 10, timespan = 1000 * 5, name = "/" }) {
+ return async (req: Request, res: Response, next: NextFunction) => {
+ let id = req.userid || getIpAdress(req); // TODO: .replaceAll(".", "_"); // for ip adress replace all dots to save in database
+
+ const limit: { count: number; start: number } = (await db.data.ratelimit.routes[name][id].get()) || {
+ count: 0,
+ start: Date.now(),
+ };
+
+ if (limit.start < Date.now() - timespan) {
+ limit.start = Date.now();
+ limit.count = 0;
+ }
+
+ if (limit.count > count) {
+ const wait = Date.now() - limit.start;
+
+ return res
+ .set("Retry-After", `${wait.toFixed(0)}`)
+ .set("X-RateLimit-Limit", `${count}`)
+ .set("X-RateLimit-Remaining", "0")
+ .set("X-RateLimit-Reset", `${limit.start + wait}`)
+ .set("X-RateLimit-Reset-After", `${wait}`)
+ .set("X-RateLimit-Bucket", name)
+ .set("X-RateLimit-Global", "false")
+ .status(429)
+ .json({
+ message: "You are being rate limited.",
+ retry_after: wait,
+ global: false,
+ });
+ }
+
+ return next();
+ };
+}
|