@rubytech/create-maxy-code 0.1.474 → 0.1.476
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/package.json +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +3 -2
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +3 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +18 -9
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +13 -3
- package/payload/platform/plugins/docs/references/calendar-booking.md +2 -2
- package/payload/platform/plugins/docs/references/google-guide.md +15 -6
- package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/google/PLUGIN.md +60 -12
- 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 +93 -14
- package/payload/platform/plugins/scheduling/PLUGIN.md +2 -2
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +158 -23
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.js +200 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js +309 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js +219 -19
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +94 -11
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +106 -22
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts +109 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js +213 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts +80 -8
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js +202 -8
- package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts +6 -4
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +334 -142
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- 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/{chunk-Y6V45R6M.js → chunk-LBCMFD4O.js} +173 -29
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/assets/{AdminLoginScreens-B44KbEuC.js → AdminLoginScreens-DximwPlS.js} +1 -1
- package/payload/server/public/assets/{AdminShell-BjxV2qkb.js → AdminShell-BehbH-Oa.js} +1 -1
- package/payload/server/public/assets/{Checkbox-DSeZNGNA.js → Checkbox-DM-eHqOS.js} +1 -1
- package/payload/server/public/assets/activity-hDwUeQd6.js +1 -0
- package/payload/server/public/assets/{admin-B4LpTCur.js → admin-CAkDnGdk.js} +1 -1
- package/payload/server/public/assets/{browser-CEFvaWwI.js → browser-DXl8hOoi.js} +1 -1
- package/payload/server/public/assets/{calendar-B3zo6V34.js → calendar-DP6hn4-6.js} +1 -1
- package/payload/server/public/assets/chat-DhOfVGYM.js +1 -0
- package/payload/server/public/assets/chevron-left-DYNBoLii.js +1 -0
- package/payload/server/public/assets/data-bq8fTo_s.js +1 -0
- package/payload/server/public/assets/{graph-RaOrnSf2.js → graph-CHcYoEJ5.js} +1 -1
- package/payload/server/public/assets/{graph-labels-GlTEIYJj.js → graph-labels-CZykslZM.js} +1 -1
- package/payload/server/public/assets/{maximize-2-CHDa8p5h.js → maximize-2-31AZEcMS.js} +1 -1
- package/payload/server/public/assets/{operator-DtqHY4jV.js → operator-BGGpdsO_.js} +1 -1
- package/payload/server/public/assets/{page-CkhFj8GQ.js → page-BloC6ygA.js} +1 -1
- package/payload/server/public/assets/{page-DxnWgPtd.js → page-DOeiiqbR.js} +1 -1
- package/payload/server/public/assets/{public-D5TUfQ3I.js → public-CGgO6IZv.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BJjVAQQY.js → rotate-ccw-BlAi6iFg.js} +1 -1
- package/payload/server/public/assets/{tasks-CM9pYYG1.js → tasks-C1giFRRL.js} +1 -1
- package/payload/server/public/assets/{time-entry-format-C5RYEYjM.js → time-entry-format-CiUUQdq7.js} +1 -1
- package/payload/server/public/assets/{triangle-alert-DLfIsuo_.js → triangle-alert-CVqKuLoa.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-7yKeiAzV.js → useCopyFeedback-ksyUe_g1.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-CWlh6AEq.js → useSelectionMode-BPrBkdTd.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-B2n9QPVI.css → useSubAccountSwitcher-K4kYeN6i.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-j3ZArZ2H.js → useVoiceRecorder-CTXP8oTW.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 +547 -423
- package/payload/server/public/assets/activity-CdipMTDp.js +0 -1
- package/payload/server/public/assets/chat-5tJdo9i_.js +0 -1
- package/payload/server/public/assets/chevron-left-BJllrPBj.js +0 -1
- package/payload/server/public/assets/data-Du79EgR-.js +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-CBlKgwms.js → useSubAccountSwitcher-DzgzTRRn.js} +0 -0
|
@@ -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":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
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 { newState, runAccountRegisterStart } from "../tools/account-register.js";
|
|
7
|
+
import { PendingStore } from "../auth/pending-store.js";
|
|
8
|
+
/** The consent URL, the pending entry and therefore the exchange must all
|
|
9
|
+
* carry one redirect. Google compares the exchange's value byte-for-byte
|
|
10
|
+
* against the one that issued the code, so a divergence here is the
|
|
11
|
+
* redirect_uri_mismatch that reads like a wrong client type. */
|
|
12
|
+
test("the consent URL and the pending entry carry the same redirect", async () => {
|
|
13
|
+
const dir = mkdtempSync(join(tmpdir(), "g-"));
|
|
14
|
+
const r = await runAccountRegisterStart({
|
|
15
|
+
accountId: "acct",
|
|
16
|
+
accountsDir: dir,
|
|
17
|
+
clientId: "cid",
|
|
18
|
+
state: newState(),
|
|
19
|
+
redirectUri: "http://127.0.0.1:54321",
|
|
20
|
+
});
|
|
21
|
+
assert.equal(r.status, "pending");
|
|
22
|
+
const inUrl = new URL(r.consentUrl).searchParams.get("redirect_uri");
|
|
23
|
+
const inPending = new PendingStore("acct", dir).read()?.redirectUri;
|
|
24
|
+
assert.equal(inUrl, "http://127.0.0.1:54321");
|
|
25
|
+
assert.equal(inPending, "http://127.0.0.1:54321");
|
|
26
|
+
assert.equal(inUrl, inPending);
|
|
27
|
+
});
|
|
28
|
+
test("the state minted by the caller is the state persisted and sent", async () => {
|
|
29
|
+
const dir = mkdtempSync(join(tmpdir(), "g-"));
|
|
30
|
+
const state = newState();
|
|
31
|
+
const r = await runAccountRegisterStart({
|
|
32
|
+
accountId: "acct",
|
|
33
|
+
accountsDir: dir,
|
|
34
|
+
clientId: "cid",
|
|
35
|
+
state,
|
|
36
|
+
redirectUri: "http://127.0.0.1:1234",
|
|
37
|
+
});
|
|
38
|
+
assert.equal(new URL(r.consentUrl).searchParams.get("state"), state);
|
|
39
|
+
assert.equal(new PendingStore("acct", dir).read()?.state, state);
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=register-redirect-chain.test.js.map
|
package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-redirect-chain.test.js","sourceRoot":"","sources":["../../src/__tests__/register-redirect-chain.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,QAAQ,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD;;;iEAGiE;AACjE,IAAI,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;IAC/E,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,MAAM,uBAAuB,CAAC;QACtC,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,GAAG;QAChB,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,QAAQ,EAAE;QACjB,WAAW,EAAE,wBAAwB;KACtC,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;IAChF,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,MAAM,uBAAuB,CAAC;QACtC,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,GAAG;QAChB,QAAQ,EAAE,KAAK;QACf,KAAK;QACL,WAAW,EAAE,uBAAuB;KACrC,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type TokenBlob } from "./token-store.js";
|
|
2
|
+
/** Google revokes a refresh token after six months without use. */
|
|
3
|
+
export declare const REFRESH_INACTIVITY_LIMIT_DAYS = 180;
|
|
4
|
+
/** How much of the inactivity clock must remain before an account is merely
|
|
5
|
+
* `ok`. Thirty days is the window in which an operator can still act. */
|
|
6
|
+
export declare const REFRESH_EXPIRING_THRESHOLD_DAYS = 30;
|
|
7
|
+
export type RefreshStatus = "ok" | "expiring" | "expired";
|
|
8
|
+
export interface AccountAuditRow {
|
|
9
|
+
accountId: string;
|
|
10
|
+
email: string;
|
|
11
|
+
refreshTtlDays: number;
|
|
12
|
+
status: RefreshStatus;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Classify one token blob against the inactivity clock.
|
|
16
|
+
*
|
|
17
|
+
* A blob holding NO refresh token is `expired` with zero days regardless of how
|
|
18
|
+
* recently it was written: it works until the access token lapses, about an hour
|
|
19
|
+
* out, and then dies. Reporting it as `ok` because `lastRefresh` is recent would
|
|
20
|
+
* be precisely the false all-clear this audit exists to prevent.
|
|
21
|
+
*/
|
|
22
|
+
export declare function classifyRefresh(blob: TokenBlob, nowMs: number): {
|
|
23
|
+
refreshTtlDays: number;
|
|
24
|
+
status: RefreshStatus;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Every connected Google account under every account, classified.
|
|
28
|
+
*
|
|
29
|
+
* An unreadable blob is skipped rather than thrown: one corrupt store must never
|
|
30
|
+
* blind the audit to every other account. It is not reported as a row because it
|
|
31
|
+
* has no TTL to report — `google-account-list` is the surface that already
|
|
32
|
+
* distinguishes `unreadable` from healthy.
|
|
33
|
+
*/
|
|
34
|
+
export declare function auditConnectedAccounts(accountsDir: string, nowMs: number): AccountAuditRow[];
|
|
35
|
+
/**
|
|
36
|
+
* One audit cycle: a line per connected account, then a heartbeat.
|
|
37
|
+
*
|
|
38
|
+
* The heartbeat fires on EVERY cycle, including cycles that find nothing. An
|
|
39
|
+
* audit that has stopped running would otherwise be indistinguishable from an
|
|
40
|
+
* audit reporting all-clear, and the standing absence of this line over more
|
|
41
|
+
* than one interval is the documented signal that the audit is not running.
|
|
42
|
+
*/
|
|
43
|
+
export declare function runAccountAudit(accountsDir: string, nowMs: number, emit: (line: string) => void): AccountAuditRow[];
|
|
44
|
+
//# sourceMappingURL=account-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-audit.d.ts","sourceRoot":"","sources":["../../src/auth/account-audit.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE9D,mEAAmE;AACnE,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD;0EAC0E;AAC1E,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAMlD,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;AAW1D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,MAAM,GACZ;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAWnD;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAkB5F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC3B,eAAe,EAAE,CAYnB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standing refresh-token audit (Task 1773).
|
|
3
|
+
*
|
|
4
|
+
* A connected account's 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. Without a periodic reconciliation, "which connected accounts
|
|
7
|
+
* are close to falling off?" is unanswerable without reading every token store by
|
|
8
|
+
* hand. This module is that reconciliation.
|
|
9
|
+
*
|
|
10
|
+
* WHAT `refreshTtlDays` MEANS. Google issues no expiry for a refresh token and
|
|
11
|
+
* the stored blob holds none — `TokenBlob` carries `accessTokenExpiry` and
|
|
12
|
+
* `lastRefresh`, nothing more. The one bounded, locally-computable clock is
|
|
13
|
+
* Google's six-month INACTIVITY revocation: a refresh token unused for 180 days
|
|
14
|
+
* is revoked. So `refreshTtlDays` is days remaining on that inactivity clock,
|
|
15
|
+
* measured from `lastRefresh`. It is NOT a expiry Google published, and it does
|
|
16
|
+
* not predict the other revocation causes (the user revoking access, a password
|
|
17
|
+
* change, or the app being unpublished), none of which are locally observable.
|
|
18
|
+
*
|
|
19
|
+
* Runs against local stores only — no network. It reads what is on disk and
|
|
20
|
+
* classifies it, so it cannot itself break a working connection.
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import { TokenStore } from "./token-store.js";
|
|
25
|
+
/** Google revokes a refresh token after six months without use. */
|
|
26
|
+
export const REFRESH_INACTIVITY_LIMIT_DAYS = 180;
|
|
27
|
+
/** How much of the inactivity clock must remain before an account is merely
|
|
28
|
+
* `ok`. Thirty days is the window in which an operator can still act. */
|
|
29
|
+
export const REFRESH_EXPIRING_THRESHOLD_DAYS = 30;
|
|
30
|
+
const DAY_MS = 86_400_000;
|
|
31
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
32
|
+
/** The audit line is space-delimited `k=v`, so a value carrying whitespace would
|
|
33
|
+
* split into bogus fields and a reader would mis-parse the record for exactly
|
|
34
|
+
* the account most likely to need attention. The directory name is already
|
|
35
|
+
* folded by `sanitizeAccountKey`, but `blob.email` comes from Google's
|
|
36
|
+
* primary-calendar id and is never sanitized on the way in. */
|
|
37
|
+
function logSafe(value) {
|
|
38
|
+
return value.replace(/\s+/g, "_");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Classify one token blob against the inactivity clock.
|
|
42
|
+
*
|
|
43
|
+
* A blob holding NO refresh token is `expired` with zero days regardless of how
|
|
44
|
+
* recently it was written: it works until the access token lapses, about an hour
|
|
45
|
+
* out, and then dies. Reporting it as `ok` because `lastRefresh` is recent would
|
|
46
|
+
* be precisely the false all-clear this audit exists to prevent.
|
|
47
|
+
*/
|
|
48
|
+
export function classifyRefresh(blob, nowMs) {
|
|
49
|
+
if (blob.refreshToken === null)
|
|
50
|
+
return { refreshTtlDays: 0, status: "expired" };
|
|
51
|
+
// Clamp idleDays at 0 so a lastRefresh in the future — a device whose clock ran
|
|
52
|
+
// ahead, or a blob restored from a host whose clock did — cannot report more
|
|
53
|
+
// days remaining than the limit this module documents as the maximum.
|
|
54
|
+
// `PendingStore.ageSec` clamps its analogous value for the same reason.
|
|
55
|
+
const idleDays = Math.max(0, Math.floor((nowMs - blob.lastRefresh) / DAY_MS));
|
|
56
|
+
const refreshTtlDays = REFRESH_INACTIVITY_LIMIT_DAYS - idleDays;
|
|
57
|
+
if (refreshTtlDays <= 0)
|
|
58
|
+
return { refreshTtlDays, status: "expired" };
|
|
59
|
+
if (refreshTtlDays <= REFRESH_EXPIRING_THRESHOLD_DAYS)
|
|
60
|
+
return { refreshTtlDays, status: "expiring" };
|
|
61
|
+
return { refreshTtlDays, status: "ok" };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Every connected Google account under every account, classified.
|
|
65
|
+
*
|
|
66
|
+
* An unreadable blob is skipped rather than thrown: one corrupt store must never
|
|
67
|
+
* blind the audit to every other account. It is not reported as a row because it
|
|
68
|
+
* has no TTL to report — `google-account-list` is the surface that already
|
|
69
|
+
* distinguishes `unreadable` from healthy.
|
|
70
|
+
*/
|
|
71
|
+
export function auditConnectedAccounts(accountsDir, nowMs) {
|
|
72
|
+
if (!existsSync(accountsDir))
|
|
73
|
+
return [];
|
|
74
|
+
const rows = [];
|
|
75
|
+
for (const accountId of readdirSync(accountsDir)) {
|
|
76
|
+
if (!UUID_RE.test(accountId))
|
|
77
|
+
continue;
|
|
78
|
+
const connectedDir = join(accountsDir, accountId, "secrets", "google", "accounts");
|
|
79
|
+
if (!existsSync(connectedDir))
|
|
80
|
+
continue;
|
|
81
|
+
for (const key of readdirSync(connectedDir)) {
|
|
82
|
+
try {
|
|
83
|
+
const blob = new TokenStore(accountId, accountsDir, key).read();
|
|
84
|
+
if (!blob)
|
|
85
|
+
continue;
|
|
86
|
+
rows.push({ accountId, email: logSafe(blob.email ?? key), ...classifyRefresh(blob, nowMs) });
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
/* unreadable store — skip, never blind the whole scan */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return rows;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* One audit cycle: a line per connected account, then a heartbeat.
|
|
97
|
+
*
|
|
98
|
+
* The heartbeat fires on EVERY cycle, including cycles that find nothing. An
|
|
99
|
+
* audit that has stopped running would otherwise be indistinguishable from an
|
|
100
|
+
* audit reporting all-clear, and the standing absence of this line over more
|
|
101
|
+
* than one interval is the documented signal that the audit is not running.
|
|
102
|
+
*/
|
|
103
|
+
export function runAccountAudit(accountsDir, nowMs, emit) {
|
|
104
|
+
const rows = auditConnectedAccounts(accountsDir, nowMs);
|
|
105
|
+
for (const r of rows) {
|
|
106
|
+
emit(`[google-account-audit] account=${r.accountId} email=${r.email} refreshTtlDays=${r.refreshTtlDays} status=${r.status}`);
|
|
107
|
+
}
|
|
108
|
+
const count = (s) => rows.filter((r) => r.status === s).length;
|
|
109
|
+
emit(`[google-account-audit] op=heartbeat accounts=${rows.length} ok=${count("ok")} expiring=${count("expiring")} expired=${count("expired")}`);
|
|
110
|
+
return rows;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=account-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-audit.js","sourceRoot":"","sources":["../../src/auth/account-audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface LoopbackListener {
|
|
2
|
+
readonly redirectUri: string;
|
|
3
|
+
readonly port: number;
|
|
4
|
+
close(reason: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/** Resolves null when the bind fails, so the caller falls back to the fixed
|
|
7
|
+
* redirect and the paste path still completes the registration. A refusal
|
|
8
|
+
* here would turn an optimisation into a regression on any install that
|
|
9
|
+
* cannot bind. */
|
|
10
|
+
export declare function startLoopbackListener(args: {
|
|
11
|
+
accountId: string;
|
|
12
|
+
state: string;
|
|
13
|
+
onCode: (code: string) => Promise<{
|
|
14
|
+
email: string;
|
|
15
|
+
}>;
|
|
16
|
+
}): Promise<LoopbackListener | null>;
|
|
17
|
+
//# sourceMappingURL=loopback-listener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback-listener.d.ts","sourceRoot":"","sources":["../../src/auth/loopback-listener.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AA0BD;;;mBAGmB;AACnB,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6HnC"}
|