@antasphere/chassis-server 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 +82 -0
- package/dist/accounts/deletion.d.ts +163 -0
- package/dist/accounts/deletion.d.ts.map +1 -0
- package/dist/accounts/deletion.js +360 -0
- package/dist/accounts/deletion.js.map +1 -0
- package/dist/accounts/erasure-log.d.ts +66 -0
- package/dist/accounts/erasure-log.d.ts.map +1 -0
- package/dist/accounts/erasure-log.js +117 -0
- package/dist/accounts/erasure-log.js.map +1 -0
- package/dist/accounts/index.d.ts +6 -0
- package/dist/accounts/index.d.ts.map +1 -0
- package/dist/accounts/index.js +6 -0
- package/dist/accounts/index.js.map +1 -0
- package/dist/accounts/mint-refusal.d.ts +47 -0
- package/dist/accounts/mint-refusal.d.ts.map +1 -0
- package/dist/accounts/mint-refusal.js +59 -0
- package/dist/accounts/mint-refusal.js.map +1 -0
- package/dist/accounts/signup-duplicate.d.ts +14 -0
- package/dist/accounts/signup-duplicate.d.ts.map +1 -0
- package/dist/accounts/signup-duplicate.js +25 -0
- package/dist/accounts/signup-duplicate.js.map +1 -0
- package/dist/accounts/superadmin.d.ts +27 -0
- package/dist/accounts/superadmin.d.ts.map +1 -0
- package/dist/accounts/superadmin.js +46 -0
- package/dist/accounts/superadmin.js.map +1 -0
- package/dist/api/apikeys.d.ts +14 -0
- package/dist/api/apikeys.d.ts.map +1 -0
- package/dist/api/apikeys.js +124 -0
- package/dist/api/apikeys.js.map +1 -0
- package/dist/api/audit.d.ts +4 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +75 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/break-glass.d.ts +48 -0
- package/dist/api/break-glass.d.ts.map +1 -0
- package/dist/api/break-glass.js +217 -0
- package/dist/api/break-glass.js.map +1 -0
- package/dist/api/cli-auth.d.ts +84 -0
- package/dist/api/cli-auth.d.ts.map +1 -0
- package/dist/api/cli-auth.js +177 -0
- package/dist/api/cli-auth.js.map +1 -0
- package/dist/api/create-api.d.ts +123 -0
- package/dist/api/create-api.d.ts.map +1 -0
- package/dist/api/create-api.js +1165 -0
- package/dist/api/create-api.js.map +1 -0
- package/dist/api/demo-passes.d.ts +45 -0
- package/dist/api/demo-passes.d.ts.map +1 -0
- package/dist/api/demo-passes.js +143 -0
- package/dist/api/demo-passes.js.map +1 -0
- package/dist/api/errors.d.ts +5 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +5 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/export.d.ts +63 -0
- package/dist/api/export.d.ts.map +1 -0
- package/dist/api/export.js +393 -0
- package/dist/api/export.js.map +1 -0
- package/dist/api/files.d.ts +40 -0
- package/dist/api/files.d.ts.map +1 -0
- package/dist/api/files.js +150 -0
- package/dist/api/files.js.map +1 -0
- package/dist/api/index.d.ts +17 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +17 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/invitations.d.ts +50 -0
- package/dist/api/invitations.d.ts.map +1 -0
- package/dist/api/invitations.js +313 -0
- package/dist/api/invitations.js.map +1 -0
- package/dist/api/members.d.ts +25 -0
- package/dist/api/members.d.ts.map +1 -0
- package/dist/api/members.js +522 -0
- package/dist/api/members.js.map +1 -0
- package/dist/api/onboarding.d.ts +26 -0
- package/dist/api/onboarding.d.ts.map +1 -0
- package/dist/api/onboarding.js +23 -0
- package/dist/api/onboarding.js.map +1 -0
- package/dist/api/openapi-doc.d.ts +21 -0
- package/dist/api/openapi-doc.d.ts.map +1 -0
- package/dist/api/openapi-doc.js +25 -0
- package/dist/api/openapi-doc.js.map +1 -0
- package/dist/api/projects.d.ts +24 -0
- package/dist/api/projects.d.ts.map +1 -0
- package/dist/api/projects.js +624 -0
- package/dist/api/projects.js.map +1 -0
- package/dist/api/scope-routes.d.ts +12 -0
- package/dist/api/scope-routes.d.ts.map +1 -0
- package/dist/api/scope-routes.js +2 -0
- package/dist/api/scope-routes.js.map +1 -0
- package/dist/api/sso-connect.d.ts +70 -0
- package/dist/api/sso-connect.d.ts.map +1 -0
- package/dist/api/sso-connect.js +164 -0
- package/dist/api/sso-connect.js.map +1 -0
- package/dist/api/sso-logout.d.ts +41 -0
- package/dist/api/sso-logout.d.ts.map +1 -0
- package/dist/api/sso-logout.js +34 -0
- package/dist/api/sso-logout.js.map +1 -0
- package/dist/api/teams.d.ts +43 -0
- package/dist/api/teams.d.ts.map +1 -0
- package/dist/api/teams.js +447 -0
- package/dist/api/teams.js.map +1 -0
- package/dist/api/workspaces.d.ts +114 -0
- package/dist/api/workspaces.d.ts.map +1 -0
- package/dist/api/workspaces.js +462 -0
- package/dist/api/workspaces.js.map +1 -0
- package/dist/apikeys/index.d.ts +3 -0
- package/dist/apikeys/index.d.ts.map +1 -0
- package/dist/apikeys/index.js +3 -0
- package/dist/apikeys/index.js.map +1 -0
- package/dist/apikeys/peppers.d.ts +53 -0
- package/dist/apikeys/peppers.d.ts.map +1 -0
- package/dist/apikeys/peppers.js +97 -0
- package/dist/apikeys/peppers.js.map +1 -0
- package/dist/apikeys/service.d.ts +56 -0
- package/dist/apikeys/service.d.ts.map +1 -0
- package/dist/apikeys/service.js +196 -0
- package/dist/apikeys/service.js.map +1 -0
- package/dist/app.d.ts +65 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +142 -0
- package/dist/app.js.map +1 -0
- package/dist/audit/filters.d.ts +38 -0
- package/dist/audit/filters.d.ts.map +1 -0
- package/dist/audit/filters.js +97 -0
- package/dist/audit/filters.js.map +1 -0
- package/dist/audit/index.d.ts +3 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +3 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/service.d.ts +65 -0
- package/dist/audit/service.d.ts.map +1 -0
- package/dist/audit/service.js +103 -0
- package/dist/audit/service.js.map +1 -0
- package/dist/boot.d.ts +8 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +822 -0
- package/dist/boot.js.map +1 -0
- package/dist/constant-time.d.ts +3 -0
- package/dist/constant-time.d.ts.map +1 -0
- package/dist/constant-time.js +10 -0
- package/dist/constant-time.js.map +1 -0
- package/dist/email/driver.d.ts +16 -0
- package/dist/email/driver.d.ts.map +1 -0
- package/dist/email/driver.js +136 -0
- package/dist/email/driver.js.map +1 -0
- package/dist/email/index.d.ts +4 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +4 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/shell.d.ts +72 -0
- package/dist/email/shell.d.ts.map +1 -0
- package/dist/email/shell.js +146 -0
- package/dist/email/shell.js.map +1 -0
- package/dist/email/templates.d.ts +83 -0
- package/dist/email/templates.d.ts.map +1 -0
- package/dist/email/templates.js +96 -0
- package/dist/email/templates.js.map +1 -0
- package/dist/entitlements/check.d.ts +140 -0
- package/dist/entitlements/check.d.ts.map +1 -0
- package/dist/entitlements/check.js +276 -0
- package/dist/entitlements/check.js.map +1 -0
- package/dist/entitlements/clock-skew.d.ts +27 -0
- package/dist/entitlements/clock-skew.d.ts.map +1 -0
- package/dist/entitlements/clock-skew.js +58 -0
- package/dist/entitlements/clock-skew.js.map +1 -0
- package/dist/entitlements/gate.d.ts +113 -0
- package/dist/entitlements/gate.d.ts.map +1 -0
- package/dist/entitlements/gate.js +430 -0
- package/dist/entitlements/gate.js.map +1 -0
- package/dist/entitlements/hub-machine-token.d.ts +83 -0
- package/dist/entitlements/hub-machine-token.d.ts.map +1 -0
- package/dist/entitlements/hub-machine-token.js +175 -0
- package/dist/entitlements/hub-machine-token.js.map +1 -0
- package/dist/entitlements/hub-subject.d.ts +32 -0
- package/dist/entitlements/hub-subject.d.ts.map +1 -0
- package/dist/entitlements/hub-subject.js +68 -0
- package/dist/entitlements/hub-subject.js.map +1 -0
- package/dist/entitlements/index.d.ts +9 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +9 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/entitlements/poster.d.ts +81 -0
- package/dist/entitlements/poster.d.ts.map +1 -0
- package/dist/entitlements/poster.js +169 -0
- package/dist/entitlements/poster.js.map +1 -0
- package/dist/entitlements/profiles.d.ts +121 -0
- package/dist/entitlements/profiles.d.ts.map +1 -0
- package/dist/entitlements/profiles.js +212 -0
- package/dist/entitlements/profiles.js.map +1 -0
- package/dist/entitlements/slot.d.ts +33 -0
- package/dist/entitlements/slot.d.ts.map +1 -0
- package/dist/entitlements/slot.js +75 -0
- package/dist/entitlements/slot.js.map +1 -0
- package/dist/env.d.ts +293 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +383 -0
- package/dist/env.js.map +1 -0
- package/dist/files/http.d.ts +23 -0
- package/dist/files/http.d.ts.map +1 -0
- package/dist/files/http.js +66 -0
- package/dist/files/http.js.map +1 -0
- package/dist/files/index.d.ts +5 -0
- package/dist/files/index.d.ts.map +1 -0
- package/dist/files/index.js +5 -0
- package/dist/files/index.js.map +1 -0
- package/dist/files/serve.d.ts +43 -0
- package/dist/files/serve.d.ts.map +1 -0
- package/dist/files/serve.js +71 -0
- package/dist/files/serve.js.map +1 -0
- package/dist/files/service.d.ts +69 -0
- package/dist/files/service.d.ts.map +1 -0
- package/dist/files/service.js +188 -0
- package/dist/files/service.js.map +1 -0
- package/dist/files/spool.d.ts +21 -0
- package/dist/files/spool.d.ts.map +1 -0
- package/dist/files/spool.js +47 -0
- package/dist/files/spool.js.map +1 -0
- package/dist/identity/better-auth.d.ts +3927 -0
- package/dist/identity/better-auth.d.ts.map +1 -0
- package/dist/identity/better-auth.js +896 -0
- package/dist/identity/better-auth.js.map +1 -0
- package/dist/identity/demo-pass-plugin.d.ts +29 -0
- package/dist/identity/demo-pass-plugin.d.ts.map +1 -0
- package/dist/identity/demo-pass-plugin.js +88 -0
- package/dist/identity/demo-pass-plugin.js.map +1 -0
- package/dist/identity/demo-pass-rules.d.ts +84 -0
- package/dist/identity/demo-pass-rules.d.ts.map +1 -0
- package/dist/identity/demo-pass-rules.js +223 -0
- package/dist/identity/demo-pass-rules.js.map +1 -0
- package/dist/identity/demo-pass.d.ts +159 -0
- package/dist/identity/demo-pass.d.ts.map +1 -0
- package/dist/identity/demo-pass.js +319 -0
- package/dist/identity/demo-pass.js.map +1 -0
- package/dist/identity/hub-grant.d.ts +182 -0
- package/dist/identity/hub-grant.d.ts.map +1 -0
- package/dist/identity/hub-grant.js +594 -0
- package/dist/identity/hub-grant.js.map +1 -0
- package/dist/identity/hub-jwt.d.ts +22 -0
- package/dist/identity/hub-jwt.d.ts.map +1 -0
- package/dist/identity/hub-jwt.js +77 -0
- package/dist/identity/hub-jwt.js.map +1 -0
- package/dist/identity/hub-live-gate.d.ts +17 -0
- package/dist/identity/hub-live-gate.d.ts.map +1 -0
- package/dist/identity/hub-live-gate.js +146 -0
- package/dist/identity/hub-live-gate.js.map +1 -0
- package/dist/identity/hub-logout.d.ts +88 -0
- package/dist/identity/hub-logout.d.ts.map +1 -0
- package/dist/identity/hub-logout.js +158 -0
- package/dist/identity/hub-logout.js.map +1 -0
- package/dist/identity/hub-projection.d.ts +103 -0
- package/dist/identity/hub-projection.d.ts.map +1 -0
- package/dist/identity/hub-projection.js +130 -0
- package/dist/identity/hub-projection.js.map +1 -0
- package/dist/identity/hub-reconcile.d.ts +151 -0
- package/dist/identity/hub-reconcile.d.ts.map +1 -0
- package/dist/identity/hub-reconcile.js +400 -0
- package/dist/identity/hub-reconcile.js.map +1 -0
- package/dist/identity/hub-sso.d.ts +363 -0
- package/dist/identity/hub-sso.d.ts.map +1 -0
- package/dist/identity/hub-sso.js +536 -0
- package/dist/identity/hub-sso.js.map +1 -0
- package/dist/identity/hub-user-client.d.ts +222 -0
- package/dist/identity/hub-user-client.d.ts.map +1 -0
- package/dist/identity/hub-user-client.js +406 -0
- package/dist/identity/hub-user-client.js.map +1 -0
- package/dist/identity/index.d.ts +13 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +13 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/oauth-jwt.d.ts +32 -0
- package/dist/identity/oauth-jwt.d.ts.map +1 -0
- package/dist/identity/oauth-jwt.js +122 -0
- package/dist/identity/oauth-jwt.js.map +1 -0
- package/dist/identity/resolve-membership.d.ts +28 -0
- package/dist/identity/resolve-membership.d.ts.map +1 -0
- package/dist/identity/resolve-membership.js +69 -0
- package/dist/identity/resolve-membership.js.map +1 -0
- package/dist/identity/signing-key.d.ts +49 -0
- package/dist/identity/signing-key.d.ts.map +1 -0
- package/dist/identity/signing-key.js +144 -0
- package/dist/identity/signing-key.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/invitations/index.d.ts +2 -0
- package/dist/invitations/index.d.ts.map +1 -0
- package/dist/invitations/index.js +2 -0
- package/dist/invitations/index.js.map +1 -0
- package/dist/invitations/service.d.ts +36 -0
- package/dist/invitations/service.d.ts.map +1 -0
- package/dist/invitations/service.js +122 -0
- package/dist/invitations/service.js.map +1 -0
- package/dist/jobs/index.d.ts +3 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +3 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/pgboss.d.ts +119 -0
- package/dist/jobs/pgboss.d.ts.map +1 -0
- package/dist/jobs/pgboss.js +521 -0
- package/dist/jobs/pgboss.js.map +1 -0
- package/dist/jobs/timers.d.ts +127 -0
- package/dist/jobs/timers.d.ts.map +1 -0
- package/dist/jobs/timers.js +228 -0
- package/dist/jobs/timers.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +64 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/errors.d.ts +37 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +77 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/http.d.ts +35 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/http.js +80 -0
- package/dist/mcp/http.js.map +1 -0
- package/dist/mcp/index.d.ts +8 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/inputs.d.ts +19 -0
- package/dist/mcp/inputs.d.ts.map +1 -0
- package/dist/mcp/inputs.js +28 -0
- package/dist/mcp/inputs.js.map +1 -0
- package/dist/mcp/projects.d.ts +31 -0
- package/dist/mcp/projects.d.ts.map +1 -0
- package/dist/mcp/projects.js +315 -0
- package/dist/mcp/projects.js.map +1 -0
- package/dist/mcp/server.d.ts +52 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +93 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/teams.d.ts +7 -0
- package/dist/mcp/teams.d.ts.map +1 -0
- package/dist/mcp/teams.js +62 -0
- package/dist/mcp/teams.js.map +1 -0
- package/dist/mcp/tool-kit.d.ts +67 -0
- package/dist/mcp/tool-kit.d.ts.map +1 -0
- package/dist/mcp/tool-kit.js +74 -0
- package/dist/mcp/tool-kit.js.map +1 -0
- package/dist/members/removal.d.ts +95 -0
- package/dist/members/removal.d.ts.map +1 -0
- package/dist/members/removal.js +143 -0
- package/dist/members/removal.js.map +1 -0
- package/dist/middleware/auth-body.d.ts +25 -0
- package/dist/middleware/auth-body.d.ts.map +1 -0
- package/dist/middleware/auth-body.js +55 -0
- package/dist/middleware/auth-body.js.map +1 -0
- package/dist/middleware/auth-context.d.ts +170 -0
- package/dist/middleware/auth-context.d.ts.map +1 -0
- package/dist/middleware/auth-context.js +251 -0
- package/dist/middleware/auth-context.js.map +1 -0
- package/dist/middleware/body-cap.d.ts +17 -0
- package/dist/middleware/body-cap.d.ts.map +1 -0
- package/dist/middleware/body-cap.js +31 -0
- package/dist/middleware/body-cap.js.map +1 -0
- package/dist/middleware/body-refusal.d.ts +20 -0
- package/dist/middleware/body-refusal.d.ts.map +1 -0
- package/dist/middleware/body-refusal.js +5 -0
- package/dist/middleware/body-refusal.js.map +1 -0
- package/dist/middleware/cross-site.d.ts +61 -0
- package/dist/middleware/cross-site.d.ts.map +1 -0
- package/dist/middleware/cross-site.js +59 -0
- package/dist/middleware/cross-site.js.map +1 -0
- package/dist/middleware/hub-managed.d.ts +45 -0
- package/dist/middleware/hub-managed.d.ts.map +1 -0
- package/dist/middleware/hub-managed.js +56 -0
- package/dist/middleware/hub-managed.js.map +1 -0
- package/dist/middleware/idempotency.d.ts +14 -0
- package/dist/middleware/idempotency.d.ts.map +1 -0
- package/dist/middleware/idempotency.js +222 -0
- package/dist/middleware/idempotency.js.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +12 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/json-depth.d.ts +32 -0
- package/dist/middleware/json-depth.d.ts.map +1 -0
- package/dist/middleware/json-depth.js +80 -0
- package/dist/middleware/json-depth.js.map +1 -0
- package/dist/middleware/no-store.d.ts +21 -0
- package/dist/middleware/no-store.d.ts.map +1 -0
- package/dist/middleware/no-store.js +32 -0
- package/dist/middleware/no-store.js.map +1 -0
- package/dist/middleware/oauth-public.d.ts +16 -0
- package/dist/middleware/oauth-public.d.ts.map +1 -0
- package/dist/middleware/oauth-public.js +50 -0
- package/dist/middleware/oauth-public.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +182 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +277 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/middleware/request-id.d.ts +10 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +42 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/middleware/scopes.d.ts +33 -0
- package/dist/middleware/scopes.d.ts.map +1 -0
- package/dist/middleware/scopes.js +139 -0
- package/dist/middleware/scopes.js.map +1 -0
- package/dist/middleware/security-headers.d.ts +53 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +96 -0
- package/dist/middleware/security-headers.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +3 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/metrics.d.ts +17 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +82 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/otel.d.ts +20 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +54 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/pagination.d.ts +57 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +90 -0
- package/dist/pagination.js.map +1 -0
- package/dist/platform/edition.d.ts +57 -0
- package/dist/platform/edition.d.ts.map +1 -0
- package/dist/platform/edition.js +90 -0
- package/dist/platform/edition.js.map +1 -0
- package/dist/platform/entitlements.d.ts +26 -0
- package/dist/platform/entitlements.d.ts.map +1 -0
- package/dist/platform/entitlements.js +28 -0
- package/dist/platform/entitlements.js.map +1 -0
- package/dist/platform/events.d.ts +87 -0
- package/dist/platform/events.d.ts.map +1 -0
- package/dist/platform/events.js +32 -0
- package/dist/platform/events.js.map +1 -0
- package/dist/platform/index.d.ts +8 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +8 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/local-identity.d.ts +39 -0
- package/dist/platform/local-identity.d.ts.map +1 -0
- package/dist/platform/local-identity.js +87 -0
- package/dist/platform/local-identity.js.map +1 -0
- package/dist/platform/registry.d.ts +23 -0
- package/dist/platform/registry.d.ts.map +1 -0
- package/dist/platform/registry.js +5 -0
- package/dist/platform/registry.js.map +1 -0
- package/dist/platform/usage.d.ts +11 -0
- package/dist/platform/usage.d.ts.map +1 -0
- package/dist/platform/usage.js +12 -0
- package/dist/platform/usage.js.map +1 -0
- package/dist/platform/workspaces.d.ts +25 -0
- package/dist/platform/workspaces.d.ts.map +1 -0
- package/dist/platform/workspaces.js +44 -0
- package/dist/platform/workspaces.js.map +1 -0
- package/dist/projects/access.d.ts +40 -0
- package/dist/projects/access.d.ts.map +1 -0
- package/dist/projects/access.js +133 -0
- package/dist/projects/access.js.map +1 -0
- package/dist/projects/index.d.ts +2 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +2 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/route-label.d.ts +23 -0
- package/dist/route-label.d.ts.map +1 -0
- package/dist/route-label.js +29 -0
- package/dist/route-label.js.map +1 -0
- package/dist/routes/health.d.ts +30 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +54 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +3 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/wellknown.d.ts +11 -0
- package/dist/routes/wellknown.d.ts.map +1 -0
- package/dist/routes/wellknown.js +45 -0
- package/dist/routes/wellknown.js.map +1 -0
- package/dist/secret.d.ts +30 -0
- package/dist/secret.d.ts.map +1 -0
- package/dist/secret.js +97 -0
- package/dist/secret.js.map +1 -0
- package/dist/setup-transport.d.ts +23 -0
- package/dist/setup-transport.d.ts.map +1 -0
- package/dist/setup-transport.js +52 -0
- package/dist/setup-transport.js.map +1 -0
- package/dist/state.d.ts +21 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +4 -0
- package/dist/state.js.map +1 -0
- package/dist/storage/driver.d.ts +38 -0
- package/dist/storage/driver.d.ts.map +1 -0
- package/dist/storage/driver.js +14 -0
- package/dist/storage/driver.js.map +1 -0
- package/dist/storage/factory.d.ts +4 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/factory.js +20 -0
- package/dist/storage/factory.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +4 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/local.d.ts +21 -0
- package/dist/storage/local.d.ts.map +1 -0
- package/dist/storage/local.js +88 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/storage/s3.d.ts +29 -0
- package/dist/storage/s3.d.ts.map +1 -0
- package/dist/storage/s3.js +82 -0
- package/dist/storage/s3.js.map +1 -0
- package/dist/testing/fake-hub.d.ts +425 -0
- package/dist/testing/fake-hub.d.ts.map +1 -0
- package/dist/testing/fake-hub.js +1074 -0
- package/dist/testing/fake-hub.js.map +1 -0
- package/dist/testing/helpers.d.ts +124 -0
- package/dist/testing/helpers.d.ts.map +1 -0
- package/dist/testing/helpers.js +174 -0
- package/dist/testing/helpers.js.map +1 -0
- package/dist/testing/index.d.ts +12 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +12 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/setup-origins.d.ts +21 -0
- package/dist/testing/setup-origins.d.ts.map +1 -0
- package/dist/testing/setup-origins.js +57 -0
- package/dist/testing/setup-origins.js.map +1 -0
- package/dist/testing/sso-helpers.d.ts +43 -0
- package/dist/testing/sso-helpers.d.ts.map +1 -0
- package/dist/testing/sso-helpers.js +159 -0
- package/dist/testing/sso-helpers.js.map +1 -0
- package/dist/tool-definition.d.ts +382 -0
- package/dist/tool-definition.d.ts.map +1 -0
- package/dist/tool-definition.js +46 -0
- package/dist/tool-definition.js.map +1 -0
- package/dist/util/index.d.ts +8 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +8 -0
- package/dist/util/index.js.map +1 -0
- package/package.json +161 -0
- package/src/accounts/deletion.ts +389 -0
- package/src/accounts/erasure-log.ts +140 -0
- package/src/accounts/index.ts +5 -0
- package/src/accounts/mint-refusal.ts +67 -0
- package/src/accounts/signup-duplicate.ts +21 -0
- package/src/accounts/superadmin.ts +46 -0
- package/src/api/apikeys.ts +147 -0
- package/src/api/audit.ts +83 -0
- package/src/api/break-glass.ts +294 -0
- package/src/api/cli-auth.ts +308 -0
- package/src/api/create-api.ts +1403 -0
- package/src/api/demo-passes.ts +207 -0
- package/src/api/errors.ts +13 -0
- package/src/api/export.ts +482 -0
- package/src/api/files.ts +200 -0
- package/src/api/index.ts +29 -0
- package/src/api/invitations.ts +396 -0
- package/src/api/members.ts +617 -0
- package/src/api/onboarding.ts +50 -0
- package/src/api/openapi-doc.ts +34 -0
- package/src/api/projects.ts +788 -0
- package/src/api/scope-routes.ts +12 -0
- package/src/api/sso-connect.ts +246 -0
- package/src/api/sso-logout.ts +76 -0
- package/src/api/teams.ts +575 -0
- package/src/api/workspaces.ts +649 -0
- package/src/apikeys/index.ts +2 -0
- package/src/apikeys/peppers.ts +118 -0
- package/src/apikeys/service.ts +223 -0
- package/src/app.ts +228 -0
- package/src/audit/filters.ts +101 -0
- package/src/audit/index.ts +9 -0
- package/src/audit/service.ts +154 -0
- package/src/boot.ts +953 -0
- package/src/constant-time.ts +9 -0
- package/src/email/driver.ts +139 -0
- package/src/email/index.ts +26 -0
- package/src/email/shell.ts +201 -0
- package/src/email/templates.ts +184 -0
- package/src/entitlements/check.ts +435 -0
- package/src/entitlements/clock-skew.ts +58 -0
- package/src/entitlements/gate.ts +636 -0
- package/src/entitlements/hub-machine-token.ts +205 -0
- package/src/entitlements/hub-subject.ts +77 -0
- package/src/entitlements/index.ts +37 -0
- package/src/entitlements/poster.ts +265 -0
- package/src/entitlements/profiles.ts +303 -0
- package/src/entitlements/slot.ts +105 -0
- package/src/env.ts +456 -0
- package/src/files/http.ts +77 -0
- package/src/files/index.ts +4 -0
- package/src/files/serve.ts +115 -0
- package/src/files/service.ts +209 -0
- package/src/files/spool.ts +58 -0
- package/src/identity/better-auth.ts +1103 -0
- package/src/identity/demo-pass-plugin.ts +121 -0
- package/src/identity/demo-pass-rules.ts +229 -0
- package/src/identity/demo-pass.ts +390 -0
- package/src/identity/hub-grant.ts +704 -0
- package/src/identity/hub-jwt.ts +78 -0
- package/src/identity/hub-live-gate.ts +167 -0
- package/src/identity/hub-logout.ts +174 -0
- package/src/identity/hub-projection.ts +251 -0
- package/src/identity/hub-reconcile.ts +572 -0
- package/src/identity/hub-sso.ts +696 -0
- package/src/identity/hub-user-client.ts +554 -0
- package/src/identity/index.ts +56 -0
- package/src/identity/oauth-jwt.ts +128 -0
- package/src/identity/resolve-membership.ts +104 -0
- package/src/identity/signing-key.ts +164 -0
- package/src/index.ts +65 -0
- package/src/invitations/index.ts +1 -0
- package/src/invitations/service.ts +171 -0
- package/src/jobs/index.ts +25 -0
- package/src/jobs/pgboss.ts +594 -0
- package/src/jobs/timers.ts +287 -0
- package/src/logger.ts +67 -0
- package/src/mcp/errors.ts +111 -0
- package/src/mcp/http.ts +129 -0
- package/src/mcp/index.ts +28 -0
- package/src/mcp/inputs.ts +33 -0
- package/src/mcp/projects.ts +480 -0
- package/src/mcp/server.ts +174 -0
- package/src/mcp/teams.ts +97 -0
- package/src/mcp/tool-kit.ts +148 -0
- package/src/members/removal.ts +216 -0
- package/src/middleware/auth-body.ts +58 -0
- package/src/middleware/auth-context.ts +384 -0
- package/src/middleware/body-cap.ts +33 -0
- package/src/middleware/body-refusal.ts +23 -0
- package/src/middleware/cross-site.ts +122 -0
- package/src/middleware/hub-managed.ts +61 -0
- package/src/middleware/idempotency.ts +264 -0
- package/src/middleware/index.ts +33 -0
- package/src/middleware/json-depth.ts +74 -0
- package/src/middleware/no-store.ts +30 -0
- package/src/middleware/oauth-public.ts +54 -0
- package/src/middleware/rate-limit.ts +432 -0
- package/src/middleware/request-id.ts +54 -0
- package/src/middleware/scopes.ts +150 -0
- package/src/middleware/security-headers.ts +129 -0
- package/src/observability/index.ts +2 -0
- package/src/observability/metrics.ts +102 -0
- package/src/observability/otel.ts +79 -0
- package/src/pagination.ts +118 -0
- package/src/platform/edition.ts +140 -0
- package/src/platform/entitlements.ts +47 -0
- package/src/platform/events.ts +71 -0
- package/src/platform/index.ts +7 -0
- package/src/platform/local-identity.ts +90 -0
- package/src/platform/registry.ts +28 -0
- package/src/platform/usage.ts +13 -0
- package/src/platform/workspaces.ts +41 -0
- package/src/projects/access.ts +160 -0
- package/src/projects/index.ts +7 -0
- package/src/route-label.ts +29 -0
- package/src/routes/health.ts +79 -0
- package/src/routes/index.ts +2 -0
- package/src/routes/wellknown.ts +67 -0
- package/src/secret.ts +115 -0
- package/src/setup-transport.ts +46 -0
- package/src/state.ts +23 -0
- package/src/storage/driver.ts +48 -0
- package/src/storage/factory.ts +34 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/local.ts +93 -0
- package/src/storage/s3.ts +109 -0
- package/src/testing/fake-hub.ts +1316 -0
- package/src/testing/helpers.ts +254 -0
- package/src/testing/index.ts +11 -0
- package/src/testing/setup-origins.ts +58 -0
- package/src/testing/sso-helpers.ts +178 -0
- package/src/tool-definition.ts +463 -0
- package/src/util/index.ts +17 -0
- package/test/fixtures/onboarding-backfill.sql +13 -0
- package/test/fixtures/operator-user-id-backfill.sql +18 -0
- package/test/host/dr-lib.sh +253 -0
- package/test/host/drizzle/0000_chassis_baseline.sql +438 -0
- package/test/host/drizzle/0001_last_owner_guard.sql +42 -0
- package/test/host/drizzle/meta/0000_snapshot.json +3566 -0
- package/test/host/drizzle/meta/_journal.json +20 -0
- package/test/host/drizzle.config.ts +17 -0
- package/test/host/identity.ts +41 -0
- package/test/host/minimal-host.ts +35 -0
- package/test/host/minimal-tool.ts +123 -0
- package/test/integration/account-oracle-uniformity.test.ts +284 -0
- package/test/integration/account-recovery.test.ts +236 -0
- package/test/integration/account.test.ts +120 -0
- package/test/integration/api-quota.test.ts +208 -0
- package/test/integration/apikey-expiry.test.ts +178 -0
- package/test/integration/apikey-pepper-rotation.test.ts +190 -0
- package/test/integration/boot-posture.test.ts +169 -0
- package/test/integration/break-glass.test.ts +484 -0
- package/test/integration/cloud-lifecycle.test.ts +233 -0
- package/test/integration/credential-boundaries.test.ts +195 -0
- package/test/integration/default-workspace.test.ts +414 -0
- package/test/integration/demo-pass-rules.test.ts +332 -0
- package/test/integration/demo-pass.test.ts +1222 -0
- package/test/integration/dr-verify-real-dump.test.ts +154 -0
- package/test/integration/edition.test.ts +868 -0
- package/test/integration/email-change.test.ts +394 -0
- package/test/integration/empty-tool.test.ts +267 -0
- package/test/integration/entitlements-null-hook.test.ts +187 -0
- package/test/integration/entitlements.test.ts +693 -0
- package/test/integration/export-entries.test.ts +321 -0
- package/test/integration/files.test.ts +320 -0
- package/test/integration/first-boot-claim.test.ts +131 -0
- package/test/integration/gdpr.test.ts +532 -0
- package/test/integration/helpers.ts +29 -0
- package/test/integration/hub-grant.test.ts +505 -0
- package/test/integration/hub-live-gate.test.ts +612 -0
- package/test/integration/hub-managed-membership.test.ts +559 -0
- package/test/integration/hub-org-selector.test.ts +281 -0
- package/test/integration/hub-reconcile.test.ts +646 -0
- package/test/integration/hub-sso.test.ts +704 -0
- package/test/integration/hub-teams.test.ts +771 -0
- package/test/integration/idempotency.test.ts +261 -0
- package/test/integration/invite-verification.test.ts +210 -0
- package/test/integration/last-owner-race.test.ts +263 -0
- package/test/integration/m9-fixes.test.ts +290 -0
- package/test/integration/mcp-projects.test.ts +463 -0
- package/test/integration/member-removal-race.test.ts +466 -0
- package/test/integration/member-removal.test.ts +794 -0
- package/test/integration/oauth-mcp.test.ts +477 -0
- package/test/integration/oauth-workspace.test.ts +371 -0
- package/test/integration/observability.test.ts +183 -0
- package/test/integration/onboarding.test.ts +268 -0
- package/test/integration/orphan-purge.test.ts +451 -0
- package/test/integration/pagination.test.ts +344 -0
- package/test/integration/platform-core.test.ts +305 -0
- package/test/integration/platform.test.ts +246 -0
- package/test/integration/pool-survives-restart.test.ts +80 -0
- package/test/integration/projects-cloud.test.ts +193 -0
- package/test/integration/projects.test.ts +1310 -0
- package/test/integration/security-fixes.test.ts +190 -0
- package/test/integration/setup-transport.test.ts +118 -0
- package/test/integration/signin-wall.test.ts +103 -0
- package/test/integration/signing-key-rotation.test.ts +349 -0
- package/test/integration/sso-helpers.ts +15 -0
- package/test/integration/sso-logout.test.ts +283 -0
- package/test/integration/teams-cloud.test.ts +194 -0
- package/test/integration/teams.test.ts +551 -0
- package/test/integration/timers.test.ts +377 -0
- package/test/integration/two-factor.test.ts +301 -0
- package/test/integration/usage-window.test.ts +161 -0
- package/test/integration/workspace-create-cloud.test.ts +523 -0
- package/test/integration/workspace-create.test.ts +510 -0
- package/test/integration/workspace-scoping.test.ts +530 -0
- package/test/integration/zz-adv-replay-owner.test.ts +205 -0
- package/test/unit/apikey-peppers.test.ts +110 -0
- package/test/unit/apikey-prefix.test.ts +34 -0
- package/test/unit/audit-filters.test.ts +135 -0
- package/test/unit/auth-origins.test.ts +92 -0
- package/test/unit/body-cap.test.ts +84 -0
- package/test/unit/clock-skew.test.ts +68 -0
- package/test/unit/cross-site.test.ts +166 -0
- package/test/unit/declared-credits.test.ts +13 -0
- package/test/unit/demo-pass-rules.test.ts +192 -0
- package/test/unit/email-driver.test.ts +127 -0
- package/test/unit/end-pool.test.ts +181 -0
- package/test/unit/entitlement-check.test.ts +492 -0
- package/test/unit/entitlement-gate.test.ts +1333 -0
- package/test/unit/entitlement-profiles.test.ts +289 -0
- package/test/unit/erasure-log.test.ts +72 -0
- package/test/unit/error-mapping.test.ts +89 -0
- package/test/unit/export-entries.test.ts +85 -0
- package/test/unit/export-sanitize.test.ts +27 -0
- package/test/unit/files-head-route.test.ts +155 -0
- package/test/unit/files-http.test.ts +97 -0
- package/test/unit/head-rewrite.test.ts +72 -0
- package/test/unit/hub-create-org.test.ts +181 -0
- package/test/unit/hub-jwt.test.ts +93 -0
- package/test/unit/hub-sso-params.test.ts +39 -0
- package/test/unit/hub-subject.test.ts +83 -0
- package/test/unit/idempotency-crypto.test.ts +45 -0
- package/test/unit/json-depth.test.ts +88 -0
- package/test/unit/logger-redaction.test.ts +66 -0
- package/test/unit/mcp-errors.test.ts +110 -0
- package/test/unit/mcp-inputs.test.ts +106 -0
- package/test/unit/mcp-project-hints.test.ts +26 -0
- package/test/unit/no-store.test.ts +49 -0
- package/test/unit/no-tool-migration-filename.test.ts +70 -0
- package/test/unit/observability.test.ts +64 -0
- package/test/unit/openapi-doc.test.ts +93 -0
- package/test/unit/rate-limit-consume-on.test.ts +76 -0
- package/test/unit/rate-limit.test.ts +39 -0
- package/test/unit/readyz-storage.test.ts +157 -0
- package/test/unit/request-quota.test.ts +146 -0
- package/test/unit/scopes.test.ts +66 -0
- package/test/unit/security-headers.test.ts +131 -0
- package/test/unit/serve-content-type.test.ts +74 -0
- package/test/unit/setup-transport.test.ts +29 -0
- package/test/unit/storage-local.test.ts +53 -0
- package/test/unit/superadmin.test.ts +32 -0
- package/test/unit/timers.test.ts +287 -0
- package/test/unit/tool-definition-guards.test.ts +166 -0
- package/test/unit/tool-entitlements-guard.test.ts +168 -0
- package/test/unit/usage-poster.test.ts +542 -0
- package/test/unit/usage-window.test.ts +48 -0
- package/test/unit/workspace-create-audit.test.ts +48 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { count, eq, lt, desc } from 'drizzle-orm';
|
|
2
|
+
import { auditListRoute } from '@antasphere/chassis-contract/routes';
|
|
3
|
+
import { auditLog, user as userTable } from '@antasphere/chassis-db';
|
|
4
|
+
import { requireRole } from '../middleware/auth-context.js';
|
|
5
|
+
import { auditFilterConditions, auditWhere, cursorId } from '../audit/filters.js';
|
|
6
|
+
export function registerAuditRoutes(api, db) {
|
|
7
|
+
api.use('/audit', requireRole('admin'));
|
|
8
|
+
api.openapi(auditListRoute, async (c) => {
|
|
9
|
+
const principal = c.get('principal');
|
|
10
|
+
const query = c.req.valid('query');
|
|
11
|
+
const { limit } = query;
|
|
12
|
+
// SECURITY: the scope is the caller's workspace and nothing in the
|
|
13
|
+
// query can widen it; every filter narrows within it, as a bound
|
|
14
|
+
// parameter (audit/filters.ts). The cursor stays the last row id, so
|
|
15
|
+
// a page is "the next `limit` rows older than the cursor that match
|
|
16
|
+
// the same filters": a client that changes a filter starts over.
|
|
17
|
+
const scope = eq(auditLog.workspaceId, principal.workspaceId);
|
|
18
|
+
const filters = auditFilterConditions(query);
|
|
19
|
+
const cursor = cursorId(query.cursor);
|
|
20
|
+
const where = auditWhere(scope, filters, cursor !== null ? lt(auditLog.id, cursor) : null);
|
|
21
|
+
const rows = await db
|
|
22
|
+
.select({
|
|
23
|
+
id: auditLog.id,
|
|
24
|
+
actorUserId: auditLog.actorUserId,
|
|
25
|
+
actorEmail: userTable.email,
|
|
26
|
+
actorVia: auditLog.actorVia,
|
|
27
|
+
apiKeyId: auditLog.apiKeyId,
|
|
28
|
+
action: auditLog.action,
|
|
29
|
+
resourceType: auditLog.resourceType,
|
|
30
|
+
resourceId: auditLog.resourceId,
|
|
31
|
+
requestId: auditLog.requestId,
|
|
32
|
+
ip: auditLog.ip,
|
|
33
|
+
metadata: auditLog.metadata,
|
|
34
|
+
createdAt: auditLog.createdAt
|
|
35
|
+
})
|
|
36
|
+
.from(auditLog)
|
|
37
|
+
.leftJoin(userTable, eq(auditLog.actorUserId, userTable.id))
|
|
38
|
+
.where(where)
|
|
39
|
+
.orderBy(desc(auditLog.id))
|
|
40
|
+
.limit(limit + 1);
|
|
41
|
+
// The total is counted once per listing, on the first page: the count
|
|
42
|
+
// walks the same join and WHERE without the cursor, and a client keeps
|
|
43
|
+
// the figure while it loads the pages after.
|
|
44
|
+
let total = null;
|
|
45
|
+
if (cursor === null) {
|
|
46
|
+
const [counted] = await db
|
|
47
|
+
.select({ n: count() })
|
|
48
|
+
.from(auditLog)
|
|
49
|
+
.leftJoin(userTable, eq(auditLog.actorUserId, userTable.id))
|
|
50
|
+
.where(auditWhere(scope, filters, null));
|
|
51
|
+
total = counted?.n ?? 0;
|
|
52
|
+
}
|
|
53
|
+
const page = rows.slice(0, limit);
|
|
54
|
+
const nextCursor = rows.length > limit ? String(page[page.length - 1]?.id ?? '') : null;
|
|
55
|
+
return c.json({
|
|
56
|
+
entries: page.map((r) => ({
|
|
57
|
+
id: r.id,
|
|
58
|
+
actorUserId: r.actorUserId,
|
|
59
|
+
actorEmail: r.actorEmail,
|
|
60
|
+
actorVia: r.actorVia,
|
|
61
|
+
apiKeyId: r.apiKeyId,
|
|
62
|
+
action: r.action,
|
|
63
|
+
resourceType: r.resourceType,
|
|
64
|
+
resourceId: r.resourceId,
|
|
65
|
+
requestId: r.requestId,
|
|
66
|
+
ip: r.ip,
|
|
67
|
+
metadata: r.metadata,
|
|
68
|
+
createdAt: r.createdAt.toISOString()
|
|
69
|
+
})),
|
|
70
|
+
nextCursor,
|
|
71
|
+
total
|
|
72
|
+
}, 200);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/api/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { OpenAPIHono } from '@hono/zod-openapi';
|
|
2
|
+
import { type Db } from '@antasphere/chassis-db';
|
|
3
|
+
import type { Auth } from '../identity/better-auth.js';
|
|
4
|
+
import type { AuditService } from '../audit/service.js';
|
|
5
|
+
import type { Logger } from '../logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Break-glass superadmin recovery (ADR 010) — the instance-level recovery
|
|
8
|
+
* surface for the per-tenant hosting model. Two capabilities only:
|
|
9
|
+
*
|
|
10
|
+
* - claim-ownership: make the calling superadmin (or a named existing user)
|
|
11
|
+
* an ACTIVE OWNER of a workspace — creating the membership when absent,
|
|
12
|
+
* reactivating and promoting when present. It ADDS an owner and never
|
|
13
|
+
* removes one, so the migration-0009 last-owner trigger is satisfied by
|
|
14
|
+
* construction. The target workspace is explicit (`workspaceId`) once the
|
|
15
|
+
* instance runs several (ADR 014); a single-workspace instance keeps the
|
|
16
|
+
* old no-argument call.
|
|
17
|
+
* - reset-2fa: clear a locked-out user's second factor (the recovery ADR 009
|
|
18
|
+
* deferred to manual DB surgery). User-level — needs no workspace; its
|
|
19
|
+
* audit row is instance-attributed.
|
|
20
|
+
*
|
|
21
|
+
* SAFETY MODEL (a bug here = full instance compromise — keep all of it):
|
|
22
|
+
*
|
|
23
|
+
* - Off by default: superadmin exists ONLY while SUPERADMIN_EMAILS is set.
|
|
24
|
+
* - Session-only, twice over: these paths are deliberately UNLISTED in the
|
|
25
|
+
* fail-closed scope allowlist (middleware/scopes.ts), so machine
|
|
26
|
+
* principals 403 before reaching the handlers; AND the handlers resolve
|
|
27
|
+
* the Better Auth session directly — a request without a session cookie
|
|
28
|
+
* can never qualify, whatever headers it carries.
|
|
29
|
+
* - Verified email required: an allowlisted address that was never proven
|
|
30
|
+
* (invitation copyable-link accounts are unverified) does NOT match.
|
|
31
|
+
* - Identity is re-read from the DB by session user id — never derived from
|
|
32
|
+
* any header, body field, or client-supplied value.
|
|
33
|
+
* - No requireAuth()/requireRole() gate: the recovering operator may hold a
|
|
34
|
+
* session with NO membership (principal resolves to null), which is
|
|
35
|
+
* exactly the state break-glass exists to fix. The handlers do their own
|
|
36
|
+
* authentication and are exempted from the generic audit middleware
|
|
37
|
+
* because they write their own richer rows (see audit/service.ts).
|
|
38
|
+
*/
|
|
39
|
+
export interface BreakGlassRouteDeps {
|
|
40
|
+
db: Db;
|
|
41
|
+
auth: Auth;
|
|
42
|
+
audit: AuditService;
|
|
43
|
+
logger: Logger;
|
|
44
|
+
/** Raw SUPERADMIN_EMAILS value (already validated by the env schema). */
|
|
45
|
+
superadminEmails: string | undefined;
|
|
46
|
+
}
|
|
47
|
+
export declare function registerBreakGlassRoutes(api: OpenAPIHono, deps: BreakGlassRouteDeps): void;
|
|
48
|
+
//# sourceMappingURL=break-glass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"break-glass.d.ts","sourceRoot":"","sources":["../../src/api/break-glass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAOrD,OAAO,EAA8D,KAAK,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAC7G,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,EAAE,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AASD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAsO1F"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { and, eq } from 'drizzle-orm';
|
|
2
|
+
import { breakGlassClaimOwnershipRoute, breakGlassResetTwoFactorRoute } from '@antasphere/chassis-contract/routes';
|
|
3
|
+
import { twoFactor, user as userTable, workspaceMembers, workspaces } from '@antasphere/chassis-db';
|
|
4
|
+
import { parseSuperadminEmails } from '../accounts/superadmin.js';
|
|
5
|
+
const err = (code, message) => ({ error: { code, message } });
|
|
6
|
+
export function registerBreakGlassRoutes(api, deps) {
|
|
7
|
+
const { db, auth, audit, logger } = deps;
|
|
8
|
+
const allowlist = parseSuperadminEmails(deps.superadminEmails);
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the caller as a superadmin. One uniform `forbidden` for every
|
|
11
|
+
* rejection reason (dormant, not listed, unverified) so the endpoint is
|
|
12
|
+
* not an oracle for the allowlist's contents.
|
|
13
|
+
*/
|
|
14
|
+
const resolveSuperadmin = async (c) => {
|
|
15
|
+
// Session-only: the verified session identity, never a header or bearer.
|
|
16
|
+
// Machine credentials died at the fail-closed scope gate already; a
|
|
17
|
+
// cookieless request has no session and stops here.
|
|
18
|
+
const session = await auth.api.getSession({ headers: c.req.raw.headers });
|
|
19
|
+
if (!session?.user)
|
|
20
|
+
return { kind: 'unauthenticated' };
|
|
21
|
+
if (allowlist.size === 0)
|
|
22
|
+
return { kind: 'forbidden' };
|
|
23
|
+
// Fresh row by session user id — email + verification state are read
|
|
24
|
+
// from the database, not trusted from session claims.
|
|
25
|
+
const [u] = await db
|
|
26
|
+
.select({
|
|
27
|
+
id: userTable.id,
|
|
28
|
+
email: userTable.email,
|
|
29
|
+
emailVerified: userTable.emailVerified,
|
|
30
|
+
name: userTable.name
|
|
31
|
+
})
|
|
32
|
+
.from(userTable)
|
|
33
|
+
.where(eq(userTable.id, session.user.id))
|
|
34
|
+
.limit(1);
|
|
35
|
+
if (!u)
|
|
36
|
+
return { kind: 'forbidden' };
|
|
37
|
+
if (!allowlist.has(u.email.toLowerCase()))
|
|
38
|
+
return { kind: 'forbidden' };
|
|
39
|
+
if (!u.emailVerified)
|
|
40
|
+
return { kind: 'forbidden' };
|
|
41
|
+
return { kind: 'ok', caller: { userId: u.id, email: u.email, name: u.name } };
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The workspace an owner-claim targets (ADR 014). Explicit `workspaceId`
|
|
45
|
+
* wins; omitted, it resolves ONLY while the instance runs a single
|
|
46
|
+
* workspace — with several, recovery must name its target (400
|
|
47
|
+
* workspace_required), never guess one.
|
|
48
|
+
*/
|
|
49
|
+
const resolveTargetWorkspace = async (explicit) => {
|
|
50
|
+
if (explicit) {
|
|
51
|
+
const [ws] = await db
|
|
52
|
+
.select({ id: workspaces.id })
|
|
53
|
+
.from(workspaces)
|
|
54
|
+
.where(eq(workspaces.id, explicit))
|
|
55
|
+
.limit(1);
|
|
56
|
+
return ws ? { kind: 'ok', id: ws.id } : { kind: 'not_found' };
|
|
57
|
+
}
|
|
58
|
+
const rows = await db.select({ id: workspaces.id }).from(workspaces).limit(2);
|
|
59
|
+
const [only] = rows;
|
|
60
|
+
if (!only)
|
|
61
|
+
return { kind: 'not_setup' };
|
|
62
|
+
if (rows.length > 1)
|
|
63
|
+
return { kind: 'ambiguous' };
|
|
64
|
+
return { kind: 'ok', id: only.id };
|
|
65
|
+
};
|
|
66
|
+
api.openapi(breakGlassClaimOwnershipRoute, async (c) => {
|
|
67
|
+
const resolved = await resolveSuperadmin(c);
|
|
68
|
+
if (resolved.kind === 'unauthenticated') {
|
|
69
|
+
return c.json(err('unauthenticated', 'Authentication required'), 401);
|
|
70
|
+
}
|
|
71
|
+
if (resolved.kind === 'forbidden') {
|
|
72
|
+
return c.json(err('forbidden', 'Break-glass is not available to this caller'), 403);
|
|
73
|
+
}
|
|
74
|
+
const caller = resolved.caller;
|
|
75
|
+
const body = c.req.valid('json');
|
|
76
|
+
const targetWs = await resolveTargetWorkspace(body.workspaceId);
|
|
77
|
+
if (targetWs.kind === 'not_setup') {
|
|
78
|
+
return c.json(err('not_setup', 'This instance has not completed setup'), 409);
|
|
79
|
+
}
|
|
80
|
+
if (targetWs.kind === 'not_found') {
|
|
81
|
+
return c.json(err('not_found', 'Target workspace not found'), 404);
|
|
82
|
+
}
|
|
83
|
+
if (targetWs.kind === 'ambiguous') {
|
|
84
|
+
return c.json(err('workspace_required', 'This instance has several workspaces — pass workspaceId explicitly'), 400);
|
|
85
|
+
}
|
|
86
|
+
const ws = { id: targetWs.id };
|
|
87
|
+
// Target: a named existing user, or the calling superadmin.
|
|
88
|
+
let target = { userId: caller.userId, email: caller.email };
|
|
89
|
+
if (body.userId) {
|
|
90
|
+
const [t] = await db
|
|
91
|
+
.select({ id: userTable.id, email: userTable.email })
|
|
92
|
+
.from(userTable)
|
|
93
|
+
.where(eq(userTable.id, body.userId))
|
|
94
|
+
.limit(1);
|
|
95
|
+
if (!t)
|
|
96
|
+
return c.json(err('not_found', 'Target user not found'), 404);
|
|
97
|
+
target = { userId: t.id, email: t.email };
|
|
98
|
+
}
|
|
99
|
+
const [before] = await db
|
|
100
|
+
.select({
|
|
101
|
+
id: workspaceMembers.id,
|
|
102
|
+
role: workspaceMembers.role,
|
|
103
|
+
isActive: workspaceMembers.isActive
|
|
104
|
+
})
|
|
105
|
+
.from(workspaceMembers)
|
|
106
|
+
.where(and(eq(workspaceMembers.workspaceId, ws.id), eq(workspaceMembers.userId, target.userId)))
|
|
107
|
+
.limit(1);
|
|
108
|
+
// Additive by construction: create-or-promote to an ACTIVE OWNER. The
|
|
109
|
+
// 0009 last-owner trigger only rejects operations that REMOVE the last
|
|
110
|
+
// active owner — adding one is always legal, including the first owner
|
|
111
|
+
// of an ownerless workspace.
|
|
112
|
+
const [after] = await db
|
|
113
|
+
.insert(workspaceMembers)
|
|
114
|
+
// origin='local' on BOTH paths (BG-1, PRDCT-1356): a break-glass owner
|
|
115
|
+
// is the tool's own business, never hub truth. Left at 'hub' (the
|
|
116
|
+
// conflict path once kept the row's old origin), the cloud reconciler's
|
|
117
|
+
// deactivation sweep — which targets origin='hub' rows the hub no
|
|
118
|
+
// longer asserts — undid the recovery ~12 s later.
|
|
119
|
+
.values({ workspaceId: ws.id, userId: target.userId, role: 'owner', isActive: true, origin: 'local' })
|
|
120
|
+
.onConflictDoUpdate({
|
|
121
|
+
target: [workspaceMembers.workspaceId, workspaceMembers.userId],
|
|
122
|
+
set: { role: 'owner', isActive: true, origin: 'local' }
|
|
123
|
+
})
|
|
124
|
+
.returning({ id: workspaceMembers.id });
|
|
125
|
+
if (!after)
|
|
126
|
+
throw new Error('break-glass ownership upsert returned no row');
|
|
127
|
+
logger.warn({
|
|
128
|
+
superadminUserId: caller.userId,
|
|
129
|
+
superadminEmail: caller.email,
|
|
130
|
+
targetUserId: target.userId,
|
|
131
|
+
targetEmail: target.email,
|
|
132
|
+
workspaceId: ws.id
|
|
133
|
+
}, 'BREAK-GLASS: workspace ownership claimed');
|
|
134
|
+
await audit.write({
|
|
135
|
+
workspaceId: ws.id,
|
|
136
|
+
principal: { userId: caller.userId, via: 'session' },
|
|
137
|
+
action: 'break_glass.claim_ownership',
|
|
138
|
+
resourceType: 'member',
|
|
139
|
+
resourceId: after.id,
|
|
140
|
+
requestId: c.get('requestId'),
|
|
141
|
+
metadata: {
|
|
142
|
+
superadminUserId: caller.userId,
|
|
143
|
+
superadminEmail: caller.email,
|
|
144
|
+
targetUserId: target.userId,
|
|
145
|
+
targetEmail: target.email,
|
|
146
|
+
before: before ? { role: before.role, isActive: before.isActive } : null,
|
|
147
|
+
after: { role: 'owner', isActive: true },
|
|
148
|
+
created: !before
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return c.json({
|
|
152
|
+
memberId: after.id,
|
|
153
|
+
userId: target.userId,
|
|
154
|
+
email: target.email,
|
|
155
|
+
workspaceId: ws.id,
|
|
156
|
+
role: 'owner',
|
|
157
|
+
isActive: true,
|
|
158
|
+
created: !before
|
|
159
|
+
}, 200);
|
|
160
|
+
});
|
|
161
|
+
api.openapi(breakGlassResetTwoFactorRoute, async (c) => {
|
|
162
|
+
const resolved = await resolveSuperadmin(c);
|
|
163
|
+
if (resolved.kind === 'unauthenticated') {
|
|
164
|
+
return c.json(err('unauthenticated', 'Authentication required'), 401);
|
|
165
|
+
}
|
|
166
|
+
if (resolved.kind === 'forbidden') {
|
|
167
|
+
return c.json(err('forbidden', 'Break-glass is not available to this caller'), 403);
|
|
168
|
+
}
|
|
169
|
+
const caller = resolved.caller;
|
|
170
|
+
const { userId } = c.req.valid('json');
|
|
171
|
+
const [target] = await db
|
|
172
|
+
.select({
|
|
173
|
+
id: userTable.id,
|
|
174
|
+
email: userTable.email,
|
|
175
|
+
twoFactorEnabled: userTable.twoFactorEnabled
|
|
176
|
+
})
|
|
177
|
+
.from(userTable)
|
|
178
|
+
.where(eq(userTable.id, userId))
|
|
179
|
+
.limit(1);
|
|
180
|
+
if (!target)
|
|
181
|
+
return c.json(err('not_found', 'Target user not found'), 404);
|
|
182
|
+
// Clear the factor: the two_factor row (secret + backup codes) and the
|
|
183
|
+
// user flag. Idempotent — resetting an unenrolled user is a no-op 200.
|
|
184
|
+
const removed = await db
|
|
185
|
+
.delete(twoFactor)
|
|
186
|
+
.where(eq(twoFactor.userId, target.id))
|
|
187
|
+
.returning({ id: twoFactor.id });
|
|
188
|
+
await db.update(userTable).set({ twoFactorEnabled: false }).where(eq(userTable.id, target.id));
|
|
189
|
+
const hadTwoFactor = removed.length > 0 || target.twoFactorEnabled === true;
|
|
190
|
+
logger.warn({
|
|
191
|
+
superadminUserId: caller.userId,
|
|
192
|
+
superadminEmail: caller.email,
|
|
193
|
+
targetUserId: target.id,
|
|
194
|
+
targetEmail: target.email,
|
|
195
|
+
hadTwoFactor
|
|
196
|
+
}, 'BREAK-GLASS: two-factor reset');
|
|
197
|
+
// INSTANCE-attributed (workspace_id NULL, ADR 014): a second factor is a
|
|
198
|
+
// user property, not any workspace's — the row needs no workspace home.
|
|
199
|
+
await audit.write({
|
|
200
|
+
workspaceId: null,
|
|
201
|
+
principal: { userId: caller.userId, via: 'session' },
|
|
202
|
+
action: 'break_glass.reset_two_factor',
|
|
203
|
+
resourceType: 'user',
|
|
204
|
+
resourceId: target.id,
|
|
205
|
+
requestId: c.get('requestId'),
|
|
206
|
+
metadata: {
|
|
207
|
+
superadminUserId: caller.userId,
|
|
208
|
+
superadminEmail: caller.email,
|
|
209
|
+
targetUserId: target.id,
|
|
210
|
+
targetEmail: target.email,
|
|
211
|
+
hadTwoFactor
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return c.json({ userId: target.id, hadTwoFactor }, 200);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=break-glass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"break-glass.js","sourceRoot":"","sources":["../../src/api/break-glass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { OpenAPIHono } from '@hono/zod-openapi';
|
|
2
|
+
import type { ScopeRoutes } from './scope-routes.js';
|
|
3
|
+
import { type Db } from '@antasphere/chassis-db';
|
|
4
|
+
import type { Auth } from '../identity/better-auth.js';
|
|
5
|
+
import type { HubSsoService } from '../identity/hub-sso.js';
|
|
6
|
+
import type { ApiKeyService } from '../apikeys/service.js';
|
|
7
|
+
import type { AuditService } from '../audit/service.js';
|
|
8
|
+
import type { EmailDriver } from '../email/driver.js';
|
|
9
|
+
import type { Logger } from '../logger.js';
|
|
10
|
+
/**
|
|
11
|
+
* Browserless CLI/agent auth (the tool CLI's `auth login-*` flow):
|
|
12
|
+
*
|
|
13
|
+
* POST /cli/auth/request → email a 6-digit sign-in OTP
|
|
14
|
+
* POST /cli/auth/complete → verify the OTP, mint an API key
|
|
15
|
+
*
|
|
16
|
+
* Built ENTIRELY on the existing email-OTP primitive — no new credential
|
|
17
|
+
* machinery. `request` delegates to the emailOTP plugin's
|
|
18
|
+
* send-verification-otp (type "sign-in"); with the instance's
|
|
19
|
+
* `disableSignUp: true` an unknown email gets a generic success and NO mail
|
|
20
|
+
* (the plugin deletes the pending code — no enumeration oracle, no user
|
|
21
|
+
* minted). `complete` delegates to the plugin's sign-in endpoint, whose
|
|
22
|
+
* verification is atomic and attempt-limited (3 per code); with
|
|
23
|
+
* `disableSignUp` an unknown email fails exactly like a wrong code. So the
|
|
24
|
+
* closed-signup invariant (the three switches) is untouched: this surface
|
|
25
|
+
* can only ever sign in accounts that already exist (setup owner, workspace
|
|
26
|
+
* invitation, collaborator claim).
|
|
27
|
+
*
|
|
28
|
+
* On success the sign-in's throwaway session is used server-side only: mint
|
|
29
|
+
* the key (the tool's read + write scopes — the agent surface, never its
|
|
30
|
+
* export scope), DELETE the session, and return the key once. The
|
|
31
|
+
* "sessions only mint keys" rule holds in spirit: the mint is bound to a
|
|
32
|
+
* fresh, fully verified interactive sign-in, not to a machine credential
|
|
33
|
+
* (machine principals can't even reach these paths — they are unlisted in
|
|
34
|
+
* the scope allowlist and 403 fail-closed).
|
|
35
|
+
*
|
|
36
|
+
* 2FA-enrolled users are REJECTED (403 two_factor_required): the config
|
|
37
|
+
* hooks.after in identity/better-auth.ts parks their OTP sign-in behind the
|
|
38
|
+
* TOTP step, which a browserless flow cannot complete — they mint keys in
|
|
39
|
+
* the dashboard instead. Never bypass that hook here.
|
|
40
|
+
*
|
|
41
|
+
* Without a delivering email driver both endpoints answer 400
|
|
42
|
+
* otp_unavailable (the emailOTP plugin is not even registered then) —
|
|
43
|
+
* self-hosters without SMTP paste a dashboard-minted key (the CLI's `login`).
|
|
44
|
+
*
|
|
45
|
+
* On EDITION=cloud (hubSso present) BOTH mint endpoints refuse outright —
|
|
46
|
+
* 403 cli_otp_disabled, checked BEFORE the mailer/plugin checks so a
|
|
47
|
+
* mailerless cloud instance steers to `antasphere login` too. This is the
|
|
48
|
+
* CLI half of the D1 hub-only entrance closure (the human half is the
|
|
49
|
+
* emailOTP sign-in refusal in identity/better-auth.ts): every cloud
|
|
50
|
+
* credential — human session AND machine key — must trace through the hub
|
|
51
|
+
* so its audit log is the complete access record. Cloud CLI keys are minted
|
|
52
|
+
* by `antasphere login` + /sso/cli-connect (api/sso-connect.ts) instead.
|
|
53
|
+
* oss keeps this flow unchanged.
|
|
54
|
+
*
|
|
55
|
+
* DELETE /cli/auth/key (the CLI's `logout`) stays OPEN on both editions: it
|
|
56
|
+
* revokes exactly the PRESENTING key — revocation narrows access and is the
|
|
57
|
+
* cleanup path every mint above needs.
|
|
58
|
+
*
|
|
59
|
+
* Rate limits (api/index.ts): request rides the OTP wall (per IP + email),
|
|
60
|
+
* complete rides the login wall (per IP + email).
|
|
61
|
+
*/
|
|
62
|
+
export interface CliAuthRouteDeps {
|
|
63
|
+
db: Db;
|
|
64
|
+
auth: Auth;
|
|
65
|
+
email: EmailDriver;
|
|
66
|
+
apiKeys: ApiKeyService;
|
|
67
|
+
audit: AuditService;
|
|
68
|
+
logger: Logger;
|
|
69
|
+
/**
|
|
70
|
+
* Cloud presence switch (internal/federation.md, D1 hub-only login): when set
|
|
71
|
+
* (EDITION=cloud boots only), the OTP mint pair refuses 403
|
|
72
|
+
* cli_otp_disabled. Only the boolean presence is consulted — the service
|
|
73
|
+
* itself is never called from this module. The self-revoke is unaffected.
|
|
74
|
+
*/
|
|
75
|
+
hubSso?: HubSsoService | undefined;
|
|
76
|
+
/** The CLI key's fixed grant — the agent surface, never the export scope. */
|
|
77
|
+
cliKeyScopes: readonly string[];
|
|
78
|
+
/** The tool's instantiation of the scope-carrying mint route. */
|
|
79
|
+
routes: Pick<ScopeRoutes, 'cliAuthCompleteRoute'>;
|
|
80
|
+
/** The tool's name in the cloud refusal sentence (`identity.displayName`). */
|
|
81
|
+
displayName: string;
|
|
82
|
+
}
|
|
83
|
+
export declare function registerCliAuthRoutes(api: OpenAPIHono, deps: CliAuthRouteDeps): void;
|
|
84
|
+
//# sourceMappingURL=cli-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-auth.d.ts","sourceRoot":"","sources":["../../src/api/cli-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAA2B,KAAK,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,EAAE,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACnC,6EAA6E;IAC7E,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,iEAAiE;IACjE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC;IAClD,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;CACrB;AAoBD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAuMpF"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { and, eq, isNull, sql } from 'drizzle-orm';
|
|
2
|
+
import { cliAuthRequestRoute, cliAuthRevokeRoute } from '@antasphere/chassis-contract/routes';
|
|
3
|
+
import { apiKeys as apiKeysTable } from '@antasphere/chassis-db';
|
|
4
|
+
import { resolveMembership } from '../identity/resolve-membership.js';
|
|
5
|
+
const err = (code, message) => ({ error: { code, message } });
|
|
6
|
+
/** better-auth APIError carries { body: { code, message } }; match by code. */
|
|
7
|
+
function betterAuthErrorCode(e) {
|
|
8
|
+
const body = e?.body;
|
|
9
|
+
return typeof body?.code === 'string' ? body.code : null;
|
|
10
|
+
}
|
|
11
|
+
export function registerCliAuthRoutes(api, deps) {
|
|
12
|
+
const { db, auth, email, apiKeys, audit, logger, hubSso, cliKeyScopes } = deps;
|
|
13
|
+
const { cliAuthCompleteRoute } = deps.routes;
|
|
14
|
+
const otpApi = auth.api;
|
|
15
|
+
/** The D1 cloud refusal — identical on both mint routes, checked FIRST. */
|
|
16
|
+
const cloudRefusal = () => err('cli_otp_disabled', 'This instance signs in through the Antasphere hub — run `antasphere login` once; ' +
|
|
17
|
+
`the ${deps.displayName} CLI then connects automatically`);
|
|
18
|
+
api.openapi(cliAuthRequestRoute, async (c) => {
|
|
19
|
+
if (hubSso)
|
|
20
|
+
return c.json(cloudRefusal(), 403);
|
|
21
|
+
if (!email.delivers || !otpApi.sendVerificationOTP) {
|
|
22
|
+
return c.json(err('otp_unavailable', 'This instance has no email driver — sign in to the dashboard and mint an API key instead'), 400);
|
|
23
|
+
}
|
|
24
|
+
const body = c.req.valid('json');
|
|
25
|
+
try {
|
|
26
|
+
// Generic success either way; the plugin sends only to existing
|
|
27
|
+
// accounts (disableSignUp) — deliberately not observable here.
|
|
28
|
+
await otpApi.sendVerificationOTP({ body: { email: body.email, type: 'sign-in' } });
|
|
29
|
+
}
|
|
30
|
+
catch (cause) {
|
|
31
|
+
// INVALID_EMAIL can't happen (contract-validated); anything else is internal.
|
|
32
|
+
logger.error({ err: cause }, 'cli-auth: OTP send failed');
|
|
33
|
+
return c.json(err('internal', 'Could not send the sign-in code — try again'), 500);
|
|
34
|
+
}
|
|
35
|
+
return c.json({ sent: true }, 200);
|
|
36
|
+
});
|
|
37
|
+
api.openapi(cliAuthCompleteRoute, async (c) => {
|
|
38
|
+
if (hubSso)
|
|
39
|
+
return c.json(cloudRefusal(), 403);
|
|
40
|
+
if (!email.delivers || !otpApi.signInEmailOTP) {
|
|
41
|
+
return c.json(err('otp_unavailable', 'This instance has no email driver — sign in to the dashboard and mint an API key instead'), 400);
|
|
42
|
+
}
|
|
43
|
+
const body = c.req.valid('json');
|
|
44
|
+
let signedIn;
|
|
45
|
+
try {
|
|
46
|
+
signedIn = await otpApi.signInEmailOTP({ body: { email: body.email, otp: body.otp } });
|
|
47
|
+
}
|
|
48
|
+
catch (cause) {
|
|
49
|
+
const code = betterAuthErrorCode(cause);
|
|
50
|
+
if (code === 'TOO_MANY_ATTEMPTS') {
|
|
51
|
+
return c.json(err('too_many_attempts', 'Too many wrong codes — request a fresh one'), 429);
|
|
52
|
+
}
|
|
53
|
+
// INVALID_OTP covers wrong code AND unknown account (disableSignUp);
|
|
54
|
+
// OTP_EXPIRED joins them — one uniform 401, no enumeration.
|
|
55
|
+
if (code === 'INVALID_OTP' || code === 'OTP_EXPIRED' || code === 'USER_NOT_FOUND') {
|
|
56
|
+
return c.json(err('invalid_otp', 'The code is wrong, expired, or not for this email'), 401);
|
|
57
|
+
}
|
|
58
|
+
logger.error({ err: cause }, 'cli-auth: OTP sign-in failed');
|
|
59
|
+
return c.json(err('internal', 'Sign-in failed — try again'), 500);
|
|
60
|
+
}
|
|
61
|
+
// The 2FA hook (identity/better-auth.ts) parks enrolled users behind the
|
|
62
|
+
// TOTP step and answers { twoFactorRedirect } with no session. A
|
|
63
|
+
// browserless flow cannot complete that dance — refuse, never bypass.
|
|
64
|
+
if (!('token' in signedIn)) {
|
|
65
|
+
return c.json(err('two_factor_required', 'This account has two-factor auth enabled — sign in to the dashboard and mint an API key there'), 403);
|
|
66
|
+
}
|
|
67
|
+
const { token: sessionToken, user } = signedIn;
|
|
68
|
+
const dropSession = async () => {
|
|
69
|
+
try {
|
|
70
|
+
const authCtx = await auth.$context;
|
|
71
|
+
await authCtx.internalAdapter.deleteSession(sessionToken);
|
|
72
|
+
}
|
|
73
|
+
catch (cause) {
|
|
74
|
+
// Advisory: the session was never handed out; expiry bounds the residue.
|
|
75
|
+
logger.warn({ err: cause }, 'cli-auth: throwaway session cleanup failed');
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
// Same live-membership discipline as every credential path: no active
|
|
79
|
+
// membership, no key (e.g. a deactivated member's account still signs in
|
|
80
|
+
// at the Better Auth layer but has no standing on this instance). The
|
|
81
|
+
// key is USER-SCOPED by default (user-scoped credential model): it acts
|
|
82
|
+
// as its holder and the target workspace is a per-request parameter.
|
|
83
|
+
// `workspaceId` in the body is an optional PIN — a requested workspace
|
|
84
|
+
// the account is not an active member of answers the SAME uniform 403
|
|
85
|
+
// as having none at all (no oracle about other workspaces).
|
|
86
|
+
const membership = await resolveMembership(db, user.id, body.workspaceId ?? null);
|
|
87
|
+
if (!membership) {
|
|
88
|
+
await dropSession();
|
|
89
|
+
return c.json(err('no_membership', 'This account has no active membership on this instance'), 403);
|
|
90
|
+
}
|
|
91
|
+
const pinnedWorkspaceId = body.workspaceId ?? null;
|
|
92
|
+
const name = body.keyName ?? `CLI login ${new Date().toISOString().slice(0, 10)}`;
|
|
93
|
+
const expiresAt = body.expiresInDays ? new Date(Date.now() + body.expiresInDays * 86_400_000) : null;
|
|
94
|
+
const minted = await apiKeys.mint({
|
|
95
|
+
workspaceId: pinnedWorkspaceId,
|
|
96
|
+
createdBy: user.id,
|
|
97
|
+
name,
|
|
98
|
+
scopes: [...cliKeyScopes],
|
|
99
|
+
expiresAt
|
|
100
|
+
});
|
|
101
|
+
await dropSession();
|
|
102
|
+
const [row] = await db.select().from(apiKeysTable).where(eq(apiKeysTable.id, minted.id)).limit(1);
|
|
103
|
+
if (!row) {
|
|
104
|
+
return c.json(err('internal', 'Key mint failed — try again'), 500);
|
|
105
|
+
}
|
|
106
|
+
// This path is principal-less (public route), so the audit middleware
|
|
107
|
+
// cannot attribute it — write the row directly, like /setup does. An
|
|
108
|
+
// unpinned mint is a USER-credential event with no one workspace home:
|
|
109
|
+
// the row is instance-attributed (workspaceId null, like the orphan
|
|
110
|
+
// purge); a pinned mint lands in the pinned workspace's trail.
|
|
111
|
+
await audit.write({
|
|
112
|
+
workspaceId: pinnedWorkspaceId,
|
|
113
|
+
principal: { userId: user.id, via: 'session' },
|
|
114
|
+
action: 'apikey.create',
|
|
115
|
+
resourceType: 'api_key',
|
|
116
|
+
resourceId: minted.id,
|
|
117
|
+
requestId: c.get('requestId'),
|
|
118
|
+
metadata: {
|
|
119
|
+
name,
|
|
120
|
+
scopes: [...cliKeyScopes],
|
|
121
|
+
via: 'cli_otp',
|
|
122
|
+
workspaceId: pinnedWorkspaceId,
|
|
123
|
+
expiresAt: expiresAt?.toISOString() ?? null
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return c.json({
|
|
127
|
+
key: minted.key,
|
|
128
|
+
apiKey: {
|
|
129
|
+
id: row.id,
|
|
130
|
+
name: row.name,
|
|
131
|
+
keyId: row.keyId,
|
|
132
|
+
scopes: row.scopes,
|
|
133
|
+
workspaceId: row.workspaceId,
|
|
134
|
+
createdBy: row.createdBy,
|
|
135
|
+
createdAt: row.createdAt.toISOString(),
|
|
136
|
+
lastUsedAt: row.lastUsedAt?.toISOString() ?? null,
|
|
137
|
+
revokedAt: row.revokedAt?.toISOString() ?? null,
|
|
138
|
+
expiresAt: row.expiresAt?.toISOString() ?? null
|
|
139
|
+
},
|
|
140
|
+
user: { id: user.id, email: user.email, name: user.name },
|
|
141
|
+
workspaceId: pinnedWorkspaceId
|
|
142
|
+
}, 201);
|
|
143
|
+
});
|
|
144
|
+
// CLI logout: revoke exactly the PRESENTING key — possession is the
|
|
145
|
+
// authority to kill itself. The ONE /cli/auth route open to machine
|
|
146
|
+
// principals (scope allowlist, the tool's write scope — every CLI-minted key
|
|
147
|
+
// carries it); there is no id parameter, so no OTHER key is nameable, and
|
|
148
|
+
// the handler acts only on principal.apiKeyId, which the credential
|
|
149
|
+
// resolver derived from the presented secret. Sessions are refused — the
|
|
150
|
+
// dashboard (DELETE /api-keys/{id}) is their key-management surface — and
|
|
151
|
+
// so are OAuth bearers (no apiKeyId). Deliberately edition-independent:
|
|
152
|
+
// on cloud, the CLI's `logout --org` must be able to kill the
|
|
153
|
+
// /sso/cli-connect-minted key server-side (revocation narrows access; the
|
|
154
|
+
// D1 closure is about MINTING).
|
|
155
|
+
api.openapi(cliAuthRevokeRoute, async (c) => {
|
|
156
|
+
const principal = c.get('principal');
|
|
157
|
+
if (!principal)
|
|
158
|
+
return c.json(err('unauthenticated', 'Authentication required'), 401);
|
|
159
|
+
if (principal.via !== 'api_key' || !principal.apiKeyId) {
|
|
160
|
+
return c.json(err('forbidden', 'Only an API key can revoke itself — use the dashboard for key management'), 403);
|
|
161
|
+
}
|
|
162
|
+
await db
|
|
163
|
+
.update(apiKeysTable)
|
|
164
|
+
.set({ revokedAt: sql `now()` })
|
|
165
|
+
.where(and(eq(apiKeysTable.id, principal.apiKeyId), isNull(apiKeysTable.revokedAt)));
|
|
166
|
+
// The generic audit middleware writes the row (machine mutation) — hand
|
|
167
|
+
// it the semantics instead of double-writing.
|
|
168
|
+
c.set('audit', {
|
|
169
|
+
action: 'apikey.revoke',
|
|
170
|
+
resourceType: 'api_key',
|
|
171
|
+
resourceId: principal.apiKeyId,
|
|
172
|
+
metadata: { via: 'cli_logout' }
|
|
173
|
+
});
|
|
174
|
+
return c.json({ revoked: true, id: principal.apiKeyId }, 200);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=cli-auth.js.map
|