From 125b3790a84785d62c8b38ccc055ce6624fbfe32 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Fri, 23 Oct 2026 16:57:25 -0700 Subject: [PATCH] Take the lobby id from a pasted Poki or CrazyGames invite link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Join Lobby only looked for /game/ in a pasted URL. Poki's invite links carry the id as ?gdgameId=…, so pasting one did nothing, and CrazyGames' (/game/openfront?gameId=…) yielded "openfront", which passes GAME_ID_REGEX. Read gdgameId/gameId from the query before the path. Co-Authored-By: Claude Opus 5.5 --- src/client/JoinLobbyModal.ts | 7 +++++++ tests/client/JoinLobbyModal.test.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/client/JoinLobbyModal.ts b/src/client/JoinLobbyModal.ts index 3d68652606..0e97d4b8f9 100644 --- a/src/client/JoinLobbyModal.ts +++ b/src/client/JoinLobbyModal.ts @@ -898,6 +898,13 @@ export class JoinLobbyModal extends BaseModal { try { const url = new URL(input); + // Portal invite links carry the id as a query param: gdgameId on Poki + // (poki.com/en/g/openfront?gdgameId=…), gameId on CrazyGames. Checked + // before the path, since CrazyGames' /game/openfront looks like an id. + for (const param of ["gdgameId", "gameId"]) { + const value = url.searchParams.get(param); + if (value && GAME_ID_REGEX.test(value)) return value; + } const match = url.pathname.match(/game\/([^/]+)/); const candidate = match?.[1]; if (candidate && GAME_ID_REGEX.test(candidate)) return candidate; diff --git a/tests/client/JoinLobbyModal.test.ts b/tests/client/JoinLobbyModal.test.ts index a0ce010786..944ad7742d 100644 --- a/tests/client/JoinLobbyModal.test.ts +++ b/tests/client/JoinLobbyModal.test.ts @@ -541,3 +541,32 @@ describe("JoinLobbyModal checkActiveLobby resilience", () => { expect((modal as any).checkArchivedGame).toHaveBeenCalledWith("AbCd1234"); }); }); + +describe("JoinLobbyModal pasted lobby links", () => { + const normalize = (input: string): string | null => + (new JoinLobbyModal() as any).normalizeLobbyId(input); + + it("takes the id from a Poki invite link", () => { + expect( + normalize( + "https://poki.com/en/preview/8d0149be-4a6f-4eb3-8af0-d7d5ee9c2cc5/58c9e7b0-5432-4117-8f51-62022219c432?gdgameId=AbCd1234", + ), + ).toBe("AbCd1234"); + expect(normalize("https://poki.com/en/g/openfront?gdgameId=AbCd1234")).toBe( + "AbCd1234", + ); + }); + + it("takes the id from a CrazyGames invite link, not its /game/ path", () => { + expect( + normalize("https://www.crazygames.com/game/openfront?gameId=AbCd1234"), + ).toBe("AbCd1234"); + }); + + it("still takes the id from our own lobby link and a bare id", () => { + expect(normalize("https://openfront.io/game/AbCd1234?lobby&s=x1y2z")).toBe( + "AbCd1234", + ); + expect(normalize("AbCd1234")).toBe("AbCd1234"); + }); +});