mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:20:47 +00:00
revert
This commit is contained in:
+1
-11
@@ -259,7 +259,6 @@ class Client {
|
||||
private storeModal: StoreModal;
|
||||
private tokenLoginModal: TokenLoginModal;
|
||||
private matchmakingModal: MatchmakingModal;
|
||||
private mostRecentJoinEvent: number;
|
||||
|
||||
private turnstileTokenPromise: Promise<{
|
||||
token: string;
|
||||
@@ -756,7 +755,6 @@ class Client {
|
||||
|
||||
private async handleJoinLobby(event: CustomEvent<JoinLobbyEvent>) {
|
||||
const lobby = event.detail;
|
||||
this.mostRecentJoinEvent = event.timeStamp;
|
||||
if (this.usernameInput && !this.usernameInput.validateOrShowError()) {
|
||||
return;
|
||||
}
|
||||
@@ -777,7 +775,7 @@ class Client {
|
||||
}
|
||||
const auth = await userAuth();
|
||||
const playerRole = auth !== false ? (auth.claims.role ?? null) : null;
|
||||
const newLobbyHandle = joinLobby(this.eventBus, {
|
||||
this.lobbyHandle = joinLobby(this.eventBus, {
|
||||
gameID: lobby.gameID,
|
||||
serverConfig: config,
|
||||
cosmetics: await getPlayerCosmeticsRefs(),
|
||||
@@ -789,14 +787,6 @@ class Client {
|
||||
gameRecord: lobby.gameRecord,
|
||||
});
|
||||
|
||||
if (this.mostRecentJoinEvent !== event.timeStamp) {
|
||||
newLobbyHandle.stop(true);
|
||||
console.warn("Join requested, but was superseded");
|
||||
return;
|
||||
}
|
||||
|
||||
this.lobbyHandle = newLobbyHandle;
|
||||
|
||||
this.lobbyHandle.prestart.then(() => {
|
||||
console.log("Closing modals");
|
||||
document.getElementById("settings-button")?.classList.add("hidden");
|
||||
|
||||
+12
-19
@@ -593,22 +593,19 @@ export class GameServer {
|
||||
(c) => c.clientID !== client.clientID,
|
||||
);
|
||||
|
||||
if (!this._hasStarted) {
|
||||
// Remove persistentId if the game has not started to prevent going over max players
|
||||
this.persistentIdToClientId.delete(client.persistentID);
|
||||
// Close lobby when host leaves before game starts
|
||||
if (
|
||||
!this.isPublic() &&
|
||||
client.persistentID === this.creatorPersistentID
|
||||
) {
|
||||
this.log.info("Host left, closing lobby", {
|
||||
gameID: this.id,
|
||||
});
|
||||
for (const c of [...this.activeClients]) {
|
||||
this.kickClient(c.clientID, KICK_REASON_HOST_LEFT);
|
||||
}
|
||||
this._hasEnded = true;
|
||||
// Close lobby when host leaves before game starts
|
||||
if (
|
||||
!this._hasStarted &&
|
||||
!this.isPublic() &&
|
||||
client.persistentID === this.creatorPersistentID
|
||||
) {
|
||||
this.log.info("Host left, closing lobby", {
|
||||
gameID: this.id,
|
||||
});
|
||||
for (const c of [...this.activeClients]) {
|
||||
this.kickClient(c.clientID, KICK_REASON_HOST_LEFT);
|
||||
}
|
||||
this._hasEnded = true;
|
||||
}
|
||||
});
|
||||
client.ws.on("error", (error: Error) => {
|
||||
@@ -626,10 +623,6 @@ export class GameServer {
|
||||
this.activeClients = this.activeClients.filter(
|
||||
(c) => c.clientID !== client.clientID,
|
||||
);
|
||||
// Remove persistentId if the game has not started to prevent going over max players
|
||||
if (!this._hasStarted) {
|
||||
this.persistentIdToClientId.delete(client.persistentID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-5
@@ -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";
|
||||
@@ -286,7 +287,16 @@ export async function startWorker() {
|
||||
// WebSocket handling
|
||||
wss.on("connection", (ws: WebSocket, req) => {
|
||||
ws.on("message", async (message: string) => {
|
||||
const ip = getClientIp(req);
|
||||
const forwarded = req.headers["x-forwarded-for"];
|
||||
const ip = Array.isArray(forwarded)
|
||||
? forwarded[0]
|
||||
: // 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
|
||||
@@ -619,8 +629,20 @@ function generateGameIdForWorker(): GameID | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getClientIp(req: http.IncomingMessage): string {
|
||||
const cfIp = req.headers["cf-connecting-ip"];
|
||||
if (typeof cfIp === "string" && cfIp) return cfIp;
|
||||
return req.socket.remoteAddress ?? "unknown";
|
||||
// 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);
|
||||
|
||||
Reference in New Issue
Block a user