Files
Epicnabbo-Catalogus-Updated…/src/lib/client-url.test.ts
T
openhands 7f39ba4257 fix: harden SSO ticket flow and revoke tickets on logout
Reuse the outstanding auth_ticket instead of minting a fresh one on every
/client load, so reloading the page or opening a second tab no longer
invalidates a game session that is still connecting. New tickets are minted
with a guard against the previously-read value so concurrent launches
converge on the same ticket.

Revoke the auth_ticket when signing out (toolbar, header and sign-out
everywhere) so a leaked ticket can no longer be replayed against the
emulator, and prevent SSO leakage via referral by setting no-referrer on the
client iframe. Strip all whitespace from the ticket prefix and build the
launch URL through a tested helper that handles query strings, existing sso
params and URL fragments correctly.
2026-08-29 20:54:06 +02:00

50 lines
1.6 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { buildClientLoginUrl } from "./client-url";
describe("buildClientLoginUrl", () => {
it("appends sso to a clean URL", () => {
expect(buildClientLoginUrl("https://game.hotel.nl", "Hotel-uuid")).toBe(
"https://game.hotel.nl?sso=Hotel-uuid",
);
});
it("uses & when a query string already exists", () => {
expect(
buildClientLoginUrl(
"https://game.hotel.nl/nitro?mode=nostrip&debug=1",
"Hotel-uuid",
),
).toBe("https://game.hotel.nl/nitro?mode=nostrip&debug=1&sso=Hotel-uuid");
});
it("replaces an existing sso param", () => {
expect(
buildClientLoginUrl("https://game.hotel.nl/nitro?sso=old&mode=1", "new"),
).toBe("https://game.hotel.nl/nitro?mode=1&sso=new");
expect(
buildClientLoginUrl("https://game.hotel.nl/nitro?sso=old", "new"),
).toBe("https://game.hotel.nl/nitro?sso=new");
});
it("keeps a fragment after the sso param", () => {
expect(
buildClientLoginUrl("https://game.hotel.nl/nitro#entry", "h-u"),
).toBe("https://game.hotel.nl/nitro?sso=h-u#entry");
expect(
buildClientLoginUrl("https://game.hotel.nl/nitro?sso=old#entry", "h-u"),
).toBe("https://game.hotel.nl/nitro?sso=h-u#entry");
});
it("leaves any existing non-sso fragment intact", () => {
expect(
buildClientLoginUrl("https://game.hotel.nl/nitro?tok=1#frag", "th"),
).toBe("https://game.hotel.nl/nitro?tok=1&sso=th#frag");
});
it("encodes the ticket value", () => {
expect(buildClientLoginUrl("https://game.hotel.nl/", "Ḟancy-ü")).toBe(
"https://game.hotel.nl/?sso=%E1%B8%9Eancy-%C3%BC",
);
});
});