eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1// Tests for the invite-link fragment codec. node test/invite.test.mjs
2import assert from "node:assert/strict";
3import {
4 parseInviteFragment,
5 buildInviteFragment,
6 hasInviteFingerprint,
7 INVITE_PREFIX,
8} from "../web/static/invite.js";
9
10let failures = 0;
11async function test(name, fn) {
12 try {
13 await fn();
14 console.log("PASS " + name);
15 } catch (e) {
16 console.log("FAIL " + name + " — " + (e && e.message));
17 failures++;
18 }
19}
20
21await test("parse: new format without name", () => {
22 assert.deepEqual(parseInviteFragment("e1.abc123"), { T: "abc123", name: "", b: "" });
23});
24
25await test("parse: new format with name", () => {
26 assert.deepEqual(parseInviteFragment("e1.abc123~Paul"), { T: "abc123", name: "Paul", b: "" });
27});
28
29await test("parse: legacy unprefixed without name", () => {
30 assert.deepEqual(parseInviteFragment("abc123"), { T: "abc123", name: "", b: "" });
31});
32
33await test("parse: legacy unprefixed with name", () => {
34 assert.deepEqual(parseInviteFragment("abc123~Paul"), { T: "abc123", name: "Paul", b: "" });
35});
36
37await test("parse: URL-encoded name", () => {
38 assert.deepEqual(parseInviteFragment("e1.abc~Paul%20Campbell"), { T: "abc", name: "Paul Campbell", b: "" });
39});
40
41await test("parse: URL-encoded unicode name", () => {
42 assert.deepEqual(parseInviteFragment("e1.abc~Zo%C3%AB%20%E2%9C%A8"), { T: "abc", name: "Zoë ✨", b: "" });
43});
44
45await test("parse: undecodable percent sequence -> empty name", () => {
46 assert.deepEqual(parseInviteFragment("e1.abc~%E0%A4%A"), { T: "abc", name: "", b: "" });
47});
48
49await test("parse: empty input", () => {
50 assert.deepEqual(parseInviteFragment(""), { T: "", name: "", b: "" });
51});
52
53await test("parse: null/undefined input", () => {
54 assert.deepEqual(parseInviteFragment(null), { T: "", name: "", b: "" });
55 assert.deepEqual(parseInviteFragment(undefined), { T: "", name: "", b: "" });
56});
57
58await test("build: carries the fingerprint", () => {
59 assert.equal(buildInviteFragment("abc123"), INVITE_PREFIX + "abc123");
60 assert.ok(hasInviteFingerprint(buildInviteFragment("abc123", "Paul")));
61});
62
63await test("build: round-trips without name", () => {
64 assert.deepEqual(parseInviteFragment(buildInviteFragment("abc123")), { T: "abc123", name: "", b: "" });
65});
66
67await test("build: round-trips with name", () => {
68 assert.deepEqual(parseInviteFragment(buildInviteFragment("abc123", "Paul Campbell")), {
69 T: "abc123",
70 name: "Paul Campbell",
71 b: "",
72 });
73});
74
75await test("build: round-trips a unicode name (incl. ~ in the name)", () => {
76 // "~" in a name must survive: encodeURIComponent leaves it bare, but the
77 // parser splits on the FIRST tilde, so the separator still wins.
78 assert.deepEqual(parseInviteFragment(buildInviteFragment("T", "Zoë ~ ✨")), { T: "T", name: "Zoë ~ ✨", b: "" });
79});
80
81await test("hasInviteFingerprint: new links yes, legacy and junk no", () => {
82 assert.equal(hasInviteFingerprint("e1.abc123"), true);
83 assert.equal(hasInviteFingerprint("abc123"), false);
84 assert.equal(hasInviteFingerprint(""), false);
85 assert.equal(hasInviteFingerprint(null), false);
86});
87
88
89await test("branding key: builds the 3-slot form and round-trips", () => {
90 // Sealed instances put the branding key b in every minted link
91 // (docs/no-plaintext.md); the name slot stays, possibly empty.
92 assert.equal(buildInviteFragment("abc123", "", "k3m7p2qx4f"), "e1.abc123~~k3m7p2qx4f");
93 assert.deepEqual(parseInviteFragment("e1.abc123~~k3m7p2qx4f"), { T: "abc123", name: "", b: "k3m7p2qx4f" });
94 assert.deepEqual(parseInviteFragment(buildInviteFragment("abc123", "Paul Campbell", "k3m7p2qx4f")), {
95 T: "abc123",
96 name: "Paul Campbell",
97 b: "k3m7p2qx4f",
98 });
99});
100
101await test("branding key: old parsers still get T from a 3-slot link", () => {
102 // Slot order is fixed (T first) so a pre-branding parser that cuts at the
103 // first "~" still claims from a new link.
104 const frag = buildInviteFragment("abc123", "Zoë", "k3m7p2qx4f").replace(/^e1\./, "");
105 assert.equal(frag.split("~")[0], "abc123");
106});
107
108await test("branding key: a legacy raw-~ name is not mistaken for a key", () => {
109 // Old builders left "~" unescaped in names. The key slot must match the
110 // base32 shape, so a decorative tail stays part of the name.
111 assert.deepEqual(parseInviteFragment("e1.T~Zo%C3%AB%20~%20%E2%9C%A8"), { T: "T", name: "Zoë ~ ✨", b: "" });
112});
113
114await test("branding key: new builders escape ~ so names with ~ round-trip beside b", () => {
115 assert.deepEqual(parseInviteFragment(buildInviteFragment("T", "Zoë ~ ✨", "k3m7p2qx4f")), {
116 T: "T",
117 name: "Zoë ~ ✨",
118 b: "k3m7p2qx4f",
119 });
120});
121
122console.log(failures === 0 ? "\nALL PASSED" : `\n${failures} FAILED`);
123process.exit(failures === 0 ? 0 : 1);
124