Display a dialog with join failure reason (#1756)

## Description:

Add an error dialog for each type of join failure.

Fixes #1447

## Please complete the following:

- [ ] 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
This commit is contained in:
Scott Anderson
2025-08-17 03:59:13 -04:00
committed by GitHub
parent 294d9dbfa4
commit e9f29be93c
@@ -38,8 +38,7 @@ export async function preJoinMessageHandler(
return;
} else if (result.success === false) {
// Join failure
const { code, description, error, reason } = result;
log.warn(`${reason}: ${description}`, error);
const { code, error, reason } = result;
if (error) {
ws.send(
JSON.stringify({
@@ -68,8 +67,7 @@ async function handleJoinMessage(
| {
success: false;
code: 1002;
description: string;
error?: string;
error: string;
reason:
| "ClientJoinMessageSchema"
| "Flag invalid"
@@ -86,7 +84,6 @@ async function handleJoinMessage(
code: 1011;
reason: "Internal server error";
error: string;
description: string;
}
> {
const forwarded = req.headers["x-forwarded-for"];
@@ -102,9 +99,9 @@ async function handleJoinMessage(
);
if (!parsed.success) {
const error = z.prettifyError(parsed.error);
log.warn("Error parsing client message:", error);
return {
code: 1002,
description: "Error parsing client message",
error,
reason: "ClientJoinMessageSchema",
success: false,
@@ -132,9 +129,10 @@ async function handleJoinMessage(
// Verify token signature
const result = await verifyClientToken(clientMsg.token, config);
if (result === false) {
log.warn("Unauthorized: Invalid token");
return {
code: 1002,
description: "Unauthorized: Invalid token",
error: "The game server did not recognize your session token",
reason: "Unauthorized",
success: false,
};
@@ -146,10 +144,13 @@ async function handleJoinMessage(
const allowedFlares = config.allowedFlares();
if (claims === null) {
// Anonymous user
if (allowedFlares !== undefined) {
// Login is required
log.warn("Unauthorized: Anonymous user attempted to join game");
return {
code: 1002,
description: "Unauthorized: Anonymous user attempted to join game",
error: "A valid login is required to join this game",
reason: "Unauthorized",
success: false,
};
@@ -158,9 +159,10 @@ async function handleJoinMessage(
// Verify token and get player permissions
const result = await getUserMe(clientMsg.token, config);
if (result === false) {
log.warn("Unauthorized: Token verification failed");
return {
code: 1002,
description: "Unauthorized: Anonymous user attempted to join game",
error: "The game server did not recognize your session token",
reason: "Unauthorized",
success: false,
};
@@ -169,14 +171,17 @@ async function handleJoinMessage(
flares = result.player.flares;
if (allowedFlares !== undefined) {
// Login is required
const allowed =
allowedFlares.length === 0 ||
allowedFlares.some((f) => flares?.includes(f));
if (!allowed) {
log.warn(
"Fobidden: player without an allowed flare attempted to join game",
);
return {
code: 1002,
description:
"Forbidden: player without an allowed flare attempted to join game",
error: "You are forbidden from joining this game",
reason: "Forbidden",
success: false,
};
@@ -191,9 +196,10 @@ async function handleJoinMessage(
.get()
.isCustomFlagAllowed(clientMsg.flag, flares);
if (allowed !== true) {
log.warn(`Flag ${allowed}: ${clientMsg.flag}`);
return {
code: 1002,
description: clientMsg.flag,
error: `The flag you have selected is ${allowed}.`,
reason: `Flag ${allowed}`,
success: false,
};
@@ -207,9 +213,10 @@ async function handleJoinMessage(
.get()
.isPatternAllowed(clientMsg.pattern, flares);
if (allowed !== true) {
log.warn(`Pattern ${allowed}: ${clientMsg.pattern}`);
return {
code: 1002,
description: clientMsg.pattern,
error: `The pattern you have selected is ${allowed}.`,
reason: `Pattern ${allowed}`,
success: false,
};
@@ -233,9 +240,10 @@ async function handleJoinMessage(
const wasFound = gm.addClient(client, clientMsg.gameID, clientMsg.lastTurn);
if (!wasFound) {
log.warn(`game ${clientMsg.gameID} not found on worker ${workerId}`);
return {
code: 1002,
description: `game ${clientMsg.gameID} not found on worker ${workerId}`,
error: "The game was not found.",
reason: "Not found",
success: false,
};
@@ -246,9 +254,9 @@ async function handleJoinMessage(
success: true,
};
} catch (error) {
log.warn(`error handling websocket message for ${ipAnonymize(ip)}`, error);
return {
code: 1011,
description: `error handling websocket message for ${ipAnonymize(ip)}`,
error: error instanceof Error ? error.message : String(error),
reason: "Internal server error",
success: false,