@rubytech/create-maxy-code 0.1.473 → 0.1.475

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/__tests__/google-client-id-env.test.js +3 -2
  2. package/package.json +1 -1
  3. package/payload/platform/neo4j/schema.cypher +4 -1
  4. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +29 -16
  5. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  6. package/payload/platform/plugins/docs/references/google-guide.md +25 -12
  7. package/payload/platform/plugins/docs/references/voice-mirror-guide.md +2 -2
  8. package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
  9. package/payload/platform/plugins/google/PLUGIN.md +73 -14
  10. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts +2 -0
  11. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts.map +1 -0
  12. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js +229 -0
  13. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js.map +1 -0
  14. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +9 -9
  15. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
  16. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts +2 -0
  17. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts.map +1 -0
  18. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js +17 -0
  19. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js.map +1 -0
  20. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts +2 -0
  21. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts.map +1 -0
  22. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js +146 -0
  23. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js.map +1 -0
  24. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts +2 -0
  25. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts.map +1 -0
  26. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js +19 -0
  27. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js.map +1 -0
  28. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts +2 -0
  29. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts.map +1 -0
  30. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js +41 -0
  31. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js.map +1 -0
  32. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts +44 -0
  33. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts.map +1 -0
  34. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js +112 -0
  35. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js.map +1 -0
  36. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts +17 -0
  37. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts.map +1 -0
  38. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js +143 -0
  39. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js.map +1 -0
  40. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts +9 -0
  41. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts.map +1 -1
  42. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.js.map +1 -1
  43. package/payload/platform/plugins/google/mcp/dist/index.js +73 -5
  44. package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -1
  45. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts +2 -0
  46. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts.map +1 -0
  47. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js +37 -0
  48. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js.map +1 -0
  49. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +20 -4
  50. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
  51. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +19 -9
  52. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
  53. package/payload/platform/plugins/google/references/auth.md +331 -367
  54. package/payload/platform/plugins/voice-mirror/PLUGIN.md +1 -1
  55. package/payload/platform/plugins/voice-mirror/mcp/dist/index.js +3 -3
  56. package/payload/platform/plugins/voice-mirror/mcp/dist/index.js.map +1 -1
  57. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.d.ts +14 -1
  58. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.d.ts.map +1 -1
  59. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.js +15 -0
  60. package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.js.map +1 -1
  61. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
  62. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +3 -1
  63. package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -1
  64. package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +51 -4
  65. package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +4 -0
  66. package/payload/platform/scripts/backfill-task-ids.sh +206 -0
  67. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +21 -3
  68. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
  69. package/payload/platform/services/claude-session-manager/dist/activity-rows.js +6 -2
  70. package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
  71. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  72. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +43 -5
  73. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  74. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +9 -0
  75. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
  76. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +78 -0
  77. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
  78. package/payload/server/public/activity.html +6 -6
  79. package/payload/server/public/assets/{AdminLoginScreens-B7TQZV8u.js → AdminLoginScreens-B44KbEuC.js} +1 -1
  80. package/payload/server/public/assets/{AdminShell-DAuri4Yh.js → AdminShell-BjxV2qkb.js} +2 -2
  81. package/payload/server/public/assets/{Checkbox-B1XhnhPk.js → Checkbox-DSeZNGNA.js} +1 -1
  82. package/payload/server/public/assets/activity-Mz1BhgB1.js +1 -0
  83. package/payload/server/public/assets/{admin-BdcccSb5.js → admin-B4LpTCur.js} +1 -1
  84. package/payload/server/public/assets/{browser-B6woQ2qX.js → browser-CEFvaWwI.js} +1 -1
  85. package/payload/server/public/assets/{calendar-CalCeg5T.js → calendar-B3zo6V34.js} +1 -1
  86. package/payload/server/public/assets/chat-5tJdo9i_.js +1 -0
  87. package/payload/server/public/assets/chevron-left-BJllrPBj.js +1 -0
  88. package/payload/server/public/assets/data-Du79EgR-.js +1 -0
  89. package/payload/server/public/assets/{graph-HeZaatSQ.js → graph-RaOrnSf2.js} +1 -1
  90. package/payload/server/public/assets/{graph-labels-4W7JuOgG.js → graph-labels-GlTEIYJj.js} +1 -1
  91. package/payload/server/public/assets/{maximize-2-DKx-aTPb.js → maximize-2-CHDa8p5h.js} +1 -1
  92. package/payload/server/public/assets/{operator-DD9L2VJM.js → operator-DtqHY4jV.js} +1 -1
  93. package/payload/server/public/assets/{page-tJxw0zNO.js → page-CkhFj8GQ.js} +1 -1
  94. package/payload/server/public/assets/{page-Ceado9Kr.js → page-DxnWgPtd.js} +1 -1
  95. package/payload/server/public/assets/{public-BYFWxyeC.js → public-D5TUfQ3I.js} +1 -1
  96. package/payload/server/public/assets/{rotate-ccw-DrzdV9h7.js → rotate-ccw-BJjVAQQY.js} +1 -1
  97. package/payload/server/public/assets/tasks-CM9pYYG1.js +1 -0
  98. package/payload/server/public/assets/{time-entry-format-Bn79w6tq.js → time-entry-format-C5RYEYjM.js} +1 -1
  99. package/payload/server/public/assets/{triangle-alert-CjDVh6r-.js → triangle-alert-DLfIsuo_.js} +1 -1
  100. package/payload/server/public/assets/{useCopyFeedback-DXHkkJw-.js → useCopyFeedback-7yKeiAzV.js} +1 -1
  101. package/payload/server/public/assets/{useSelectionMode-D2H8jAhE.js → useSelectionMode-CWlh6AEq.js} +1 -1
  102. package/payload/server/public/assets/{useSubAccountSwitcher-Br7Z6Cpu.css → useSubAccountSwitcher-B2n9QPVI.css} +1 -1
  103. package/payload/server/public/assets/{useVoiceRecorder-zUvPe55I.js → useVoiceRecorder-j3ZArZ2H.js} +1 -1
  104. package/payload/server/public/browser.html +5 -5
  105. package/payload/server/public/calendar.html +6 -6
  106. package/payload/server/public/chat.html +12 -12
  107. package/payload/server/public/data.html +11 -11
  108. package/payload/server/public/graph.html +11 -11
  109. package/payload/server/public/index.html +14 -14
  110. package/payload/server/public/operator.html +14 -14
  111. package/payload/server/public/public.html +12 -12
  112. package/payload/server/public/tasks.html +5 -5
  113. package/payload/server/server.js +433 -313
  114. package/payload/server/public/assets/activity-kRwzxEKU.js +0 -1
  115. package/payload/server/public/assets/chat-9s2-L06v.js +0 -1
  116. package/payload/server/public/assets/chevron-left-C3ho8SnB.js +0 -1
  117. package/payload/server/public/assets/data-Cfr-7ERI.js +0 -1
  118. package/payload/server/public/assets/tasks-DSwoxGzh.js +0 -1
  119. /package/payload/server/public/assets/{useSubAccountSwitcher-CUJpgkKI.js → useSubAccountSwitcher-CBlKgwms.js} +0 -0
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Refresh-TTL audit (Task 1773).
3
+ *
4
+ * The audit exists because a refresh token expiring emits no event and does not
5
+ * reproduce on demand — nothing touches the account, it simply stops working at
6
+ * some future date. So every test here drives the audit ALONE. None of them call
7
+ * a register or poll path first: that is the path that already worked, and a test
8
+ * that primes it proves nothing about the audit.
9
+ */
10
+ import { strict as assert } from "node:assert";
11
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { test } from "node:test";
15
+ import { TokenStore } from "../auth/token-store.js";
16
+ import { REFRESH_EXPIRING_THRESHOLD_DAYS, REFRESH_INACTIVITY_LIMIT_DAYS, auditConnectedAccounts, classifyRefresh, runAccountAudit, } from "../auth/account-audit.js";
17
+ const DAY_MS = 86_400_000;
18
+ const ACCOUNT_A = "aaaaaaaa-1111-4111-8111-aaaaaaaaaaaa";
19
+ const ACCOUNT_B = "bbbbbbbb-2222-4222-8222-bbbbbbbbbbbb";
20
+ function freshDir() {
21
+ return mkdtempSync(join(tmpdir(), "google-audit-"));
22
+ }
23
+ /** Write a real encrypted token blob through TokenStore, then rewrite it with a
24
+ * chosen lastRefresh — the audit must read the stored value, not a live clock. */
25
+ function seedAccount(accountsDir, accountId, email, opts, nowMs) {
26
+ const store = new TokenStore(accountId, accountsDir, email);
27
+ store.writeBlobForTest({
28
+ accessToken: "at",
29
+ refreshToken: opts.refreshToken,
30
+ accessTokenExpiry: nowMs + 3_600_000,
31
+ lastRefresh: nowMs - opts.lastRefreshAgeDays * DAY_MS,
32
+ email,
33
+ scopes: ["https://www.googleapis.com/auth/calendar"],
34
+ });
35
+ }
36
+ test("classifyRefresh: a healthy recently-refreshed token is ok", () => {
37
+ const now = Date.now();
38
+ const r = classifyRefresh({
39
+ accessToken: "at",
40
+ refreshToken: "rt",
41
+ accessTokenExpiry: now,
42
+ lastRefresh: now - 3 * DAY_MS,
43
+ email: "a@example.com",
44
+ scopes: [],
45
+ }, now);
46
+ assert.equal(r.status, "ok");
47
+ assert.equal(r.refreshTtlDays, REFRESH_INACTIVITY_LIMIT_DAYS - 3);
48
+ });
49
+ test("classifyRefresh: inside the expiring threshold is expiring, not ok", () => {
50
+ const now = Date.now();
51
+ // 175 days idle leaves 5 days of the 180-day inactivity clock.
52
+ const r = classifyRefresh({
53
+ accessToken: "at",
54
+ refreshToken: "rt",
55
+ accessTokenExpiry: now,
56
+ lastRefresh: now - 175 * DAY_MS,
57
+ email: "a@example.com",
58
+ scopes: [],
59
+ }, now);
60
+ assert.equal(r.refreshTtlDays, 5);
61
+ assert.equal(r.status, "expiring");
62
+ assert.ok(r.refreshTtlDays <= REFRESH_EXPIRING_THRESHOLD_DAYS);
63
+ });
64
+ test("classifyRefresh: past the inactivity limit is expired", () => {
65
+ const now = Date.now();
66
+ const r = classifyRefresh({
67
+ accessToken: "at",
68
+ refreshToken: "rt",
69
+ accessTokenExpiry: now,
70
+ lastRefresh: now - 200 * DAY_MS,
71
+ email: "a@example.com",
72
+ scopes: [],
73
+ }, now);
74
+ assert.equal(r.status, "expired");
75
+ assert.ok(r.refreshTtlDays <= 0);
76
+ });
77
+ test("classifyRefresh: no refresh token at all is expired with zero days", () => {
78
+ const now = Date.now();
79
+ // A connection Google issued no refresh token for dies with its access token,
80
+ // about an hour out. It is not 'ok' merely because it was just written.
81
+ const r = classifyRefresh({
82
+ accessToken: "at",
83
+ refreshToken: null,
84
+ accessTokenExpiry: now,
85
+ lastRefresh: now,
86
+ email: "a@example.com",
87
+ scopes: [],
88
+ }, now);
89
+ assert.equal(r.status, "expired");
90
+ assert.equal(r.refreshTtlDays, 0);
91
+ });
92
+ test("classifyRefresh: a lastRefresh in the future never exceeds the documented limit", () => {
93
+ // A device whose clock ran ahead, or a blob restored from such a host. Without
94
+ // the clamp this reports e.g. refreshTtlDays=200, a value the module documents
95
+ // as impossible.
96
+ const now = Date.now();
97
+ const r = classifyRefresh({
98
+ accessToken: "at",
99
+ refreshToken: "rt",
100
+ accessTokenExpiry: now,
101
+ lastRefresh: now + 20 * DAY_MS,
102
+ email: "a@example.com",
103
+ scopes: [],
104
+ }, now);
105
+ assert.equal(r.refreshTtlDays, REFRESH_INACTIVITY_LIMIT_DAYS);
106
+ assert.equal(r.status, "ok");
107
+ });
108
+ test("an email carrying whitespace cannot split the audit line into bogus fields", () => {
109
+ const dir = freshDir();
110
+ const now = Date.now();
111
+ const lines = [];
112
+ try {
113
+ const store = new TokenStore(ACCOUNT_A, dir, "spacey@example.com");
114
+ store.writeBlobForTest({
115
+ accessToken: "at",
116
+ refreshToken: "rt",
117
+ accessTokenExpiry: now + 3_600_000,
118
+ lastRefresh: now,
119
+ email: "bad id@example.com",
120
+ scopes: [],
121
+ });
122
+ runAccountAudit(dir, now, (l) => lines.push(l));
123
+ const line = lines.find((l) => l.includes("refreshTtlDays="));
124
+ assert.ok(line);
125
+ // status must remain the LAST field and parse cleanly: an unescaped space
126
+ // would push `status=` out of position for any k=v reader.
127
+ const fields = Object.fromEntries(line.split(" ").slice(1).map((p) => p.split("=")));
128
+ assert.equal(fields.status, "ok");
129
+ assert.equal(fields.refreshTtlDays, String(REFRESH_INACTIVITY_LIMIT_DAYS));
130
+ assert.equal(fields.email, "bad_id@example.com");
131
+ }
132
+ finally {
133
+ rmSync(dir, { recursive: true, force: true });
134
+ }
135
+ });
136
+ test("auditConnectedAccounts reports every connected account across accounts", () => {
137
+ const dir = freshDir();
138
+ const now = Date.now();
139
+ try {
140
+ seedAccount(dir, ACCOUNT_A, "one@example.com", { lastRefreshAgeDays: 1, refreshToken: "rt" }, now);
141
+ seedAccount(dir, ACCOUNT_A, "two@example.com", { lastRefreshAgeDays: 175, refreshToken: "rt" }, now);
142
+ seedAccount(dir, ACCOUNT_B, "three@example.com", { lastRefreshAgeDays: 0, refreshToken: null }, now);
143
+ const rows = auditConnectedAccounts(dir, now);
144
+ assert.equal(rows.length, 3);
145
+ const byEmail = new Map(rows.map((r) => [r.email, r]));
146
+ assert.equal(byEmail.get("one@example.com")?.status, "ok");
147
+ assert.equal(byEmail.get("two@example.com")?.status, "expiring");
148
+ assert.equal(byEmail.get("three@example.com")?.status, "expired");
149
+ assert.equal(byEmail.get("one@example.com")?.accountId, ACCOUNT_A);
150
+ assert.equal(byEmail.get("three@example.com")?.accountId, ACCOUNT_B);
151
+ }
152
+ finally {
153
+ rmSync(dir, { recursive: true, force: true });
154
+ }
155
+ });
156
+ test("one unreadable blob does not blind the scan", () => {
157
+ const dir = freshDir();
158
+ const now = Date.now();
159
+ try {
160
+ seedAccount(dir, ACCOUNT_A, "good@example.com", { lastRefreshAgeDays: 1, refreshToken: "rt" }, now);
161
+ // Corrupt ciphertext under the same account — decrypt will throw.
162
+ const badDir = join(dir, ACCOUNT_A, "secrets", "google", "accounts", "bad@example.com");
163
+ mkdirSync(badDir, { recursive: true });
164
+ writeFileSync(join(badDir, "tokens.enc"), "not:validciphertext");
165
+ const rows = auditConnectedAccounts(dir, now);
166
+ // The healthy account still reports; the corrupt one is skipped, not fatal.
167
+ assert.ok(rows.some((r) => r.email === "good@example.com" && r.status === "ok"));
168
+ }
169
+ finally {
170
+ rmSync(dir, { recursive: true, force: true });
171
+ }
172
+ });
173
+ test("non-uuid directories under accountsDir are ignored", () => {
174
+ const dir = freshDir();
175
+ const now = Date.now();
176
+ try {
177
+ mkdirSync(join(dir, "not-an-account", "secrets", "google", "accounts", "x@example.com"), {
178
+ recursive: true,
179
+ });
180
+ assert.deepEqual(auditConnectedAccounts(dir, now), []);
181
+ }
182
+ finally {
183
+ rmSync(dir, { recursive: true, force: true });
184
+ }
185
+ });
186
+ test("a missing accounts directory yields no rows and does not throw", () => {
187
+ assert.deepEqual(auditConnectedAccounts(join(tmpdir(), "google-audit-absent-dir"), Date.now()), []);
188
+ });
189
+ test("runAccountAudit emits one line per account plus a heartbeat", () => {
190
+ const dir = freshDir();
191
+ const now = Date.now();
192
+ const lines = [];
193
+ try {
194
+ seedAccount(dir, ACCOUNT_A, "one@example.com", { lastRefreshAgeDays: 1, refreshToken: "rt" }, now);
195
+ seedAccount(dir, ACCOUNT_A, "two@example.com", { lastRefreshAgeDays: 175, refreshToken: "rt" }, now);
196
+ runAccountAudit(dir, now, (l) => lines.push(l));
197
+ const perAccount = lines.filter((l) => l.includes("account=") && !l.includes("op=heartbeat"));
198
+ assert.equal(perAccount.length, 2);
199
+ assert.ok(perAccount.some((l) => l.includes("[google-account-audit]") &&
200
+ l.includes(`account=${ACCOUNT_A}`) &&
201
+ l.includes("email=two@example.com") &&
202
+ l.includes("refreshTtlDays=5") &&
203
+ l.includes("status=expiring")), `expected an expiring line, got: ${perAccount.join(" | ")}`);
204
+ const heartbeat = lines.filter((l) => l.includes("op=heartbeat"));
205
+ assert.equal(heartbeat.length, 1);
206
+ assert.ok(heartbeat[0].includes("accounts=2"));
207
+ assert.ok(heartbeat[0].includes("ok=1"));
208
+ assert.ok(heartbeat[0].includes("expiring=1"));
209
+ assert.ok(heartbeat[0].includes("expired=0"));
210
+ }
211
+ finally {
212
+ rmSync(dir, { recursive: true, force: true });
213
+ }
214
+ });
215
+ test("the heartbeat is emitted on a cycle that finds nothing", () => {
216
+ // This is the whole point of the heartbeat: an audit that stopped running must
217
+ // not be indistinguishable from an audit reporting all-clear.
218
+ const dir = freshDir();
219
+ const lines = [];
220
+ try {
221
+ runAccountAudit(dir, Date.now(), (l) => lines.push(l));
222
+ assert.equal(lines.length, 1);
223
+ assert.ok(lines[0].includes("[google-account-audit] op=heartbeat accounts=0"));
224
+ }
225
+ finally {
226
+ rmSync(dir, { recursive: true, force: true });
227
+ }
228
+ });
229
+ //# sourceMappingURL=account-audit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-audit.test.js","sourceRoot":"","sources":["../../src/__tests__/account-audit.test.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { createHash } from "node:crypto";
4
4
  import { mkdtempSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join } from "node:path";
7
- import { newPkce, buildConsentUrl, runAccountRegisterStart, runAccountRegisterPoll, listConnected, CALENDAR_SCOPE, LOOPBACK_REDIRECT_URI, normalisePastedCode, runAccountRegisterSubmit, } from "../tools/account-register.js";
7
+ import { newPkce, newState, buildConsentUrl, runAccountRegisterStart, runAccountRegisterPoll, listConnected, CALENDAR_SCOPE, LOOPBACK_REDIRECT_URI, normalisePastedCode, runAccountRegisterSubmit, } from "../tools/account-register.js";
8
8
  import { TokenStore } from "../auth/token-store.js";
9
9
  import { PendingStore } from "../auth/pending-store.js";
10
10
  function newDir() {
@@ -20,7 +20,7 @@ test("consent URL carries offline access, forced consent, and the calendar scope
20
20
  clientId: "cid",
21
21
  state: "st",
22
22
  challenge: "ch",
23
- accountId: "acct1",
23
+ redirectUri: LOOPBACK_REDIRECT_URI,
24
24
  }));
25
25
  assert.equal(url.searchParams.get("access_type"), "offline");
26
26
  assert.equal(url.searchParams.get("prompt"), "consent");
@@ -37,7 +37,7 @@ test("redirect_uri carries no query string at all", () => {
37
37
  clientId: "cid",
38
38
  state: "nonce",
39
39
  challenge: "ch",
40
- accountId: "acct1",
40
+ redirectUri: LOOPBACK_REDIRECT_URI,
41
41
  }));
42
42
  const redirect = url.searchParams.get("redirect_uri");
43
43
  assert.ok(!redirect.includes("?"), `redirect_uri must have no query: ${redirect}`);
@@ -45,7 +45,7 @@ test("redirect_uri carries no query string at all", () => {
45
45
  });
46
46
  test("register stores the same opaque state it sends, and no account id", async () => {
47
47
  const dir = newDir();
48
- const res = await runAccountRegisterStart({ accountId: "acct1", accountsDir: dir, clientId: "cid" });
48
+ const res = await runAccountRegisterStart({ accountId: "acct1", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
49
49
  const sent = new URL(res.consentUrl).searchParams.get("state");
50
50
  const { PendingStore: PS } = await import("../auth/pending-store.js");
51
51
  assert.equal(new PS("acct1", dir).read()?.state, sent, "pending must hold exactly what was sent");
@@ -53,7 +53,7 @@ test("register stores the same opaque state it sends, and no account id", async
53
53
  });
54
54
  test("a second register while one is live is refused as in-progress", async () => {
55
55
  const dir = newDir();
56
- const args = { accountId: "acct1", accountsDir: dir, clientId: "cid" };
56
+ const args = { accountId: "acct1", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI };
57
57
  const first = await runAccountRegisterStart(args);
58
58
  assert.equal(first.status, "pending");
59
59
  assert.ok(first.consentUrl);
@@ -67,7 +67,7 @@ test("poll reports none with nothing connected and nothing pending", async () =>
67
67
  });
68
68
  test("poll reports pending while a fresh registration is live", async () => {
69
69
  const dir = newDir();
70
- await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "c" });
70
+ await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "c", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
71
71
  const res = await runAccountRegisterPoll({ accountId: "a", accountsDir: dir });
72
72
  assert.equal(res.status, "pending");
73
73
  });
@@ -80,7 +80,7 @@ test("listConnected reports a stored account by email", () => {
80
80
  assert.equal(connected[0].status, "ok");
81
81
  });
82
82
  test("consent redirect is the loopback IP literal, never localhost or https", () => {
83
- const url = new URL(buildConsentUrl({ clientId: "cid", state: "nonce", challenge: "ch", accountId: "a" }));
83
+ const url = new URL(buildConsentUrl({ clientId: "cid", state: "nonce", challenge: "ch", redirectUri: LOOPBACK_REDIRECT_URI }));
84
84
  const r = url.searchParams.get("redirect_uri");
85
85
  assert.equal(r, LOOPBACK_REDIRECT_URI);
86
86
  assert.equal(r, "http://127.0.0.1:8571");
@@ -116,7 +116,7 @@ test("normalisePastedCode never throws on a malformed percent escape", () => {
116
116
  });
117
117
  test("submit exchanges with the identical loopback redirect and stores the email", async () => {
118
118
  const dir = newDir();
119
- await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid" });
119
+ await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
120
120
  const calls = [];
121
121
  const fake = (async (url, init = {}) => {
122
122
  calls.push({ url: String(url), body: String(init.body ?? "") });
@@ -141,7 +141,7 @@ test("submit refuses when no registration is pending", async () => {
141
141
  });
142
142
  test("submit preserves the Google error body on a failed exchange", async () => {
143
143
  const dir = newDir();
144
- await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid" });
144
+ await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
145
145
  const fake = (async () => new Response('{"error":"invalid_grant"}', { status: 400 }));
146
146
  await assert.rejects(() => runAccountRegisterSubmit({
147
147
  accountId: "a", accountsDir: dir, clientId: "c", clientSecret: "s", code: "4/0x", fetchImpl: fake,
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.test.js","sourceRoot":"","sources":["../../src/__tests__/account-register.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-register.test.js","sourceRoot":"","sources":["../../src/__tests__/account-register.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=consent-url-redirect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-url-redirect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/consent-url-redirect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { buildConsentUrl } from "../tools/account-register.js";
4
+ test("the consent URL carries the redirect it was given", () => {
5
+ const u = new URL(buildConsentUrl({ clientId: "cid", state: "s", challenge: "c", redirectUri: "http://127.0.0.1:54321" }));
6
+ assert.equal(u.searchParams.get("redirect_uri"), "http://127.0.0.1:54321");
7
+ });
8
+ test("the consent URL never uses the localhost hostname", () => {
9
+ const u = buildConsentUrl({
10
+ clientId: "cid",
11
+ state: "s",
12
+ challenge: "c",
13
+ redirectUri: "http://127.0.0.1:8571",
14
+ });
15
+ assert.ok(!u.includes("localhost"));
16
+ });
17
+ //# sourceMappingURL=consent-url-redirect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-url-redirect.test.js","sourceRoot":"","sources":["../../src/__tests__/consent-url-redirect.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,MAAM,CAAC,GAAG,IAAI,GAAG,CACf,eAAe,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC,CACxG,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,wBAAwB,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,MAAM,CAAC,GAAG,eAAe,CAAC;QACxB,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,GAAG;QACV,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,uBAAuB;KACrC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=loopback-listener.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-listener.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/loopback-listener.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { createServer } from "node:http";
4
+ import { startLoopbackListener } from "../auth/loopback-listener.js";
5
+ async function get(url) {
6
+ const res = await fetch(url);
7
+ return { status: res.status, body: await res.text() };
8
+ }
9
+ /** A port is only proven released by rebinding it. A boolean the code under
10
+ * test sets would prove the code ran, not that the socket closed. */
11
+ async function isFree(port) {
12
+ return await new Promise((resolve) => {
13
+ const s = createServer();
14
+ s.once("error", () => resolve(false));
15
+ s.listen(port, "127.0.0.1", () => s.close(() => resolve(true)));
16
+ });
17
+ }
18
+ test("a matching state completes and the page names the account", async () => {
19
+ let seen = "";
20
+ const l = await startLoopbackListener({
21
+ accountId: "a",
22
+ state: "st-1",
23
+ onCode: async (code) => {
24
+ seen = code;
25
+ return { email: "kit@example.com" };
26
+ },
27
+ });
28
+ assert.ok(l);
29
+ const r = await get(`${l.redirectUri}/?state=st-1&code=xyz`);
30
+ assert.equal(r.status, 200);
31
+ assert.equal(seen, "xyz");
32
+ assert.match(r.body, /kit@example\.com/);
33
+ await l.close("test");
34
+ });
35
+ test("a mismatched state is refused and onCode never runs", async () => {
36
+ let ran = false;
37
+ const l = await startLoopbackListener({
38
+ accountId: "a",
39
+ state: "st-2",
40
+ onCode: async () => {
41
+ ran = true;
42
+ return { email: "x@y.z" };
43
+ },
44
+ });
45
+ assert.ok(l);
46
+ const r = await get(`${l.redirectUri}/?state=WRONG&code=xyz`);
47
+ assert.equal(r.status, 400);
48
+ assert.equal(ran, false);
49
+ await l.close("test");
50
+ });
51
+ test("an onCode failure renders Google's error rather than claiming success", async () => {
52
+ const l = await startLoopbackListener({
53
+ accountId: "a",
54
+ state: "st-3",
55
+ onCode: async () => {
56
+ throw new Error("token exchange failed (400): invalid_grant");
57
+ },
58
+ });
59
+ assert.ok(l);
60
+ const r = await get(`${l.redirectUri}/?state=st-3&code=xyz`);
61
+ assert.equal(r.status, 400);
62
+ assert.match(r.body, /invalid_grant/);
63
+ await l.close("test");
64
+ });
65
+ test("close releases the port", async () => {
66
+ const l = await startLoopbackListener({
67
+ accountId: "a",
68
+ state: "st-4",
69
+ onCode: async () => ({ email: "x@y.z" }),
70
+ });
71
+ assert.ok(l);
72
+ const port = l.port;
73
+ await l.close("test");
74
+ assert.equal(await isFree(port), true);
75
+ });
76
+ test("a completed exchange releases the port without an explicit close", async () => {
77
+ const l = await startLoopbackListener({
78
+ accountId: "a",
79
+ state: "st-5",
80
+ onCode: async () => ({ email: "x@y.z" }),
81
+ });
82
+ assert.ok(l);
83
+ const port = l.port;
84
+ await get(`${l.redirectUri}/?state=st-5&code=xyz`);
85
+ await new Promise((r) => setTimeout(r, 50));
86
+ assert.equal(await isFree(port), true);
87
+ });
88
+ test("a reload during the exchange does not run onCode twice", async () => {
89
+ let calls = 0;
90
+ const l = await startLoopbackListener({
91
+ accountId: "a",
92
+ state: "st-7",
93
+ onCode: async () => {
94
+ calls += 1;
95
+ await new Promise((r) => setTimeout(r, 80));
96
+ return { email: "x@y.z" };
97
+ },
98
+ });
99
+ assert.ok(l);
100
+ const first = get(`${l.redirectUri}/?state=st-7&code=xyz`);
101
+ await new Promise((r) => setTimeout(r, 20));
102
+ const second = await get(`${l.redirectUri}/?state=st-7&code=xyz`);
103
+ await first;
104
+ assert.equal(calls, 1, "the second request must not re-exchange the code");
105
+ assert.equal(second.status, 409);
106
+ });
107
+ test("a denied consent says so rather than blaming the link", async () => {
108
+ let ran = false;
109
+ const l = await startLoopbackListener({
110
+ accountId: "a",
111
+ state: "st-8",
112
+ onCode: async () => {
113
+ ran = true;
114
+ return { email: "x@y.z" };
115
+ },
116
+ });
117
+ assert.ok(l);
118
+ const r = await get(`${l.redirectUri}/?state=st-8&error=access_denied`);
119
+ assert.equal(r.status, 400);
120
+ assert.match(r.body, /access_denied/);
121
+ assert.doesNotMatch(r.body, /did not match/);
122
+ assert.equal(ran, false);
123
+ });
124
+ test("responses keep the code out of caches and referrers", async () => {
125
+ const l = await startLoopbackListener({
126
+ accountId: "a",
127
+ state: "st-9",
128
+ onCode: async () => ({ email: "x@y.z" }),
129
+ });
130
+ assert.ok(l);
131
+ const res = await fetch(`${l.redirectUri}/?state=st-9&code=xyz`);
132
+ assert.equal(res.headers.get("cache-control"), "no-store");
133
+ assert.equal(res.headers.get("referrer-policy"), "no-referrer");
134
+ await l.close("test");
135
+ });
136
+ test("the listener binds the loopback literal, never localhost", async () => {
137
+ const l = await startLoopbackListener({
138
+ accountId: "a",
139
+ state: "st-6",
140
+ onCode: async () => ({ email: "x@y.z" }),
141
+ });
142
+ assert.ok(l);
143
+ assert.match(l.redirectUri, /^http:\/\/127\.0\.0\.1:\d+$/);
144
+ await l.close("test");
145
+ });
146
+ //# sourceMappingURL=loopback-listener.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-listener.test.js","sourceRoot":"","sources":["../../src/__tests__/loopback-listener.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pending-redirect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-redirect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pending-redirect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { PendingStore } from "../auth/pending-store.js";
7
+ test("a pending entry round-trips its redirectUri", () => {
8
+ const dir = mkdtempSync(join(tmpdir(), "g-"));
9
+ const p = new PendingStore("acct-1", dir);
10
+ p.write({ state: "s1", verifier: "v1", createdAt: Date.now(), redirectUri: "http://127.0.0.1:54321" });
11
+ assert.equal(p.read()?.redirectUri, "http://127.0.0.1:54321");
12
+ });
13
+ test("a legacy pending entry with no redirectUri still reads", () => {
14
+ const dir = mkdtempSync(join(tmpdir(), "g-"));
15
+ const p = new PendingStore("acct-2", dir);
16
+ p.write({ state: "s2", verifier: "v2", createdAt: Date.now() });
17
+ assert.equal(p.read()?.redirectUri, undefined);
18
+ });
19
+ //# sourceMappingURL=pending-redirect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-redirect.test.js","sourceRoot":"","sources":["../../src/__tests__/pending-redirect.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;IACvD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC,CAAC;IACvG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,wBAAwB,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;IAClE,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=register-redirect-chain.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-redirect-chain.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/register-redirect-chain.test.ts"],"names":[],"mappings":""}