mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:20:47 +00:00
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:
@@ -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 (
|
||||
|
||||
@@ -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`, {
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
Reference in New Issue
Block a user