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,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aurawallet token — Profile-first token tooling
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx aurawallet token preview --profile dev
|
|
6
|
+
* npx aurawallet token preview --profile strict --profile-version v1 --json
|
|
7
|
+
* npx aurawallet token preview --profile dev --overrides '{"ttlSeconds":900}'
|
|
8
|
+
*
|
|
9
|
+
* Auth:
|
|
10
|
+
* Requires admin token in AURA_TOKEN (or --token <token>)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { fetchJson } from '../lib/http';
|
|
14
|
+
import { getErrorMessage } from '../../lib/error';
|
|
15
|
+
|
|
16
|
+
type Json = Record<string, unknown>;
|
|
17
|
+
|
|
18
|
+
interface PolicyPreviewResponse {
|
|
19
|
+
version: string;
|
|
20
|
+
profile: { id: string; version: string; displayName?: string; rationale?: string };
|
|
21
|
+
request: {
|
|
22
|
+
profile: string;
|
|
23
|
+
profileVersion?: string;
|
|
24
|
+
profileOverrides?: Json;
|
|
25
|
+
};
|
|
26
|
+
effectivePolicy: {
|
|
27
|
+
permissions: string[];
|
|
28
|
+
credentialAccess: { read: string[]; write: string[] };
|
|
29
|
+
excludeFields: string[];
|
|
30
|
+
ttlSeconds: number;
|
|
31
|
+
maxReads: number | null;
|
|
32
|
+
rateBudget: {
|
|
33
|
+
state: 'none' | 'inherited' | 'explicit';
|
|
34
|
+
requests: number | null;
|
|
35
|
+
windowSeconds: number | null;
|
|
36
|
+
source: 'none' | 'profile' | 'override';
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
effectivePolicyHash: string;
|
|
40
|
+
warnings: string[];
|
|
41
|
+
denyExamples: Array<{ code: string; message: string }>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface TokenCliArgs {
|
|
45
|
+
subcommand?: string;
|
|
46
|
+
profile?: string;
|
|
47
|
+
profileVersion?: string;
|
|
48
|
+
overridesRaw?: string;
|
|
49
|
+
token?: string;
|
|
50
|
+
json: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function parseTokenArgs(args: string[]): TokenCliArgs {
|
|
54
|
+
const getValue = (flag: string): string | undefined => {
|
|
55
|
+
const idx = args.indexOf(flag);
|
|
56
|
+
return idx >= 0 ? args[idx + 1] : undefined;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
subcommand: args[0],
|
|
61
|
+
profile: getValue('--profile'),
|
|
62
|
+
profileVersion: getValue('--profile-version'),
|
|
63
|
+
overridesRaw: getValue('--overrides'),
|
|
64
|
+
token: getValue('--token'),
|
|
65
|
+
json: args.includes('--json'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseOverrides(raw?: string): Json | undefined {
|
|
70
|
+
if (!raw) return undefined;
|
|
71
|
+
const parsed = JSON.parse(raw) as unknown;
|
|
72
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
73
|
+
throw new Error('--overrides must be a JSON object');
|
|
74
|
+
}
|
|
75
|
+
return parsed as Json;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function formatPolicyPreview(preview: PolicyPreviewResponse): string {
|
|
79
|
+
const lines: string[] = [];
|
|
80
|
+
lines.push(`Profile: ${preview.profile.id}@${preview.profile.version}`);
|
|
81
|
+
lines.push(`Hash: ${preview.effectivePolicyHash}`);
|
|
82
|
+
lines.push(`Permissions: ${preview.effectivePolicy.permissions.join(', ') || '(none)'}`);
|
|
83
|
+
lines.push(`Credential read scope: ${preview.effectivePolicy.credentialAccess.read.join(', ') || '(none)'}`);
|
|
84
|
+
lines.push(`Credential write scope: ${preview.effectivePolicy.credentialAccess.write.join(', ') || '(none)'}`);
|
|
85
|
+
lines.push(`Excluded fields: ${preview.effectivePolicy.excludeFields.join(', ') || '(none)'}`);
|
|
86
|
+
lines.push(`TTL seconds: ${preview.effectivePolicy.ttlSeconds}`);
|
|
87
|
+
lines.push(`Max reads: ${preview.effectivePolicy.maxReads ?? 'unlimited'}`);
|
|
88
|
+
|
|
89
|
+
const rb = preview.effectivePolicy.rateBudget;
|
|
90
|
+
lines.push(`Rate budget: ${rb.state} (${rb.requests ?? 'n/a'} / ${rb.windowSeconds ?? 'n/a'}s, source=${rb.source})`);
|
|
91
|
+
|
|
92
|
+
if (preview.warnings.length > 0) {
|
|
93
|
+
lines.push('Warnings:');
|
|
94
|
+
for (const warning of preview.warnings) lines.push(` - ${warning}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (preview.denyExamples.length > 0) {
|
|
98
|
+
lines.push('Expected deny examples:');
|
|
99
|
+
for (const deny of preview.denyExamples) lines.push(` - ${deny.code}: ${deny.message}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return lines.join('\n');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function showHelp(): void {
|
|
106
|
+
console.log(`
|
|
107
|
+
aurawallet token — Token policy preview
|
|
108
|
+
|
|
109
|
+
Usage:
|
|
110
|
+
npx aurawallet token preview --profile <id> [--profile-version <v>] [--overrides <json>] [--json]
|
|
111
|
+
|
|
112
|
+
Options:
|
|
113
|
+
--profile <id> Profile id (required)
|
|
114
|
+
--profile-version <v> Profile version (default: v1)
|
|
115
|
+
--overrides <json> JSON object for profile overrides (tighten-only)
|
|
116
|
+
--json Print raw PolicyPreviewV1 payload
|
|
117
|
+
--token <token> Admin token (falls back to AURA_TOKEN env)
|
|
118
|
+
|
|
119
|
+
Examples:
|
|
120
|
+
npx aurawallet token preview --profile dev
|
|
121
|
+
npx aurawallet token preview --profile strict --profile-version v1 --json
|
|
122
|
+
npx aurawallet token preview --profile dev --overrides '{"ttlSeconds":900}'
|
|
123
|
+
`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function main(): Promise<void> {
|
|
127
|
+
const parsed = parseTokenArgs(process.argv.slice(2));
|
|
128
|
+
|
|
129
|
+
if (!parsed.subcommand || parsed.subcommand === '--help' || parsed.subcommand === '-h') {
|
|
130
|
+
showHelp();
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (parsed.subcommand !== 'preview') {
|
|
135
|
+
console.error(`Unknown token subcommand: ${parsed.subcommand}`);
|
|
136
|
+
showHelp();
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!parsed.profile) {
|
|
141
|
+
console.error('--profile is required');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const token = parsed.token || process.env.AURA_TOKEN;
|
|
146
|
+
if (!token) {
|
|
147
|
+
console.error('Admin auth required. Provide --token or set AURA_TOKEN.');
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const profileOverrides = parseOverrides(parsed.overridesRaw);
|
|
153
|
+
const preview = await fetchJson<PolicyPreviewResponse>('/actions/token/preview', {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
token,
|
|
156
|
+
body: {
|
|
157
|
+
profile: parsed.profile,
|
|
158
|
+
profileVersion: parsed.profileVersion,
|
|
159
|
+
profileOverrides,
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (parsed.json) {
|
|
164
|
+
console.log(JSON.stringify(preview, null, 2));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(formatPolicyPreview(preview));
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(`Token preview failed: ${getErrorMessage(error)}`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
176
|
+
main().catch((error) => {
|
|
177
|
+
console.error(`Token preview failed: ${getErrorMessage(error)}`);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aurawallet unlock — Unlock the vault interactively
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { fetchPublicKey, fetchJson, isServerRunning } from '../lib/http';
|
|
6
|
+
import { promptPassword } from '../lib/prompt';
|
|
7
|
+
import { encryptPassword, generateAgentKeypair } from '../../cli/transport-client';
|
|
8
|
+
import { getErrorMessage } from '../../lib/error';
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
// Check server is running
|
|
12
|
+
if (!(await isServerRunning())) {
|
|
13
|
+
console.error('Wallet server is not running.');
|
|
14
|
+
console.error('Start it with: npx aurawallet start');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Get public key
|
|
19
|
+
const publicKey = await fetchPublicKey();
|
|
20
|
+
|
|
21
|
+
// Prompt for password
|
|
22
|
+
const password = await promptPassword('Password');
|
|
23
|
+
|
|
24
|
+
// Encrypt and unlock
|
|
25
|
+
const encrypted = encryptPassword(password, publicKey);
|
|
26
|
+
const { publicKey: agentPubkey } = generateAgentKeypair();
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const result = await fetchJson<{
|
|
30
|
+
success: boolean;
|
|
31
|
+
address: string;
|
|
32
|
+
token: string;
|
|
33
|
+
error?: string;
|
|
34
|
+
}>('/unlock', { body: { encrypted, pubkey: agentPubkey } });
|
|
35
|
+
|
|
36
|
+
console.log(`\nWallet unlocked.`);
|
|
37
|
+
console.log(` Address: ${result.address}`);
|
|
38
|
+
console.log(` Token: ${result.token.substring(0, 20)}...`);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
const msg = getErrorMessage(error);
|
|
41
|
+
console.error(`\nFailed to unlock: ${msg}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
main().catch((error) => {
|
|
47
|
+
console.error('Error:', getErrorMessage(error));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
});
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* aurawallet vault — Retrieve credentials from the vault
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* npx aurawallet vault list List all credential names
|
|
6
|
+
* npx aurawallet vault get <name> Print all fields as key=value
|
|
7
|
+
* npx aurawallet vault get <name> --field <f> Print single field value (raw, for piping)
|
|
8
|
+
* npx aurawallet vault get <name> --json JSON output
|
|
9
|
+
* npx aurawallet vault get <name> --first Use first match if multiple results
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
generateEphemeralKeypair,
|
|
14
|
+
bootstrapViaSocket,
|
|
15
|
+
decryptWithPrivateKey,
|
|
16
|
+
createReadToken,
|
|
17
|
+
EphemeralKeypair,
|
|
18
|
+
} from '../../lib/credential-transport';
|
|
19
|
+
import { serverUrl } from '../lib/http';
|
|
20
|
+
import { getErrorMessage } from '../../lib/error';
|
|
21
|
+
import { evaluateProjectScopeAccess, emitProjectScopeEvent } from '../../lib/project-scope';
|
|
22
|
+
import { printHelp } from '../lib/theme';
|
|
23
|
+
|
|
24
|
+
// ── Auth: socket or AURA_TOKEN env var ──
|
|
25
|
+
|
|
26
|
+
async function getAuthToken(keypair: EphemeralKeypair): Promise<string> {
|
|
27
|
+
try {
|
|
28
|
+
return await bootstrapViaSocket('cli-vault', keypair);
|
|
29
|
+
} catch (socketErr) {
|
|
30
|
+
// Socket bootstrap is preferred; env token is fallback for headless/CI.
|
|
31
|
+
const envToken = process.env.AURA_TOKEN;
|
|
32
|
+
if (envToken) return envToken;
|
|
33
|
+
throw socketErr;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function decryptCredentialPayload(encrypted: string, keypair: EphemeralKeypair): DecryptedCredential {
|
|
38
|
+
const plaintext = decryptWithPrivateKey(encrypted, keypair.privateKeyPem);
|
|
39
|
+
return JSON.parse(plaintext);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function getReadToken(authToken: string, keypair: EphemeralKeypair): Promise<string> {
|
|
43
|
+
return createReadToken(serverUrl(), authToken, keypair, 'cli-vault-reader');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── API helpers ──
|
|
47
|
+
|
|
48
|
+
interface CredentialMeta {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
type: string;
|
|
52
|
+
vaultId: string;
|
|
53
|
+
meta: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface DecryptedCredential {
|
|
57
|
+
id: string;
|
|
58
|
+
vaultId: string;
|
|
59
|
+
type: string;
|
|
60
|
+
fields: Array<{ key: string; value: string; type?: string; sensitive?: boolean }>;
|
|
61
|
+
health?: {
|
|
62
|
+
status: string;
|
|
63
|
+
flags: { weak: boolean; reused: boolean; breached: boolean; unknown: boolean };
|
|
64
|
+
lastScannedAt: string | null;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface CredentialHealthSummaryResponse {
|
|
69
|
+
summary: {
|
|
70
|
+
totalAnalyzed: number;
|
|
71
|
+
safe: number;
|
|
72
|
+
weak: number;
|
|
73
|
+
reused: number;
|
|
74
|
+
breached: number;
|
|
75
|
+
unknown: number;
|
|
76
|
+
lastScanAt: string | null;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function listCredentials(token: string, query?: string): Promise<CredentialMeta[]> {
|
|
81
|
+
const base = serverUrl();
|
|
82
|
+
const qs = query ? `?q=${encodeURIComponent(query)}` : '';
|
|
83
|
+
const res = await fetch(`${base}/credentials${qs}`, {
|
|
84
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
85
|
+
signal: AbortSignal.timeout(5000),
|
|
86
|
+
});
|
|
87
|
+
if (!res.ok) throw new Error(`List failed (${res.status})`);
|
|
88
|
+
const data = await res.json() as { credentials: CredentialMeta[] };
|
|
89
|
+
return data.credentials || [];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function readCredential(
|
|
93
|
+
credentialId: string,
|
|
94
|
+
readToken: string,
|
|
95
|
+
keypair: EphemeralKeypair,
|
|
96
|
+
): Promise<DecryptedCredential> {
|
|
97
|
+
const base = serverUrl();
|
|
98
|
+
const res = await fetch(`${base}/credentials/${credentialId}/read`, {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'Authorization': `Bearer ${readToken}` },
|
|
101
|
+
signal: AbortSignal.timeout(5000),
|
|
102
|
+
});
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
const text = await res.text();
|
|
105
|
+
throw new Error(`Read failed (${res.status}): ${text}`);
|
|
106
|
+
}
|
|
107
|
+
const data = await res.json() as { encrypted: string };
|
|
108
|
+
return decryptCredentialPayload(data.encrypted, keypair);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── Search helpers ──
|
|
112
|
+
|
|
113
|
+
async function searchCredentials(token: string, name: string): Promise<CredentialMeta[]> {
|
|
114
|
+
const base = serverUrl();
|
|
115
|
+
for (const param of [`q=${encodeURIComponent(name)}`, `tag=${encodeURIComponent(name)}`]) {
|
|
116
|
+
const res = await fetch(`${base}/credentials?${param}`, {
|
|
117
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
118
|
+
signal: AbortSignal.timeout(5000),
|
|
119
|
+
});
|
|
120
|
+
if (res.ok) {
|
|
121
|
+
const data = await res.json() as { credentials: CredentialMeta[] };
|
|
122
|
+
if (data.credentials && data.credentials.length > 0) {
|
|
123
|
+
return data.credentials;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function fetchTotpCode(credentialId: string, token: string): Promise<{ code: string; remaining: number }> {
|
|
131
|
+
const base = serverUrl();
|
|
132
|
+
const res = await fetch(`${base}/credentials/${credentialId}/totp`, {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
135
|
+
signal: AbortSignal.timeout(5000),
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok) {
|
|
138
|
+
const data = await res.json().catch(() => ({ error: `HTTP ${res.status}` })) as { error?: string };
|
|
139
|
+
throw new Error(data.error || `TOTP request failed (${res.status})`);
|
|
140
|
+
}
|
|
141
|
+
const data = await res.json() as { code: string; remaining: number };
|
|
142
|
+
return data;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function fetchVaultNameMap(): Promise<Map<string, string>> {
|
|
146
|
+
const base = serverUrl();
|
|
147
|
+
const res = await fetch(`${base}/setup/vaults`, {
|
|
148
|
+
signal: AbortSignal.timeout(5000),
|
|
149
|
+
});
|
|
150
|
+
if (!res.ok) return new Map();
|
|
151
|
+
const data = await res.json() as { vaults?: Array<{ id: string; name: string }> };
|
|
152
|
+
return new Map((data.vaults || []).map((v) => [v.id, v.name]));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function fetchHealthSummary(token: string): Promise<CredentialHealthSummaryResponse['summary']> {
|
|
156
|
+
const base = serverUrl();
|
|
157
|
+
const res = await fetch(`${base}/credentials/health/summary`, {
|
|
158
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
159
|
+
signal: AbortSignal.timeout(5000),
|
|
160
|
+
});
|
|
161
|
+
if (!res.ok) throw new Error(`Health summary failed (${res.status})`);
|
|
162
|
+
const data = await res.json() as CredentialHealthSummaryResponse;
|
|
163
|
+
return data.summary;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ── CLI ──
|
|
167
|
+
|
|
168
|
+
function showHelp(): void {
|
|
169
|
+
printHelp('VAULT', 'npx aurawallet vault <subcommand> [options]', [
|
|
170
|
+
{ name: 'list', desc: 'List all credential names' },
|
|
171
|
+
{ name: 'get <name>', desc: 'Print fields as key=value' },
|
|
172
|
+
{ name: 'health', desc: 'Print credential health summary' },
|
|
173
|
+
], [
|
|
174
|
+
'Options:',
|
|
175
|
+
' --field <f> Print single field value (raw)',
|
|
176
|
+
' --vault <v> Restrict lookup to a specific vault name',
|
|
177
|
+
' --json JSON output',
|
|
178
|
+
' --first Use first match if ambiguous',
|
|
179
|
+
' --totp Print current TOTP code only',
|
|
180
|
+
'',
|
|
181
|
+
'Auth: Uses Unix socket by default. Set AURA_TOKEN env var for headless/CI.',
|
|
182
|
+
]);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Parse CLI arguments into structured options */
|
|
186
|
+
export function parseArgs(args: string[]): {
|
|
187
|
+
subcommand: string | undefined;
|
|
188
|
+
flagJson: boolean;
|
|
189
|
+
flagFirst: boolean;
|
|
190
|
+
flagTotp: boolean;
|
|
191
|
+
fieldName: string | undefined;
|
|
192
|
+
vaultName: string | undefined;
|
|
193
|
+
positional: string[];
|
|
194
|
+
} {
|
|
195
|
+
const subcommand = args[0];
|
|
196
|
+
const flagJson = args.includes('--json');
|
|
197
|
+
const flagFirst = args.includes('--first');
|
|
198
|
+
const flagTotp = args.includes('--totp');
|
|
199
|
+
const fieldIdx = args.indexOf('--field');
|
|
200
|
+
const fieldName = fieldIdx !== -1 ? args[fieldIdx + 1] : undefined;
|
|
201
|
+
const vaultIdx = args.indexOf('--vault');
|
|
202
|
+
const vaultName = vaultIdx !== -1 ? args[vaultIdx + 1] : undefined;
|
|
203
|
+
|
|
204
|
+
const positional: string[] = [];
|
|
205
|
+
for (let i = 1; i < args.length; i++) {
|
|
206
|
+
if (args[i].startsWith('--')) {
|
|
207
|
+
if (args[i] === '--field' || args[i] === '--vault') i++; // skip flag values
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
positional.push(args[i]);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { subcommand, flagJson, flagFirst, flagTotp, fieldName, vaultName, positional };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Format a decrypted credential for output */
|
|
217
|
+
export function formatCredential(
|
|
218
|
+
target: { name: string; type: string; id: string },
|
|
219
|
+
decrypted: DecryptedCredential,
|
|
220
|
+
opts: { json: boolean; fieldName?: string },
|
|
221
|
+
): { output: string; exitCode: number } {
|
|
222
|
+
if (opts.json) {
|
|
223
|
+
return {
|
|
224
|
+
output: JSON.stringify({
|
|
225
|
+
name: target.name,
|
|
226
|
+
type: target.type,
|
|
227
|
+
id: target.id,
|
|
228
|
+
fields: decrypted.fields,
|
|
229
|
+
}, null, 2),
|
|
230
|
+
exitCode: 0,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (opts.fieldName) {
|
|
235
|
+
const field = decrypted.fields.find(f => f.key.toLowerCase() === opts.fieldName!.toLowerCase());
|
|
236
|
+
if (!field) {
|
|
237
|
+
return {
|
|
238
|
+
output: `Field "${opts.fieldName}" not found. Available: ${decrypted.fields.map(f => f.key).join(', ')}`,
|
|
239
|
+
exitCode: 1,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return { output: field.value, exitCode: 0 };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Default: key=value format
|
|
246
|
+
return {
|
|
247
|
+
output: decrypted.fields.map(f => `${f.key}=${f.value}`).join('\n'),
|
|
248
|
+
exitCode: 0,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export async function runVaultCli(args: string[]): Promise<number> {
|
|
253
|
+
const { subcommand, flagJson, flagFirst, flagTotp, fieldName, vaultName, positional } = parseArgs(args);
|
|
254
|
+
|
|
255
|
+
if (!subcommand || subcommand === '--help' || subcommand === '-h') {
|
|
256
|
+
showHelp();
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const keypair = generateEphemeralKeypair();
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
// Auth via socket or AURA_TOKEN fallback
|
|
264
|
+
const token = await getAuthToken(keypair);
|
|
265
|
+
|
|
266
|
+
if (subcommand === 'list') {
|
|
267
|
+
const credentials = await listCredentials(token);
|
|
268
|
+
if (flagJson) {
|
|
269
|
+
console.log(JSON.stringify(credentials.map(c => ({ name: c.name, type: c.type, id: c.id })), null, 2));
|
|
270
|
+
} else {
|
|
271
|
+
if (credentials.length === 0) {
|
|
272
|
+
console.log('No credentials found.');
|
|
273
|
+
} else {
|
|
274
|
+
for (const c of credentials) {
|
|
275
|
+
console.log(`${c.name} (${c.type})`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (subcommand === 'health') {
|
|
283
|
+
const summary = await fetchHealthSummary(token);
|
|
284
|
+
if (flagJson) {
|
|
285
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
286
|
+
} else {
|
|
287
|
+
console.log(`Analyzed: ${summary.totalAnalyzed}`);
|
|
288
|
+
console.log(`Safe: ${summary.safe}`);
|
|
289
|
+
console.log(`Weak: ${summary.weak}`);
|
|
290
|
+
console.log(`Reused: ${summary.reused}`);
|
|
291
|
+
console.log(`Breached: ${summary.breached}`);
|
|
292
|
+
console.log(`Unknown: ${summary.unknown}`);
|
|
293
|
+
}
|
|
294
|
+
return 0;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (subcommand === 'get') {
|
|
298
|
+
const name = positional[0];
|
|
299
|
+
if (!name) {
|
|
300
|
+
console.error('Usage: npx aurawallet vault get <name>');
|
|
301
|
+
return 1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Search
|
|
305
|
+
const matches = await searchCredentials(token, name);
|
|
306
|
+
if (matches.length === 0) {
|
|
307
|
+
console.error(`No credential found matching "${name}"`);
|
|
308
|
+
return 1;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const vaultNames = await fetchVaultNameMap();
|
|
312
|
+
const scopedDecision = evaluateProjectScopeAccess({
|
|
313
|
+
surface: 'cli_vault_get',
|
|
314
|
+
requested: { vaultName: vaultName || null, credentialName: name },
|
|
315
|
+
candidates: matches.map((m) => ({
|
|
316
|
+
id: m.id,
|
|
317
|
+
name: m.name,
|
|
318
|
+
vaultName: vaultNames.get(m.vaultId) || null,
|
|
319
|
+
})),
|
|
320
|
+
actor: 'cli-vault',
|
|
321
|
+
});
|
|
322
|
+
emitProjectScopeEvent({
|
|
323
|
+
actor: 'cli-vault',
|
|
324
|
+
surface: 'cli_vault_get',
|
|
325
|
+
requestedCredential: { vaultName: vaultName || null, credentialName: name },
|
|
326
|
+
decision: scopedDecision,
|
|
327
|
+
});
|
|
328
|
+
if (!scopedDecision.allowed) {
|
|
329
|
+
console.error(`${scopedDecision.code}: ${scopedDecision.remediation}`);
|
|
330
|
+
return 1;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const allowedIds = new Set(scopedDecision.allowedCandidates.map((c) => c.id).filter(Boolean));
|
|
334
|
+
const scopedMatches = matches.filter((m) => allowedIds.has(m.id));
|
|
335
|
+
const vaultFiltered = vaultName
|
|
336
|
+
? scopedMatches.filter((m) => (vaultNames.get(m.vaultId) || '').toLowerCase() === vaultName.toLowerCase())
|
|
337
|
+
: scopedMatches;
|
|
338
|
+
|
|
339
|
+
if (vaultFiltered.length === 0) {
|
|
340
|
+
console.error(`PROJECT_SCOPE_DENIED: No allowed credential found for "${name}" in vault "${vaultName}".`);
|
|
341
|
+
return 1;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
let target: CredentialMeta;
|
|
345
|
+
if (vaultFiltered.length > 1 && !flagFirst) {
|
|
346
|
+
console.error(`Multiple credentials match "${name}":`);
|
|
347
|
+
for (const m of vaultFiltered) {
|
|
348
|
+
const resolvedVault = vaultNames.get(m.vaultId) || m.vaultId;
|
|
349
|
+
console.error(` - ${m.name} (${m.type}, vault: ${resolvedVault}, id: ${m.id})`);
|
|
350
|
+
}
|
|
351
|
+
console.error('\nUse --first to select the first match, or specify --vault.');
|
|
352
|
+
return 1;
|
|
353
|
+
}
|
|
354
|
+
target = vaultFiltered[0];
|
|
355
|
+
|
|
356
|
+
// --totp: just print the TOTP code
|
|
357
|
+
if (flagTotp) {
|
|
358
|
+
try {
|
|
359
|
+
const totp = await fetchTotpCode(target.id, token);
|
|
360
|
+
process.stdout.write(totp.code);
|
|
361
|
+
return 0;
|
|
362
|
+
} catch (err) {
|
|
363
|
+
console.error(`TOTP error: ${getErrorMessage(err)}`);
|
|
364
|
+
return 1;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Get scoped read token and decrypt
|
|
369
|
+
const readToken = await getReadToken(token, keypair);
|
|
370
|
+
const decrypted = await readCredential(target.id, readToken, keypair);
|
|
371
|
+
|
|
372
|
+
// If credential has TOTP, fetch the current code and append
|
|
373
|
+
const hasTotpField = decrypted.fields.some(f => f.key === 'totp' || f.key === 'otp');
|
|
374
|
+
if (hasTotpField) {
|
|
375
|
+
try {
|
|
376
|
+
const totp = await fetchTotpCode(target.id, token);
|
|
377
|
+
decrypted.fields.push({ key: 'totp_code', value: totp.code, type: 'text', sensitive: false });
|
|
378
|
+
} catch {
|
|
379
|
+
// TOTP fetch failed — skip silently (may lack permission)
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const result = formatCredential(target, decrypted, { json: flagJson, fieldName });
|
|
384
|
+
if (result.exitCode !== 0) {
|
|
385
|
+
console.error(result.output);
|
|
386
|
+
return result.exitCode;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (fieldName) {
|
|
390
|
+
// Raw value — no newline for piping
|
|
391
|
+
process.stdout.write(result.output);
|
|
392
|
+
} else {
|
|
393
|
+
console.log(result.output);
|
|
394
|
+
}
|
|
395
|
+
return 0;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
console.error(`Unknown vault subcommand: ${subcommand}`);
|
|
399
|
+
showHelp();
|
|
400
|
+
return 1;
|
|
401
|
+
} catch (error) {
|
|
402
|
+
console.error(`Error: ${getErrorMessage(error)}`);
|
|
403
|
+
return 1;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async function main(): Promise<void> {
|
|
408
|
+
const exitCode = await runVaultCli(process.argv.slice(2));
|
|
409
|
+
process.exit(exitCode);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (require.main === module) {
|
|
413
|
+
main().catch((error) => {
|
|
414
|
+
console.error(`Error: ${getErrorMessage(error)}`);
|
|
415
|
+
process.exit(1);
|
|
416
|
+
});
|
|
417
|
+
}
|