backend: add gateway ratelimit

This commit is contained in:
hippoz 2022-04-14 17:17:54 +03:00
parent 2f19cb211d
commit 9c9f764e6d
Signed by: hippoz
GPG key ID: 7C52899193467641
3 changed files with 12 additions and 2 deletions

View file

@ -12,4 +12,5 @@ export const gatewayErrors = {
BAD_AUTH: { code: 4002, message: "Bad authentication" }, BAD_AUTH: { code: 4002, message: "Bad authentication" },
AUTHENTICATION_TIMEOUT: { code: 4003, message: "Authentication timeout" }, AUTHENTICATION_TIMEOUT: { code: 4003, message: "Authentication timeout" },
NO_PING: { code: 4004, message: "No ping" }, NO_PING: { code: 4004, message: "No ping" },
FLOODING: { code: 4005, message: "Flooding (exceeded maximum messages per batch)" },
}; };

View file

@ -9,6 +9,7 @@ import { GatewayPayloadType } from "./gatewaypayloadtype";
const GATEWAY_BATCH_INTERVAL = 50000; const GATEWAY_BATCH_INTERVAL = 50000;
const GATEWAY_PING_INTERVAL = 40000; const GATEWAY_PING_INTERVAL = 40000;
const MAX_CLIENT_MESSAGES_PER_BATCH = 6; // TODO: how well does this work for weak connections?
// mapping between a dispatch id and a websocket client // mapping between a dispatch id and a websocket client
const dispatchChannels = new Map<string, Set<WebSocket>>(); const dispatchChannels = new Map<string, Set<WebSocket>>();
@ -128,6 +129,7 @@ export default function(server: Server) {
if (!e.state.alive) { if (!e.state.alive) {
return closeWithError(e, gatewayErrors.NO_PING); return closeWithError(e, gatewayErrors.NO_PING);
} }
e.state.messagesSinceLastCheck = 0;
} }
}); });
}, GATEWAY_BATCH_INTERVAL); }, GATEWAY_BATCH_INTERVAL);
@ -144,7 +146,8 @@ export default function(server: Server) {
alive: false, alive: false,
ready: false, ready: false,
lastAliveCheck: performance.now(), lastAliveCheck: performance.now(),
dispatchChannels: new Set() dispatchChannels: new Set(),
messagesSinceLastCheck: 0
}; };
sendPayload(ws, { sendPayload(ws, {
@ -163,6 +166,11 @@ export default function(server: Server) {
return closeWithBadPayload(ws, "Binary messages are not supported"); return closeWithBadPayload(ws, "Binary messages are not supported");
} }
ws.state.messagesSinceLastCheck++;
if (ws.state.messagesSinceLastCheck > MAX_CLIENT_MESSAGES_PER_BATCH) {
return closeWithError(ws, gatewayErrors.FLOODING);
}
const payload = ensureFormattedGatewayPayload(parseJsonOrNull(rawData.toString())); const payload = ensureFormattedGatewayPayload(parseJsonOrNull(rawData.toString()));
if (!payload) { if (!payload) {
return closeWithBadPayload(ws, "Invalid JSON or message does not match schema"); return closeWithBadPayload(ws, "Invalid JSON or message does not match schema");

View file

@ -3,5 +3,6 @@ interface GatewayClientState {
ready: boolean, ready: boolean,
alive: boolean, alive: boolean,
lastAliveCheck: number, lastAliveCheck: number,
dispatchChannels: Set<string> dispatchChannels: Set<string>,
messagesSinceLastCheck: number
} }