auramaxx 1.0.0-alpha.4
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/LICENSE +26 -0
- package/README.md +112 -0
- package/bin/aurawallet.js +121 -0
- package/docs/ADAPTERS.md +467 -0
- package/docs/API.md +2679 -0
- package/docs/APPS.md +198 -0
- package/docs/ARCHITECTURE.md +350 -0
- package/docs/AUTH.md +698 -0
- package/docs/BEST-PRACTICES.md +121 -0
- package/docs/CLI.md +61 -0
- package/docs/DEVELOPING-APPS.md +452 -0
- package/docs/EXTENSION.md +97 -0
- package/docs/JOBS.md +33 -0
- package/docs/MCP.md +76 -0
- package/docs/PROTOCOL.md +142 -0
- package/docs/SETUP.md +219 -0
- package/docs/WORKSPACE.md +672 -0
- package/docs/agent-auth.md +63 -0
- package/docs/aura-file.md +48 -0
- package/docs/credentials.md +53 -0
- package/docs/external/getting-started.md +65 -0
- package/docs/external/overview.md +45 -0
- package/docs/external/use-cases.md +48 -0
- package/docs/external/why-aura.md +35 -0
- package/docs/jobs/connect-agent.md +77 -0
- package/docs/jobs/migrate-from-dotenv.md +79 -0
- package/docs/jobs/recover-from-lockout.md +72 -0
- package/docs/jobs/secure-ci.md +63 -0
- package/docs/oauth2.md +42 -0
- package/docs/passkeys.md +60 -0
- package/docs/security.md +540 -0
- package/docs/specs/aura-open-protocol.md +61 -0
- package/docs/specs/aura-provider-plugin.md +24 -0
- package/docs/specs/aura-registry-model.md +31 -0
- package/docs/specs/fixtures/invalid-bad-key.aura +1 -0
- package/docs/specs/fixtures/invalid-bad-unicode-escape.aura +1 -0
- package/docs/specs/fixtures/invalid-duplicate-key.aura +2 -0
- package/docs/specs/fixtures/valid-basic.aura +4 -0
- package/docs/specs/fixtures/valid-provider-ref.aura +1 -0
- package/docs/specs/fixtures/valid-quoted-escapes.aura +2 -0
- package/docs/templates/RELEASE_NOTES_TEMPLATE.md +22 -0
- package/docs/totp.md +40 -0
- package/docs/wallet/AI.md +508 -0
- package/docs/wallet/DEVELOPING-STRATEGIES.md +713 -0
- package/docs/wallet/README.md +47 -0
- package/docs/wallet/STRATEGY.md +89 -0
- package/next.config.ts +21 -0
- package/package.json +151 -0
- package/postcss.config.mjs +8 -0
- package/prisma/migrations/20260214170000_baseline/migration.sql +511 -0
- package/prisma/migrations/20260216214537_add_passkey_model/migration.sql +18 -0
- package/prisma/migrations/20260217150500_add_credential_access_audit/migration.sql +31 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +447 -0
- package/public/logo-chevron.svg +31 -0
- package/public/logo-concentric.svg +31 -0
- package/public/logo-crosshatch.svg +39 -0
- package/public/logo-dashed.svg +39 -0
- package/public/logo-horizontal.svg +31 -0
- package/public/logo-m56.svg +64 -0
- package/public/logo.webp +0 -0
- package/scripts/add-app.js +245 -0
- package/scripts/init.sh +57 -0
- package/scripts/migrate-apikeys-to-credentials.ts +35 -0
- package/scripts/sandbox-agent-flow.sh +235 -0
- package/scripts/sandbox.sh +175 -0
- package/scripts/validate-job-docs.mjs +125 -0
- package/server/abi/SwapHelper.json +438 -0
- package/server/cli/approval.ts +447 -0
- package/server/cli/commands/app.ts +204 -0
- package/server/cli/commands/cron.ts +24 -0
- package/server/cli/commands/doctor.ts +1007 -0
- package/server/cli/commands/env.ts +456 -0
- package/server/cli/commands/init.ts +752 -0
- package/server/cli/commands/mcp.ts +125 -0
- package/server/cli/commands/restore.ts +314 -0
- package/server/cli/commands/shell-hook.ts +468 -0
- package/server/cli/commands/start.ts +62 -0
- package/server/cli/commands/status.ts +59 -0
- package/server/cli/commands/stop.ts +14 -0
- package/server/cli/commands/token.ts +180 -0
- package/server/cli/commands/unlock.ts +49 -0
- package/server/cli/commands/vault.ts +417 -0
- package/server/cli/index.ts +328 -0
- package/server/cli/lib/aura-parser.ts +64 -0
- package/server/cli/lib/credential-create.ts +74 -0
- package/server/cli/lib/credential-resolve.ts +254 -0
- package/server/cli/lib/dotenv-migrate.ts +116 -0
- package/server/cli/lib/dotenv-parser.ts +146 -0
- package/server/cli/lib/http.ts +91 -0
- package/server/cli/lib/init-steps.ts +76 -0
- package/server/cli/lib/local-agent-trust.ts +45 -0
- package/server/cli/lib/process.ts +136 -0
- package/server/cli/lib/prompt.ts +85 -0
- package/server/cli/lib/theme.ts +240 -0
- package/server/cli/socket.ts +570 -0
- package/server/cli/transport-client.ts +50 -0
- package/server/cron/index.ts +137 -0
- package/server/cron/job.ts +31 -0
- package/server/cron/jobs/balance-sync.ts +436 -0
- package/server/cron/jobs/incoming-scan.ts +506 -0
- package/server/cron/jobs/native-price.ts +70 -0
- package/server/cron/jobs/orphan-cleanup.ts +40 -0
- package/server/cron/jobs/strategy-runner.ts +175 -0
- package/server/cron/scheduler.ts +125 -0
- package/server/index.ts +406 -0
- package/server/lib/adapters/factory.ts +110 -0
- package/server/lib/adapters/index.ts +19 -0
- package/server/lib/adapters/router.ts +297 -0
- package/server/lib/adapters/telegram.ts +645 -0
- package/server/lib/adapters/types.ts +89 -0
- package/server/lib/adapters/webhook.ts +95 -0
- package/server/lib/address.ts +49 -0
- package/server/lib/agent-auth/contracts.ts +1194 -0
- package/server/lib/agent-profiles.ts +328 -0
- package/server/lib/ai.ts +285 -0
- package/server/lib/api-registry/contracts.ts +86 -0
- package/server/lib/api-registry/validation.ts +172 -0
- package/server/lib/apikey-migration.ts +189 -0
- package/server/lib/app-installer.ts +505 -0
- package/server/lib/app-tokens.ts +247 -0
- package/server/lib/auth.ts +314 -0
- package/server/lib/batch.ts +242 -0
- package/server/lib/cold.ts +874 -0
- package/server/lib/config.ts +381 -0
- package/server/lib/credential-access-audit.ts +85 -0
- package/server/lib/credential-access-policy.ts +110 -0
- package/server/lib/credential-health.ts +343 -0
- package/server/lib/credential-import.ts +487 -0
- package/server/lib/credential-scope.ts +87 -0
- package/server/lib/credential-shares.ts +190 -0
- package/server/lib/credential-transport.ts +342 -0
- package/server/lib/credential-vault.ts +77 -0
- package/server/lib/credentials.ts +333 -0
- package/server/lib/crypto.ts +8 -0
- package/server/lib/db.ts +15 -0
- package/server/lib/defaults.ts +366 -0
- package/server/lib/dex/index.ts +80 -0
- package/server/lib/dex/relay.ts +235 -0
- package/server/lib/dex/types.ts +59 -0
- package/server/lib/dex/uniswap.ts +370 -0
- package/server/lib/e2e-agent/artifacts.ts +36 -0
- package/server/lib/e2e-agent/contracts.ts +112 -0
- package/server/lib/e2e-agent/validation.ts +135 -0
- package/server/lib/encrypt.ts +128 -0
- package/server/lib/error.ts +20 -0
- package/server/lib/events.ts +205 -0
- package/server/lib/hot.ts +357 -0
- package/server/lib/key-fingerprint.ts +28 -0
- package/server/lib/logger.ts +331 -0
- package/server/lib/network.ts +137 -0
- package/server/lib/notifications.ts +219 -0
- package/server/lib/oauth2-refresh.ts +241 -0
- package/server/lib/oursecret.ts +54 -0
- package/server/lib/passkey-credential.ts +360 -0
- package/server/lib/passkey.ts +68 -0
- package/server/lib/permissions.ts +248 -0
- package/server/lib/pino.ts +24 -0
- package/server/lib/policy-preview.ts +138 -0
- package/server/lib/price.ts +338 -0
- package/server/lib/prices.ts +34 -0
- package/server/lib/project-scope.ts +239 -0
- package/server/lib/resolve-action.ts +427 -0
- package/server/lib/resolve.ts +36 -0
- package/server/lib/sessions.ts +632 -0
- package/server/lib/solana/connection.ts +26 -0
- package/server/lib/solana/jupiter.ts +128 -0
- package/server/lib/solana/transfer.ts +108 -0
- package/server/lib/solana/wallet.ts +136 -0
- package/server/lib/strategy/emits.ts +21 -0
- package/server/lib/strategy/engine.ts +1305 -0
- package/server/lib/strategy/executor.ts +115 -0
- package/server/lib/strategy/hook-context.ts +158 -0
- package/server/lib/strategy/hooks.ts +990 -0
- package/server/lib/strategy/index.ts +28 -0
- package/server/lib/strategy/installer.ts +305 -0
- package/server/lib/strategy/loader.ts +256 -0
- package/server/lib/strategy/message.ts +235 -0
- package/server/lib/strategy/repository.ts +218 -0
- package/server/lib/strategy/session-logger.ts +693 -0
- package/server/lib/strategy/sources.ts +288 -0
- package/server/lib/strategy/state.ts +189 -0
- package/server/lib/strategy/templates.ts +403 -0
- package/server/lib/strategy/tick.ts +404 -0
- package/server/lib/strategy/types.ts +230 -0
- package/server/lib/swap.ts +3 -0
- package/server/lib/temp.ts +86 -0
- package/server/lib/token-metadata.ts +86 -0
- package/server/lib/token-safety.ts +200 -0
- package/server/lib/token-search.ts +444 -0
- package/server/lib/totp.ts +194 -0
- package/server/lib/transactions.ts +123 -0
- package/server/lib/transport.ts +75 -0
- package/server/lib/txhistory/decoder.ts +262 -0
- package/server/lib/txhistory/enricher.ts +652 -0
- package/server/lib/txhistory/index.ts +391 -0
- package/server/lib/txhistory/signatures.ts +59 -0
- package/server/lib/verified-summary.ts +421 -0
- package/server/mcp/profile-policy.ts +30 -0
- package/server/mcp/server.ts +619 -0
- package/server/mcp/tools.ts +523 -0
- package/server/middleware/auth.ts +119 -0
- package/server/middleware/requestLogger.ts +84 -0
- package/server/routes/actions.ts +459 -0
- package/server/routes/adapters.ts +703 -0
- package/server/routes/addressbook.ts +113 -0
- package/server/routes/ai.ts +34 -0
- package/server/routes/apikeys.ts +295 -0
- package/server/routes/apps.ts +601 -0
- package/server/routes/auth.ts +457 -0
- package/server/routes/backup.ts +340 -0
- package/server/routes/batch.ts +270 -0
- package/server/routes/bookmarks.ts +162 -0
- package/server/routes/credential-shares.ts +198 -0
- package/server/routes/credential-vaults.ts +154 -0
- package/server/routes/credentials.ts +1290 -0
- package/server/routes/dashboard.ts +71 -0
- package/server/routes/defaults.ts +124 -0
- package/server/routes/fund.ts +229 -0
- package/server/routes/import.ts +352 -0
- package/server/routes/launch.ts +665 -0
- package/server/routes/lock.ts +54 -0
- package/server/routes/logs.ts +68 -0
- package/server/routes/nuke.ts +111 -0
- package/server/routes/passkey-credentials.ts +99 -0
- package/server/routes/passkey.ts +346 -0
- package/server/routes/portfolio.ts +217 -0
- package/server/routes/price.ts +63 -0
- package/server/routes/resolve.ts +31 -0
- package/server/routes/security.ts +45 -0
- package/server/routes/send-evm.ts +241 -0
- package/server/routes/send-solana.ts +281 -0
- package/server/routes/send.ts +178 -0
- package/server/routes/setup.ts +210 -0
- package/server/routes/strategy.ts +894 -0
- package/server/routes/swap-evm.ts +353 -0
- package/server/routes/swap-solana.ts +177 -0
- package/server/routes/swap.ts +356 -0
- package/server/routes/token.ts +247 -0
- package/server/routes/unlock.ts +403 -0
- package/server/routes/wallet-assets.ts +361 -0
- package/server/routes/wallet-transactions.ts +515 -0
- package/server/routes/wallet.ts +710 -0
- package/server/types.ts +146 -0
- package/skills/aurawallet/SKILL.md +739 -0
- package/skills/aurawallet-setup/SKILL.md +74 -0
- package/skills/security-review/SKILL.md +148 -0
- package/src/app/api/agent-requests/route.ts +30 -0
- package/src/app/api/apps/install/route.ts +126 -0
- package/src/app/api/apps/manifests/route.ts +16 -0
- package/src/app/api/apps/static/[...path]/route.ts +57 -0
- package/src/app/api/events/route.ts +92 -0
- package/src/app/api/page.tsx +212 -0
- package/src/app/api/workspace/[id]/apps/[wid]/route.ts +119 -0
- package/src/app/api/workspace/[id]/apps/route.ts +81 -0
- package/src/app/api/workspace/[id]/export/route.ts +67 -0
- package/src/app/api/workspace/[id]/route.ts +168 -0
- package/src/app/api/workspace/auth.ts +34 -0
- package/src/app/api/workspace/config/route.ts +106 -0
- package/src/app/api/workspace/import/route.ts +127 -0
- package/src/app/api/workspace/route.ts +116 -0
- package/src/app/app/page.tsx +2122 -0
- package/src/app/apple-icon.png +0 -0
- package/src/app/docs/page.tsx +178 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +572 -0
- package/src/app/health/page.tsx +5 -0
- package/src/app/hello/page.tsx +15 -0
- package/src/app/icon.png +0 -0
- package/src/app/layout.tsx +34 -0
- package/src/app/page.tsx +986 -0
- package/src/app/providers.tsx +90 -0
- package/src/app/share/[token]/page.tsx +295 -0
- package/src/components/ChainSelector.tsx +144 -0
- package/src/components/HumanActionBar.tsx +695 -0
- package/src/components/NotificationDrawer.tsx +129 -0
- package/src/components/apps/AgentKeysApp.tsx +490 -0
- package/src/components/apps/App.tsx +153 -0
- package/src/components/apps/AppGrid.tsx +15 -0
- package/src/components/apps/DetailedAddressDrawer.tsx +325 -0
- package/src/components/apps/DraggableApp.tsx +562 -0
- package/src/components/apps/IFrameApp.tsx +73 -0
- package/src/components/apps/LogsApp.tsx +360 -0
- package/src/components/apps/SendApp.tsx +394 -0
- package/src/components/apps/SetupWizardApp.tsx +1004 -0
- package/src/components/apps/SystemDefaultsApp.tsx +845 -0
- package/src/components/apps/ThirdPartyApp.tsx +428 -0
- package/src/components/apps/TokenApp.tsx +319 -0
- package/src/components/apps/TransactionsApp.tsx +438 -0
- package/src/components/apps/WalletDetailApp.tsx +1505 -0
- package/src/components/apps/index.ts +13 -0
- package/src/components/design-system/Button.tsx +53 -0
- package/src/components/design-system/ChainIndicator.tsx +65 -0
- package/src/components/design-system/ChainSelector.tsx +137 -0
- package/src/components/design-system/ConfirmationModal.tsx +106 -0
- package/src/components/design-system/ConfirmationPopover.tsx +81 -0
- package/src/components/design-system/Drawer.tsx +123 -0
- package/src/components/design-system/FilterDropdown.tsx +72 -0
- package/src/components/design-system/Modal.tsx +206 -0
- package/src/components/design-system/Popover.tsx +142 -0
- package/src/components/design-system/TextInput.tsx +85 -0
- package/src/components/design-system/Toggle.tsx +58 -0
- package/src/components/design-system/index.ts +11 -0
- package/src/components/docs/DocsThemeToggle.tsx +49 -0
- package/src/components/health/CredentialHealthDashboard.tsx +214 -0
- package/src/components/icons/ChainIcons.tsx +72 -0
- package/src/components/layout/AppStoreDrawer.tsx +369 -0
- package/src/components/layout/ContentArea.tsx +21 -0
- package/src/components/layout/TabBar.tsx +278 -0
- package/src/components/layout/WalletSidebar.tsx +1033 -0
- package/src/components/layout/index.ts +4 -0
- package/src/components/marketing/AuraWalletSpecOverlay.tsx +635 -0
- package/src/components/marketing/DeviceMorphExperience.tsx +216 -0
- package/src/components/vault/ApiKeysConsole.tsx +1080 -0
- package/src/components/vault/AuditConsole.tsx +584 -0
- package/src/components/vault/CredentialDetail.tsx +455 -0
- package/src/components/vault/CredentialEmpty.tsx +55 -0
- package/src/components/vault/CredentialField.tsx +361 -0
- package/src/components/vault/CredentialForm.tsx +1212 -0
- package/src/components/vault/CredentialList.tsx +165 -0
- package/src/components/vault/CredentialRow.tsx +97 -0
- package/src/components/vault/CredentialShareModal.tsx +178 -0
- package/src/components/vault/CredentialVault.tsx +754 -0
- package/src/components/vault/CredentialWalletWidget.tsx +103 -0
- package/src/components/vault/ImportCredentialsModal.tsx +515 -0
- package/src/components/vault/LargeTypeModal.tsx +64 -0
- package/src/components/vault/PasswordGenerator.tsx +224 -0
- package/src/components/vault/TOTPDisplay.tsx +123 -0
- package/src/components/vault/VaultSidebar.tsx +413 -0
- package/src/components/vault/types.ts +54 -0
- package/src/context/AuthContext.tsx +337 -0
- package/src/context/PriceContext.tsx +113 -0
- package/src/context/ThemeContext.tsx +164 -0
- package/src/context/WebSocketContext.tsx +269 -0
- package/src/context/WorkspaceContext.tsx +668 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useAgentActions.ts +368 -0
- package/src/hooks/useBalance.ts +103 -0
- package/src/hooks/useBalances.ts +129 -0
- package/src/instrumentation.ts +12 -0
- package/src/lib/api.ts +449 -0
- package/src/lib/app-loader.ts +148 -0
- package/src/lib/app-registry.ts +178 -0
- package/src/lib/app-sdk.ts +157 -0
- package/src/lib/audit-console-adapter.ts +151 -0
- package/src/lib/auth-client.ts +75 -0
- package/src/lib/config.ts +74 -0
- package/src/lib/crypto.ts +112 -0
- package/src/lib/db.ts +21 -0
- package/src/lib/docs.ts +390 -0
- package/src/lib/events.ts +361 -0
- package/src/lib/pino.ts +24 -0
- package/src/lib/theme-handlers.ts +168 -0
- package/src/lib/theme.ts +351 -0
- package/src/lib/tokenData.ts +378 -0
- package/src/lib/vault-crypto.ts +129 -0
- package/src/lib/websocket-server.ts +302 -0
- package/src/lib/websocket-setup.ts +79 -0
- package/src/lib/wordlist.ts +2050 -0
- package/src/lib/workspace-handlers.ts +285 -0
- package/start.sh +80 -0
- package/tailwind.config.ts +99 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createHash, createPublicKey } from 'crypto';
|
|
2
|
+
|
|
3
|
+
function normalizeFingerprint(hex: string): string {
|
|
4
|
+
return hex.toLowerCase().replace(/[^a-f0-9]/g, '').match(/.{1,2}/g)?.join(':') || '';
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function computeSshFingerprint(publicKeyOrPrivateKey: string): string | null {
|
|
8
|
+
const material = publicKeyOrPrivateKey?.trim();
|
|
9
|
+
if (!material) return null;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const keyObject = createPublicKey(material);
|
|
13
|
+
const der = keyObject.export({ format: 'der', type: 'spki' }) as Buffer;
|
|
14
|
+
const digest = createHash('sha256').update(der).digest('hex');
|
|
15
|
+
return normalizeFingerprint(digest);
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function computeGpgFingerprint(material: string): string | null {
|
|
22
|
+
const normalized = material?.trim();
|
|
23
|
+
if (!normalized) return null;
|
|
24
|
+
|
|
25
|
+
// Deterministic pseudo-fingerprint for armored key material (v1 scope).
|
|
26
|
+
const digest = createHash('sha1').update(normalized).digest('hex');
|
|
27
|
+
return normalizeFingerprint(digest);
|
|
28
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event logger helper for consistent event emission across Express routes
|
|
3
|
+
* Convenience wrapper around events.custom() for structured logging
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { events } from './events';
|
|
7
|
+
|
|
8
|
+
export type EventCategory = 'auth' | 'wallet' | 'transaction' | 'token' | 'request' | 'system' | 'agent';
|
|
9
|
+
|
|
10
|
+
export interface LogParams {
|
|
11
|
+
category: EventCategory;
|
|
12
|
+
action: string;
|
|
13
|
+
description: string;
|
|
14
|
+
agentId?: string;
|
|
15
|
+
walletAddress?: string;
|
|
16
|
+
txHash?: string;
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Log an event with structured data
|
|
22
|
+
* Emits to WebSocket and stores in database
|
|
23
|
+
*/
|
|
24
|
+
export function logEvent(params: LogParams): void {
|
|
25
|
+
const eventType = `${params.category}:${params.action}`;
|
|
26
|
+
events.custom(eventType, {
|
|
27
|
+
description: params.description,
|
|
28
|
+
agentId: params.agentId,
|
|
29
|
+
walletAddress: params.walletAddress,
|
|
30
|
+
txHash: params.txHash,
|
|
31
|
+
timestamp: Date.now(),
|
|
32
|
+
...params.metadata,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Convenience methods for common events
|
|
38
|
+
*/
|
|
39
|
+
export const logger = {
|
|
40
|
+
// ── Auth Events ──────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
/** Wallet unlocked event */
|
|
43
|
+
unlocked: (address: string) =>
|
|
44
|
+
logEvent({
|
|
45
|
+
category: 'auth',
|
|
46
|
+
action: 'unlocked',
|
|
47
|
+
description: `Wallet unlocked: ${address.slice(0, 10)}...`,
|
|
48
|
+
walletAddress: address,
|
|
49
|
+
}),
|
|
50
|
+
|
|
51
|
+
/** Wallet locked event */
|
|
52
|
+
locked: () =>
|
|
53
|
+
logEvent({
|
|
54
|
+
category: 'auth',
|
|
55
|
+
action: 'locked',
|
|
56
|
+
description: 'Wallet locked',
|
|
57
|
+
}),
|
|
58
|
+
|
|
59
|
+
/** Auth failure (invalid/expired/revoked token, missing header) */
|
|
60
|
+
authFailed: (reason: string, path: string, metadata?: Record<string, unknown>) =>
|
|
61
|
+
logEvent({
|
|
62
|
+
category: 'auth',
|
|
63
|
+
action: 'auth_failed',
|
|
64
|
+
description: `Auth failed: ${reason}`,
|
|
65
|
+
metadata: { path, reason, ...metadata },
|
|
66
|
+
}),
|
|
67
|
+
|
|
68
|
+
/** Permission denied */
|
|
69
|
+
permissionDenied: (permission: string, agentId: string, path: string) =>
|
|
70
|
+
logEvent({
|
|
71
|
+
category: 'auth',
|
|
72
|
+
action: 'permission_denied',
|
|
73
|
+
description: `Permission denied: ${permission}`,
|
|
74
|
+
agentId,
|
|
75
|
+
metadata: { permission, path },
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
/** Token validated successfully */
|
|
79
|
+
tokenValidated: (agentId: string, tokenHash: string) =>
|
|
80
|
+
logEvent({
|
|
81
|
+
category: 'auth',
|
|
82
|
+
action: 'token_validated',
|
|
83
|
+
description: `Token validated for ${agentId}`,
|
|
84
|
+
agentId,
|
|
85
|
+
metadata: { tokenHash },
|
|
86
|
+
}),
|
|
87
|
+
|
|
88
|
+
// ── Token Events ─────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
/** Agent token created */
|
|
91
|
+
tokenCreated: (agentId: string, tokenHash: string, limit: number, permissions: string[]) =>
|
|
92
|
+
logEvent({
|
|
93
|
+
category: 'token',
|
|
94
|
+
action: 'created',
|
|
95
|
+
description: `Token created for ${agentId} (limit: ${limit} ETH)`,
|
|
96
|
+
agentId,
|
|
97
|
+
metadata: { tokenHash, limit, permissions },
|
|
98
|
+
}),
|
|
99
|
+
|
|
100
|
+
/** Agent token revoked */
|
|
101
|
+
tokenRevoked: (tokenHash: string, revokedBy?: string) =>
|
|
102
|
+
logEvent({
|
|
103
|
+
category: 'token',
|
|
104
|
+
action: 'revoked',
|
|
105
|
+
description: `Token revoked: ${tokenHash.slice(0, 12)}...`,
|
|
106
|
+
metadata: { tokenHash, revokedBy },
|
|
107
|
+
}),
|
|
108
|
+
|
|
109
|
+
/** Spending limit exceeded */
|
|
110
|
+
limitExceeded: (agentId: string, limitType: string, requested: number, remaining: number) =>
|
|
111
|
+
logEvent({
|
|
112
|
+
category: 'token',
|
|
113
|
+
action: 'limit_exceeded',
|
|
114
|
+
description: `${limitType} limit exceeded: requested ${requested}, remaining ${remaining}`,
|
|
115
|
+
agentId,
|
|
116
|
+
metadata: { limitType, requested, remaining },
|
|
117
|
+
}),
|
|
118
|
+
|
|
119
|
+
// ── Wallet Events ────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
/** Cold wallet setup event */
|
|
122
|
+
setup: (address: string) =>
|
|
123
|
+
logEvent({
|
|
124
|
+
category: 'wallet',
|
|
125
|
+
action: 'setup',
|
|
126
|
+
description: `Cold wallet created: ${address.slice(0, 10)}...`,
|
|
127
|
+
walletAddress: address,
|
|
128
|
+
}),
|
|
129
|
+
|
|
130
|
+
/** Hot/temp wallet created event */
|
|
131
|
+
walletCreated: (address: string, tier: string, agentId?: string) =>
|
|
132
|
+
logEvent({
|
|
133
|
+
category: 'wallet',
|
|
134
|
+
action: 'created',
|
|
135
|
+
description: `${tier} wallet created`,
|
|
136
|
+
walletAddress: address,
|
|
137
|
+
agentId,
|
|
138
|
+
metadata: { tier },
|
|
139
|
+
}),
|
|
140
|
+
|
|
141
|
+
/** Wallet renamed/updated */
|
|
142
|
+
walletRenamed: (address: string, agentId?: string) =>
|
|
143
|
+
logEvent({
|
|
144
|
+
category: 'wallet',
|
|
145
|
+
action: 'renamed',
|
|
146
|
+
description: `Wallet updated: ${address.slice(0, 10)}...`,
|
|
147
|
+
walletAddress: address,
|
|
148
|
+
agentId,
|
|
149
|
+
}),
|
|
150
|
+
|
|
151
|
+
/** Wallet private key exported */
|
|
152
|
+
walletExported: (address: string, agentId?: string) =>
|
|
153
|
+
logEvent({
|
|
154
|
+
category: 'wallet',
|
|
155
|
+
action: 'exported',
|
|
156
|
+
description: `Private key exported: ${address.slice(0, 10)}...`,
|
|
157
|
+
walletAddress: address,
|
|
158
|
+
agentId,
|
|
159
|
+
}),
|
|
160
|
+
|
|
161
|
+
/** Seed phrase exported */
|
|
162
|
+
seedExported: (vaultId?: string) =>
|
|
163
|
+
logEvent({
|
|
164
|
+
category: 'wallet',
|
|
165
|
+
action: 'seed_exported',
|
|
166
|
+
description: `Seed phrase exported${vaultId ? ` (vault: ${vaultId})` : ''}`,
|
|
167
|
+
metadata: { vaultId },
|
|
168
|
+
}),
|
|
169
|
+
|
|
170
|
+
// ── Transaction Events ───────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
/** ETH send event */
|
|
173
|
+
send: (from: string, to: string, amount: string, txHash: string, agentId?: string) =>
|
|
174
|
+
logEvent({
|
|
175
|
+
category: 'transaction',
|
|
176
|
+
action: 'send',
|
|
177
|
+
description: `Sent ${amount} ETH`,
|
|
178
|
+
walletAddress: from,
|
|
179
|
+
txHash,
|
|
180
|
+
agentId,
|
|
181
|
+
metadata: { to, amount },
|
|
182
|
+
}),
|
|
183
|
+
|
|
184
|
+
/** Cold to hot fund transfer event */
|
|
185
|
+
fund: (to: string, amount: string, txHash: string, agentId?: string) =>
|
|
186
|
+
logEvent({
|
|
187
|
+
category: 'transaction',
|
|
188
|
+
action: 'fund',
|
|
189
|
+
description: `Funded ${amount} ETH`,
|
|
190
|
+
walletAddress: to,
|
|
191
|
+
txHash,
|
|
192
|
+
agentId,
|
|
193
|
+
metadata: { amount },
|
|
194
|
+
}),
|
|
195
|
+
|
|
196
|
+
/** Token swap event */
|
|
197
|
+
swap: (wallet: string, fromToken: string, toToken: string, amount: string, txHash: string, agentId?: string) =>
|
|
198
|
+
logEvent({
|
|
199
|
+
category: 'transaction',
|
|
200
|
+
action: 'swap',
|
|
201
|
+
description: `Swapped ${amount} ${fromToken} to ${toToken}`,
|
|
202
|
+
walletAddress: wallet,
|
|
203
|
+
txHash,
|
|
204
|
+
agentId,
|
|
205
|
+
metadata: { fromToken, toToken, amount },
|
|
206
|
+
}),
|
|
207
|
+
|
|
208
|
+
// ── Agent Events ─────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
/** Agent requested access */
|
|
211
|
+
agentRequested: (agentId: string, requestId: string, limit: number) =>
|
|
212
|
+
logEvent({
|
|
213
|
+
category: 'agent',
|
|
214
|
+
action: 'access_requested',
|
|
215
|
+
description: `${agentId} requested access (limit: ${limit} ETH)`,
|
|
216
|
+
agentId,
|
|
217
|
+
metadata: { requestId, limit },
|
|
218
|
+
}),
|
|
219
|
+
|
|
220
|
+
/** Agent polled for token */
|
|
221
|
+
agentPolled: (requestId: string) =>
|
|
222
|
+
logEvent({
|
|
223
|
+
category: 'agent',
|
|
224
|
+
action: 'polled',
|
|
225
|
+
description: `Token poll for request ${requestId}`,
|
|
226
|
+
metadata: { requestId },
|
|
227
|
+
}),
|
|
228
|
+
|
|
229
|
+
/** Permission update requested */
|
|
230
|
+
permissionRequested: (agentId: string, requestId: string, permissions: string[]) =>
|
|
231
|
+
logEvent({
|
|
232
|
+
category: 'agent',
|
|
233
|
+
action: 'permission_requested',
|
|
234
|
+
description: `${agentId} requested permission update`,
|
|
235
|
+
agentId,
|
|
236
|
+
metadata: { requestId, permissions },
|
|
237
|
+
}),
|
|
238
|
+
|
|
239
|
+
/** Action created by agent */
|
|
240
|
+
actionCreated: (agentId: string, requestId: string, type: string, summary: string) =>
|
|
241
|
+
logEvent({
|
|
242
|
+
category: 'agent',
|
|
243
|
+
action: 'action_created',
|
|
244
|
+
description: `${agentId} created ${type}: ${summary}`,
|
|
245
|
+
agentId,
|
|
246
|
+
metadata: { requestId, type, summary },
|
|
247
|
+
}),
|
|
248
|
+
|
|
249
|
+
/** Action resolved (approved/rejected) */
|
|
250
|
+
actionResolved: (requestId: string, type: string, approved: boolean, resolvedBy: string) =>
|
|
251
|
+
logEvent({
|
|
252
|
+
category: 'agent',
|
|
253
|
+
action: 'action_resolved',
|
|
254
|
+
description: `${type} ${approved ? 'approved' : 'rejected'} by ${resolvedBy}`,
|
|
255
|
+
metadata: { requestId, type, approved, resolvedBy },
|
|
256
|
+
}),
|
|
257
|
+
|
|
258
|
+
// ── System Events ────────────────────────────────────────────
|
|
259
|
+
|
|
260
|
+
/** System nuke (full reset) */
|
|
261
|
+
nuke: () =>
|
|
262
|
+
logEvent({
|
|
263
|
+
category: 'system',
|
|
264
|
+
action: 'nuke',
|
|
265
|
+
description: 'System nuke: all data wiped',
|
|
266
|
+
}),
|
|
267
|
+
|
|
268
|
+
/** Database backup */
|
|
269
|
+
backup: (filename: string) =>
|
|
270
|
+
logEvent({
|
|
271
|
+
category: 'system',
|
|
272
|
+
action: 'backup',
|
|
273
|
+
description: `Database backup created: ${filename}`,
|
|
274
|
+
metadata: { filename },
|
|
275
|
+
}),
|
|
276
|
+
|
|
277
|
+
/** API key created */
|
|
278
|
+
apiKeyCreated: (service: string, name: string) =>
|
|
279
|
+
logEvent({
|
|
280
|
+
category: 'system',
|
|
281
|
+
action: 'apikey_created',
|
|
282
|
+
description: `API key created: ${service}/${name}`,
|
|
283
|
+
metadata: { service, name },
|
|
284
|
+
}),
|
|
285
|
+
|
|
286
|
+
/** API key deleted */
|
|
287
|
+
apiKeyDeleted: (service: string, name: string) =>
|
|
288
|
+
logEvent({
|
|
289
|
+
category: 'system',
|
|
290
|
+
action: 'apikey_deleted',
|
|
291
|
+
description: `API key deleted: ${service}/${name}`,
|
|
292
|
+
metadata: { service, name },
|
|
293
|
+
}),
|
|
294
|
+
|
|
295
|
+
/** Strategy toggled */
|
|
296
|
+
strategyToggled: (strategyId: string, enabled: boolean) =>
|
|
297
|
+
logEvent({
|
|
298
|
+
category: 'system',
|
|
299
|
+
action: 'strategy_toggled',
|
|
300
|
+
description: `Strategy ${strategyId} ${enabled ? 'enabled' : 'disabled'}`,
|
|
301
|
+
metadata: { strategyId, enabled },
|
|
302
|
+
}),
|
|
303
|
+
|
|
304
|
+
/** Adapter configuration changed */
|
|
305
|
+
adapterChanged: (action: string, type: string) =>
|
|
306
|
+
logEvent({
|
|
307
|
+
category: 'system',
|
|
308
|
+
action: 'adapter_changed',
|
|
309
|
+
description: `Adapter ${type}: ${action}`,
|
|
310
|
+
metadata: { action, type },
|
|
311
|
+
}),
|
|
312
|
+
|
|
313
|
+
/** App operation */
|
|
314
|
+
appOperation: (operation: string, appId: string, agentId?: string) =>
|
|
315
|
+
logEvent({
|
|
316
|
+
category: 'system',
|
|
317
|
+
action: 'app_operation',
|
|
318
|
+
description: `App ${operation}: ${appId}`,
|
|
319
|
+
agentId,
|
|
320
|
+
metadata: { operation, appId },
|
|
321
|
+
}),
|
|
322
|
+
|
|
323
|
+
/** Server error */
|
|
324
|
+
error: (message: string, path?: string, metadata?: Record<string, unknown>) =>
|
|
325
|
+
logEvent({
|
|
326
|
+
category: 'system',
|
|
327
|
+
action: 'error',
|
|
328
|
+
description: `Error: ${message}`,
|
|
329
|
+
metadata: { path, ...metadata },
|
|
330
|
+
}),
|
|
331
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network / SSRF Utilities
|
|
3
|
+
* ========================
|
|
4
|
+
* Shared utilities for validating external URLs and preventing SSRF attacks.
|
|
5
|
+
* Used by the strategy executor, source fetcher, app fetch proxy,
|
|
6
|
+
* webhook adapter, and app installer.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { isIPv4, isIPv6 } from 'net';
|
|
10
|
+
import dns from 'dns';
|
|
11
|
+
import { getErrorMessage } from './error';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check whether a resolved IP address is in a private/reserved range.
|
|
15
|
+
* Handles both IPv4 and IPv6 (including IPv4-mapped IPv6 addresses).
|
|
16
|
+
*/
|
|
17
|
+
export function isPrivateIp(ip: string): boolean {
|
|
18
|
+
if (isIPv4(ip)) {
|
|
19
|
+
const parts = ip.split('.').map(Number);
|
|
20
|
+
const [a, b] = parts;
|
|
21
|
+
if (a === 127) return true; // 127.0.0.0/8 loopback
|
|
22
|
+
if (a === 10) return true; // 10.0.0.0/8 private
|
|
23
|
+
if (a === 172 && b >= 16 && b <= 31) return true; // 172.16.0.0/12 private
|
|
24
|
+
if (a === 192 && b === 168) return true; // 192.168.0.0/16 private
|
|
25
|
+
if (a === 169 && b === 254) return true; // 169.254.0.0/16 link-local
|
|
26
|
+
if (a === 0) return true; // 0.0.0.0/8
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (isIPv6(ip)) {
|
|
31
|
+
const normalized = ip.toLowerCase();
|
|
32
|
+
|
|
33
|
+
// Loopback
|
|
34
|
+
if (normalized === '::1') return true;
|
|
35
|
+
|
|
36
|
+
// IPv4-mapped IPv6 — ::ffff:a.b.c.d
|
|
37
|
+
if (normalized.startsWith('::ffff:')) {
|
|
38
|
+
const embedded = normalized.slice(7);
|
|
39
|
+
if (isIPv4(embedded)) return isPrivateIp(embedded);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Link-local fe80::/10 — first 10 bits = 1111 1110 10
|
|
43
|
+
// Covers fe80:: through febf::
|
|
44
|
+
const firstSegment = normalized.split(':')[0];
|
|
45
|
+
if (firstSegment.length >= 3) {
|
|
46
|
+
const prefix = firstSegment.slice(0, 3);
|
|
47
|
+
if (prefix === 'fe8' || prefix === 'fe9' || prefix === 'fea' || prefix === 'feb') return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Unique local fc00::/7 — first 7 bits = 1111 110
|
|
51
|
+
// Covers fc00:: through fdff::
|
|
52
|
+
if (normalized.startsWith('fc') || normalized.startsWith('fd')) return true;
|
|
53
|
+
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Unknown format — treat as suspicious
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Resolve a hostname via DNS and verify the resolved IP is not private.
|
|
63
|
+
* Throws if the hostname resolves to a private/reserved IP.
|
|
64
|
+
*/
|
|
65
|
+
export async function resolveAndValidateHost(hostname: string): Promise<void> {
|
|
66
|
+
// If the hostname is already a raw IP, check directly
|
|
67
|
+
if (isIPv4(hostname) || isIPv6(hostname)) {
|
|
68
|
+
if (isPrivateIp(hostname)) {
|
|
69
|
+
throw new Error(`Address "${hostname}" is a private/reserved IP`);
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let address: string;
|
|
75
|
+
try {
|
|
76
|
+
const result = await dns.promises.lookup(hostname);
|
|
77
|
+
address = result.address;
|
|
78
|
+
} catch (err) {
|
|
79
|
+
const msg = getErrorMessage(err);
|
|
80
|
+
throw new Error(`DNS lookup failed for "${hostname}": ${msg}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (isPrivateIp(address)) {
|
|
84
|
+
throw new Error(`Host "${hostname}" resolves to private IP ${address}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Full validation pipeline for an external URL:
|
|
90
|
+
* 1. Parse the URL
|
|
91
|
+
* 2. Verify protocol is http: or https:
|
|
92
|
+
* 3. If allowedHosts is provided, verify hostname is in the list
|
|
93
|
+
* 4. DNS-resolve and verify the IP is not private
|
|
94
|
+
*/
|
|
95
|
+
// Reserved test TLDs (RFC 2606) — skip DNS resolution in test environments
|
|
96
|
+
const TEST_TLDS = ['.example.com', '.example.org', '.example.net', '.test', '.localhost'];
|
|
97
|
+
|
|
98
|
+
export async function validateExternalUrl(
|
|
99
|
+
url: string,
|
|
100
|
+
allowedHosts?: string[],
|
|
101
|
+
): Promise<void> {
|
|
102
|
+
let parsed: URL;
|
|
103
|
+
try {
|
|
104
|
+
parsed = new URL(url);
|
|
105
|
+
} catch {
|
|
106
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
110
|
+
throw new Error(`Protocol "${parsed.protocol}" is not allowed. Only http: and https: are permitted`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (allowedHosts && allowedHosts.length > 0) {
|
|
114
|
+
if (!allowedHosts.includes(parsed.hostname)) {
|
|
115
|
+
throw new Error(`Host "${parsed.hostname}" is not in the allowed hosts list`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Skip DNS resolution for RFC 2606 reserved test domains in test environments
|
|
120
|
+
if (process.env.NODE_ENV === 'test' && TEST_TLDS.some(tld => parsed.hostname.endsWith(tld))) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await resolveAndValidateHost(parsed.hostname);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Sanitize a path segment (e.g., strategyId, appId) to prevent
|
|
129
|
+
* path traversal when interpolated into REST API URLs.
|
|
130
|
+
* Throws if the segment contains forbidden characters.
|
|
131
|
+
*/
|
|
132
|
+
export function sanitizePathSegment(segment: string): string {
|
|
133
|
+
if (segment.includes('/') || segment.includes('..') || segment.includes('\\')) {
|
|
134
|
+
throw new Error(`Invalid path segment: "${segment}" contains forbidden characters`);
|
|
135
|
+
}
|
|
136
|
+
return segment;
|
|
137
|
+
}
|