mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-24 04:58:01 +00:00
only allow 1 ip per game, don't allow modifying public games
This commit is contained in:
@@ -40,6 +40,10 @@ export class GameManager {
|
||||
console.warn(`game ${gameID} not found`);
|
||||
return;
|
||||
}
|
||||
if (game.isPublic) {
|
||||
console.warn(`cannot update public game ${gameID}`);
|
||||
return;
|
||||
}
|
||||
game.updateGameConfig(gameConfig);
|
||||
}
|
||||
|
||||
@@ -53,7 +57,7 @@ export class GameManager {
|
||||
disableBots: false,
|
||||
disableNPCs: false,
|
||||
creativeMode: false,
|
||||
}),
|
||||
})
|
||||
);
|
||||
return id;
|
||||
}
|
||||
@@ -61,7 +65,7 @@ export class GameManager {
|
||||
hasActiveGame(gameID: GameID): boolean {
|
||||
const game = this.games
|
||||
.filter(
|
||||
(g) => g.phase() == GamePhase.Lobby || g.phase() == GamePhase.Active,
|
||||
(g) => g.phase() == GamePhase.Lobby || g.phase() == GamePhase.Active
|
||||
)
|
||||
.find((g) => g.id == gameID);
|
||||
return game != null;
|
||||
@@ -122,7 +126,7 @@ export class GameManager {
|
||||
disableBots: false,
|
||||
disableNPCs: false,
|
||||
creativeMode: false,
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -28,7 +28,7 @@ export enum GamePhase {
|
||||
|
||||
export class GameServer {
|
||||
private rateLimiter = new RateLimiterMemory({
|
||||
points: 20, // 20 messages
|
||||
points: 50,
|
||||
duration: 1, // per 1 second
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ export class GameServer {
|
||||
public readonly createdAt: number,
|
||||
public readonly isPublic: boolean,
|
||||
private config: ServerConfig,
|
||||
public gameConfig: GameConfig,
|
||||
public gameConfig: GameConfig
|
||||
) {}
|
||||
|
||||
public updateGameConfig(gameConfig: GameConfig): void {
|
||||
@@ -91,13 +91,13 @@ export class GameServer {
|
||||
});
|
||||
// Remove stale client if this is a reconnect
|
||||
const existing = this.activeClients.find(
|
||||
(c) => c.clientID == client.clientID || client.ip == c.ip,
|
||||
(c) => c.clientID == client.clientID || client.ip == c.ip
|
||||
);
|
||||
if (existing != null) {
|
||||
existing.ws.removeAllListeners("message");
|
||||
}
|
||||
this.activeClients = this.activeClients.filter(
|
||||
(c) => c.clientID != client.clientID,
|
||||
(c) => c.clientID != client.clientID
|
||||
);
|
||||
this.activeClients.push(client);
|
||||
client.lastPing = Date.now();
|
||||
@@ -113,7 +113,7 @@ export class GameServer {
|
||||
}
|
||||
try {
|
||||
const clientMsg: ClientMessage = ClientMessageSchema.parse(
|
||||
JSON.parse(message),
|
||||
JSON.parse(message)
|
||||
);
|
||||
if (this.allClients.has(clientMsg.clientID)) {
|
||||
const client = this.allClients.get(clientMsg.clientID);
|
||||
@@ -133,7 +133,7 @@ export class GameServer {
|
||||
this.addIntent(clientMsg.intent);
|
||||
} else {
|
||||
console.warn(
|
||||
`${this.id}: client ${clientMsg.clientID} sent to wrong game`,
|
||||
`${this.id}: client ${clientMsg.clientID} sent to wrong game`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -146,14 +146,14 @@ export class GameServer {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(
|
||||
`error handline websocket request in game server: ${error}`,
|
||||
`error handline websocket request in game server: ${error}`
|
||||
);
|
||||
}
|
||||
});
|
||||
client.ws.on("close", () => {
|
||||
console.log(`${this.id}: client ${client.clientID} disconnected`);
|
||||
this.activeClients = this.activeClients.filter(
|
||||
(c) => c.clientID != client.clientID,
|
||||
(c) => c.clientID != client.clientID
|
||||
);
|
||||
});
|
||||
client.ws.on("error", (error: Error) => {
|
||||
@@ -190,7 +190,7 @@ export class GameServer {
|
||||
|
||||
this.endTurnIntervalID = setInterval(
|
||||
() => this.endTurn(),
|
||||
this.config.turnIntervalMs(),
|
||||
this.config.turnIntervalMs()
|
||||
);
|
||||
this.activeClients.forEach((c) => {
|
||||
console.log(`${this.id}: sending start message to ${c.clientID}`);
|
||||
@@ -209,8 +209,8 @@ export class GameServer {
|
||||
type: "start",
|
||||
turns: this.turns.slice(lastTurn),
|
||||
config: this.gameConfig,
|
||||
}),
|
||||
),
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ export class GameServer {
|
||||
ServerTurnMessageSchema.parse({
|
||||
type: "turn",
|
||||
turn: pastTurn,
|
||||
}),
|
||||
})
|
||||
);
|
||||
this.activeClients.forEach((c) => {
|
||||
c.ws.send(msg);
|
||||
@@ -244,12 +244,12 @@ export class GameServer {
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
`${this.id}: ending game ${this.id} with ${this.turns.length} turns`,
|
||||
`${this.id}: ending game ${this.id} with ${this.turns.length} turns`
|
||||
);
|
||||
try {
|
||||
if (this.allClients.size > 0) {
|
||||
const playerRecords: PlayerRecord[] = Array.from(
|
||||
this.allClients.values(),
|
||||
this.allClients.values()
|
||||
).map((client) => ({
|
||||
ip: client.ip,
|
||||
clientID: client.clientID,
|
||||
@@ -264,8 +264,8 @@ export class GameServer {
|
||||
this.turns,
|
||||
this._startTime,
|
||||
Date.now(),
|
||||
this.winner,
|
||||
),
|
||||
this.winner
|
||||
)
|
||||
);
|
||||
} else {
|
||||
console.log(`${this.id}: no clients joined, not archiving game`);
|
||||
@@ -301,7 +301,7 @@ export class GameServer {
|
||||
for (const client of this.activeClients) {
|
||||
if (now - client.lastPing > 60_000) {
|
||||
console.log(
|
||||
`${this.id}: no pings from ${client.clientID}, terminating connection`,
|
||||
`${this.id}: no pings from ${client.clientID}, terminating connection`
|
||||
);
|
||||
if (client.ws.readyState === WebSocket.OPEN) {
|
||||
client.ws.close(1000, "no heartbeats received, closing connection");
|
||||
|
||||
@@ -59,11 +59,11 @@ app.use(
|
||||
rateLimit({
|
||||
windowMs: 1000, // 1 second
|
||||
max: 20, // 20 requests per IP per second
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
const rateLimiter = new RateLimiterMemory({
|
||||
points: 20, // 20 messages
|
||||
points: 50, // 50 messages
|
||||
duration: 1, // per 1 second
|
||||
});
|
||||
|
||||
@@ -259,7 +259,7 @@ wss.on("connection", (ws, req) => {
|
||||
}
|
||||
try {
|
||||
const clientMsg: ClientMessage = ClientMessageSchema.parse(
|
||||
JSON.parse(message),
|
||||
JSON.parse(message)
|
||||
);
|
||||
if (clientMsg.type == "join") {
|
||||
const forwarded = req.headers["x-forwarded-for"];
|
||||
@@ -272,7 +272,7 @@ wss.on("connection", (ws, req) => {
|
||||
const { isValid, error } = validateUsername(clientMsg.username);
|
||||
if (!isValid) {
|
||||
console.log(
|
||||
`game ${clientMsg.gameID}, client ${clientMsg.clientID} received invalid username, ${error}`,
|
||||
`game ${clientMsg.gameID}, client ${clientMsg.clientID} received invalid username, ${error}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -283,10 +283,10 @@ wss.on("connection", (ws, req) => {
|
||||
clientMsg.persistentID,
|
||||
ip,
|
||||
clientMsg.username,
|
||||
ws,
|
||||
ws
|
||||
),
|
||||
clientMsg.gameID,
|
||||
clientMsg.lastTurn,
|
||||
clientMsg.lastTurn
|
||||
);
|
||||
if (!wasFound) {
|
||||
console.log(`game ${clientMsg.gameID} not found, loading from gcs`);
|
||||
@@ -313,7 +313,7 @@ wss.on("connection", (ws, req) => {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`errror handling websocket message: ${error}`);
|
||||
console.warn(`errror handling websocket message for ${ip}: ${error}`);
|
||||
}
|
||||
});
|
||||
ws.on("error", (error: Error) => {
|
||||
|
||||
Reference in New Issue
Block a user