backend/gateway: add session count limit per user id

This commit is contained in:
hippoz 2022-04-14 21:52:42 +03:00
parent bf5e4f554e
commit e329c64eb7
Signed by: hippoz
GPG key ID: 7C52899193467641
2 changed files with 27 additions and 1 deletions

View file

@ -15,4 +15,5 @@ export const gatewayErrors = {
FLOODING: { code: 4005, message: "Flooding (exceeded maximum messages per batch)" },
ALREADY_AUTHENTICATED: { code: 4006, message: "Already authenticated" },
PAYLOAD_TOO_LARGE: { code: 4007, message: "Payload too large" },
TOO_MANY_SESSIONS: { code: 4008, message: "Too many sessions" },
};

View file

@ -10,10 +10,14 @@ import { GatewayPayloadType } from "./gatewaypayloadtype";
const GATEWAY_BATCH_INTERVAL = 50000;
const GATEWAY_PING_INTERVAL = 40000;
const MAX_CLIENT_MESSAGES_PER_BATCH = 6; // TODO: how well does this work for weak connections?
const MAX_GATEWAY_SESSIONS_PER_USER = 5;
// mapping between a dispatch id and a websocket client
const dispatchChannels = new Map<string, Set<WebSocket>>();
// mapping between a user id and the websocket sessions it has
const sessionsByUserId = new Map<number, Set<WebSocket>>();
function clientSubscribe(ws: WebSocket, dispatchChannel: string) {
ws.state.dispatchChannels.add(dispatchChannel);
if (!dispatchChannels.get(dispatchChannel)) {
@ -159,6 +163,15 @@ export default function(server: Server) {
ws.on("close", () => {
clientUnsubscribeAll(ws);
if (ws.state.user && ws.state.user.id) {
const sessions = sessionsByUserId.get(ws.state.user.id);
if (sessions) {
sessions.delete(ws);
if (sessions.size < 1) {
sessionsByUserId.delete(ws.state.user.id);
}
}
}
});
ws.on("message", async (rawData, isBinary) => {
@ -195,7 +208,19 @@ export default function(server: Server) {
if (!user) {
return closeWithError(ws, gatewayErrors.BAD_AUTH);
}
// each user should have their own list of channels that they join
let sessions = sessionsByUserId.get(user.id);
if (sessions) {
if ((sessions.size + 1) > MAX_GATEWAY_SESSIONS_PER_USER) {
return closeWithError(ws, gatewayErrors.TOO_MANY_SESSIONS);
}
} else {
sessions = new Set();
sessionsByUserId.set(user.id, sessions);
}
sessions.add(ws);
// TODO: each user should have their own list of channels that they join
const channels = await query("SELECT id, name, owner_id FROM channels");
clientSubscribe(ws, "*");