@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.
- package/dist/__tests__/google-client-id-env.test.js +3 -2
- package/package.json +1 -1
- package/payload/platform/neo4j/schema.cypher +4 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +29 -16
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/google-guide.md +25 -12
- package/payload/platform/plugins/docs/references/voice-mirror-guide.md +2 -2
- package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/google/PLUGIN.md +73 -14
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js +229 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +9 -9
- package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
- package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js +17 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js +146 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js +19 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js +41 -0
- package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts +44 -0
- package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js +112 -0
- package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts +17 -0
- package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js +143 -0
- package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts +9 -0
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts.map +1 -1
- package/payload/platform/plugins/google/mcp/dist/auth/pending-store.js.map +1 -1
- package/payload/platform/plugins/google/mcp/dist/index.js +73 -5
- package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts +2 -0
- package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js +37 -0
- package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js.map +1 -0
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +20 -4
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +19 -9
- package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
- package/payload/platform/plugins/google/references/auth.md +331 -367
- package/payload/platform/plugins/voice-mirror/PLUGIN.md +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/index.js +3 -3
- package/payload/platform/plugins/voice-mirror/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.d.ts +14 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.js +15 -0
- package/payload/platform/plugins/voice-mirror/mcp/dist/lib/voice-corpus.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +3 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +51 -4
- package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +4 -0
- package/payload/platform/scripts/backfill-task-ids.sh +206 -0
- package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +21 -3
- package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/activity-rows.js +6 -2
- package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +43 -5
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +78 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/assets/{AdminLoginScreens-B7TQZV8u.js → AdminLoginScreens-B44KbEuC.js} +1 -1
- package/payload/server/public/assets/{AdminShell-DAuri4Yh.js → AdminShell-BjxV2qkb.js} +2 -2
- package/payload/server/public/assets/{Checkbox-B1XhnhPk.js → Checkbox-DSeZNGNA.js} +1 -1
- package/payload/server/public/assets/activity-Mz1BhgB1.js +1 -0
- package/payload/server/public/assets/{admin-BdcccSb5.js → admin-B4LpTCur.js} +1 -1
- package/payload/server/public/assets/{browser-B6woQ2qX.js → browser-CEFvaWwI.js} +1 -1
- package/payload/server/public/assets/{calendar-CalCeg5T.js → calendar-B3zo6V34.js} +1 -1
- package/payload/server/public/assets/chat-5tJdo9i_.js +1 -0
- package/payload/server/public/assets/chevron-left-BJllrPBj.js +1 -0
- package/payload/server/public/assets/data-Du79EgR-.js +1 -0
- package/payload/server/public/assets/{graph-HeZaatSQ.js → graph-RaOrnSf2.js} +1 -1
- package/payload/server/public/assets/{graph-labels-4W7JuOgG.js → graph-labels-GlTEIYJj.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DKx-aTPb.js → maximize-2-CHDa8p5h.js} +1 -1
- package/payload/server/public/assets/{operator-DD9L2VJM.js → operator-DtqHY4jV.js} +1 -1
- package/payload/server/public/assets/{page-tJxw0zNO.js → page-CkhFj8GQ.js} +1 -1
- package/payload/server/public/assets/{page-Ceado9Kr.js → page-DxnWgPtd.js} +1 -1
- package/payload/server/public/assets/{public-BYFWxyeC.js → public-D5TUfQ3I.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-DrzdV9h7.js → rotate-ccw-BJjVAQQY.js} +1 -1
- package/payload/server/public/assets/tasks-CM9pYYG1.js +1 -0
- package/payload/server/public/assets/{time-entry-format-Bn79w6tq.js → time-entry-format-C5RYEYjM.js} +1 -1
- package/payload/server/public/assets/{triangle-alert-CjDVh6r-.js → triangle-alert-DLfIsuo_.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-DXHkkJw-.js → useCopyFeedback-7yKeiAzV.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-D2H8jAhE.js → useSelectionMode-CWlh6AEq.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-Br7Z6Cpu.css → useSubAccountSwitcher-B2n9QPVI.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-zUvPe55I.js → useVoiceRecorder-j3ZArZ2H.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +6 -6
- package/payload/server/public/chat.html +12 -12
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +11 -11
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +12 -12
- package/payload/server/public/tasks.html +5 -5
- package/payload/server/server.js +433 -313
- package/payload/server/public/assets/activity-kRwzxEKU.js +0 -1
- package/payload/server/public/assets/chat-9s2-L06v.js +0 -1
- package/payload/server/public/assets/chevron-left-C3ho8SnB.js +0 -1
- package/payload/server/public/assets/data-Cfr-7ERI.js +0 -1
- package/payload/server/public/assets/tasks-DSwoxGzh.js +0 -1
- /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
|
-
|
|
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
|
-
|
|
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",
|
|
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":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,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,EACL,OAAO,EACP,eAAe,EACf,uBAAuB,EACvB,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,SAAS,MAAM;IACb,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,CAAC;IAC1C,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACnF,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4EAA4E,EAAE,GAAG,EAAE;IACtF,MAAM,GAAG,GAAG,IAAI,GAAG,CACjB,eAAe,CAAC;QACd,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI;QACf,
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-redirect-chain.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/register-redirect-chain.test.ts"],"names":[],"mappings":""}
|