add ws rate limiter

This commit is contained in:
Evan
2025-02-21 09:21:04 -08:00
parent cdf913ce26
commit 5dd323856e
5 changed files with 40 additions and 3 deletions
+7
View File
@@ -43,6 +43,7 @@
"protobufjs": "^7.3.2",
"pureimage": "^0.4.13",
"raphael": "^2.3.0",
"rate-limiter-flexible": "^5.0.5",
"twemoji": "^14.0.2",
"uuid": "^10.0.0",
"wheelnav": "^1.7.1",
@@ -13674,6 +13675,12 @@
"eve-raphael": "0.5.0"
}
},
"node_modules/rate-limiter-flexible": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-5.0.5.tgz",
"integrity": "sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==",
"license": "ISC"
},
"node_modules/raw-body": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+1
View File
@@ -106,6 +106,7 @@
"protobufjs": "^7.3.2",
"pureimage": "^0.4.13",
"raphael": "^2.3.0",
"rate-limiter-flexible": "^5.0.5",
"twemoji": "^14.0.2",
"uuid": "^10.0.0",
"wheelnav": "^1.7.1",
+1 -1
View File
@@ -144,7 +144,7 @@
</g>
</svg>
<div class="flex justify-center text-sm font-bold mt-[-5px] logo-version">
v0.15.2
v0.15.3
</div>
</div>
+13 -1
View File
@@ -18,6 +18,7 @@ import WebSocket from "ws";
import { slog } from "./StructuredLog";
import { CreateGameRecord } from "../core/Util";
import { archive } from "./Archive";
import { RateLimiterMemory } from "rate-limiter-flexible";
export enum GamePhase {
Lobby = "LOBBY",
@@ -26,6 +27,11 @@ export enum GamePhase {
}
export class GameServer {
private rateLimiter = new RateLimiterMemory({
points: 20, // 20 messages
duration: 1, // per 1 second
});
private maxGameDuration = 5 * 60 * 60 * 1000; // 5 hours
private turns: Turn[] = [];
@@ -98,7 +104,13 @@ export class GameServer {
this.allClients.set(client.clientID, client);
client.ws.on("message", (message: string) => {
client.ws.on("message", async (message: string) => {
try {
await this.rateLimiter.consume(client.ip);
} catch (error) {
console.warn(`Rate limit exceeded for ${client.ip}`);
return;
}
try {
const clientMsg: ClientMessage = ClientMessageSchema.parse(
JSON.parse(message),
+18 -1
View File
@@ -23,6 +23,7 @@ import {
} from "../core/validations/username";
import { Request, Response } from "express";
import rateLimit from "express-rate-limit";
import { RateLimiterMemory } from "rate-limiter-flexible";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@@ -43,6 +44,11 @@ app.use(
}),
);
const rateLimiter = new RateLimiterMemory({
points: 20, // 20 messages
duration: 1, // per 1 second
});
const gm = new GameManager(getServerConfig());
const bot = new DiscordBot();
@@ -153,7 +159,18 @@ app.get("*", function (req, res) {
});
wss.on("connection", (ws, req) => {
ws.on("message", (message: string) => {
ws.on("message", async (message: string) => {
let ip = "";
try {
const forwarded = req.headers["x-forwarded-for"];
ip = Array.isArray(forwarded)
? forwarded[0]
: forwarded || req.socket.remoteAddress;
await rateLimiter.consume(ip);
} catch (error) {
console.warn(`rate limit exceede for ${ip}`);
return;
}
try {
const clientMsg: ClientMessage = ClientMessageSchema.parse(
JSON.parse(message),