@cat-factory/server 0.6.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/dist/agents/CompositeAgentExecutor.d.ts +39 -0
- package/dist/agents/CompositeAgentExecutor.d.ts.map +1 -0
- package/dist/agents/CompositeAgentExecutor.js +169 -0
- package/dist/agents/CompositeAgentExecutor.js.map +1 -0
- package/dist/agents/ContainerAgentExecutor.d.ts +235 -0
- package/dist/agents/ContainerAgentExecutor.d.ts.map +1 -0
- package/dist/agents/ContainerAgentExecutor.js +825 -0
- package/dist/agents/ContainerAgentExecutor.js.map +1 -0
- package/dist/agents/ContainerRepoBootstrapper.d.ts +78 -0
- package/dist/agents/ContainerRepoBootstrapper.d.ts.map +1 -0
- package/dist/agents/ContainerRepoBootstrapper.js +279 -0
- package/dist/agents/ContainerRepoBootstrapper.js.map +1 -0
- package/dist/agents/ModelRouter.d.ts +69 -0
- package/dist/agents/ModelRouter.d.ts.map +1 -0
- package/dist/agents/ModelRouter.js +84 -0
- package/dist/agents/ModelRouter.js.map +1 -0
- package/dist/agents/RunnerJobClient.d.ts +41 -0
- package/dist/agents/RunnerJobClient.d.ts.map +1 -0
- package/dist/agents/RunnerJobClient.js +43 -0
- package/dist/agents/RunnerJobClient.js.map +1 -0
- package/dist/agents/modelProviderResolver.d.ts +33 -0
- package/dist/agents/modelProviderResolver.d.ts.map +1 -0
- package/dist/agents/modelProviderResolver.js +48 -0
- package/dist/agents/modelProviderResolver.js.map +1 -0
- package/dist/agents/providerCapabilities.d.ts +22 -0
- package/dist/agents/providerCapabilities.d.ts.map +1 -0
- package/dist/agents/providerCapabilities.js +43 -0
- package/dist/agents/providerCapabilities.js.map +1 -0
- package/dist/agents/resolveRepoTarget.d.ts +33 -0
- package/dist/agents/resolveRepoTarget.d.ts.map +1 -0
- package/dist/agents/resolveRepoTarget.js +81 -0
- package/dist/agents/resolveRepoTarget.js.map +1 -0
- package/dist/app.d.ts +12 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +102 -0
- package/dist/app.js.map +1 -0
- package/dist/auth/GitHubOAuth.d.ts +39 -0
- package/dist/auth/GitHubOAuth.d.ts.map +1 -0
- package/dist/auth/GitHubOAuth.js +90 -0
- package/dist/auth/GitHubOAuth.js.map +1 -0
- package/dist/auth/GoogleOAuth.d.ts +35 -0
- package/dist/auth/GoogleOAuth.d.ts.map +1 -0
- package/dist/auth/GoogleOAuth.js +66 -0
- package/dist/auth/GoogleOAuth.js.map +1 -0
- package/dist/auth/middleware.d.ts +15 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +63 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/signing.d.ts +50 -0
- package/dist/auth/signing.d.ts.map +1 -0
- package/dist/auth/signing.js +96 -0
- package/dist/auth/signing.js.map +1 -0
- package/dist/auth/wsTicket.d.ts +34 -0
- package/dist/auth/wsTicket.d.ts.map +1 -0
- package/dist/auth/wsTicket.js +50 -0
- package/dist/auth/wsTicket.js.map +1 -0
- package/dist/config/types.d.ts +294 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/url-safety.d.ts +8 -0
- package/dist/config/url-safety.d.ts.map +1 -0
- package/dist/config/url-safety.js +11 -0
- package/dist/config/url-safety.js.map +1 -0
- package/dist/containers/ContainerSessionService.d.ts +67 -0
- package/dist/containers/ContainerSessionService.d.ts.map +1 -0
- package/dist/containers/ContainerSessionService.js +44 -0
- package/dist/containers/ContainerSessionService.js.map +1 -0
- package/dist/crypto/WebCryptoPasswordHasher.d.ts +9 -0
- package/dist/crypto/WebCryptoPasswordHasher.d.ts.map +1 -0
- package/dist/crypto/WebCryptoPasswordHasher.js +67 -0
- package/dist/crypto/WebCryptoPasswordHasher.js.map +1 -0
- package/dist/crypto/WebCryptoPersonalSecretCipher.d.ts +6 -0
- package/dist/crypto/WebCryptoPersonalSecretCipher.d.ts.map +1 -0
- package/dist/crypto/WebCryptoPersonalSecretCipher.js +57 -0
- package/dist/crypto/WebCryptoPersonalSecretCipher.js.map +1 -0
- package/dist/crypto/WebCryptoSecretCipher.d.ts +23 -0
- package/dist/crypto/WebCryptoSecretCipher.d.ts.map +1 -0
- package/dist/crypto/WebCryptoSecretCipher.js +60 -0
- package/dist/crypto/WebCryptoSecretCipher.js.map +1 -0
- package/dist/crypto/encoding.d.ts +14 -0
- package/dist/crypto/encoding.d.ts.map +1 -0
- package/dist/crypto/encoding.js +58 -0
- package/dist/crypto/encoding.js.map +1 -0
- package/dist/events/FanOutEventPublisher.d.ts +32 -0
- package/dist/events/FanOutEventPublisher.d.ts.map +1 -0
- package/dist/events/FanOutEventPublisher.js +76 -0
- package/dist/events/FanOutEventPublisher.js.map +1 -0
- package/dist/events/InAppNotificationChannel.d.ts +20 -0
- package/dist/events/InAppNotificationChannel.d.ts.map +1 -0
- package/dist/events/InAppNotificationChannel.js +23 -0
- package/dist/events/InAppNotificationChannel.js.map +1 -0
- package/dist/github/FetchGitHubClient.d.ts +72 -0
- package/dist/github/FetchGitHubClient.d.ts.map +1 -0
- package/dist/github/FetchGitHubClient.js +485 -0
- package/dist/github/FetchGitHubClient.js.map +1 -0
- package/dist/github/FetchGitHubProvisioningClient.d.ts +13 -0
- package/dist/github/FetchGitHubProvisioningClient.d.ts.map +1 -0
- package/dist/github/FetchGitHubProvisioningClient.js +59 -0
- package/dist/github/FetchGitHubProvisioningClient.js.map +1 -0
- package/dist/github/GitHubAppAuth.d.ts +30 -0
- package/dist/github/GitHubAppAuth.d.ts.map +1 -0
- package/dist/github/GitHubAppAuth.js +95 -0
- package/dist/github/GitHubAppAuth.js.map +1 -0
- package/dist/github/GitHubAppRegistry.d.ts +57 -0
- package/dist/github/GitHubAppRegistry.d.ts.map +1 -0
- package/dist/github/GitHubAppRegistry.js +51 -0
- package/dist/github/GitHubAppRegistry.js.map +1 -0
- package/dist/github/GitHubCiStatusProvider.d.ts +21 -0
- package/dist/github/GitHubCiStatusProvider.d.ts.map +1 -0
- package/dist/github/GitHubCiStatusProvider.js +39 -0
- package/dist/github/GitHubCiStatusProvider.js.map +1 -0
- package/dist/github/GitHubMergeabilityProvider.d.ts +26 -0
- package/dist/github/GitHubMergeabilityProvider.d.ts.map +1 -0
- package/dist/github/GitHubMergeabilityProvider.js +38 -0
- package/dist/github/GitHubMergeabilityProvider.js.map +1 -0
- package/dist/github/GitHubPullRequestMerger.d.ts +23 -0
- package/dist/github/GitHubPullRequestMerger.d.ts.map +1 -0
- package/dist/github/GitHubPullRequestMerger.js +38 -0
- package/dist/github/GitHubPullRequestMerger.js.map +1 -0
- package/dist/github/WebCryptoWebhookVerifier.d.ts +9 -0
- package/dist/github/WebCryptoWebhookVerifier.d.ts.map +1 -0
- package/dist/github/WebCryptoWebhookVerifier.js +40 -0
- package/dist/github/WebCryptoWebhookVerifier.js.map +1 -0
- package/dist/github/ensureWorkBranch.d.ts +26 -0
- package/dist/github/ensureWorkBranch.d.ts.map +1 -0
- package/dist/github/ensureWorkBranch.js +97 -0
- package/dist/github/ensureWorkBranch.js.map +1 -0
- package/dist/github/state.d.ts +19 -0
- package/dist/github/state.d.ts.map +1 -0
- package/dist/github/state.js +55 -0
- package/dist/github/state.js.map +1 -0
- package/dist/http/authGate.d.ts +21 -0
- package/dist/http/authGate.d.ts.map +1 -0
- package/dist/http/authGate.js +77 -0
- package/dist/http/authGate.js.map +1 -0
- package/dist/http/cors.d.ts +13 -0
- package/dist/http/cors.d.ts.map +1 -0
- package/dist/http/cors.js +30 -0
- package/dist/http/cors.js.map +1 -0
- package/dist/http/env.d.ts +68 -0
- package/dist/http/env.d.ts.map +1 -0
- package/dist/http/env.js +2 -0
- package/dist/http/env.js.map +1 -0
- package/dist/http/errorHandler.d.ts +4 -0
- package/dist/http/errorHandler.d.ts.map +1 -0
- package/dist/http/errorHandler.js +33 -0
- package/dist/http/errorHandler.js.map +1 -0
- package/dist/http/params.d.ts +8 -0
- package/dist/http/params.d.ts.map +1 -0
- package/dist/http/params.js +13 -0
- package/dist/http/params.js.map +1 -0
- package/dist/http/validation.d.ts +12 -0
- package/dist/http/validation.d.ts.map +1 -0
- package/dist/http/validation.js +21 -0
- package/dist/http/validation.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/accounts/AccountController.d.ts +10 -0
- package/dist/modules/accounts/AccountController.d.ts.map +1 -0
- package/dist/modules/accounts/AccountController.js +197 -0
- package/dist/modules/accounts/AccountController.js.map +1 -0
- package/dist/modules/agentRuns/AgentRunController.d.ts +10 -0
- package/dist/modules/agentRuns/AgentRunController.d.ts.map +1 -0
- package/dist/modules/agentRuns/AgentRunController.js +65 -0
- package/dist/modules/agentRuns/AgentRunController.js.map +1 -0
- package/dist/modules/auth/AuthController.d.ts +12 -0
- package/dist/modules/auth/AuthController.d.ts.map +1 -0
- package/dist/modules/auth/AuthController.js +457 -0
- package/dist/modules/auth/AuthController.js.map +1 -0
- package/dist/modules/board/BoardController.d.ts +8 -0
- package/dist/modules/board/BoardController.d.ts.map +1 -0
- package/dist/modules/board/BoardController.js +89 -0
- package/dist/modules/board/BoardController.js.map +1 -0
- package/dist/modules/boardScan/BoardScanController.d.ts +10 -0
- package/dist/modules/boardScan/BoardScanController.d.ts.map +1 -0
- package/dist/modules/boardScan/BoardScanController.js +53 -0
- package/dist/modules/boardScan/BoardScanController.js.map +1 -0
- package/dist/modules/bootstrap/BootstrapController.d.ts +10 -0
- package/dist/modules/bootstrap/BootstrapController.d.ts.map +1 -0
- package/dist/modules/bootstrap/BootstrapController.js +75 -0
- package/dist/modules/bootstrap/BootstrapController.js.map +1 -0
- package/dist/modules/clarity/ClarityReviewController.d.ts +11 -0
- package/dist/modules/clarity/ClarityReviewController.d.ts.map +1 -0
- package/dist/modules/clarity/ClarityReviewController.js +97 -0
- package/dist/modules/clarity/ClarityReviewController.js.map +1 -0
- package/dist/modules/consensus/ConsensusController.d.ts +12 -0
- package/dist/modules/consensus/ConsensusController.d.ts.map +1 -0
- package/dist/modules/consensus/ConsensusController.js +23 -0
- package/dist/modules/consensus/ConsensusController.js.map +1 -0
- package/dist/modules/documents/DocumentSourceController.d.ts +10 -0
- package/dist/modules/documents/DocumentSourceController.d.ts.map +1 -0
- package/dist/modules/documents/DocumentSourceController.js +116 -0
- package/dist/modules/documents/DocumentSourceController.js.map +1 -0
- package/dist/modules/environments/EnvironmentController.d.ts +10 -0
- package/dist/modules/environments/EnvironmentController.d.ts.map +1 -0
- package/dist/modules/environments/EnvironmentController.js +95 -0
- package/dist/modules/environments/EnvironmentController.js.map +1 -0
- package/dist/modules/events/EventsController.d.ts +26 -0
- package/dist/modules/events/EventsController.d.ts.map +1 -0
- package/dist/modules/events/EventsController.js +56 -0
- package/dist/modules/events/EventsController.js.map +1 -0
- package/dist/modules/execution/ExecutionController.d.ts +10 -0
- package/dist/modules/execution/ExecutionController.d.ts.map +1 -0
- package/dist/modules/execution/ExecutionController.js +156 -0
- package/dist/modules/execution/ExecutionController.js.map +1 -0
- package/dist/modules/fragmentLibrary/FragmentLibraryController.d.ts +14 -0
- package/dist/modules/fragmentLibrary/FragmentLibraryController.d.ts.map +1 -0
- package/dist/modules/fragmentLibrary/FragmentLibraryController.js +128 -0
- package/dist/modules/fragmentLibrary/FragmentLibraryController.js.map +1 -0
- package/dist/modules/github/GitHubController.d.ts +12 -0
- package/dist/modules/github/GitHubController.d.ts.map +1 -0
- package/dist/modules/github/GitHubController.js +234 -0
- package/dist/modules/github/GitHubController.js.map +1 -0
- package/dist/modules/github/GitHubWebhookController.d.ts +13 -0
- package/dist/modules/github/GitHubWebhookController.d.ts.map +1 -0
- package/dist/modules/github/GitHubWebhookController.js +74 -0
- package/dist/modules/github/GitHubWebhookController.js.map +1 -0
- package/dist/modules/llmProxy/LlmProxyController.d.ts +18 -0
- package/dist/modules/llmProxy/LlmProxyController.d.ts.map +1 -0
- package/dist/modules/llmProxy/LlmProxyController.js +567 -0
- package/dist/modules/llmProxy/LlmProxyController.js.map +1 -0
- package/dist/modules/localModels/LocalModelEndpointController.d.ts +4 -0
- package/dist/modules/localModels/LocalModelEndpointController.d.ts.map +1 -0
- package/dist/modules/localModels/LocalModelEndpointController.js +58 -0
- package/dist/modules/localModels/LocalModelEndpointController.js.map +1 -0
- package/dist/modules/merge/MergePresetController.d.ts +9 -0
- package/dist/modules/merge/MergePresetController.d.ts.map +1 -0
- package/dist/modules/merge/MergePresetController.js +46 -0
- package/dist/modules/merge/MergePresetController.js.map +1 -0
- package/dist/modules/modelDefaults/ModelDefaultsController.d.ts +9 -0
- package/dist/modules/modelDefaults/ModelDefaultsController.d.ts.map +1 -0
- package/dist/modules/modelDefaults/ModelDefaultsController.js +32 -0
- package/dist/modules/modelDefaults/ModelDefaultsController.js.map +1 -0
- package/dist/modules/models/ModelController.d.ts +11 -0
- package/dist/modules/models/ModelController.d.ts.map +1 -0
- package/dist/modules/models/ModelController.js +38 -0
- package/dist/modules/models/ModelController.js.map +1 -0
- package/dist/modules/notifications/NotificationController.d.ts +13 -0
- package/dist/modules/notifications/NotificationController.d.ts.map +1 -0
- package/dist/modules/notifications/NotificationController.js +67 -0
- package/dist/modules/notifications/NotificationController.js.map +1 -0
- package/dist/modules/pipelines/PipelineController.d.ts +5 -0
- package/dist/modules/pipelines/PipelineController.d.ts.map +1 -0
- package/dist/modules/pipelines/PipelineController.js +46 -0
- package/dist/modules/pipelines/PipelineController.js.map +1 -0
- package/dist/modules/promptFragments/PromptFragmentController.d.ts +11 -0
- package/dist/modules/promptFragments/PromptFragmentController.d.ts.map +1 -0
- package/dist/modules/promptFragments/PromptFragmentController.js +18 -0
- package/dist/modules/promptFragments/PromptFragmentController.js.map +1 -0
- package/dist/modules/providers/ApiKeyController.d.ts +13 -0
- package/dist/modules/providers/ApiKeyController.d.ts.map +1 -0
- package/dist/modules/providers/ApiKeyController.js +98 -0
- package/dist/modules/providers/ApiKeyController.js.map +1 -0
- package/dist/modules/providers/PersonalSubscriptionController.d.ts +4 -0
- package/dist/modules/providers/PersonalSubscriptionController.d.ts.map +1 -0
- package/dist/modules/providers/PersonalSubscriptionController.js +48 -0
- package/dist/modules/providers/PersonalSubscriptionController.js.map +1 -0
- package/dist/modules/providers/VendorCredentialController.d.ts +4 -0
- package/dist/modules/providers/VendorCredentialController.d.ts.map +1 -0
- package/dist/modules/providers/VendorCredentialController.js +55 -0
- package/dist/modules/providers/VendorCredentialController.js.map +1 -0
- package/dist/modules/providers/personalCredentialGate.d.ts +34 -0
- package/dist/modules/providers/personalCredentialGate.d.ts.map +1 -0
- package/dist/modules/providers/personalCredentialGate.js +106 -0
- package/dist/modules/providers/personalCredentialGate.js.map +1 -0
- package/dist/modules/recurring/RecurringPipelineController.d.ts +8 -0
- package/dist/modules/recurring/RecurringPipelineController.d.ts.map +1 -0
- package/dist/modules/recurring/RecurringPipelineController.js +58 -0
- package/dist/modules/recurring/RecurringPipelineController.js.map +1 -0
- package/dist/modules/recurring/TrackerSettingsController.d.ts +8 -0
- package/dist/modules/recurring/TrackerSettingsController.d.ts.map +1 -0
- package/dist/modules/recurring/TrackerSettingsController.js +30 -0
- package/dist/modules/recurring/TrackerSettingsController.js.map +1 -0
- package/dist/modules/releaseHealth/ReleaseHealthController.d.ts +9 -0
- package/dist/modules/releaseHealth/ReleaseHealthController.d.ts.map +1 -0
- package/dist/modules/releaseHealth/ReleaseHealthController.js +58 -0
- package/dist/modules/releaseHealth/ReleaseHealthController.js.map +1 -0
- package/dist/modules/requirements/RequirementReviewController.d.ts +12 -0
- package/dist/modules/requirements/RequirementReviewController.d.ts.map +1 -0
- package/dist/modules/requirements/RequirementReviewController.js +107 -0
- package/dist/modules/requirements/RequirementReviewController.js.map +1 -0
- package/dist/modules/runners/RunnerPoolController.d.ts +10 -0
- package/dist/modules/runners/RunnerPoolController.d.ts.map +1 -0
- package/dist/modules/runners/RunnerPoolController.js +52 -0
- package/dist/modules/runners/RunnerPoolController.js.map +1 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.d.ts +9 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.d.ts.map +1 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.js +32 -0
- package/dist/modules/serviceFragmentDefaults/ServiceFragmentDefaultsController.js.map +1 -0
- package/dist/modules/services/ServiceMountController.d.ts +11 -0
- package/dist/modules/services/ServiceMountController.d.ts.map +1 -0
- package/dist/modules/services/ServiceMountController.js +64 -0
- package/dist/modules/services/ServiceMountController.js.map +1 -0
- package/dist/modules/settings/WorkspaceSettingsController.d.ts +9 -0
- package/dist/modules/settings/WorkspaceSettingsController.d.ts.map +1 -0
- package/dist/modules/settings/WorkspaceSettingsController.js +32 -0
- package/dist/modules/settings/WorkspaceSettingsController.js.map +1 -0
- package/dist/modules/slack/SlackController.d.ts +17 -0
- package/dist/modules/slack/SlackController.d.ts.map +1 -0
- package/dist/modules/slack/SlackController.js +135 -0
- package/dist/modules/slack/SlackController.js.map +1 -0
- package/dist/modules/tasks/TaskSourceController.d.ts +9 -0
- package/dist/modules/tasks/TaskSourceController.d.ts.map +1 -0
- package/dist/modules/tasks/TaskSourceController.js +103 -0
- package/dist/modules/tasks/TaskSourceController.js.map +1 -0
- package/dist/modules/webSearch/WebSearchProxyController.d.ts +4 -0
- package/dist/modules/webSearch/WebSearchProxyController.d.ts.map +1 -0
- package/dist/modules/webSearch/WebSearchProxyController.js +78 -0
- package/dist/modules/webSearch/WebSearchProxyController.js.map +1 -0
- package/dist/modules/webSearch/upstreams.d.ts +50 -0
- package/dist/modules/webSearch/upstreams.d.ts.map +1 -0
- package/dist/modules/webSearch/upstreams.js +107 -0
- package/dist/modules/webSearch/upstreams.js.map +1 -0
- package/dist/modules/workspaces/WorkspaceController.d.ts +5 -0
- package/dist/modules/workspaces/WorkspaceController.d.ts.map +1 -0
- package/dist/modules/workspaces/WorkspaceController.js +167 -0
- package/dist/modules/workspaces/WorkspaceController.js.map +1 -0
- package/dist/observability/logger.d.ts +9 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +39 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/persistence/mappers.d.ts +101 -0
- package/dist/persistence/mappers.d.ts.map +1 -0
- package/dist/persistence/mappers.js +260 -0
- package/dist/persistence/mappers.js.map +1 -0
- package/dist/runtime/escalateNotifications.d.ts +12 -0
- package/dist/runtime/escalateNotifications.d.ts.map +1 -0
- package/dist/runtime/escalateNotifications.js +25 -0
- package/dist/runtime/escalateNotifications.js.map +1 -0
- package/dist/runtime/gateways.d.ts +159 -0
- package/dist/runtime/gateways.d.ts.map +1 -0
- package/dist/runtime/gateways.js +2 -0
- package/dist/runtime/gateways.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitHubOAuth.js","sourceRoot":"","sources":["../../src/auth/GitHubOAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface GoogleOAuthDependencies {
|
|
2
|
+
clientId: string;
|
|
3
|
+
clientSecret: string;
|
|
4
|
+
/** OAuth host (authorize). Defaults to accounts.google.com. */
|
|
5
|
+
oauthBase?: string;
|
|
6
|
+
/** Userinfo API base. Defaults to www.googleapis.com. */
|
|
7
|
+
apiBase?: string;
|
|
8
|
+
}
|
|
9
|
+
/** The Google identity behind an authorization code (the OAuth provider's subject). */
|
|
10
|
+
export interface GoogleIdentity {
|
|
11
|
+
/** Google `sub` — the stable identity subject. */
|
|
12
|
+
subject: string;
|
|
13
|
+
email: string | null;
|
|
14
|
+
/** Whether Google has verified the user owns `email` (gates domain-allowlist + link). */
|
|
15
|
+
emailVerified: boolean;
|
|
16
|
+
name: string | null;
|
|
17
|
+
avatarUrl: string | null;
|
|
18
|
+
}
|
|
19
|
+
export declare class GoogleOAuth {
|
|
20
|
+
private readonly deps;
|
|
21
|
+
constructor(deps: GoogleOAuthDependencies);
|
|
22
|
+
private get oauthBase();
|
|
23
|
+
private get apiBase();
|
|
24
|
+
/** The Google URL the browser is sent to in order to authorise. */
|
|
25
|
+
authorizeUrl(params: {
|
|
26
|
+
redirectUri: string;
|
|
27
|
+
state: string;
|
|
28
|
+
scope?: string;
|
|
29
|
+
}): string;
|
|
30
|
+
/** Exchange the callback `code` for an access token. */
|
|
31
|
+
exchangeCode(code: string, redirectUri: string): Promise<string>;
|
|
32
|
+
/** Resolve the authenticated Google user behind an access token. */
|
|
33
|
+
fetchUser(accessToken: string): Promise<GoogleIdentity>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=GoogleOAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GoogleOAuth.d.ts","sourceRoot":"","sources":["../../src/auth/GoogleOAuth.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAiBD,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,yFAAyF;IACzF,aAAa,EAAE,OAAO,CAAA;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,uBAAuB,EAAI;IAE9D,OAAO,KAAK,SAAS,GAEpB;IACD,OAAO,KAAK,OAAO,GAElB;IAED,mEAAmE;IACnE,YAAY,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAQnF;IAED,wDAAwD;IAClD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBrE;IAED,oEAAoE;IAC9D,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAa5D;CACF"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Minimal Google OAuth2 / OpenID Connect web-flow client (the user login flow).
|
|
2
|
+
// Built on `fetch` only, so it runs in a plain Workers isolate and in Node — a
|
|
3
|
+
// mirror of GitHubOAuth. Endpoints default to Google's but are overridable for tests.
|
|
4
|
+
const DEFAULT_OAUTH_BASE = 'https://accounts.google.com';
|
|
5
|
+
const DEFAULT_API_BASE = 'https://www.googleapis.com';
|
|
6
|
+
const TOKEN_PATH = 'https://oauth2.googleapis.com/token';
|
|
7
|
+
export class GoogleOAuth {
|
|
8
|
+
deps;
|
|
9
|
+
constructor(deps) {
|
|
10
|
+
this.deps = deps;
|
|
11
|
+
}
|
|
12
|
+
get oauthBase() {
|
|
13
|
+
return this.deps.oauthBase || DEFAULT_OAUTH_BASE;
|
|
14
|
+
}
|
|
15
|
+
get apiBase() {
|
|
16
|
+
return this.deps.apiBase || DEFAULT_API_BASE;
|
|
17
|
+
}
|
|
18
|
+
/** The Google URL the browser is sent to in order to authorise. */
|
|
19
|
+
authorizeUrl(params) {
|
|
20
|
+
const url = new URL('/o/oauth2/v2/auth', this.oauthBase);
|
|
21
|
+
url.searchParams.set('client_id', this.deps.clientId);
|
|
22
|
+
url.searchParams.set('redirect_uri', params.redirectUri);
|
|
23
|
+
url.searchParams.set('state', params.state);
|
|
24
|
+
url.searchParams.set('response_type', 'code');
|
|
25
|
+
url.searchParams.set('scope', params.scope ?? 'openid email profile');
|
|
26
|
+
return url.toString();
|
|
27
|
+
}
|
|
28
|
+
/** Exchange the callback `code` for an access token. */
|
|
29
|
+
async exchangeCode(code, redirectUri) {
|
|
30
|
+
const res = await fetch(TOKEN_PATH, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: { accept: 'application/json', 'content-type': 'application/x-www-form-urlencoded' },
|
|
33
|
+
body: new URLSearchParams({
|
|
34
|
+
client_id: this.deps.clientId,
|
|
35
|
+
client_secret: this.deps.clientSecret,
|
|
36
|
+
code,
|
|
37
|
+
redirect_uri: redirectUri,
|
|
38
|
+
grant_type: 'authorization_code',
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
if (!res.ok)
|
|
42
|
+
throw new Error(`Google token exchange failed (HTTP ${res.status})`);
|
|
43
|
+
const body = (await res.json());
|
|
44
|
+
if (!body.access_token) {
|
|
45
|
+
throw new Error(body.error_description || body.error || 'Google returned no access token');
|
|
46
|
+
}
|
|
47
|
+
return body.access_token;
|
|
48
|
+
}
|
|
49
|
+
/** Resolve the authenticated Google user behind an access token. */
|
|
50
|
+
async fetchUser(accessToken) {
|
|
51
|
+
const res = await fetch(new URL('/oauth2/v3/userinfo', this.apiBase), {
|
|
52
|
+
headers: { authorization: `Bearer ${accessToken}` },
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok)
|
|
55
|
+
throw new Error(`Google userinfo fetch failed (HTTP ${res.status})`);
|
|
56
|
+
const info = (await res.json());
|
|
57
|
+
return {
|
|
58
|
+
subject: info.sub,
|
|
59
|
+
email: info.email ?? null,
|
|
60
|
+
emailVerified: info.email_verified === true || info.email_verified === 'true',
|
|
61
|
+
name: info.name ?? null,
|
|
62
|
+
avatarUrl: info.picture ?? null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=GoogleOAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GoogleOAuth.js","sourceRoot":"","sources":["../../src/auth/GoogleOAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { AppEnv } from '../http/env.js';
|
|
3
|
+
import { type SessionPayload } from './signing.js';
|
|
4
|
+
/** Extract the bearer token from the Authorization header, if present. */
|
|
5
|
+
export declare function bearerToken<E extends AppEnv>(c: Context<E>): string | null;
|
|
6
|
+
/** Verify the request's bearer token against the configured session secret. */
|
|
7
|
+
export declare function verifySession<E extends AppEnv>(c: Context<E>): Promise<SessionPayload | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Gate a route group. Preflight (OPTIONS) is always allowed so CORS isn't broken.
|
|
10
|
+
* When auth is enabled, require a valid session and stash the user on the
|
|
11
|
+
* context. When it is NOT configured, fail closed (503) — unless the local-dev
|
|
12
|
+
* escape hatch `AUTH_DEV_OPEN` is set, which passes through (dev + tests).
|
|
13
|
+
*/
|
|
14
|
+
export declare function requireAuth<E extends AppEnv>(): MiddlewareHandler<E>;
|
|
15
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAgB9E,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAK1E;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQ7F;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,KAAK,iBAAiB,CAAC,CAAC,CAAC,CA0BpE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { HmacSigner, TOKEN_AUDIENCE } from './signing.js';
|
|
2
|
+
// Bearer-token auth for the API. The session token is minted by the OAuth
|
|
3
|
+
// callback (see the facade's AuthController) and carried by the SPA as
|
|
4
|
+
// `Authorization: Bearer <token>`.
|
|
5
|
+
//
|
|
6
|
+
// The gate FAILS CLOSED: if auth is unconfigured, protected routes are refused
|
|
7
|
+
// (503) rather than served openly — production must always have auth present.
|
|
8
|
+
// The only way to run open is the explicit local-dev/test escape hatch
|
|
9
|
+
// `AUTH_DEV_OPEN=true` (config.auth.devOpen).
|
|
10
|
+
// The functions are generic over the Hono env so a facade whose app adds runtime
|
|
11
|
+
// `Bindings` (e.g. the Worker's `Env`) on top of the shared Variables can still use
|
|
12
|
+
// them — Hono's Context is invariant, so a non-generic `Context<AppEnv>` would reject
|
|
13
|
+
// a `Context<AppEnv & { Bindings }>`.
|
|
14
|
+
/** Extract the bearer token from the Authorization header, if present. */
|
|
15
|
+
export function bearerToken(c) {
|
|
16
|
+
const header = c.req.header('Authorization');
|
|
17
|
+
if (!header)
|
|
18
|
+
return null;
|
|
19
|
+
const match = /^Bearer\s+(.+)$/i.exec(header.trim());
|
|
20
|
+
return match ? match[1] : null;
|
|
21
|
+
}
|
|
22
|
+
/** Verify the request's bearer token against the configured session secret. */
|
|
23
|
+
export function verifySession(c) {
|
|
24
|
+
const cfg = c.get('container').config.auth;
|
|
25
|
+
if (!cfg.enabled)
|
|
26
|
+
return Promise.resolve(null);
|
|
27
|
+
// Pin the `session` audience: a container LLM-proxy token or a WS ticket — both
|
|
28
|
+
// signed with the same secret — must NOT be accepted as a user session.
|
|
29
|
+
return new HmacSigner(cfg.sessionSecret).verify(bearerToken(c), {
|
|
30
|
+
aud: TOKEN_AUDIENCE.session,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Gate a route group. Preflight (OPTIONS) is always allowed so CORS isn't broken.
|
|
35
|
+
* When auth is enabled, require a valid session and stash the user on the
|
|
36
|
+
* context. When it is NOT configured, fail closed (503) — unless the local-dev
|
|
37
|
+
* escape hatch `AUTH_DEV_OPEN` is set, which passes through (dev + tests).
|
|
38
|
+
*/
|
|
39
|
+
export function requireAuth() {
|
|
40
|
+
return async (c, next) => {
|
|
41
|
+
if (c.req.method === 'OPTIONS')
|
|
42
|
+
return next();
|
|
43
|
+
const cfg = c.get('container').config.auth;
|
|
44
|
+
if (!cfg.enabled) {
|
|
45
|
+
if (cfg.devOpen)
|
|
46
|
+
return next();
|
|
47
|
+
return c.json({
|
|
48
|
+
error: {
|
|
49
|
+
code: 'auth_not_configured',
|
|
50
|
+
message: 'Authentication is required but not configured. Set the GitHub OAuth ' +
|
|
51
|
+
'credentials and AUTH_SESSION_SECRET, or AUTH_DEV_OPEN=true for local dev.',
|
|
52
|
+
},
|
|
53
|
+
}, 503);
|
|
54
|
+
}
|
|
55
|
+
const user = await verifySession(c);
|
|
56
|
+
if (!user) {
|
|
57
|
+
return c.json({ error: { code: 'unauthorized', message: 'Authentication required' } }, 401);
|
|
58
|
+
}
|
|
59
|
+
c.set('user', user);
|
|
60
|
+
await next();
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAuB,MAAM,cAAc,CAAA;AAE9E,0EAA0E;AAC1E,uEAAuE;AACvE,mCAAmC;AACnC,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,uEAAuE;AACvE,8CAA8C;AAE9C,iFAAiF;AACjF,oFAAoF;AACpF,sFAAsF;AACtF,sCAAsC;AAEtC,0EAA0E;AAC1E,MAAM,UAAU,WAAW,CAAmB,CAAa;IACzD,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;IAC5C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACpD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACjC,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAmB,CAAa;IAC3D,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;IAC1C,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9C,gFAAgF;IAChF,wEAAwE;IACxE,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,CAAiB,WAAW,CAAC,CAAC,CAAC,EAAE;QAC9E,GAAG,EAAE,cAAc,CAAC,OAAO;KAC5B,CAAC,CAAA;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,EAAE,CAAA;QAC7C,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;QAC1C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,IAAI,EAAE,CAAA;YAC9B,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,KAAK,EAAE;oBACL,IAAI,EAAE,qBAAqB;oBAC3B,OAAO,EACL,sEAAsE;wBACtE,2EAA2E;iBAC9E;aACF,EACD,GAAG,CACJ,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,CAAC,CAAC,CAAA;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,yBAAyB,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;QAC7F,CAAC;QACD,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QACnB,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Distinct token audiences. Each verifier pins exactly one of these. */
|
|
2
|
+
export declare const TOKEN_AUDIENCE: {
|
|
3
|
+
/** SPA user session (Authorization: Bearer). */
|
|
4
|
+
readonly session: 'session';
|
|
5
|
+
/** OAuth login `state` nonce. */
|
|
6
|
+
readonly oauthState: 'oauth-state';
|
|
7
|
+
/** Implementation-container → LLM proxy token. */
|
|
8
|
+
readonly container: 'llm-proxy';
|
|
9
|
+
/** Single-workspace WebSocket event-stream ticket. */
|
|
10
|
+
readonly wsTicket: 'ws';
|
|
11
|
+
};
|
|
12
|
+
export type TokenAudience = (typeof TOKEN_AUDIENCE)[keyof typeof TOKEN_AUDIENCE];
|
|
13
|
+
/** Identity we surface to the client. */
|
|
14
|
+
export interface SessionUser {
|
|
15
|
+
/** Internal user id (`usr_*`) — stable across login providers. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** Display handle (GitHub login for GitHub users, else email/local-part). */
|
|
18
|
+
login: string;
|
|
19
|
+
name: string | null;
|
|
20
|
+
avatarUrl: string | null;
|
|
21
|
+
/** Primary email, when known. */
|
|
22
|
+
email?: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** A signed session: the user plus an absolute expiry (epoch ms). */
|
|
25
|
+
export interface SessionPayload extends SessionUser {
|
|
26
|
+
/** Audience pin — always `session` for a user session. */
|
|
27
|
+
aud: typeof TOKEN_AUDIENCE.session;
|
|
28
|
+
exp: number;
|
|
29
|
+
}
|
|
30
|
+
export declare class HmacSigner {
|
|
31
|
+
private readonly secret;
|
|
32
|
+
private keyPromise?;
|
|
33
|
+
constructor(secret: string);
|
|
34
|
+
sign(payload: object): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Return the payload when the signature is valid, unexpired, and (when an
|
|
37
|
+
* expected audience is given) carries a matching `aud` claim; else null.
|
|
38
|
+
*
|
|
39
|
+
* `opts.aud` is REQUIRED in practice for every protected verification: it pins
|
|
40
|
+
* the token class so a token minted for another audience (e.g. a container
|
|
41
|
+
* proxy token) cannot be replayed here. It is optional only so the same
|
|
42
|
+
* primitive can verify legacy/audience-less payloads in tests.
|
|
43
|
+
*/
|
|
44
|
+
verify<T extends object>(token: string | null | undefined, opts?: {
|
|
45
|
+
aud?: TokenAudience;
|
|
46
|
+
}): Promise<T | null>;
|
|
47
|
+
private mac;
|
|
48
|
+
private importKey;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=signing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/auth/signing.ts"],"names":[],"mappings":"AAqBA,yEAAyE;AACzE,eAAO,MAAM,cAAc;IACzB,gDAAgD;aAChD,OAAO,EAAE,SAAS;IAClB,iCAAiC;aACjC,UAAU,EAAE,aAAa;IACzB,kDAAkD;aAClD,SAAS,EAAE,WAAW;IACtB,sDAAsD;aACtD,QAAQ,EAAE,IAAI;CACN,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,OAAO,cAAc,CAAC,CAAA;AAEhF,yCAAyC;AACzC,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAA;IACV,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,0DAA0D;IAC1D,GAAG,EAAE,OAAO,cAAc,CAAC,OAAO,CAAA;IAClC,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,qBAAa,UAAU;IAGT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,UAAU,CAAC,CAAoB;IAEvC,YAA6B,MAAM,EAAE,MAAM,EAAI;IAEzC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG3C;IAED;;;;;;;;OAQG;IACG,MAAM,CAAC,CAAC,SAAS,MAAM,EAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,aAAa,CAAA;KAAE,GAC7B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CA6BnB;YAEa,GAAG;IAKjB,OAAO,CAAC,SAAS;CAYlB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { base64url, base64urlToBytes, timingSafeEqual } from '../crypto/encoding.js';
|
|
2
|
+
// Stateless signed tokens for the auth flow, built on Web Crypto (HMAC-SHA256) —
|
|
3
|
+
// no Node `crypto` module, so it runs in a plain Workers isolate and in Node. The
|
|
4
|
+
// same primitive (and the same session secret) backs several distinct token classes:
|
|
5
|
+
// - the *session token* the SPA carries as `Authorization: Bearer`
|
|
6
|
+
// - the OAuth *state* nonce that protects the login round-trip from CSRF
|
|
7
|
+
// - the *container* token an implementation container uses against the LLM proxy
|
|
8
|
+
// - the short-lived *ws ticket* that authorises one WebSocket event stream
|
|
9
|
+
//
|
|
10
|
+
// Because they share a key and verifier, every token MUST carry an `aud`
|
|
11
|
+
// (audience) claim and every verifier MUST pin the audience it expects, so a
|
|
12
|
+
// token minted for one purpose cannot be replayed as another (e.g. a container
|
|
13
|
+
// proxy token acting as a full user session). `verify` rejects any token whose
|
|
14
|
+
// `aud` does not match the caller's expected audience.
|
|
15
|
+
//
|
|
16
|
+
// Format: `base64url(JSON payload).base64url(HMAC(base64url(JSON payload)))`.
|
|
17
|
+
// The payload is base64url (no dots), so the dot split is unambiguous. Payloads
|
|
18
|
+
// carrying an `exp` (epoch ms) are rejected once expired. There is no server-side
|
|
19
|
+
// store: logout is a client-side drop and expiry bounds the blast radius.
|
|
20
|
+
/** Distinct token audiences. Each verifier pins exactly one of these. */
|
|
21
|
+
export const TOKEN_AUDIENCE = {
|
|
22
|
+
/** SPA user session (Authorization: Bearer). */
|
|
23
|
+
session: 'session',
|
|
24
|
+
/** OAuth login `state` nonce. */
|
|
25
|
+
oauthState: 'oauth-state',
|
|
26
|
+
/** Implementation-container → LLM proxy token. */
|
|
27
|
+
container: 'llm-proxy',
|
|
28
|
+
/** Single-workspace WebSocket event-stream ticket. */
|
|
29
|
+
wsTicket: 'ws',
|
|
30
|
+
};
|
|
31
|
+
export class HmacSigner {
|
|
32
|
+
secret;
|
|
33
|
+
keyPromise;
|
|
34
|
+
constructor(secret) {
|
|
35
|
+
this.secret = secret;
|
|
36
|
+
}
|
|
37
|
+
async sign(payload) {
|
|
38
|
+
const body = base64url(JSON.stringify(payload));
|
|
39
|
+
return `${body}.${base64url(await this.mac(body))}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Return the payload when the signature is valid, unexpired, and (when an
|
|
43
|
+
* expected audience is given) carries a matching `aud` claim; else null.
|
|
44
|
+
*
|
|
45
|
+
* `opts.aud` is REQUIRED in practice for every protected verification: it pins
|
|
46
|
+
* the token class so a token minted for another audience (e.g. a container
|
|
47
|
+
* proxy token) cannot be replayed here. It is optional only so the same
|
|
48
|
+
* primitive can verify legacy/audience-less payloads in tests.
|
|
49
|
+
*/
|
|
50
|
+
async verify(token, opts) {
|
|
51
|
+
if (!token)
|
|
52
|
+
return null;
|
|
53
|
+
const dot = token.indexOf('.');
|
|
54
|
+
if (dot <= 0 || dot === token.length - 1)
|
|
55
|
+
return null;
|
|
56
|
+
const body = token.slice(0, dot);
|
|
57
|
+
// Decode the signature segment defensively: a malformed base64url tail must
|
|
58
|
+
// fail closed (null → 401), never throw out of `atob` into a 500.
|
|
59
|
+
let provided;
|
|
60
|
+
try {
|
|
61
|
+
provided = base64urlToBytes(token.slice(dot + 1));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const expected = new Uint8Array(await this.mac(body));
|
|
67
|
+
if (!timingSafeEqual(provided, expected))
|
|
68
|
+
return null;
|
|
69
|
+
let payload;
|
|
70
|
+
try {
|
|
71
|
+
payload = JSON.parse(new TextDecoder().decode(base64urlToBytes(body)));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const exp = payload.exp;
|
|
77
|
+
if (typeof exp === 'number' && exp < Date.now())
|
|
78
|
+
return null;
|
|
79
|
+
// Audience pin: when the caller expects a specific audience, the token's
|
|
80
|
+
// `aud` must match exactly. This is the cross-token-confusion defence.
|
|
81
|
+
if (opts?.aud !== undefined && payload.aud !== opts.aud)
|
|
82
|
+
return null;
|
|
83
|
+
return payload;
|
|
84
|
+
}
|
|
85
|
+
async mac(input) {
|
|
86
|
+
const key = await this.importKey();
|
|
87
|
+
return crypto.subtle.sign('HMAC', key, new TextEncoder().encode(input));
|
|
88
|
+
}
|
|
89
|
+
importKey() {
|
|
90
|
+
if (!this.keyPromise) {
|
|
91
|
+
this.keyPromise = crypto.subtle.importKey('raw', new TextEncoder().encode(this.secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
92
|
+
}
|
|
93
|
+
return this.keyPromise;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../src/auth/signing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AuthConfig } from '../config/types.js';
|
|
2
|
+
import { TOKEN_AUDIENCE } from './signing.js';
|
|
3
|
+
/** Ticket lifetime: just long enough to open the socket. */
|
|
4
|
+
export declare const WS_TICKET_TTL_MS: number;
|
|
5
|
+
export interface WsTicket {
|
|
6
|
+
aud: typeof TOKEN_AUDIENCE.wsTicket;
|
|
7
|
+
workspaceId: string;
|
|
8
|
+
exp: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Mint a workspace-scoped WS ticket. Returns `''` when auth is disabled (dev) — the
|
|
12
|
+
* handshake is then open and no ticket is needed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mintWsTicket(auth: AuthConfig, workspaceId: string): Promise<string>;
|
|
15
|
+
/**
|
|
16
|
+
* The verdict of authorising a WS upgrade, modelled so each facade maps it to its own
|
|
17
|
+
* transport's rejection (an HTTP status on the Worker's `Response`, a raw status line
|
|
18
|
+
* on the Node socket).
|
|
19
|
+
*/
|
|
20
|
+
export type WsUpgradeAuth = {
|
|
21
|
+
ok: true;
|
|
22
|
+
} | {
|
|
23
|
+
ok: false;
|
|
24
|
+
status: 401 | 503;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Authorise a WS event-stream upgrade for `workspaceId` from its `?ticket=`:
|
|
29
|
+
* - auth enabled → require a valid, unexpired, workspace-matching ticket (else 401)
|
|
30
|
+
* - auth disabled but dev-open → allow (open handshake)
|
|
31
|
+
* - auth unconfigured in production → 503 (mirror `requireAuth`: fail closed)
|
|
32
|
+
*/
|
|
33
|
+
export declare function authorizeWsUpgrade(auth: AuthConfig, ticket: string | undefined, workspaceId: string): Promise<WsUpgradeAuth>;
|
|
34
|
+
//# sourceMappingURL=wsTicket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsTicket.d.ts","sourceRoot":"","sources":["../../src/auth/wsTicket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAc,cAAc,EAAE,MAAM,cAAc,CAAA;AAczD,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,QAAY,CAAA;AAEzC,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,OAAO,cAAc,CAAC,QAAQ,CAAA;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQzF;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5F;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC,CAcxB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { HmacSigner, TOKEN_AUDIENCE } from './signing.js';
|
|
2
|
+
// The short-lived, single-workspace ticket that authorises ONE WebSocket event-stream
|
|
3
|
+
// handshake. A browser can't set `Authorization` on a WS handshake, so the SPA mints
|
|
4
|
+
// this over the authenticated REST channel (`POST .../events/ticket`) and passes it as
|
|
5
|
+
// `?ticket=`. It is audience-pinned (`ws`) and bound to one `workspaceId`, so it cannot
|
|
6
|
+
// be replayed as a session, against the LLM proxy, or for another workspace.
|
|
7
|
+
//
|
|
8
|
+
// The mint + verify live here (not inline in the controller) because both runtimes need
|
|
9
|
+
// them: the Cloudflare Worker verifies inside the shared `eventsController` GET handler,
|
|
10
|
+
// while the Node service verifies in its HTTP-server `upgrade` listener (the upgrade
|
|
11
|
+
// can't be expressed as a Hono `Response` there, so it bypasses the controller). One
|
|
12
|
+
// implementation keeps the two handshakes authorising identically.
|
|
13
|
+
/** Ticket lifetime: just long enough to open the socket. */
|
|
14
|
+
export const WS_TICKET_TTL_MS = 60 * 1000;
|
|
15
|
+
/**
|
|
16
|
+
* Mint a workspace-scoped WS ticket. Returns `''` when auth is disabled (dev) — the
|
|
17
|
+
* handshake is then open and no ticket is needed.
|
|
18
|
+
*/
|
|
19
|
+
export async function mintWsTicket(auth, workspaceId) {
|
|
20
|
+
if (!auth.enabled)
|
|
21
|
+
return '';
|
|
22
|
+
const ticket = {
|
|
23
|
+
aud: TOKEN_AUDIENCE.wsTicket,
|
|
24
|
+
workspaceId,
|
|
25
|
+
exp: Date.now() + WS_TICKET_TTL_MS,
|
|
26
|
+
};
|
|
27
|
+
return new HmacSigner(auth.sessionSecret).sign(ticket);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Authorise a WS event-stream upgrade for `workspaceId` from its `?ticket=`:
|
|
31
|
+
* - auth enabled → require a valid, unexpired, workspace-matching ticket (else 401)
|
|
32
|
+
* - auth disabled but dev-open → allow (open handshake)
|
|
33
|
+
* - auth unconfigured in production → 503 (mirror `requireAuth`: fail closed)
|
|
34
|
+
*/
|
|
35
|
+
export async function authorizeWsUpgrade(auth, ticket, workspaceId) {
|
|
36
|
+
if (auth.enabled) {
|
|
37
|
+
const verified = await new HmacSigner(auth.sessionSecret).verify(ticket, {
|
|
38
|
+
aud: TOKEN_AUDIENCE.wsTicket,
|
|
39
|
+
});
|
|
40
|
+
if (!verified || verified.workspaceId !== workspaceId) {
|
|
41
|
+
return { ok: false, status: 401, message: 'unauthorized' };
|
|
42
|
+
}
|
|
43
|
+
return { ok: true };
|
|
44
|
+
}
|
|
45
|
+
if (!auth.devOpen) {
|
|
46
|
+
return { ok: false, status: 503, message: 'authentication is required but not configured' };
|
|
47
|
+
}
|
|
48
|
+
return { ok: true };
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=wsTicket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsTicket.js","sourceRoot":"","sources":["../../src/auth/wsTicket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAEzD,sFAAsF;AACtF,qFAAqF;AACrF,uFAAuF;AACvF,wFAAwF;AACxF,6EAA6E;AAC7E,EAAE;AACF,wFAAwF;AACxF,yFAAyF;AACzF,qFAAqF;AACrF,qFAAqF;AACrF,mEAAmE;AAEnE,4DAA4D;AAC5D,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAA;AAQzC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAgB,EAAE,WAAmB;IACtE,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAa;QACvB,GAAG,EAAE,cAAc,CAAC,QAAQ;QAC5B,WAAW;QACX,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB;KACnC,CAAA;IACD,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AACxD,CAAC;AASD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAgB,EAChB,MAA0B,EAC1B,WAAmB;IAEnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAW,MAAM,EAAE;YACjF,GAAG,EAAE,cAAc,CAAC,QAAQ;SAC7B,CAAC,CAAA;QACF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;YACtD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAA;QAC5D,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;IACrB,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,+CAA+C,EAAE,CAAA;IAC7F,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;AACrB,CAAC"}
|