Increase max intent size to 2kb (#3852)

## Description:

Raised MAX_INTENT_SIZE from 500 to 2000 bytes — the move_warship intent
could exceed the old limit and get rejected.
Removed the separate MAX_CONFIG_INTENT_SIZE (also 2000) and the
intentType branching, since both paths now share the same cap.
## Please complete the following:

- [ ] 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-05-05 14:59:09 -06:00
committed by GitHub
parent af5249655c
commit 7f9b63a24c
3 changed files with 13 additions and 18 deletions
+3 -15
View File
@@ -3,8 +3,7 @@ import { ClientID } from "../core/Schemas";
const INTENTS_PER_SECOND = 10;
const INTENTS_PER_MINUTE = 150;
const MAX_INTENT_SIZE = 500;
const MAX_CONFIG_INTENT_SIZE = 2000;
const MAX_INTENT_SIZE = 2000;
const TOTAL_BYTES = 2 * 1024 * 1024; // 2MB per client
export type RateLimitResult = "ok" | "limit" | "kick";
@@ -17,30 +16,19 @@ interface ClientBucket {
export class ClientMsgRateLimiter {
private buckets = new Map<ClientID, ClientBucket>();
check(
clientID: ClientID,
type: string,
bytes: number,
intentType?: string,
): RateLimitResult {
check(clientID: ClientID, type: string, bytes: number): RateLimitResult {
const bucket = this.getOrCreate(clientID);
bucket.totalBytes += bytes;
if (bucket.totalBytes >= TOTAL_BYTES) return "kick";
if (type === "intent") {
// Config updates are lobby-only and not stored in turn history,
// so they can be larger than regular intents.
const maxSize =
intentType === "update_game_config"
? MAX_CONFIG_INTENT_SIZE
: MAX_INTENT_SIZE;
// Intents are stored in turn history for the duration of the game, so
// oversized intents would accumulate and fill up server RAM.
// Intents are also sent to all players, so it increase outgoing
// data.
// Intents should never be larger than MAX_INTENT_SIZE, so we assume the client is malicious.
if (bytes > maxSize) {
if (bytes > MAX_INTENT_SIZE) {
return "kick";
}
if (
-3
View File
@@ -349,13 +349,10 @@ export class GameServer {
}
const clientMsg = parsed.data;
const bytes = Buffer.byteLength(message, "utf8");
const intentType =
clientMsg.type === "intent" ? clientMsg.intent.type : undefined;
const rateResult = this.intentRateLimiter.check(
client.clientID,
clientMsg.type,
bytes,
intentType,
);
if (rateResult === "kick") {
this.log.warn(`Client rate limit exceeded, kicking`, {
+10
View File
@@ -28,6 +28,16 @@ describe("ClientMsgRateLimiter", () => {
}
expect(limiter.check(CLIENT_B, "intent", SMALL)).toBe("ok");
});
it("allows intents up to MAX_INTENT_SIZE", () => {
const limiter = new ClientMsgRateLimiter();
expect(limiter.check(CLIENT_A, "intent", 2000)).toBe("ok");
});
it("kicks intents exceeding MAX_INTENT_SIZE", () => {
const limiter = new ClientMsgRateLimiter();
expect(limiter.check(CLIENT_A, "intent", 2001)).toBe("kick");
});
});
describe("non-intent messages", () => {