Session ids become directory names server-side and topic levels on the broker, so they must reject path separators, ./.., whitespace and Windows reserved device names. toSessionId derives a safe id from a display name; isValidSessionId is the boundary check shared by the CLI and the web client.
74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import {
|
|
SESSION_ID_MAX_LENGTH,
|
|
isValidSessionId,
|
|
toSessionId,
|
|
} from "./session-id";
|
|
|
|
describe("isValidSessionId", () => {
|
|
test.each(["default", "a", "A1", "my-game", "under_score", "-"])(
|
|
"accepts %p",
|
|
(id) => {
|
|
expect(isValidSessionId(id)).toBe(true);
|
|
},
|
|
);
|
|
|
|
test.each([
|
|
"",
|
|
".",
|
|
"..",
|
|
"../evil",
|
|
"..\\..\\evil",
|
|
"a/b",
|
|
"a\\b",
|
|
"a b",
|
|
"a.b",
|
|
"a/b/../c",
|
|
])("rejects %p", (id) => {
|
|
expect(isValidSessionId(id)).toBe(false);
|
|
});
|
|
|
|
test("rejects non-strings and over-long ids", () => {
|
|
expect(isValidSessionId(null)).toBe(false);
|
|
expect(isValidSessionId(undefined)).toBe(false);
|
|
expect(isValidSessionId(42)).toBe(false);
|
|
expect(isValidSessionId("a".repeat(SESSION_ID_MAX_LENGTH + 1))).toBe(false);
|
|
});
|
|
|
|
test("rejects Windows reserved device names", () => {
|
|
expect(isValidSessionId("con")).toBe(false);
|
|
expect(isValidSessionId("COM1")).toBe(false);
|
|
expect(isValidSessionId("Nul")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("toSessionId", () => {
|
|
test("slugifies names", () => {
|
|
expect(toSessionId("My Game")).toBe("my-game");
|
|
expect(toSessionId(" Curse of Strahd!! ")).toBe("curse-of-strahd");
|
|
expect(toSessionId("")).toBe("session");
|
|
expect(toSessionId("!!!")).toBe("session");
|
|
});
|
|
|
|
test("avoids Windows reserved device names", () => {
|
|
expect(toSessionId("CON")).toBe("con-session");
|
|
expect(isValidSessionId(toSessionId("CON"))).toBe(true);
|
|
});
|
|
|
|
test("always yields a valid id, including for hostile input", () => {
|
|
const names = [
|
|
"My Game",
|
|
"",
|
|
"..",
|
|
"../etc/passwd",
|
|
"a/b\\c",
|
|
"CON",
|
|
"Ünïcödé",
|
|
"x".repeat(200),
|
|
"\0\0",
|
|
];
|
|
for (const name of names) {
|
|
expect(isValidSessionId(toSessionId(name))).toBe(true);
|
|
}
|
|
});
|
|
});
|