@agent-native/core 0.15.1 → 0.15.3
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/server/auth.d.ts +3 -4
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/google-auth-plugin.d.ts +2 -2
- package/dist/server/google-auth-plugin.d.ts.map +1 -1
- package/dist/server/google-auth-plugin.js +51 -9
- package/dist/server/google-auth-plugin.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +2 -2
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +53 -13
- package/dist/server/onboarding-html.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/dev-mode.d.ts +0 -14
- package/dist/client/dev-mode.d.ts.map +0 -1
- package/dist/client/dev-mode.js +0 -14
- package/dist/client/dev-mode.js.map +0 -1
- package/dist/client/extensions/EmbeddedTool.d.ts +0 -20
- package/dist/client/extensions/EmbeddedTool.d.ts.map +0 -1
- package/dist/client/extensions/EmbeddedTool.js +0 -199
- package/dist/client/extensions/EmbeddedTool.js.map +0 -1
- package/dist/client/extensions/ToolEditor.d.ts +0 -5
- package/dist/client/extensions/ToolEditor.d.ts.map +0 -1
- package/dist/client/extensions/ToolEditor.js +0 -129
- package/dist/client/extensions/ToolEditor.js.map +0 -1
- package/dist/client/extensions/ToolViewer.d.ts +0 -5
- package/dist/client/extensions/ToolViewer.d.ts.map +0 -1
- package/dist/client/extensions/ToolViewer.js +0 -400
- package/dist/client/extensions/ToolViewer.js.map +0 -1
- package/dist/client/extensions/ToolViewerPage.d.ts +0 -2
- package/dist/client/extensions/ToolViewerPage.d.ts.map +0 -1
- package/dist/client/extensions/ToolViewerPage.js +0 -24
- package/dist/client/extensions/ToolViewerPage.js.map +0 -1
- package/dist/client/extensions/ToolsListPage.d.ts +0 -2
- package/dist/client/extensions/ToolsListPage.d.ts.map +0 -1
- package/dist/client/extensions/ToolsListPage.js +0 -67
- package/dist/client/extensions/ToolsListPage.js.map +0 -1
- package/dist/client/extensions/ToolsSidebarSection.d.ts +0 -2
- package/dist/client/extensions/ToolsSidebarSection.d.ts.map +0 -1
- package/dist/client/extensions/ToolsSidebarSection.js +0 -236
- package/dist/client/extensions/ToolsSidebarSection.js.map +0 -1
- package/dist/client/extensions/tool-order.d.ts +0 -7
- package/dist/client/extensions/tool-order.d.ts.map +0 -1
- package/dist/client/extensions/tool-order.js +0 -47
- package/dist/client/extensions/tool-order.js.map +0 -1
- package/dist/client/tools/EmbeddedTool.d.ts +0 -20
- package/dist/client/tools/EmbeddedTool.d.ts.map +0 -1
- package/dist/client/tools/EmbeddedTool.js +0 -199
- package/dist/client/tools/EmbeddedTool.js.map +0 -1
- package/dist/client/tools/ExtensionSlot.d.ts +0 -27
- package/dist/client/tools/ExtensionSlot.d.ts.map +0 -1
- package/dist/client/tools/ExtensionSlot.js +0 -96
- package/dist/client/tools/ExtensionSlot.js.map +0 -1
- package/dist/client/tools/ToolEditor.d.ts +0 -5
- package/dist/client/tools/ToolEditor.d.ts.map +0 -1
- package/dist/client/tools/ToolEditor.js +0 -129
- package/dist/client/tools/ToolEditor.js.map +0 -1
- package/dist/client/tools/ToolViewer.d.ts +0 -5
- package/dist/client/tools/ToolViewer.d.ts.map +0 -1
- package/dist/client/tools/ToolViewer.js +0 -400
- package/dist/client/tools/ToolViewer.js.map +0 -1
- package/dist/client/tools/ToolViewerPage.d.ts +0 -2
- package/dist/client/tools/ToolViewerPage.d.ts.map +0 -1
- package/dist/client/tools/ToolViewerPage.js +0 -24
- package/dist/client/tools/ToolViewerPage.js.map +0 -1
- package/dist/client/tools/ToolsListPage.d.ts +0 -2
- package/dist/client/tools/ToolsListPage.d.ts.map +0 -1
- package/dist/client/tools/ToolsListPage.js +0 -67
- package/dist/client/tools/ToolsListPage.js.map +0 -1
- package/dist/client/tools/ToolsSidebarSection.d.ts +0 -2
- package/dist/client/tools/ToolsSidebarSection.d.ts.map +0 -1
- package/dist/client/tools/ToolsSidebarSection.js +0 -236
- package/dist/client/tools/ToolsSidebarSection.js.map +0 -1
- package/dist/client/tools/iframe-bridge.d.ts +0 -38
- package/dist/client/tools/iframe-bridge.d.ts.map +0 -1
- package/dist/client/tools/iframe-bridge.js +0 -207
- package/dist/client/tools/iframe-bridge.js.map +0 -1
- package/dist/client/tools/index.d.ts +0 -8
- package/dist/client/tools/index.d.ts.map +0 -1
- package/dist/client/tools/index.js +0 -8
- package/dist/client/tools/index.js.map +0 -1
- package/dist/client/tools/tool-order.d.ts +0 -7
- package/dist/client/tools/tool-order.d.ts.map +0 -1
- package/dist/client/tools/tool-order.js +0 -47
- package/dist/client/tools/tool-order.js.map +0 -1
- package/dist/server/local-migration.d.ts +0 -41
- package/dist/server/local-migration.d.ts.map +0 -1
- package/dist/server/local-migration.js +0 -235
- package/dist/server/local-migration.js.map +0 -1
- package/dist/tools/actions.d.ts +0 -3
- package/dist/tools/actions.d.ts.map +0 -1
- package/dist/tools/actions.js +0 -272
- package/dist/tools/actions.js.map +0 -1
- package/dist/tools/fetch-tool.d.ts +0 -23
- package/dist/tools/fetch-tool.d.ts.map +0 -1
- package/dist/tools/fetch-tool.js +0 -178
- package/dist/tools/fetch-tool.js.map +0 -1
- package/dist/tools/html-shell.d.ts +0 -45
- package/dist/tools/html-shell.d.ts.map +0 -1
- package/dist/tools/html-shell.js +0 -514
- package/dist/tools/html-shell.js.map +0 -1
- package/dist/tools/proxy-security.d.ts +0 -12
- package/dist/tools/proxy-security.d.ts.map +0 -1
- package/dist/tools/proxy-security.js +0 -158
- package/dist/tools/proxy-security.js.map +0 -1
- package/dist/tools/routes.d.ts +0 -2
- package/dist/tools/routes.d.ts.map +0 -1
- package/dist/tools/routes.js +0 -627
- package/dist/tools/routes.js.map +0 -1
- package/dist/tools/schema.d.ts +0 -664
- package/dist/tools/schema.d.ts.map +0 -1
- package/dist/tools/schema.js +0 -146
- package/dist/tools/schema.js.map +0 -1
- package/dist/tools/slots/routes.d.ts +0 -15
- package/dist/tools/slots/routes.d.ts.map +0 -1
- package/dist/tools/slots/routes.js +0 -94
- package/dist/tools/slots/routes.js.map +0 -1
- package/dist/tools/slots/schema.d.ts +0 -303
- package/dist/tools/slots/schema.d.ts.map +0 -1
- package/dist/tools/slots/schema.js +0 -76
- package/dist/tools/slots/schema.js.map +0 -1
- package/dist/tools/slots/store.d.ts +0 -66
- package/dist/tools/slots/store.d.ts.map +0 -1
- package/dist/tools/slots/store.js +0 -227
- package/dist/tools/slots/store.js.map +0 -1
- package/dist/tools/store.d.ts +0 -40
- package/dist/tools/store.d.ts.map +0 -1
- package/dist/tools/store.js +0 -193
- package/dist/tools/store.js.map +0 -1
- package/dist/tools/theme.d.ts +0 -2
- package/dist/tools/theme.d.ts.map +0 -1
- package/dist/tools/theme.js +0 -67
- package/dist/tools/theme.js.map +0 -1
- package/dist/tools/url-safety.d.ts +0 -24
- package/dist/tools/url-safety.d.ts.map +0 -1
- package/dist/tools/url-safety.js +0 -224
- package/dist/tools/url-safety.js.map +0 -1
package/dist/tools/store.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/tools/store.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { getDbExec, isPostgres, retryOnDdlRace } from \"../db/client.js\";\nimport { createGetDb } from \"../db/create-get-db.js\";\nimport {\n accessFilter,\n assertAccess,\n resolveAccess,\n} from \"../sharing/access.js\";\nimport {\n getRequestUserEmail,\n getRequestOrgId,\n} from \"../server/request-context.js\";\nimport { registerShareableResource } from \"../sharing/registry.js\";\nimport {\n tools,\n toolShares,\n TOOLS_CREATE_SQL,\n TOOLS_CREATE_SQL_PG,\n TOOL_SHARES_CREATE_SQL,\n TOOL_SHARES_CREATE_SQL_PG,\n TOOL_DATA_CREATE_SQL,\n TOOL_DATA_CREATE_SQL_PG,\n TOOL_DATA_ITEM_INDEX_SQL,\n TOOL_DATA_ITEM_INDEX_SQL_PG,\n TOOL_DATA_DROP_OLD_INDEX_SQL,\n TOOL_DATA_DROP_OLD_INDEX_SQL_PG,\n TOOLS_OWNER_INDEX_SQL,\n TOOLS_ORG_INDEX_SQL,\n TOOL_SHARES_RESOURCE_INDEX_SQL,\n TOOL_CONSENTS_CREATE_SQL,\n TOOL_CONSENTS_CREATE_SQL_PG,\n TOOL_CONSENTS_VIEWER_INDEX_SQL,\n} from \"./schema.js\";\n\nconst getDb = createGetDb({ tools, toolShares });\n\nlet _initPromise: Promise<void> | undefined;\n\nexport async function ensureToolsTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const pg = isPostgres();\n await retryOnDdlRace(() =>\n client.execute(pg ? TOOLS_CREATE_SQL_PG : TOOLS_CREATE_SQL),\n );\n await retryOnDdlRace(() =>\n client.execute(pg ? TOOL_SHARES_CREATE_SQL_PG : TOOL_SHARES_CREATE_SQL),\n );\n await retryOnDdlRace(() =>\n client.execute(pg ? TOOL_DATA_CREATE_SQL_PG : TOOL_DATA_CREATE_SQL),\n );\n await ensureToolDataItemId(client, pg);\n await ensureToolDataScope(client, pg);\n await client.execute(\n pg ? TOOL_DATA_DROP_OLD_INDEX_SQL_PG : TOOL_DATA_DROP_OLD_INDEX_SQL,\n );\n await retryOnDdlRace(() =>\n client.execute(\n pg ? TOOL_DATA_ITEM_INDEX_SQL_PG : TOOL_DATA_ITEM_INDEX_SQL,\n ),\n );\n await retryOnDdlRace(() => client.execute(TOOLS_OWNER_INDEX_SQL));\n await retryOnDdlRace(() => client.execute(TOOLS_ORG_INDEX_SQL));\n await retryOnDdlRace(() =>\n client.execute(TOOL_SHARES_RESOURCE_INDEX_SQL),\n );\n // tool_consents was introduced for an audit-C1 per-viewer consent\n // gate that we removed once we settled on intra-org trust as the\n // baseline. The table is kept (additive — never drop) so deploys\n // that already created it stay healthy; the runtime consent code\n // is gone. Idempotent CREATE IF NOT EXISTS for fresh schemas.\n await retryOnDdlRace(() =>\n client.execute(\n pg ? TOOL_CONSENTS_CREATE_SQL_PG : TOOL_CONSENTS_CREATE_SQL,\n ),\n );\n await retryOnDdlRace(() =>\n client.execute(TOOL_CONSENTS_VIEWER_INDEX_SQL),\n );\n })();\n }\n return _initPromise;\n}\n\nasync function ensureToolDataItemId(\n client: ReturnType<typeof getDbExec>,\n pg: boolean,\n): Promise<void> {\n if (pg) {\n await client.execute(\n `ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS item_id TEXT`,\n );\n return;\n }\n\n // Keep this additive: legacy rows with item_id=id are still read correctly\n // through COALESCE(item_id, id), so SQLite never needs a table rebuild here.\n try {\n await client.execute(`ALTER TABLE tool_data ADD COLUMN item_id TEXT`);\n } catch (err: any) {\n if (\n !String(err?.message ?? err)\n .toLowerCase()\n .includes(\"duplicate\")\n ) {\n throw err;\n }\n }\n}\n\nasync function ensureToolDataScope(\n client: ReturnType<typeof getDbExec>,\n pg: boolean,\n): Promise<void> {\n const addCol = (name: string, def: string) => {\n if (pg) {\n return client.execute(\n `ALTER TABLE tool_data ADD COLUMN IF NOT EXISTS ${name} ${def}`,\n );\n }\n return client\n .execute(`ALTER TABLE tool_data ADD COLUMN ${name} ${def}`)\n .catch((err: any) => {\n if (\n !String(err?.message ?? err)\n .toLowerCase()\n .includes(\"duplicate\")\n )\n throw err;\n });\n };\n await addCol(\"scope\", \"TEXT NOT NULL DEFAULT 'user'\");\n await addCol(\"org_id\", \"TEXT\");\n await addCol(\"scope_key\", \"TEXT NOT NULL DEFAULT 'local@localhost'\");\n // One-time backfill migration: replaces the dev-mode DEFAULT scope_key\n // with each row's real owner_email. Not a per-request fallback.\n await client.execute(\n // guard:allow-localhost-fallback — one-time backfill migration replacing dev-mode default scope_key with the row's real owner_email\n `UPDATE tool_data SET scope_key = owner_email WHERE scope_key = 'local@localhost' AND owner_email != 'local@localhost'`,\n );\n}\n\nexport function registerToolsShareable() {\n registerShareableResource({\n type: \"tool\",\n resourceTable: tools,\n sharesTable: toolShares,\n displayName: \"Tool\",\n titleColumn: \"name\",\n getDb: () => getDb(),\n });\n}\n\nexport interface ToolRow {\n id: string;\n name: string;\n description: string;\n content: string;\n icon: string | null;\n createdAt: string;\n updatedAt: string;\n ownerEmail: string;\n orgId: string | null;\n visibility: \"private\" | \"org\" | \"public\";\n}\n\nexport async function listTools(): Promise<ToolRow[]> {\n await ensureToolsTables();\n const db = getDb();\n return db\n .select()\n .from(tools)\n .where(accessFilter(tools, toolShares)) as Promise<ToolRow[]>;\n}\n\nexport async function getTool(id: string): Promise<ToolRow | null> {\n await ensureToolsTables();\n const access = await resolveAccess(\"tool\", id);\n return (access?.resource as ToolRow | undefined) ?? null;\n}\n\nexport interface CreateToolData {\n name: string;\n description?: string;\n content?: string;\n icon?: string;\n}\n\nexport async function createTool(data: CreateToolData): Promise<ToolRow> {\n await ensureToolsTables();\n const db = getDb();\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n const orgId = getRequestOrgId();\n const id = randomUUID();\n const now = new Date().toISOString();\n const row: ToolRow = {\n id,\n name: data.name,\n description: data.description ?? \"\",\n content: data.content ?? \"\",\n icon: data.icon ?? null,\n createdAt: now,\n updatedAt: now,\n ownerEmail: userEmail,\n orgId: orgId ?? null,\n // Default to org-visibility when the user has an active organization so\n // teammates see the tool in their sidebar — matching how analytics\n // dashboards/analyses are scoped (`templates/analytics/server/lib/\n // dashboards-store.ts:356`). Solo users (no org) get the private\n // default. Owners can still flip back to private via update-tool.\n visibility: orgId ? \"org\" : \"private\",\n };\n await db.insert(tools).values(row);\n return row;\n}\n\nexport interface UpdateToolData {\n name?: string;\n description?: string;\n icon?: string;\n visibility?: \"private\" | \"org\" | \"public\";\n}\n\nexport async function updateTool(\n id: string,\n data: UpdateToolData,\n): Promise<ToolRow | null> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"editor\");\n const db = getDb();\n const updates: Record<string, unknown> = {\n updatedAt: new Date().toISOString(),\n };\n if (data.name !== undefined) updates.name = data.name;\n if (data.description !== undefined) updates.description = data.description;\n if (data.icon !== undefined) updates.icon = data.icon;\n if (data.visibility !== undefined) updates.visibility = data.visibility;\n await db.update(tools).set(updates).where(eq(tools.id, id));\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n return (rows[0] as ToolRow) ?? null;\n}\n\nexport interface UpdateToolContentOpts {\n content?: string;\n patches?: Array<{ find: string; replace: string }>;\n}\n\nexport async function updateToolContent(\n id: string,\n opts: UpdateToolContentOpts,\n): Promise<ToolRow | null> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"editor\");\n const db = getDb();\n\n let newContent: string;\n if (opts.content !== undefined) {\n newContent = opts.content;\n } else if (opts.patches) {\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n if (!rows[0]) return null;\n newContent = (rows[0] as ToolRow).content;\n for (const patch of opts.patches) {\n newContent = newContent.replace(patch.find, patch.replace);\n }\n } else {\n return null;\n }\n\n await db\n .update(tools)\n .set({ content: newContent, updatedAt: new Date().toISOString() })\n .where(eq(tools.id, id));\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n return (rows[0] as ToolRow) ?? null;\n}\n\nexport async function deleteTool(id: string): Promise<boolean> {\n await ensureToolsTables();\n await assertAccess(\"tool\", id, \"admin\");\n const db = getDb();\n const rows = await db.select().from(tools).where(eq(tools.id, id));\n if (!rows[0]) return false;\n await db.delete(toolShares).where(eq(toolShares.resourceId, id));\n await getDbExec().execute({\n sql: `DELETE FROM tool_data WHERE tool_id = ?`,\n args: [id],\n });\n const { cascadeDeleteToolSlots } = await import(\"./slots/store.js\");\n await cascadeDeleteToolSlots(id);\n await db.delete(tools).where(eq(tools.id, id));\n return true;\n}\n"]}
|
package/dist/tools/theme.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/tools/theme.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAkErD"}
|
package/dist/tools/theme.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
export function getThemeVars(isDark) {
|
|
2
|
-
if (isDark) {
|
|
3
|
-
return `
|
|
4
|
-
:root {
|
|
5
|
-
--background: 240 10% 3.9%;
|
|
6
|
-
--foreground: 0 0% 98%;
|
|
7
|
-
--card: 240 10% 3.9%;
|
|
8
|
-
--card-foreground: 0 0% 98%;
|
|
9
|
-
--popover: 240 10% 3.9%;
|
|
10
|
-
--popover-foreground: 0 0% 98%;
|
|
11
|
-
--primary: 0 0% 98%;
|
|
12
|
-
--primary-foreground: 240 5.9% 10%;
|
|
13
|
-
--secondary: 240 3.7% 15.9%;
|
|
14
|
-
--secondary-foreground: 0 0% 98%;
|
|
15
|
-
--muted: 240 3.7% 15.9%;
|
|
16
|
-
--muted-foreground: 240 5% 64.9%;
|
|
17
|
-
--accent: 240 3.7% 15.9%;
|
|
18
|
-
--accent-foreground: 0 0% 98%;
|
|
19
|
-
--destructive: 0 62.8% 30.6%;
|
|
20
|
-
--destructive-foreground: 0 0% 98%;
|
|
21
|
-
--border: 240 3.7% 15.9%;
|
|
22
|
-
--input: 240 3.7% 15.9%;
|
|
23
|
-
--ring: 240 4.9% 83.9%;
|
|
24
|
-
--radius: 0.5rem;
|
|
25
|
-
--sidebar-background: 240 5.9% 10%;
|
|
26
|
-
--sidebar-foreground: 240 4.8% 95.9%;
|
|
27
|
-
--sidebar-primary: 224.3 76.3% 48%;
|
|
28
|
-
--sidebar-primary-foreground: 0 0% 100%;
|
|
29
|
-
--sidebar-accent: 240 3.7% 15.9%;
|
|
30
|
-
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
|
31
|
-
--sidebar-border: 240 3.7% 15.9%;
|
|
32
|
-
--sidebar-ring: 240 4.9% 83.9%;
|
|
33
|
-
}`;
|
|
34
|
-
}
|
|
35
|
-
return `
|
|
36
|
-
:root {
|
|
37
|
-
--background: 0 0% 100%;
|
|
38
|
-
--foreground: 240 10% 3.9%;
|
|
39
|
-
--card: 0 0% 100%;
|
|
40
|
-
--card-foreground: 240 10% 3.9%;
|
|
41
|
-
--popover: 0 0% 100%;
|
|
42
|
-
--popover-foreground: 240 10% 3.9%;
|
|
43
|
-
--primary: 240 5.9% 10%;
|
|
44
|
-
--primary-foreground: 0 0% 98%;
|
|
45
|
-
--secondary: 240 4.8% 95.9%;
|
|
46
|
-
--secondary-foreground: 240 5.9% 10%;
|
|
47
|
-
--muted: 240 4.8% 95.9%;
|
|
48
|
-
--muted-foreground: 240 3.8% 46.1%;
|
|
49
|
-
--accent: 240 4.8% 95.9%;
|
|
50
|
-
--accent-foreground: 240 5.9% 10%;
|
|
51
|
-
--destructive: 0 84.2% 60.2%;
|
|
52
|
-
--destructive-foreground: 0 0% 98%;
|
|
53
|
-
--border: 240 5.9% 90%;
|
|
54
|
-
--input: 240 5.9% 90%;
|
|
55
|
-
--ring: 240 5.9% 10%;
|
|
56
|
-
--radius: 0.5rem;
|
|
57
|
-
--sidebar-background: 0 0% 98%;
|
|
58
|
-
--sidebar-foreground: 240 5.3% 26.1%;
|
|
59
|
-
--sidebar-primary: 240 5.9% 10%;
|
|
60
|
-
--sidebar-primary-foreground: 0 0% 98%;
|
|
61
|
-
--sidebar-accent: 240 4.8% 95.9%;
|
|
62
|
-
--sidebar-accent-foreground: 240 5.9% 10%;
|
|
63
|
-
--sidebar-border: 220 13% 91%;
|
|
64
|
-
--sidebar-ring: 240 5.9% 10%;
|
|
65
|
-
}`;
|
|
66
|
-
}
|
|
67
|
-
//# sourceMappingURL=theme.js.map
|
package/dist/tools/theme.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/tools/theme.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,MAAgB;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BT,CAAC;IACD,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BP,CAAC;AACH,CAAC","sourcesContent":["export function getThemeVars(isDark?: boolean): string {\n if (isDark) {\n return `\n:root {\n --background: 240 10% 3.9%;\n --foreground: 0 0% 98%;\n --card: 240 10% 3.9%;\n --card-foreground: 0 0% 98%;\n --popover: 240 10% 3.9%;\n --popover-foreground: 0 0% 98%;\n --primary: 0 0% 98%;\n --primary-foreground: 240 5.9% 10%;\n --secondary: 240 3.7% 15.9%;\n --secondary-foreground: 0 0% 98%;\n --muted: 240 3.7% 15.9%;\n --muted-foreground: 240 5% 64.9%;\n --accent: 240 3.7% 15.9%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 240 3.7% 15.9%;\n --input: 240 3.7% 15.9%;\n --ring: 240 4.9% 83.9%;\n --radius: 0.5rem;\n --sidebar-background: 240 5.9% 10%;\n --sidebar-foreground: 240 4.8% 95.9%;\n --sidebar-primary: 224.3 76.3% 48%;\n --sidebar-primary-foreground: 0 0% 100%;\n --sidebar-accent: 240 3.7% 15.9%;\n --sidebar-accent-foreground: 240 4.8% 95.9%;\n --sidebar-border: 240 3.7% 15.9%;\n --sidebar-ring: 240 4.9% 83.9%;\n}`;\n }\n\n return `\n:root {\n --background: 0 0% 100%;\n --foreground: 240 10% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 240 10% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 240 10% 3.9%;\n --primary: 240 5.9% 10%;\n --primary-foreground: 0 0% 98%;\n --secondary: 240 4.8% 95.9%;\n --secondary-foreground: 240 5.9% 10%;\n --muted: 240 4.8% 95.9%;\n --muted-foreground: 240 3.8% 46.1%;\n --accent: 240 4.8% 95.9%;\n --accent-foreground: 240 5.9% 10%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 240 5.9% 90%;\n --input: 240 5.9% 90%;\n --ring: 240 5.9% 10%;\n --radius: 0.5rem;\n --sidebar-background: 0 0% 98%;\n --sidebar-foreground: 240 5.3% 26.1%;\n --sidebar-primary: 240 5.9% 10%;\n --sidebar-primary-foreground: 0 0% 98%;\n --sidebar-accent: 240 4.8% 95.9%;\n --sidebar-accent-foreground: 240 5.9% 10%;\n --sidebar-border: 220 13% 91%;\n --sidebar-ring: 240 5.9% 10%;\n}`;\n}\n"]}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export declare function isBlockedToolUrl(url: string): boolean;
|
|
2
|
-
/**
|
|
3
|
-
* Async SSRF guard for environments that can resolve DNS. The synchronous
|
|
4
|
-
* guard catches literals and known rebinding domains; this closes the common
|
|
5
|
-
* "public hostname resolves to a private address" gap before dispatch.
|
|
6
|
-
*/
|
|
7
|
-
export declare function isBlockedToolUrlWithDns(url: string): Promise<boolean>;
|
|
8
|
-
/**
|
|
9
|
-
* Build an undici Dispatcher whose connect-time DNS lookup runs through a
|
|
10
|
-
* private-IP guard. This closes the TOCTOU gap where:
|
|
11
|
-
* 1. We resolve hostname → public IP and pass.
|
|
12
|
-
* 2. Between that lookup and the actual connect, DNS rebinding flips the
|
|
13
|
-
* record to a private IP.
|
|
14
|
-
* 3. fetch() resolves again and connects to the private IP.
|
|
15
|
-
*
|
|
16
|
-
* With a custom dispatcher, the same lookup that produces the IP also gates
|
|
17
|
-
* the connect: if the IP is in the private set, the connect throws.
|
|
18
|
-
*
|
|
19
|
-
* Returns `null` if undici / node:dns are not available (e.g. some edge
|
|
20
|
-
* runtimes); the caller should fall back to the regular `fetch` path —
|
|
21
|
-
* `isBlockedToolUrlWithDns` will still have caught most rebinding cases.
|
|
22
|
-
*/
|
|
23
|
-
export declare function createSsrfSafeDispatcher(): Promise<unknown | null>;
|
|
24
|
-
//# sourceMappingURL=url-safety.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"url-safety.d.ts","sourceRoot":"","sources":["../../src/tools/url-safety.ts"],"names":[],"mappings":"AA4FA,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAoBrD;AASD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB3E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA+DxE"}
|
package/dist/tools/url-safety.js
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
const METADATA_HOSTS = [
|
|
2
|
-
"metadata.google.internal",
|
|
3
|
-
"metadata.google.internal.",
|
|
4
|
-
];
|
|
5
|
-
const DNS_REBIND_SUFFIXES = [
|
|
6
|
-
".nip.io",
|
|
7
|
-
".sslip.io",
|
|
8
|
-
".xip.io",
|
|
9
|
-
".localtest.me",
|
|
10
|
-
".lvh.me",
|
|
11
|
-
];
|
|
12
|
-
function isPrivateIpv4(a, b, c = 0, d = 0) {
|
|
13
|
-
if (![a, b, c, d].every((part) => part >= 0 && part <= 255))
|
|
14
|
-
return true;
|
|
15
|
-
if (a === 127)
|
|
16
|
-
return true;
|
|
17
|
-
if (a === 10)
|
|
18
|
-
return true;
|
|
19
|
-
if (a === 172 && b >= 16 && b <= 31)
|
|
20
|
-
return true;
|
|
21
|
-
if (a === 192 && b === 168)
|
|
22
|
-
return true;
|
|
23
|
-
if (a === 169 && b === 254)
|
|
24
|
-
return true;
|
|
25
|
-
if (a === 0)
|
|
26
|
-
return true;
|
|
27
|
-
if (a === 100 && b >= 64 && b <= 127)
|
|
28
|
-
return true;
|
|
29
|
-
if (a === 192 && b === 0)
|
|
30
|
-
return true;
|
|
31
|
-
if (a === 198 && (b === 18 || b === 19))
|
|
32
|
-
return true;
|
|
33
|
-
if (a === 192 && b === 0 && c === 2)
|
|
34
|
-
return true;
|
|
35
|
-
if (a === 198 && b === 51 && c === 100)
|
|
36
|
-
return true;
|
|
37
|
-
if (a === 203 && b === 0 && c === 113)
|
|
38
|
-
return true;
|
|
39
|
-
if (a >= 224)
|
|
40
|
-
return true;
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
function isPrivateIpv4MappedHex(host) {
|
|
44
|
-
const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
|
|
45
|
-
if (!mapped)
|
|
46
|
-
return false;
|
|
47
|
-
const high = Number.parseInt(mapped[1], 16);
|
|
48
|
-
const low = Number.parseInt(mapped[2], 16);
|
|
49
|
-
if (high < 0 || high > 0xffff || low < 0 || low > 0xffff)
|
|
50
|
-
return false;
|
|
51
|
-
const a = (high >> 8) & 0xff;
|
|
52
|
-
const b = high & 0xff;
|
|
53
|
-
const c = (low >> 8) & 0xff;
|
|
54
|
-
const d = low & 0xff;
|
|
55
|
-
return isPrivateIpv4(a, b, c, d);
|
|
56
|
-
}
|
|
57
|
-
function isPrivateHost(hostname) {
|
|
58
|
-
const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
59
|
-
if (host === "localhost" ||
|
|
60
|
-
host === "::1" ||
|
|
61
|
-
host === "::0" ||
|
|
62
|
-
host === "::") {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
if (METADATA_HOSTS.includes(host))
|
|
66
|
-
return true;
|
|
67
|
-
// IPv6 ULA/link-local/multicast.
|
|
68
|
-
if (/^f[cd]/.test(host) || /^fe[89ab]/.test(host))
|
|
69
|
-
return true;
|
|
70
|
-
if (/^ff/i.test(host))
|
|
71
|
-
return true;
|
|
72
|
-
// IPv4-mapped IPv6. URL parsing may preserve dotted form in some runtimes
|
|
73
|
-
// or normalize it to hex, e.g. [::ffff:127.0.0.1] -> ::ffff:7f00:1.
|
|
74
|
-
const v4mappedDotted = host.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/);
|
|
75
|
-
if (v4mappedDotted) {
|
|
76
|
-
const [a, b, c, d] = v4mappedDotted[1].split(".").map(Number);
|
|
77
|
-
if (isPrivateIpv4(a, b, c, d))
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
if (isPrivateIpv4MappedHex(host))
|
|
81
|
-
return true;
|
|
82
|
-
// Dotted IPv4. URL parsing normalizes shorthand/octal/hex IPv4 forms to
|
|
83
|
-
// dotted decimal before we reach this point.
|
|
84
|
-
const parts = host.split(".");
|
|
85
|
-
if (parts.length === 4 && parts.every((p) => /^\d+$/.test(p))) {
|
|
86
|
-
const [a, b, c, d] = parts.map(Number);
|
|
87
|
-
if (isPrivateIpv4(a, b, c, d))
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
// Decimal integer IPv4.
|
|
91
|
-
if (/^\d+$/.test(host)) {
|
|
92
|
-
const num = Number(host);
|
|
93
|
-
if (num >= 0 && num <= 0xffffffff) {
|
|
94
|
-
const a = (num >>> 24) & 0xff;
|
|
95
|
-
const b = (num >>> 16) & 0xff;
|
|
96
|
-
const c = (num >>> 8) & 0xff;
|
|
97
|
-
const d = num & 0xff;
|
|
98
|
-
if (isPrivateIpv4(a, b, c, d))
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
export function isBlockedToolUrl(url) {
|
|
105
|
-
try {
|
|
106
|
-
const parsed = new URL(url);
|
|
107
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
const host = parsed.hostname.toLowerCase();
|
|
111
|
-
if (isPrivateHost(host))
|
|
112
|
-
return true;
|
|
113
|
-
if (DNS_REBIND_SUFFIXES.some((suffix) => {
|
|
114
|
-
const bare = suffix.slice(1);
|
|
115
|
-
return host === bare || host.endsWith(suffix);
|
|
116
|
-
})) {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
function isIpLiteralHost(hostname) {
|
|
126
|
-
const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
127
|
-
if (host.includes(":"))
|
|
128
|
-
return true;
|
|
129
|
-
const parts = host.split(".");
|
|
130
|
-
return parts.length === 4 && parts.every((p) => /^\d+$/.test(p));
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Async SSRF guard for environments that can resolve DNS. The synchronous
|
|
134
|
-
* guard catches literals and known rebinding domains; this closes the common
|
|
135
|
-
* "public hostname resolves to a private address" gap before dispatch.
|
|
136
|
-
*/
|
|
137
|
-
export async function isBlockedToolUrlWithDns(url) {
|
|
138
|
-
if (isBlockedToolUrl(url))
|
|
139
|
-
return true;
|
|
140
|
-
let hostname;
|
|
141
|
-
try {
|
|
142
|
-
hostname = new URL(url).hostname.toLowerCase();
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
if (!hostname || isIpLiteralHost(hostname))
|
|
148
|
-
return false;
|
|
149
|
-
try {
|
|
150
|
-
const { lookup } = await import("node:dns/promises");
|
|
151
|
-
const records = await lookup(hostname, { all: true, verbatim: true });
|
|
152
|
-
return records.some((record) => isPrivateHost(record.address));
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
// Some edge runtimes do not expose DNS lookup. Keep the deterministic
|
|
156
|
-
// parser-based protections instead of failing every outbound request.
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Build an undici Dispatcher whose connect-time DNS lookup runs through a
|
|
162
|
-
* private-IP guard. This closes the TOCTOU gap where:
|
|
163
|
-
* 1. We resolve hostname → public IP and pass.
|
|
164
|
-
* 2. Between that lookup and the actual connect, DNS rebinding flips the
|
|
165
|
-
* record to a private IP.
|
|
166
|
-
* 3. fetch() resolves again and connects to the private IP.
|
|
167
|
-
*
|
|
168
|
-
* With a custom dispatcher, the same lookup that produces the IP also gates
|
|
169
|
-
* the connect: if the IP is in the private set, the connect throws.
|
|
170
|
-
*
|
|
171
|
-
* Returns `null` if undici / node:dns are not available (e.g. some edge
|
|
172
|
-
* runtimes); the caller should fall back to the regular `fetch` path —
|
|
173
|
-
* `isBlockedToolUrlWithDns` will still have caught most rebinding cases.
|
|
174
|
-
*/
|
|
175
|
-
export async function createSsrfSafeDispatcher() {
|
|
176
|
-
// Dynamic import + `any`: undici is not a direct dependency, so the type
|
|
177
|
-
// declarations may not resolve. The runtime path is still safe — if the
|
|
178
|
-
// import throws we return null and the caller falls back to plain fetch.
|
|
179
|
-
let undici;
|
|
180
|
-
let dnsModule;
|
|
181
|
-
try {
|
|
182
|
-
undici = await import("undici");
|
|
183
|
-
dnsModule = await import("node:dns");
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
const { Agent } = undici;
|
|
189
|
-
const { lookup } = dnsModule;
|
|
190
|
-
if (!Agent || !lookup)
|
|
191
|
-
return null;
|
|
192
|
-
return new Agent({
|
|
193
|
-
connect: {
|
|
194
|
-
// Override DNS lookup at connect time so the IP we hand to undici's
|
|
195
|
-
// socket is the one we authorized. Reject any record in the private
|
|
196
|
-
// set BEFORE the TCP handshake.
|
|
197
|
-
lookup: (hostname, options, callback) => {
|
|
198
|
-
lookup(hostname, { all: true, verbatim: true }, (err, addresses) => {
|
|
199
|
-
if (err)
|
|
200
|
-
return callback(err);
|
|
201
|
-
const list = Array.isArray(addresses)
|
|
202
|
-
? addresses
|
|
203
|
-
: [{ address: addresses, family: 4 }];
|
|
204
|
-
for (const record of list) {
|
|
205
|
-
if (isPrivateHost(record.address)) {
|
|
206
|
-
const e = new Error(`Connect blocked: ${hostname} resolved to private address ${record.address}`);
|
|
207
|
-
e.code = "EAI_BLOCKED";
|
|
208
|
-
return callback(e);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
// Mirror Node's lookup behavior: when `all` is true, return the
|
|
212
|
-
// array; otherwise the first entry. undici's connect honors
|
|
213
|
-
// `options.all`.
|
|
214
|
-
if (options && options.all) {
|
|
215
|
-
return callback(null, list);
|
|
216
|
-
}
|
|
217
|
-
const first = list[0];
|
|
218
|
-
return callback(null, first.address, first.family);
|
|
219
|
-
});
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
//# sourceMappingURL=url-safety.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"url-safety.js","sourceRoot":"","sources":["../../src/tools/url-safety.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG;IACrB,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAEF,MAAM,mBAAmB,GAAG;IAC1B,SAAS;IACT,WAAW;IACX,SAAS;IACT,eAAe;IACf,SAAS;CACV,CAAC;AAEF,SAAS,aAAa,CAAC,CAAS,EAAE,CAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC;IACvD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACzE,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACpD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAY;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,MAAM;QAAE,OAAO,KAAK,CAAC;IACvE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;IACrB,OAAO,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC5D,IACE,IAAI,KAAK,WAAW;QACpB,IAAI,KAAK,KAAK;QACd,IAAI,KAAK,KAAK;QACd,IAAI,KAAK,IAAI,EACb,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/C,iCAAiC;IACjC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,0EAA0E;IAC1E,oEAAoE;IACpE,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnE,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IACD,IAAI,sBAAsB,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,wEAAwE;IACxE,6CAA6C;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IAED,wBAAwB;IACxB,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;YAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;YAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;YAC7B,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;YACrB,IAAI,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,aAAa,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,IACE,mBAAmB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YAClC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC7B,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,EACF,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB;IACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC5D,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,GAAW;IACvD,IAAI,gBAAgB,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,eAAe,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAEzD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;QACtE,sEAAsE;QACtE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,IAAI,MAAW,CAAC;IAChB,IAAI,SAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,MAAM,CAAC,QAAkB,CAAC,CAAC;QAC1C,SAAS,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEnC,OAAO,IAAI,KAAK,CAAC;QACf,OAAO,EAAE;YACP,oEAAoE;YACpE,oEAAoE;YACpE,gCAAgC;YAChC,MAAM,EAAE,CACN,QAAgB,EAChB,OAAY,EACZ,QAIS,EACT,EAAE;gBACF,MAAM,CACJ,QAAQ,EACR,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAC7B,CAAC,GAAiC,EAAE,SAAc,EAAE,EAAE;oBACpD,IAAI,GAAG;wBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;oBAC9B,MAAM,IAAI,GAA0C,KAAK,CAAC,OAAO,CAC/D,SAAS,CACV;wBACC,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;oBACxC,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;wBAC1B,IAAI,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;4BAClC,MAAM,CAAC,GAAG,IAAI,KAAK,CACjB,oBAAoB,QAAQ,gCAAgC,MAAM,CAAC,OAAO,EAAE,CACpD,CAAC;4BAC3B,CAAC,CAAC,IAAI,GAAG,aAAa,CAAC;4BACvB,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;wBACrB,CAAC;oBACH,CAAC;oBACD,gEAAgE;oBAChE,4DAA4D;oBAC5D,iBAAiB;oBACjB,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;wBAC3B,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAW,CAAC,CAAC;oBACrC,CAAC;oBACD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;oBACtB,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;gBACrD,CAAC,CACF,CAAC;YACJ,CAAC;SACF;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["const METADATA_HOSTS = [\n \"metadata.google.internal\",\n \"metadata.google.internal.\",\n];\n\nconst DNS_REBIND_SUFFIXES = [\n \".nip.io\",\n \".sslip.io\",\n \".xip.io\",\n \".localtest.me\",\n \".lvh.me\",\n];\n\nfunction isPrivateIpv4(a: number, b: number, c = 0, d = 0): boolean {\n if (![a, b, c, d].every((part) => part >= 0 && part <= 255)) return true;\n if (a === 127) return true;\n if (a === 10) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 169 && b === 254) return true;\n if (a === 0) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n if (a === 192 && b === 0) return true;\n if (a === 198 && (b === 18 || b === 19)) return true;\n if (a === 192 && b === 0 && c === 2) return true;\n if (a === 198 && b === 51 && c === 100) return true;\n if (a === 203 && b === 0 && c === 113) return true;\n if (a >= 224) return true;\n return false;\n}\n\nfunction isPrivateIpv4MappedHex(host: string): boolean {\n const mapped = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);\n if (!mapped) return false;\n const high = Number.parseInt(mapped[1], 16);\n const low = Number.parseInt(mapped[2], 16);\n if (high < 0 || high > 0xffff || low < 0 || low > 0xffff) return false;\n const a = (high >> 8) & 0xff;\n const b = high & 0xff;\n const c = (low >> 8) & 0xff;\n const d = low & 0xff;\n return isPrivateIpv4(a, b, c, d);\n}\n\nfunction isPrivateHost(hostname: string): boolean {\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (\n host === \"localhost\" ||\n host === \"::1\" ||\n host === \"::0\" ||\n host === \"::\"\n ) {\n return true;\n }\n if (METADATA_HOSTS.includes(host)) return true;\n\n // IPv6 ULA/link-local/multicast.\n if (/^f[cd]/.test(host) || /^fe[89ab]/.test(host)) return true;\n if (/^ff/i.test(host)) return true;\n\n // IPv4-mapped IPv6. URL parsing may preserve dotted form in some runtimes\n // or normalize it to hex, e.g. [::ffff:127.0.0.1] -> ::ffff:7f00:1.\n const v4mappedDotted = host.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/);\n if (v4mappedDotted) {\n const [a, b, c, d] = v4mappedDotted[1].split(\".\").map(Number);\n if (isPrivateIpv4(a, b, c, d)) return true;\n }\n if (isPrivateIpv4MappedHex(host)) return true;\n\n // Dotted IPv4. URL parsing normalizes shorthand/octal/hex IPv4 forms to\n // dotted decimal before we reach this point.\n const parts = host.split(\".\");\n if (parts.length === 4 && parts.every((p) => /^\\d+$/.test(p))) {\n const [a, b, c, d] = parts.map(Number);\n if (isPrivateIpv4(a, b, c, d)) return true;\n }\n\n // Decimal integer IPv4.\n if (/^\\d+$/.test(host)) {\n const num = Number(host);\n if (num >= 0 && num <= 0xffffffff) {\n const a = (num >>> 24) & 0xff;\n const b = (num >>> 16) & 0xff;\n const c = (num >>> 8) & 0xff;\n const d = num & 0xff;\n if (isPrivateIpv4(a, b, c, d)) return true;\n }\n }\n\n return false;\n}\n\nexport function isBlockedToolUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return true;\n }\n const host = parsed.hostname.toLowerCase();\n if (isPrivateHost(host)) return true;\n if (\n DNS_REBIND_SUFFIXES.some((suffix) => {\n const bare = suffix.slice(1);\n return host === bare || host.endsWith(suffix);\n })\n ) {\n return true;\n }\n } catch {\n return true;\n }\n return false;\n}\n\nfunction isIpLiteralHost(hostname: string): boolean {\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (host.includes(\":\")) return true;\n const parts = host.split(\".\");\n return parts.length === 4 && parts.every((p) => /^\\d+$/.test(p));\n}\n\n/**\n * Async SSRF guard for environments that can resolve DNS. The synchronous\n * guard catches literals and known rebinding domains; this closes the common\n * \"public hostname resolves to a private address\" gap before dispatch.\n */\nexport async function isBlockedToolUrlWithDns(url: string): Promise<boolean> {\n if (isBlockedToolUrl(url)) return true;\n\n let hostname: string;\n try {\n hostname = new URL(url).hostname.toLowerCase();\n } catch {\n return true;\n }\n if (!hostname || isIpLiteralHost(hostname)) return false;\n\n try {\n const { lookup } = await import(\"node:dns/promises\");\n const records = await lookup(hostname, { all: true, verbatim: true });\n return records.some((record) => isPrivateHost(record.address));\n } catch {\n // Some edge runtimes do not expose DNS lookup. Keep the deterministic\n // parser-based protections instead of failing every outbound request.\n return false;\n }\n}\n\n/**\n * Build an undici Dispatcher whose connect-time DNS lookup runs through a\n * private-IP guard. This closes the TOCTOU gap where:\n * 1. We resolve hostname → public IP and pass.\n * 2. Between that lookup and the actual connect, DNS rebinding flips the\n * record to a private IP.\n * 3. fetch() resolves again and connects to the private IP.\n *\n * With a custom dispatcher, the same lookup that produces the IP also gates\n * the connect: if the IP is in the private set, the connect throws.\n *\n * Returns `null` if undici / node:dns are not available (e.g. some edge\n * runtimes); the caller should fall back to the regular `fetch` path —\n * `isBlockedToolUrlWithDns` will still have caught most rebinding cases.\n */\nexport async function createSsrfSafeDispatcher(): Promise<unknown | null> {\n // Dynamic import + `any`: undici is not a direct dependency, so the type\n // declarations may not resolve. The runtime path is still safe — if the\n // import throws we return null and the caller falls back to plain fetch.\n let undici: any;\n let dnsModule: any;\n try {\n undici = await import(\"undici\" as string);\n dnsModule = await import(\"node:dns\");\n } catch {\n return null;\n }\n\n const { Agent } = undici;\n const { lookup } = dnsModule;\n if (!Agent || !lookup) return null;\n\n return new Agent({\n connect: {\n // Override DNS lookup at connect time so the IP we hand to undici's\n // socket is the one we authorized. Reject any record in the private\n // set BEFORE the TCP handshake.\n lookup: (\n hostname: string,\n options: any,\n callback: (\n err: NodeJS.ErrnoException | null,\n address?: string | { address: string; family: number }[],\n family?: number,\n ) => void,\n ) => {\n lookup(\n hostname,\n { all: true, verbatim: true },\n (err: NodeJS.ErrnoException | null, addresses: any) => {\n if (err) return callback(err);\n const list: { address: string; family: number }[] = Array.isArray(\n addresses,\n )\n ? addresses\n : [{ address: addresses, family: 4 }];\n for (const record of list) {\n if (isPrivateHost(record.address)) {\n const e = new Error(\n `Connect blocked: ${hostname} resolved to private address ${record.address}`,\n ) as NodeJS.ErrnoException;\n e.code = \"EAI_BLOCKED\";\n return callback(e);\n }\n }\n // Mirror Node's lookup behavior: when `all` is true, return the\n // array; otherwise the first entry. undici's connect honors\n // `options.all`.\n if (options && options.all) {\n return callback(null, list as any);\n }\n const first = list[0];\n return callback(null, first.address, first.family);\n },\n );\n },\n },\n });\n}\n"]}
|