Close socket on ClientMessageSchema, improve zod error (#1003)

## Description:

- Close the socket on parse failure.
- Use `safeParse` and `prettifyError` to improve logging output on zod
validation failures.

## Please complete the following:

- [x] 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
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
Scott Anderson
2025-06-04 12:48:48 -04:00
committed by GitHub
parent a18b5e418b
commit 14ab1bcbba
2 changed files with 20 additions and 9 deletions
+10 -6
View File
@@ -1,9 +1,9 @@
import ipAnonymize from "ip-anonymize";
import { Logger } from "winston";
import WebSocket from "ws";
import { z } from "zod/v4";
import {
ClientID,
ClientMessage,
ClientMessageSchema,
ClientSendWinnerMessage,
GameConfig,
@@ -178,12 +178,16 @@ export class GameServer {
"message",
gatekeeper.wsHandler(client.ip, async (message: string) => {
try {
let clientMsg: ClientMessage | null = null;
try {
clientMsg = ClientMessageSchema.parse(JSON.parse(message));
} catch (error) {
throw Error(`error parsing schema for ${ipAnonymize(client.ip)}`);
const parsed = ClientMessageSchema.safeParse(JSON.parse(message));
if (!parsed.success) {
const error = z.prettifyError(parsed.error);
this.log.error("Failed to parse client message", error, {
clientID: client.clientID,
});
client.ws.close();
return;
}
const clientMsg = parsed.data;
if (clientMsg.type === "intent") {
if (clientMsg.intent.clientID !== client.clientID) {
this.log.warn(
+10 -3
View File
@@ -10,7 +10,8 @@ import { GameEnv } from "../core/configuration/Config";
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
import { GameType } from "../core/game/Game";
import {
ClientMessageSchema,
ClientJoinMessageSchema,
GameConfig,
GameRecord,
GameRecordSchema,
} from "../core/Schemas";
@@ -293,11 +294,17 @@ export function startWorker() {
: forwarded || req.socket.remoteAddress || "unknown";
try {
// Process WebSocket messages as in your original code
// Parse and handle client messages
const clientMsg = ClientMessageSchema.parse(
const parsed = ClientJoinMessageSchema.safeParse(
JSON.parse(message.toString()),
);
if (!parsed.success) {
const error = z.prettifyError(parsed.error);
log.warn("Error parsing join message client", error);
ws.close();
return;
}
const clientMsg = parsed.data;
if (clientMsg.type === "join") {
// Verify this worker should handle this game