mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Have Worker rate limit ws messages (#3449)
## Description: Prevent client from spamming ws messages before joining a game server. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
This commit is contained in:
@@ -3,6 +3,7 @@ import express, { NextFunction, Request, Response } from "express";
|
||||
import rateLimit from "express-rate-limit";
|
||||
import http from "http";
|
||||
import ipAnonymize from "ip-anonymize";
|
||||
import { RateLimiter } from "limiter";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { WebSocket, WebSocketServer } from "ws";
|
||||
@@ -289,6 +290,11 @@ export async function startWorker() {
|
||||
: // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
forwarded || req.socket.remoteAddress || "unknown";
|
||||
|
||||
if (!getWsIpLimiter(ip).tryRemoveTokens(1)) {
|
||||
ws.close(1008, "Rate limit exceeded");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Parse and handle client messages
|
||||
const parsed = ClientMessageSchema.safeParse(
|
||||
@@ -609,3 +615,21 @@ function generateGameIdForWorker(): GameID | null {
|
||||
log.warn(`Failed to generate game ID for worker ${workerId}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Per-IP rate limiter for pre-join WebSocket messages.
|
||||
// Prevents unauthenticated connections from spamming messages
|
||||
// (e.g. pings) before joining a game.
|
||||
const wsIpLimiters = new Map<string, RateLimiter>();
|
||||
function getWsIpLimiter(ip: string): RateLimiter {
|
||||
let limiter = wsIpLimiters.get(ip);
|
||||
if (!limiter) {
|
||||
limiter = new RateLimiter({
|
||||
tokensPerInterval: 5,
|
||||
interval: "second",
|
||||
});
|
||||
wsIpLimiters.set(ip, limiter);
|
||||
}
|
||||
return limiter;
|
||||
}
|
||||
// Clean up stale IP limiters every 10 minutes
|
||||
setInterval(() => wsIpLimiters.clear(), 10 * 60 * 1000);
|
||||
|
||||
Reference in New Issue
Block a user