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:
Evan
2026-03-16 20:45:05 -07:00
committed by GitHub
parent 5e7317a818
commit dd2c239aa1
+24
View File
@@ -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);