dodo-mcp 1.0.0
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 +21 -0
- package/README.md +425 -0
- package/dist/auth/adapter.js +43 -0
- package/dist/auth/adapter.js.map +1 -0
- package/dist/auth/clientDeletion.js +45 -0
- package/dist/auth/clientDeletion.js.map +1 -0
- package/dist/auth/clients.js +55 -0
- package/dist/auth/clients.js.map +1 -0
- package/dist/auth/constants.js +10 -0
- package/dist/auth/constants.js.map +1 -0
- package/dist/auth/interactions.js +184 -0
- package/dist/auth/interactions.js.map +1 -0
- package/dist/auth/keys.js +56 -0
- package/dist/auth/keys.js.map +1 -0
- package/dist/auth/provider.js +131 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/auth/verifier.js +74 -0
- package/dist/auth/verifier.js.map +1 -0
- package/dist/cli/kill.js +124 -0
- package/dist/cli/kill.js.map +1 -0
- package/dist/cli/main.js +1393 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/menu.js +127 -0
- package/dist/cli/menu.js.map +1 -0
- package/dist/cli/terminal.js +30 -0
- package/dist/cli/terminal.js.map +1 -0
- package/dist/config/globalConfig.js +144 -0
- package/dist/config/globalConfig.js.map +1 -0
- package/dist/config/limits.js +42 -0
- package/dist/config/limits.js.map +1 -0
- package/dist/config/paths.js +94 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/projectConfig.js +63 -0
- package/dist/config/projectConfig.js.map +1 -0
- package/dist/config/stateImport.js +306 -0
- package/dist/config/stateImport.js.map +1 -0
- package/dist/config/tunnelConfig.js +23 -0
- package/dist/config/tunnelConfig.js.map +1 -0
- package/dist/errors.js +82 -0
- package/dist/errors.js.map +1 -0
- package/dist/evaluation/contracts.js +86 -0
- package/dist/evaluation/contracts.js.map +1 -0
- package/dist/evaluation/dodoBench.js +69 -0
- package/dist/evaluation/dodoBench.js.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/authentication.js +117 -0
- package/dist/ipc/authentication.js.map +1 -0
- package/dist/ipc/client.js +86 -0
- package/dist/ipc/client.js.map +1 -0
- package/dist/ipc/installationClient.js +83 -0
- package/dist/ipc/installationClient.js.map +1 -0
- package/dist/ipc/ownerControl.js +46 -0
- package/dist/ipc/ownerControl.js.map +1 -0
- package/dist/ipc/protocol.js +2 -0
- package/dist/ipc/protocol.js.map +1 -0
- package/dist/ipc/server.js +108 -0
- package/dist/ipc/server.js.map +1 -0
- package/dist/platform/execResolve.js +64 -0
- package/dist/platform/execResolve.js.map +1 -0
- package/dist/platform/fileIdentity.js +26 -0
- package/dist/platform/fileIdentity.js.map +1 -0
- package/dist/platform/fsRetry.js +22 -0
- package/dist/platform/fsRetry.js.map +1 -0
- package/dist/platform/pathPolicy.js +29 -0
- package/dist/platform/pathPolicy.js.map +1 -0
- package/dist/platform/privateFs.js +116 -0
- package/dist/platform/privateFs.js.map +1 -0
- package/dist/platform/processTree.js +31 -0
- package/dist/platform/processTree.js.map +1 -0
- package/dist/platform/shell.js +74 -0
- package/dist/platform/shell.js.map +1 -0
- package/dist/platform/speech.js +94 -0
- package/dist/platform/speech.js.map +1 -0
- package/dist/platform/system.js +28 -0
- package/dist/platform/system.js.map +1 -0
- package/dist/platform/windowsSandbox.js +129 -0
- package/dist/platform/windowsSandbox.js.map +1 -0
- package/dist/projects/federation.js +312 -0
- package/dist/projects/federation.js.map +1 -0
- package/dist/projects/registry.js +291 -0
- package/dist/projects/registry.js.map +1 -0
- package/dist/security/accessMode.js +19 -0
- package/dist/security/accessMode.js.map +1 -0
- package/dist/security/approvals.js +56 -0
- package/dist/security/approvals.js.map +1 -0
- package/dist/security/env.js +57 -0
- package/dist/security/env.js.map +1 -0
- package/dist/security/mutationQueue.js +78 -0
- package/dist/security/mutationQueue.js.map +1 -0
- package/dist/security/policy.js +22 -0
- package/dist/security/policy.js.map +1 -0
- package/dist/security/projectAuthority.js +22 -0
- package/dist/security/projectAuthority.js.map +1 -0
- package/dist/security/redact.js +30 -0
- package/dist/security/redact.js.map +1 -0
- package/dist/server/aiAdmin.js +201 -0
- package/dist/server/aiAdmin.js.map +1 -0
- package/dist/server/appServer.js +461 -0
- package/dist/server/appServer.js.map +1 -0
- package/dist/server/bootstrap.js +185 -0
- package/dist/server/bootstrap.js.map +1 -0
- package/dist/server/configUi/app.css +347 -0
- package/dist/server/configUi/app.js +958 -0
- package/dist/server/configUi/index.html +379 -0
- package/dist/server/configUi/ui/alerts.js +92 -0
- package/dist/server/configUi/ui/dom.js +19 -0
- package/dist/server/configUi/ui/tooltips.js +115 -0
- package/dist/server/configUi/vendor/VERSION.txt +1 -0
- package/dist/server/configUi/vendor/sweetalert2.min.css +1 -0
- package/dist/server/configUi/vendor/sweetalert2.min.js +5 -0
- package/dist/server/configUi/workbench.css +62 -0
- package/dist/server/configUi/workbench.js +394 -0
- package/dist/server/installationRuntime.js +155 -0
- package/dist/server/installationRuntime.js.map +1 -0
- package/dist/server/instructions.js +17 -0
- package/dist/server/instructions.js.map +1 -0
- package/dist/server/ipcDispatch.js +225 -0
- package/dist/server/ipcDispatch.js.map +1 -0
- package/dist/server/localConfig.js +561 -0
- package/dist/server/localConfig.js.map +1 -0
- package/dist/server/optionalServices.js +30 -0
- package/dist/server/optionalServices.js.map +1 -0
- package/dist/server/projectLease.js +46 -0
- package/dist/server/projectLease.js.map +1 -0
- package/dist/server/stdioServer.js +75 -0
- package/dist/server/stdioServer.js.map +1 -0
- package/dist/server/version.js +13 -0
- package/dist/server/version.js.map +1 -0
- package/dist/server/workspaceHost.js +194 -0
- package/dist/server/workspaceHost.js.map +1 -0
- package/dist/services/agent/agentService.js +598 -0
- package/dist/services/agent/agentService.js.map +1 -0
- package/dist/services/agent/contracts.js +102 -0
- package/dist/services/agent/contracts.js.map +1 -0
- package/dist/services/ai/adapters.js +287 -0
- package/dist/services/ai/adapters.js.map +1 -0
- package/dist/services/ai/contracts.js +39 -0
- package/dist/services/ai/contracts.js.map +1 -0
- package/dist/services/ai/credentials.js +77 -0
- package/dist/services/ai/credentials.js.map +1 -0
- package/dist/services/ai/network.js +113 -0
- package/dist/services/ai/network.js.map +1 -0
- package/dist/services/ai/settings.js +178 -0
- package/dist/services/ai/settings.js.map +1 -0
- package/dist/services/ai/subagents.js +468 -0
- package/dist/services/ai/subagents.js.map +1 -0
- package/dist/services/assistance/analysis.js +352 -0
- package/dist/services/assistance/analysis.js.map +1 -0
- package/dist/services/assistance/contracts.js +54 -0
- package/dist/services/assistance/contracts.js.map +1 -0
- package/dist/services/assistance/verification.js +274 -0
- package/dist/services/assistance/verification.js.map +1 -0
- package/dist/services/brain/brainParser.js +97 -0
- package/dist/services/brain/brainParser.js.map +1 -0
- package/dist/services/brain/brainService.js +733 -0
- package/dist/services/brain/brainService.js.map +1 -0
- package/dist/services/brain/brainWorker.js +212 -0
- package/dist/services/brain/brainWorker.js.map +1 -0
- package/dist/services/brain/contracts.js +154 -0
- package/dist/services/brain/contracts.js.map +1 -0
- package/dist/services/brain/protocol.js +2 -0
- package/dist/services/brain/protocol.js.map +1 -0
- package/dist/services/changes/applier.js +544 -0
- package/dist/services/changes/applier.js.map +1 -0
- package/dist/services/changes/contentBudget.js +11 -0
- package/dist/services/changes/contentBudget.js.map +1 -0
- package/dist/services/changes/planner.js +284 -0
- package/dist/services/changes/planner.js.map +1 -0
- package/dist/services/changes/types.js +3 -0
- package/dist/services/changes/types.js.map +1 -0
- package/dist/services/context/contextEngine.js +746 -0
- package/dist/services/context/contextEngine.js.map +1 -0
- package/dist/services/context/contracts.js +88 -0
- package/dist/services/context/contracts.js.map +1 -0
- package/dist/services/desktop/desktopPolicy.js +76 -0
- package/dist/services/desktop/desktopPolicy.js.map +1 -0
- package/dist/services/desktop/desktopService.js +130 -0
- package/dist/services/desktop/desktopService.js.map +1 -0
- package/dist/services/desktop/nativeBackend.js +174 -0
- package/dist/services/desktop/nativeBackend.js.map +1 -0
- package/dist/services/desktop/protocol.js +32 -0
- package/dist/services/desktop/protocol.js.map +1 -0
- package/dist/services/files/readService.js +136 -0
- package/dist/services/files/readService.js.map +1 -0
- package/dist/services/git/gitService.js +369 -0
- package/dist/services/git/gitService.js.map +1 -0
- package/dist/services/intelligence/intelService.js +136 -0
- package/dist/services/intelligence/intelService.js.map +1 -0
- package/dist/services/intelligence/protocol.js +2 -0
- package/dist/services/intelligence/protocol.js.map +1 -0
- package/dist/services/intelligence/tsWorker.js +419 -0
- package/dist/services/intelligence/tsWorker.js.map +1 -0
- package/dist/services/jobs/commandInput.js +34 -0
- package/dist/services/jobs/commandInput.js.map +1 -0
- package/dist/services/jobs/jobManager.js +398 -0
- package/dist/services/jobs/jobManager.js.map +1 -0
- package/dist/services/jobs/sandbox.js +156 -0
- package/dist/services/jobs/sandbox.js.map +1 -0
- package/dist/services/jobs/sandboxWiring.js +37 -0
- package/dist/services/jobs/sandboxWiring.js.map +1 -0
- package/dist/services/jobs/spool.js +112 -0
- package/dist/services/jobs/spool.js.map +1 -0
- package/dist/services/jobs/windowsSandboxChild.js +24 -0
- package/dist/services/jobs/windowsSandboxChild.js.map +1 -0
- package/dist/services/jobs/windowsSandboxWorker.js +155 -0
- package/dist/services/jobs/windowsSandboxWorker.js.map +1 -0
- package/dist/services/lsp/documentUri.js +16 -0
- package/dist/services/lsp/documentUri.js.map +1 -0
- package/dist/services/lsp/jsonrpc.js +382 -0
- package/dist/services/lsp/jsonrpc.js.map +1 -0
- package/dist/services/lsp/lspService.js +1051 -0
- package/dist/services/lsp/lspService.js.map +1 -0
- package/dist/services/memory/contracts.js +94 -0
- package/dist/services/memory/contracts.js.map +1 -0
- package/dist/services/memory/memoryService.js +683 -0
- package/dist/services/memory/memoryService.js.map +1 -0
- package/dist/services/multimodal/browserService.js +407 -0
- package/dist/services/multimodal/browserService.js.map +1 -0
- package/dist/services/multimodal/byteRange.js +31 -0
- package/dist/services/multimodal/byteRange.js.map +1 -0
- package/dist/services/multimodal/contracts.js +59 -0
- package/dist/services/multimodal/contracts.js.map +1 -0
- package/dist/services/multimodal/gameService.js +95 -0
- package/dist/services/multimodal/gameService.js.map +1 -0
- package/dist/services/multimodal/images.js +107 -0
- package/dist/services/multimodal/images.js.map +1 -0
- package/dist/services/multimodal/mediaService.js +279 -0
- package/dist/services/multimodal/mediaService.js.map +1 -0
- package/dist/services/multimodal/mediaWorker.js +143 -0
- package/dist/services/multimodal/mediaWorker.js.map +1 -0
- package/dist/services/multimodal/multimodalService.js +51 -0
- package/dist/services/multimodal/multimodalService.js.map +1 -0
- package/dist/services/multimodal/network.js +69 -0
- package/dist/services/multimodal/network.js.map +1 -0
- package/dist/services/multimodal/operations.js +40 -0
- package/dist/services/multimodal/operations.js.map +1 -0
- package/dist/services/multimodal/storage.js +160 -0
- package/dist/services/multimodal/storage.js.map +1 -0
- package/dist/services/multimodal/workflowService.js +179 -0
- package/dist/services/multimodal/workflowService.js.map +1 -0
- package/dist/services/overview.js +284 -0
- package/dist/services/overview.js.map +1 -0
- package/dist/services/resources/casStore.js +304 -0
- package/dist/services/resources/casStore.js.map +1 -0
- package/dist/services/resources/contracts.js +75 -0
- package/dist/services/resources/contracts.js.map +1 -0
- package/dist/services/resources/mime.js +77 -0
- package/dist/services/resources/mime.js.map +1 -0
- package/dist/services/resources/providerRegistry.js +22 -0
- package/dist/services/resources/providerRegistry.js.map +1 -0
- package/dist/services/resources/providers.js +120 -0
- package/dist/services/resources/providers.js.map +1 -0
- package/dist/services/resources/resourceService.js +282 -0
- package/dist/services/resources/resourceService.js.map +1 -0
- package/dist/services/runtime/contracts.js +65 -0
- package/dist/services/runtime/contracts.js.map +1 -0
- package/dist/services/runtime/runtimeService.js +364 -0
- package/dist/services/runtime/runtimeService.js.map +1 -0
- package/dist/services/schedules/scheduleService.js +198 -0
- package/dist/services/schedules/scheduleService.js.map +1 -0
- package/dist/services/search/searchService.js +434 -0
- package/dist/services/search/searchService.js.map +1 -0
- package/dist/services/search/searchWorker.js +58 -0
- package/dist/services/search/searchWorker.js.map +1 -0
- package/dist/setup/componentProbes.js +259 -0
- package/dist/setup/componentProbes.js.map +1 -0
- package/dist/setup/download.js +139 -0
- package/dist/setup/download.js.map +1 -0
- package/dist/setup/managedTools.js +118 -0
- package/dist/setup/managedTools.js.map +1 -0
- package/dist/setup/sandboxProbe.js +172 -0
- package/dist/setup/sandboxProbe.js.map +1 -0
- package/dist/setup/setup.js +522 -0
- package/dist/setup/setup.js.map +1 -0
- package/dist/setup/windowsChromiumAcl.js +56 -0
- package/dist/setup/windowsChromiumAcl.js.map +1 -0
- package/dist/setup/windowsSandboxInstall.js +94 -0
- package/dist/setup/windowsSandboxInstall.js.map +1 -0
- package/dist/setup/windowsSpeechInstall.js +86 -0
- package/dist/setup/windowsSpeechInstall.js.map +1 -0
- package/dist/store/db.js +711 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/scopeEncoding.js +15 -0
- package/dist/store/scopeEncoding.js.map +1 -0
- package/dist/store/store.js +467 -0
- package/dist/store/store.js.map +1 -0
- package/dist/tools/agentRuntimeTools.js +216 -0
- package/dist/tools/agentRuntimeTools.js.map +1 -0
- package/dist/tools/agentTools.js +317 -0
- package/dist/tools/agentTools.js.map +1 -0
- package/dist/tools/assistanceTools.js +126 -0
- package/dist/tools/assistanceTools.js.map +1 -0
- package/dist/tools/brainTools.js +130 -0
- package/dist/tools/brainTools.js.map +1 -0
- package/dist/tools/catalog.js +30 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/tools/changeTools.js +188 -0
- package/dist/tools/changeTools.js.map +1 -0
- package/dist/tools/context.js +243 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/contextTools.js +57 -0
- package/dist/tools/contextTools.js.map +1 -0
- package/dist/tools/coreCatalog.js +82 -0
- package/dist/tools/coreCatalog.js.map +1 -0
- package/dist/tools/desktopTools.js +41 -0
- package/dist/tools/desktopTools.js.map +1 -0
- package/dist/tools/directTools.js +273 -0
- package/dist/tools/directTools.js.map +1 -0
- package/dist/tools/envelope.js +71 -0
- package/dist/tools/envelope.js.map +1 -0
- package/dist/tools/extraTools.js +298 -0
- package/dist/tools/extraTools.js.map +1 -0
- package/dist/tools/gitTools.js +93 -0
- package/dist/tools/gitTools.js.map +1 -0
- package/dist/tools/jobTools.js +454 -0
- package/dist/tools/jobTools.js.map +1 -0
- package/dist/tools/memoryTools.js +102 -0
- package/dist/tools/memoryTools.js.map +1 -0
- package/dist/tools/metaTools.js +153 -0
- package/dist/tools/metaTools.js.map +1 -0
- package/dist/tools/multimodalTools.js +262 -0
- package/dist/tools/multimodalTools.js.map +1 -0
- package/dist/tools/projectTools.js +261 -0
- package/dist/tools/projectTools.js.map +1 -0
- package/dist/tools/resourceTools.js +81 -0
- package/dist/tools/resourceTools.js.map +1 -0
- package/dist/tools/runtimeTools.js +137 -0
- package/dist/tools/runtimeTools.js.map +1 -0
- package/dist/tools/scheduleTools.js +10 -0
- package/dist/tools/scheduleTools.js.map +1 -0
- package/dist/tools/semanticTools.js +141 -0
- package/dist/tools/semanticTools.js.map +1 -0
- package/dist/tools/subagentTools.js +32 -0
- package/dist/tools/subagentTools.js.map +1 -0
- package/dist/tools/surface.js +644 -0
- package/dist/tools/surface.js.map +1 -0
- package/dist/tunnel/control.js +113 -0
- package/dist/tunnel/control.js.map +1 -0
- package/dist/tunnel/credentials.js +392 -0
- package/dist/tunnel/credentials.js.map +1 -0
- package/dist/tunnel/log.js +84 -0
- package/dist/tunnel/log.js.map +1 -0
- package/dist/tunnel/runtime.js +55 -0
- package/dist/tunnel/runtime.js.map +1 -0
- package/dist/tunnel/supervisor.js +280 -0
- package/dist/tunnel/supervisor.js.map +1 -0
- package/dist/util/bytes.js +53 -0
- package/dist/util/bytes.js.map +1 -0
- package/dist/util/hash.js +53 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/workspace/fs.js +305 -0
- package/dist/workspace/fs.js.map +1 -0
- package/dist/workspace/identity.js +17 -0
- package/dist/workspace/identity.js.map +1 -0
- package/dist/workspace/ignores.js +173 -0
- package/dist/workspace/ignores.js.map +1 -0
- package/dist/workspace/root.js +59 -0
- package/dist/workspace/root.js.map +1 -0
- package/docs/AGENT_RUNTIME.md +154 -0
- package/docs/AI_PROVIDERS.md +110 -0
- package/docs/ARCHITECTURE.md +331 -0
- package/docs/ASSISTANCE.md +31 -0
- package/docs/AUTH.md +59 -0
- package/docs/BRAIN.md +92 -0
- package/docs/COMPATIBILITY.md +92 -0
- package/docs/CONFIRMATION.md +13 -0
- package/docs/CONTEXT.md +87 -0
- package/docs/DESKTOP.md +35 -0
- package/docs/EVALUATION.md +86 -0
- package/docs/LARGE_INPUTS.md +21 -0
- package/docs/LSP.md +21 -0
- package/docs/MANUAL_ACCEPTANCE.md +283 -0
- package/docs/MEMORY.md +128 -0
- package/docs/MULTIMODAL.md +32 -0
- package/docs/PROJECTS.md +146 -0
- package/docs/RELEASE_1.0.0.md +111 -0
- package/docs/RELEASE_NOTES.md +92 -0
- package/docs/RESOURCES.md +83 -0
- package/docs/RUNTIME.md +125 -0
- package/docs/SCHEDULES.md +23 -0
- package/docs/SECURITY.md +250 -0
- package/docs/TEST_REPORT.md +312 -0
- package/docs/TUNNEL.md +86 -0
- package/docs/WEB_CLIENTS.md +43 -0
- package/docs/WINDOWS.md +79 -0
- package/docs/adr/001-one-process-one-workspace.md +22 -0
- package/docs/adr/002-external-tunnel.md +19 -0
- package/docs/adr/003-sdk-v2-legacy-stateless.md +20 -0
- package/docs/adr/004-embedded-oauth-provider.md +19 -0
- package/docs/adr/005-static-client-baseline.md +19 -0
- package/docs/adr/006-guarded-fs-explicit-exec.md +16 -0
- package/docs/adr/007-preview-hash-journal.md +18 -0
- package/docs/adr/008-ts-js-semantics-first.md +17 -0
- package/docs/adr/009-jobs-polling.md +18 -0
- package/docs/adr/010-sqlite-better-sqlite3.md +18 -0
- package/docs/adr/011-env-example-secure-default.md +19 -0
- package/docs/adr/012-workspace-scope-grant.md +24 -0
- package/docs/adr/013-loopback-proxy-trust.md +18 -0
- package/docs/adr/014-direct-coding-tier.md +48 -0
- package/docs/adr/015-coding-agent-parity.md +56 -0
- package/docs/adr/016-oidc-openid-consent.md +15 -0
- package/docs/adr/017-installation-identity-local-config.md +44 -0
- package/docs/adr/018-access-scope-encoding.md +11 -0
- package/docs/adr/019-runtime-workspace-switch.md +59 -0
- package/docs/adr/020-desktop-access.md +50 -0
- package/docs/adr/021-persistent-desktop-consent.md +39 -0
- package/docs/adr/022-owner-kill-preserves-login.md +30 -0
- package/docs/adr/023-large-coding-inputs.md +49 -0
- package/docs/adr/024-usage-rounds-and-schedules.md +72 -0
- package/docs/adr/025-owner-chat-whitelist.md +53 -0
- package/docs/adr/026-remove-conversation-confirmation.md +35 -0
- package/docs/adr/027-workspace-client-list.md +20 -0
- package/docs/adr/028-owner-client-deletion.md +25 -0
- package/docs/adr/029-compact-tool-surface.md +121 -0
- package/docs/adr/030-windows-native-candidate.md +71 -0
- package/docs/adr/031-owner-selected-tunnel-supervision.md +13 -0
- package/docs/adr/032-owner-project-registry.md +43 -0
- package/docs/adr/033-read-only-project-federation.md +61 -0
- package/docs/adr/034-universal-resource-cas.md +60 -0
- package/docs/adr/035-project-brain-incremental-index.md +51 -0
- package/docs/adr/036-context-engine-evidence.md +53 -0
- package/docs/adr/037-owner-reviewed-memory.md +46 -0
- package/docs/adr/038-runtime-intelligence.md +46 -0
- package/docs/adr/039-advanced-agent-runtime.md +57 -0
- package/docs/adr/040-dodobench-release-gate.md +43 -0
- package/docs/adr/041-local-macos-docker-linux-gates.md +32 -0
- package/docs/adr/042-project-directory-generation-identity.md +36 -0
- package/docs/adr/043-trusted-self-hosted-platform-gates.md +38 -0
- package/docs/adr/044-global-launcher-and-cli-menu.md +43 -0
- package/docs/adr/045-ai-providers-multiproject.md +56 -0
- package/docs/adr/046-personal-access-mode.md +32 -0
- package/docs/adr/README.md +64 -0
- package/examples/.dodo.json.example +20 -0
- package/examples/cloudflared.yml +23 -0
- package/examples/reverse-proxy-fixture.mjs +37 -0
- package/native/desktop-linux.py +387 -0
- package/native/desktop-windows.cs +180 -0
- package/native/desktop.swift +212 -0
- package/package.json +145 -0
- package/schemas/global-config.schema.json +497 -0
- package/schemas/project-config.schema.json +75 -0
- package/schemas/tools.compact.json +3236 -0
- package/schemas/tools.hybrid.json +8194 -0
- package/schemas/tools.json +34518 -0
- package/scripts/guard-publish.mjs +12 -0
- package/scripts/setup-multimodal.mjs +70 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { phraseFor } from '../util/hash.js';
|
|
3
|
+
import { ALL_SCOPES } from '../security/policy.js';
|
|
4
|
+
import { INSTALLATION_AUTHORITY_EPOCH, INSTALLATION_AUTHORITY_ID, OWNER_ACCOUNT_ID } from './constants.js';
|
|
5
|
+
import { isPersonalMode } from '../security/accessMode.js';
|
|
6
|
+
/**
|
|
7
|
+
* Owner-consent interactions (spec §8.4).
|
|
8
|
+
*
|
|
9
|
+
* Flow: OAuth client starts → provider creates an interaction bound to the
|
|
10
|
+
* BROWSER session cookie → the page shows a request id + phrase → the owner
|
|
11
|
+
* verifies details on the terminal (`dodo auth pending`) and approves over
|
|
12
|
+
* the private IPC socket (`dodo auth approve -- <id>`) → the SAME browser
|
|
13
|
+
* session completes the interaction (custom-header + SameSite protected) →
|
|
14
|
+
* the provider issues the code to the registered exact redirect URI.
|
|
15
|
+
*
|
|
16
|
+
* The public listener has NO endpoint that approves an interaction from a
|
|
17
|
+
* request id alone: approval state changes only over local IPC, and the
|
|
18
|
+
* complete endpoint requires the provider's own session cookie.
|
|
19
|
+
*/
|
|
20
|
+
const MAX_PENDING_OAUTH = 20;
|
|
21
|
+
export const OAUTH_INTERACTION_TTL_MS = 5 * 60 * 1000;
|
|
22
|
+
export function interactionRouter(opts) {
|
|
23
|
+
const { provider, store } = opts;
|
|
24
|
+
const authority = { workspaceId: INSTALLATION_AUTHORITY_ID, epoch: INSTALLATION_AUTHORITY_EPOCH };
|
|
25
|
+
const router = Router();
|
|
26
|
+
router.get('/interaction/:uid', async (req, res) => {
|
|
27
|
+
try {
|
|
28
|
+
const details = await provider.interactionDetails(req, res);
|
|
29
|
+
const params = details.params;
|
|
30
|
+
const clientId = String(params['client_id'] ?? '');
|
|
31
|
+
if (!store.getOAuthClient(clientId))
|
|
32
|
+
throw new Error('unknown client');
|
|
33
|
+
const redirectUri = String(params['redirect_uri'] ?? '');
|
|
34
|
+
const requested = typeof params['scope'] === 'string' ? params['scope'].split(' ').filter(Boolean) : [];
|
|
35
|
+
const scopes = requested.filter((s) => ALL_SCOPES.includes(s));
|
|
36
|
+
const effectiveScopes = scopes.length > 0 ? scopes : [...ALL_SCOPES];
|
|
37
|
+
const { workspaceId, epoch } = authority;
|
|
38
|
+
const existing = store.getApproval(details.uid);
|
|
39
|
+
if (existing && (existing.workspaceId !== workspaceId || existing.epoch !== epoch)) {
|
|
40
|
+
res.status(400).send('Workspace changed; start a fresh authorization request.');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!existing) {
|
|
44
|
+
if (store.listPendingApprovals('oauth').length >= MAX_PENDING_OAUTH) {
|
|
45
|
+
res.status(429).type('text/plain').send('Too many pending authorization requests. Try again later.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const summary = {
|
|
49
|
+
clientId,
|
|
50
|
+
redirectUri,
|
|
51
|
+
scopes: effectiveScopes,
|
|
52
|
+
phrase: phraseFor(details.uid),
|
|
53
|
+
};
|
|
54
|
+
store.createApproval({
|
|
55
|
+
kind: 'oauth',
|
|
56
|
+
workspaceId,
|
|
57
|
+
epoch,
|
|
58
|
+
id: details.uid,
|
|
59
|
+
summary: JSON.stringify(summary),
|
|
60
|
+
ttlMs: OAUTH_INTERACTION_TTL_MS,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
res
|
|
64
|
+
.status(200)
|
|
65
|
+
.type('html')
|
|
66
|
+
.setHeader('Cache-Control', 'no-store')
|
|
67
|
+
.setHeader('Content-Security-Policy', "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src 'self'")
|
|
68
|
+
.send(interactionPage(details.uid, phraseFor(details.uid), clientId, effectiveScopes, isPersonalMode(store)));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
res.status(400).type('text/plain').send('Unknown or expired authorization request.');
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
router.get('/interaction/:uid/status', async (req, res) => {
|
|
75
|
+
try {
|
|
76
|
+
const details = await provider.interactionDetails(req, res); // session-cookie bound
|
|
77
|
+
const approval = store.getApproval(details.uid);
|
|
78
|
+
res.setHeader('Cache-Control', 'no-store').json({ status: approval?.status ?? 'pending' });
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
res.status(400).json({ status: 'unknown' });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
router.post('/interaction/:uid/complete', async (req, res) => {
|
|
85
|
+
try {
|
|
86
|
+
const details = await provider.interactionDetails(req, res); // session-cookie bound
|
|
87
|
+
// Cross-site form posts cannot set custom headers; require one.
|
|
88
|
+
if (req.headers['x-dodo-interaction'] !== details.uid) {
|
|
89
|
+
res.status(403).json({ error: 'bad interaction header' });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const { workspaceId, epoch } = authority;
|
|
93
|
+
const approval = store.getApproval(details.uid);
|
|
94
|
+
if (!approval || approval.kind !== 'oauth' || approval.workspaceId !== workspaceId || approval.epoch !== epoch || approval.status !== 'approved') {
|
|
95
|
+
res.status(403).json({ error: 'not approved' });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!store.setApprovalStatus(details.uid, 'consumed')) {
|
|
99
|
+
res.status(403).json({ error: 'approval expired' });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const summary = JSON.parse(approval.summary);
|
|
103
|
+
const params = details.params;
|
|
104
|
+
const clientId = String(params['client_id'] ?? '');
|
|
105
|
+
if (clientId !== summary.clientId || !store.getOAuthClient(clientId)) {
|
|
106
|
+
res.status(403).json({ error: 'client mismatch' });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const grant = new provider.Grant({ accountId: OWNER_ACCOUNT_ID, clientId });
|
|
110
|
+
// Grant at both levels: OIDC scope satisfies the authorization request's
|
|
111
|
+
// `scope` param; resource scope binds the token audience to /mcp.
|
|
112
|
+
// OIDC clients request openid in addition to resource permissions. It
|
|
113
|
+
// must be consented at the OIDC level or the provider prompts forever.
|
|
114
|
+
// Never add it to the workspace's resource permissions.
|
|
115
|
+
const requestedScopes = typeof params['scope'] === 'string' ? params['scope'].split(/\s+/) : [];
|
|
116
|
+
const oidcScopes = [...summary.scopes, 'offline_access'];
|
|
117
|
+
if (requestedScopes.includes('openid'))
|
|
118
|
+
oidcScopes.push('openid');
|
|
119
|
+
grant.addOIDCScope(oidcScopes.join(' '));
|
|
120
|
+
grant.addResourceScope(opts.resourceUrl, summary.scopes.join(' '));
|
|
121
|
+
const grantId = await grant.save();
|
|
122
|
+
// Deletion may run while provider persistence yields. Never recreate ACLs.
|
|
123
|
+
if (!store.getOAuthClient(clientId)) {
|
|
124
|
+
await grant.destroy();
|
|
125
|
+
throw new Error('client was deleted');
|
|
126
|
+
}
|
|
127
|
+
store.putGrant({
|
|
128
|
+
id: grantId,
|
|
129
|
+
workspaceId,
|
|
130
|
+
clientId,
|
|
131
|
+
accountId: OWNER_ACCOUNT_ID,
|
|
132
|
+
scopes: summary.scopes,
|
|
133
|
+
});
|
|
134
|
+
store.setMeta(`identity-grant:${grantId}`, '2');
|
|
135
|
+
const returnTo = await provider.interactionResult(req, res, { login: { accountId: OWNER_ACCOUNT_ID }, consent: { grantId } }, { mergeWithLastSubmission: false });
|
|
136
|
+
res.setHeader('Cache-Control', 'no-store').json({ returnTo });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
res.status(400).json({ error: 'interaction failed' });
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
return router;
|
|
143
|
+
}
|
|
144
|
+
function interactionPage(uid, phrase, clientId, scopes, personal) {
|
|
145
|
+
const esc = (s) => s.replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]);
|
|
146
|
+
return `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>DODO authorization</title>
|
|
147
|
+
<body style="font-family:system-ui;max-width:38rem;margin:3rem auto;line-height:1.5;padding:0 1rem">
|
|
148
|
+
<h1 style="font-size:1.4rem">Authorize this connection on your terminal</h1>
|
|
149
|
+
<p>A client is asking to connect to this DODO installation.</p>
|
|
150
|
+
<p><strong>${personal ? 'Personal mode is active.' : 'Managed mode is active.'}</strong> ${personal ? 'After local approval, this client can use owner-registered projects according to these OAuth scopes; no second project permission step is needed.' : 'This login grants no project access. The owner assigns each project and its read/write/exec scopes later in Local Config.'}</p>
|
|
151
|
+
<table style="border-collapse:collapse">
|
|
152
|
+
<tr><td style="padding:.2rem .8rem .2rem 0;color:#555">Request ID</td><td><code>${esc(uid)}</code></td></tr>
|
|
153
|
+
<tr><td style="padding:.2rem .8rem .2rem 0;color:#555">Check phrase</td><td><strong>${esc(phrase)}</strong></td></tr>
|
|
154
|
+
<tr><td style="padding:.2rem .8rem .2rem 0;color:#555">Client</td><td><code>${esc(clientId)}</code></td></tr>
|
|
155
|
+
<tr><td style="padding:.2rem .8rem .2rem 0;color:#555">Scopes</td><td><code>${esc(scopes.join(' '))}</code></td></tr>
|
|
156
|
+
</table>
|
|
157
|
+
<p>On the machine running DODO, verify the same request ID, phrase, client and callback URL with:</p>
|
|
158
|
+
<pre style="background:#f4f4f4;padding:.6rem">dodo auth pending
|
|
159
|
+
dodo auth approve -- ${esc(uid)}</pre>
|
|
160
|
+
<p id="st" aria-live="polite">Waiting for local approval…</p>
|
|
161
|
+
<script>
|
|
162
|
+
(function(){
|
|
163
|
+
var uid=${JSON.stringify(uid)};
|
|
164
|
+
var done=false;
|
|
165
|
+
function tick(){
|
|
166
|
+
if(done)return;
|
|
167
|
+
fetch('/interaction/'+uid+'/status',{headers:{'accept':'application/json'}}).then(function(r){return r.json()}).then(function(d){
|
|
168
|
+
if(d.status==='approved'){
|
|
169
|
+
done=true;
|
|
170
|
+
document.getElementById('st').textContent='Approved — finishing sign-in…';
|
|
171
|
+
fetch('/interaction/'+uid+'/complete',{method:'POST',headers:{'x-dodo-interaction':uid}}).then(function(r){return r.json()}).then(function(d){
|
|
172
|
+
if(d.returnTo){window.location.assign(d.returnTo);}else{document.getElementById('st').textContent='Error: '+(d.error||'unknown');}
|
|
173
|
+
});
|
|
174
|
+
} else if(d.status==='denied'||d.status==='expired'){
|
|
175
|
+
done=true;document.getElementById('st').textContent='Request '+d.status+'.';
|
|
176
|
+
} else { setTimeout(tick,2000); }
|
|
177
|
+
}).catch(function(){setTimeout(tick,3000)});
|
|
178
|
+
}
|
|
179
|
+
tick();
|
|
180
|
+
})();
|
|
181
|
+
</script>
|
|
182
|
+
</body>`;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=interactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactions.js","sourceRoot":"","sources":["../../src/auth/interactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { generateKeyPairSync, randomBytes, createPrivateKey, createPublicKey } from 'node:crypto';
|
|
3
|
+
import { DodoError } from '../errors.js';
|
|
4
|
+
export function loadOrCreateJwks(jwksFile) {
|
|
5
|
+
try {
|
|
6
|
+
const raw = fs.readFileSync(jwksFile, 'utf8');
|
|
7
|
+
const parsed = JSON.parse(raw);
|
|
8
|
+
if (!Array.isArray(parsed.keys) || parsed.keys.length === 0)
|
|
9
|
+
throw new Error('empty');
|
|
10
|
+
return parsed;
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
if (err.code !== 'ENOENT') {
|
|
14
|
+
throw new DodoError('INTERNAL_ERROR', 'signing key store is corrupt; refusing to regenerate silently', {
|
|
15
|
+
recovery: `inspect ${jwksFile}; deleting it invalidates all issued tokens`,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const { privateKey } = generateKeyPairSync('ec', { namedCurve: 'P-256' });
|
|
20
|
+
const jwk = privateKey.export({ format: 'jwk' });
|
|
21
|
+
jwk['kid'] = `dodo-${randomBytes(6).toString('hex')}`;
|
|
22
|
+
jwk['alg'] = 'ES256';
|
|
23
|
+
jwk['use'] = 'sig';
|
|
24
|
+
const out = { keys: [jwk] };
|
|
25
|
+
fs.writeFileSync(jwksFile, JSON.stringify(out, null, 2), { mode: 0o600 });
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/** Public JWKS derived from the private file (for local verification). */
|
|
29
|
+
export function publicJwks(jwks) {
|
|
30
|
+
return {
|
|
31
|
+
keys: jwks.keys.map((priv) => {
|
|
32
|
+
const key = createPrivateKey({ key: priv, format: 'jwk' });
|
|
33
|
+
const pub = createPublicKey(key).export({ format: 'jwk' });
|
|
34
|
+
pub['kid'] = priv['kid'];
|
|
35
|
+
pub['alg'] = priv['alg'];
|
|
36
|
+
pub['use'] = 'sig';
|
|
37
|
+
return pub;
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function loadOrCreateCookieKeys(cookieKeysFile) {
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(fs.readFileSync(cookieKeysFile, 'utf8'));
|
|
44
|
+
if (Array.isArray(parsed.keys) && parsed.keys.length > 0)
|
|
45
|
+
return parsed.keys;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
if (err.code !== 'ENOENT') {
|
|
49
|
+
throw new DodoError('INTERNAL_ERROR', 'cookie key store is corrupt', { recovery: `inspect ${cookieKeysFile}` });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const keys = [randomBytes(32).toString('hex'), randomBytes(32).toString('hex')];
|
|
53
|
+
fs.writeFileSync(cookieKeysFile, JSON.stringify({ keys }, null, 2), { mode: 0o600 });
|
|
54
|
+
return keys;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/auth/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import Provider from 'oidc-provider';
|
|
2
|
+
import { createAdapterFactory } from './adapter.js';
|
|
3
|
+
import { ALL_SCOPES } from '../security/policy.js';
|
|
4
|
+
import { OWNER_ACCOUNT_ID } from './constants.js';
|
|
5
|
+
export { OWNER_ACCOUNT_ID } from './constants.js';
|
|
6
|
+
export function buildProvider(opts) {
|
|
7
|
+
const { store, resourceUrl } = opts;
|
|
8
|
+
const activeWorkspaceId = () => (typeof opts.workspaceId === 'function' ? opts.workspaceId() : opts.workspaceId);
|
|
9
|
+
const scopeString = ALL_SCOPES.join(' ');
|
|
10
|
+
const configuration = {
|
|
11
|
+
adapter: createAdapterFactory(store),
|
|
12
|
+
clients: [],
|
|
13
|
+
jwks: { keys: opts.jwks.keys },
|
|
14
|
+
cookies: {
|
|
15
|
+
keys: opts.cookieKeys,
|
|
16
|
+
short: { signed: true, httpOnly: true, sameSite: 'lax' },
|
|
17
|
+
long: { signed: true, httpOnly: true, sameSite: 'lax' },
|
|
18
|
+
},
|
|
19
|
+
// dodo:* are advertised both as global scopes (so the authorization
|
|
20
|
+
// request's `scope` param is accepted) and as resource scopes via
|
|
21
|
+
// resourceIndicators below (so the access token's audience is the /mcp
|
|
22
|
+
// resource). The grant binds both levels; the verifier still checks the
|
|
23
|
+
// exact resource audience.
|
|
24
|
+
scopes: ['offline_access', ...ALL_SCOPES],
|
|
25
|
+
claims: {},
|
|
26
|
+
clientDefaults: {
|
|
27
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
28
|
+
response_types: ['code'],
|
|
29
|
+
token_endpoint_auth_method: 'client_secret_basic',
|
|
30
|
+
// The signing key set is ES256-only; align client alg defaults with it.
|
|
31
|
+
id_token_signed_response_alg: 'ES256',
|
|
32
|
+
},
|
|
33
|
+
pkce: {
|
|
34
|
+
required: () => true,
|
|
35
|
+
},
|
|
36
|
+
responseTypes: ['code'],
|
|
37
|
+
interactions: {
|
|
38
|
+
// The default login+consent policy still applies; we simply render the
|
|
39
|
+
// prompt ourselves (owner terminal approval) at this URL. On resume the
|
|
40
|
+
// interaction result carries both login and consent, satisfying it.
|
|
41
|
+
url: (_ctx, interaction) => `/interaction/${interaction.uid}`,
|
|
42
|
+
},
|
|
43
|
+
findAccount: async (_ctx, id) => id === OWNER_ACCOUNT_ID
|
|
44
|
+
? {
|
|
45
|
+
accountId: OWNER_ACCOUNT_ID,
|
|
46
|
+
claims: async () => ({ sub: OWNER_ACCOUNT_ID }),
|
|
47
|
+
}
|
|
48
|
+
: undefined,
|
|
49
|
+
/**
|
|
50
|
+
* Reuse the DODO grant the owner just approved (or approved earlier) for
|
|
51
|
+
* THIS client and THIS workspace. Consent for the single owner is granted
|
|
52
|
+
* once over local IPC; the flow must not then re-prompt in the browser.
|
|
53
|
+
* A grant bound to a different workspace never authorizes this one (spec
|
|
54
|
+
* §6, AUTH-07) — it is filtered out, forcing a fresh owner approval.
|
|
55
|
+
*/
|
|
56
|
+
loadExistingGrant: async (ctx) => {
|
|
57
|
+
const clientId = ctx.oidc.client?.clientId;
|
|
58
|
+
const result = ctx.oidc.result;
|
|
59
|
+
const accountId = ctx.oidc.session?.accountId ?? result?.login?.accountId;
|
|
60
|
+
if (!clientId || accountId !== OWNER_ACCOUNT_ID)
|
|
61
|
+
return undefined;
|
|
62
|
+
// Prefer a grantId explicitly carried by the just-submitted interaction.
|
|
63
|
+
const explicit = result?.consent?.grantId;
|
|
64
|
+
const wsId = activeWorkspaceId();
|
|
65
|
+
const candidate = (explicit && store.getGrant(explicit)) ||
|
|
66
|
+
store
|
|
67
|
+
.listGrants()
|
|
68
|
+
.filter((g) => g.clientId === clientId && g.revokedAt === null && (g.workspaceId === wsId || store.getMeta(`identity-grant:${g.id}`) === '2'))
|
|
69
|
+
.pop();
|
|
70
|
+
if (!candidate || candidate.revokedAt !== null || (candidate.workspaceId !== wsId && store.getMeta(`identity-grant:${candidate.id}`) !== '2'))
|
|
71
|
+
return undefined;
|
|
72
|
+
return ctx.oidc.provider.Grant.find(candidate.id);
|
|
73
|
+
},
|
|
74
|
+
issueRefreshToken: async (_ctx, client) => client.grantTypeAllowed('refresh_token'),
|
|
75
|
+
rotateRefreshToken: true,
|
|
76
|
+
extraTokenClaims: async (_ctx, token) => {
|
|
77
|
+
// Preserve the original grant and version across refresh. dodo_ws is
|
|
78
|
+
// retained for legacy tokens; v2 authorization checks the active ACL.
|
|
79
|
+
const grantId = token.grantId;
|
|
80
|
+
const appGrant = grantId ? store.getGrant(grantId) : undefined;
|
|
81
|
+
return {
|
|
82
|
+
dodo_grant: grantId ?? null,
|
|
83
|
+
dodo_ws: appGrant?.workspaceId ?? null,
|
|
84
|
+
dodo_auth: grantId && store.getMeta(`identity-grant:${grantId}`) === '2' ? 2 : 1,
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
ttl: {
|
|
88
|
+
AccessToken: opts.accessTokenTtlSec ?? 600,
|
|
89
|
+
IdToken: 600,
|
|
90
|
+
AuthorizationCode: 60,
|
|
91
|
+
Grant: 30 * 24 * 3600,
|
|
92
|
+
Interaction: 300,
|
|
93
|
+
Session: 14 * 24 * 3600,
|
|
94
|
+
RefreshToken: 30 * 24 * 3600,
|
|
95
|
+
},
|
|
96
|
+
features: {
|
|
97
|
+
devInteractions: { enabled: false },
|
|
98
|
+
revocation: { enabled: true },
|
|
99
|
+
introspection: { enabled: false },
|
|
100
|
+
registration: { enabled: false }, // DCR off by default (spec §8.3)
|
|
101
|
+
rpInitiatedLogout: { enabled: false },
|
|
102
|
+
resourceIndicators: {
|
|
103
|
+
enabled: true,
|
|
104
|
+
defaultResource: () => resourceUrl,
|
|
105
|
+
useGrantedResource: () => true,
|
|
106
|
+
getResourceServerInfo: () => ({
|
|
107
|
+
scope: scopeString,
|
|
108
|
+
audience: resourceUrl,
|
|
109
|
+
accessTokenTTL: opts.accessTokenTtlSec ?? 600,
|
|
110
|
+
accessTokenFormat: 'jwt',
|
|
111
|
+
jwt: { sign: { alg: 'ES256' } },
|
|
112
|
+
}),
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
renderError: async (ctx, out, _error) => {
|
|
116
|
+
ctx.type = 'html';
|
|
117
|
+
ctx.body = `<!doctype html><meta charset="utf-8"><title>DODO auth error</title><body style="font-family:system-ui;max-width:36rem;margin:4rem auto"><h1>Authorization error</h1><p>${escapeHtml(out.error ?? 'error')}</p><p>${escapeHtml(out.error_description ?? '')}</p></body>`;
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const provider = new Provider(opts.issuer, configuration);
|
|
121
|
+
// The only hop in front of DODO is the owner's local tunnel daemon on
|
|
122
|
+
// loopback; X-Forwarded-Proto from it is trusted so secure-cookie and
|
|
123
|
+
// https checks reflect the public HTTPS origin (ADR-013; Host is
|
|
124
|
+
// allowlisted before the provider ever sees a request).
|
|
125
|
+
provider.proxy = true;
|
|
126
|
+
return provider;
|
|
127
|
+
}
|
|
128
|
+
function escapeHtml(s) {
|
|
129
|
+
return s.replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/auth/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createLocalJWKSet, jwtVerify } from 'jose';
|
|
2
|
+
import { OAuthError, OAuthErrorCode } from '@modelcontextprotocol/server';
|
|
3
|
+
import { publicJwks } from './keys.js';
|
|
4
|
+
export function buildTokenVerifier(opts) {
|
|
5
|
+
const jwkSet = createLocalJWKSet(publicJwks(opts.jwks));
|
|
6
|
+
const active = () => {
|
|
7
|
+
if (opts.active)
|
|
8
|
+
return opts.active();
|
|
9
|
+
if (opts.workspaceId === undefined || opts.store === undefined)
|
|
10
|
+
throw new Error('verifier needs workspaceId+store or active()');
|
|
11
|
+
return { workspaceId: opts.workspaceId, store: opts.store };
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
async verifyAccessToken(token) {
|
|
15
|
+
const { workspaceId, store } = active();
|
|
16
|
+
let payload;
|
|
17
|
+
try {
|
|
18
|
+
const result = await jwtVerify(token, jwkSet, {
|
|
19
|
+
issuer: opts.issuer,
|
|
20
|
+
audience: opts.resourceUrl,
|
|
21
|
+
algorithms: ['ES256'],
|
|
22
|
+
typ: 'at+jwt',
|
|
23
|
+
});
|
|
24
|
+
payload = result.payload;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new OAuthError(OAuthErrorCode.InvalidToken, 'invalid access token');
|
|
28
|
+
}
|
|
29
|
+
const grantId = payload['dodo_grant'];
|
|
30
|
+
const tokenWs = payload['dodo_ws'];
|
|
31
|
+
const clientId = payload['client_id'];
|
|
32
|
+
const exp = payload['exp'];
|
|
33
|
+
if (typeof grantId !== 'string' || typeof tokenWs !== 'string' || typeof clientId !== 'string' || typeof exp !== 'number') {
|
|
34
|
+
throw new OAuthError(OAuthErrorCode.InvalidToken, 'invalid access token');
|
|
35
|
+
}
|
|
36
|
+
const grant = store.getGrant(grantId);
|
|
37
|
+
if (!store.getOAuthClient(clientId) || !grant || grant.revokedAt !== null) {
|
|
38
|
+
throw new OAuthError(OAuthErrorCode.InvalidToken, 'grant revoked or unknown');
|
|
39
|
+
}
|
|
40
|
+
if (grant.clientId !== clientId) {
|
|
41
|
+
throw new OAuthError(OAuthErrorCode.InvalidToken, 'client mismatch');
|
|
42
|
+
}
|
|
43
|
+
const identityGrant = payload['dodo_auth'] === 2 && store.getMeta(`identity-grant:${grantId}`) === '2';
|
|
44
|
+
if (!identityGrant && (tokenWs !== grant.workspaceId || (!opts.targetRouting && tokenWs !== workspaceId))) {
|
|
45
|
+
// Token from another workspace on the same hostname: consent is
|
|
46
|
+
// per-workspace; never disclose the current root in the refusal.
|
|
47
|
+
throw new OAuthError(OAuthErrorCode.InvalidToken, 'token is not valid for this workspace');
|
|
48
|
+
}
|
|
49
|
+
let scopes = typeof payload['scope'] === 'string' ? payload['scope'].split(' ').filter(Boolean) : [];
|
|
50
|
+
const tokenScopes = [...scopes];
|
|
51
|
+
{
|
|
52
|
+
const access = store.clientAccess(workspaceId, clientId);
|
|
53
|
+
scopes = scopes.filter((scope) => access.includes(scope) && grant.scopes.includes(scope));
|
|
54
|
+
// Authentication remains valid with no workspace permissions. Tool gate
|
|
55
|
+
// returns WORKSPACE_ACCESS_REQUIRED without an OAuth relinking challenge.
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
token,
|
|
59
|
+
clientId,
|
|
60
|
+
scopes,
|
|
61
|
+
expiresAt: exp,
|
|
62
|
+
resource: new URL(opts.resourceUrl),
|
|
63
|
+
extra: {
|
|
64
|
+
tokenScopes,
|
|
65
|
+
identityGrant,
|
|
66
|
+
grantId,
|
|
67
|
+
workspaceId,
|
|
68
|
+
sub: typeof payload['sub'] === 'string' ? payload['sub'] : 'owner',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../src/auth/verifier.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/kill.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { ipcIdentity } from '../ipc/authentication.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { ipcSocketPath, statePaths } from '../config/paths.js';
|
|
5
|
+
import { openDatabaseReadonly } from '../store/db.js';
|
|
6
|
+
import { Store } from '../store/store.js';
|
|
7
|
+
import { mintWorkspaceId } from '../workspace/identity.js';
|
|
8
|
+
import { ipcCall, IpcError } from '../ipc/client.js';
|
|
9
|
+
const LiveStatus = z.looseObject({
|
|
10
|
+
pid: z.number().int().positive(), root: z.string().min(1).max(4096),
|
|
11
|
+
workspaceId: z.string(), workspaceEpoch: z.string().min(1),
|
|
12
|
+
version: z.string(), transport: z.enum(['http', 'stdio']),
|
|
13
|
+
});
|
|
14
|
+
/** Owner-only shutdown discovery. Never sends signals to PIDs or scans ports. */
|
|
15
|
+
export async function killServers(configDir, timeoutMs = 30_000) {
|
|
16
|
+
const report = { configDir, stopped: [], failed: [], authPreserved: true };
|
|
17
|
+
const dbFile = statePaths(configDir).dbFile;
|
|
18
|
+
if (!fs.existsSync(dbFile))
|
|
19
|
+
return report;
|
|
20
|
+
const db = openDatabaseReadonly(dbFile);
|
|
21
|
+
if (!db)
|
|
22
|
+
throw new Error('cannot read DODO state; no processes were stopped');
|
|
23
|
+
const candidates = [];
|
|
24
|
+
try {
|
|
25
|
+
const secret = new Store(db).readInstallSecret();
|
|
26
|
+
if (!secret)
|
|
27
|
+
throw new Error('DODO installation identity is missing; no processes were stopped');
|
|
28
|
+
let roots = db.prepare('SELECT id, root FROM workspaces ORDER BY root LIMIT 10001').all();
|
|
29
|
+
if (roots.length > 10000)
|
|
30
|
+
throw new Error('too many workspace records to inspect safely; use dodo stop for a specific workspace');
|
|
31
|
+
roots = roots.filter(w => typeof w.root === 'string' && typeof w.id === 'string' && w.id === mintWorkspaceId(secret, w.root));
|
|
32
|
+
for (const w of roots)
|
|
33
|
+
candidates.push({ ...w, socket: ipcSocketPath(configDir, w.id, { createDirectory: false }) });
|
|
34
|
+
const instances = db.prepare("SELECT value FROM meta WHERE key LIKE 'ipc-instance:%' LIMIT 10001").all();
|
|
35
|
+
if (instances.length > 10000)
|
|
36
|
+
throw new Error('too many instance records to inspect safely');
|
|
37
|
+
const Instance = z.object({ socketKey: z.string().regex(/^[a-f0-9]{32}$/), workspaceId: z.string(), root: z.string() }).strict();
|
|
38
|
+
for (const row of instances) {
|
|
39
|
+
try {
|
|
40
|
+
const i = Instance.parse(JSON.parse(row.value));
|
|
41
|
+
if (!roots.some(w => w.id === i.workspaceId && w.root === i.root))
|
|
42
|
+
continue;
|
|
43
|
+
candidates.unshift({ id: i.workspaceId, root: i.root, socket: ipcSocketPath(configDir, i.socketKey, { createDirectory: false }), instance: true });
|
|
44
|
+
}
|
|
45
|
+
catch { /* malformed historical metadata cannot authorize a target */ }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
db.close();
|
|
50
|
+
}
|
|
51
|
+
// Probe all candidates before stopping anything, so root aliases cannot race
|
|
52
|
+
// their per-instance endpoints. Never trust stored PIDs as signal targets.
|
|
53
|
+
// Windows identity/credential validation runs synchronous ACL probes. A
|
|
54
|
+
// second worker would block the event loop while the first awaits its IPC
|
|
55
|
+
// handshake, spending that request's deadline on unrelated PowerShell work.
|
|
56
|
+
// Serialize there; retain every live identity and credential recheck.
|
|
57
|
+
const concurrency = process.platform === 'win32' ? 1 : 8;
|
|
58
|
+
const live = new Map();
|
|
59
|
+
let index = 0;
|
|
60
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, candidates.length) }, async () => {
|
|
61
|
+
while (index < candidates.length) {
|
|
62
|
+
const w = candidates[index++], { socket } = w;
|
|
63
|
+
try {
|
|
64
|
+
const original = socketIdentity(socket);
|
|
65
|
+
if (!original)
|
|
66
|
+
continue;
|
|
67
|
+
let status;
|
|
68
|
+
try {
|
|
69
|
+
status = LiveStatus.parse(await ipcCall(socket, 'status', {}, 1500));
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
if (isNotRunning(e))
|
|
73
|
+
continue;
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
if (status.workspaceId !== w.id || status.root !== w.root)
|
|
77
|
+
throw new Error('IPC identity does not match the registered workspace');
|
|
78
|
+
if (socketIdentity(socket) !== original)
|
|
79
|
+
throw new Error('server changed while checking; retry dodo kill');
|
|
80
|
+
if (!live.has(status.pid) || (w.instance && !live.get(status.pid).candidate.instance))
|
|
81
|
+
live.set(status.pid, { candidate: w, status, identity: original });
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
if (!isNotRunning(e))
|
|
85
|
+
report.failed.push({ root: w.root, reason: e instanceof Error ? e.message : 'shutdown failed' });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}));
|
|
89
|
+
const targets = [...live.values()];
|
|
90
|
+
index = 0;
|
|
91
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, targets.length) }, async () => {
|
|
92
|
+
while (index < targets.length) {
|
|
93
|
+
const { candidate: w, status, identity } = targets[index++];
|
|
94
|
+
try {
|
|
95
|
+
if (socketIdentity(w.socket) !== identity)
|
|
96
|
+
throw new Error('server changed before shutdown; retry dodo kill');
|
|
97
|
+
const result = await ipcCall(w.socket, 'stop', { expectedPid: status.pid, expectedEpoch: status.workspaceEpoch }, 1500);
|
|
98
|
+
if (!z.object({ stopping: z.literal(true) }).safeParse(result).success)
|
|
99
|
+
throw new Error('server did not acknowledge shutdown');
|
|
100
|
+
const deadline = Date.now() + timeoutMs;
|
|
101
|
+
while (socketIdentity(w.socket) === identity) {
|
|
102
|
+
if (Date.now() >= deadline)
|
|
103
|
+
throw new Error('shutdown is still draining work; retry status later (no force kill sent)');
|
|
104
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
105
|
+
}
|
|
106
|
+
report.stopped.push({ pid: status.pid, root: status.root, transport: status.transport });
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
if (!isNotRunning(e))
|
|
110
|
+
report.failed.push({ root: w.root, reason: e instanceof Error ? e.message : 'shutdown failed' });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
report.stopped.sort((a, b) => a.root.localeCompare(b.root));
|
|
115
|
+
report.failed.sort((a, b) => a.root.localeCompare(b.root));
|
|
116
|
+
return report;
|
|
117
|
+
}
|
|
118
|
+
function isNotRunning(e) {
|
|
119
|
+
return e instanceof IpcError && e.message.startsWith('no running DODO server');
|
|
120
|
+
}
|
|
121
|
+
function socketIdentity(socket) {
|
|
122
|
+
return ipcIdentity(socket);
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=kill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kill.js","sourceRoot":"","sources":["../../src/cli/kill.ts"],"names":[],"mappings":"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"}
|