@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,61 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Cross-site request forgery defence for the whole `/api/v1` surface.
|
|
4
|
+
*
|
|
5
|
+
* The session cookie authenticates every business route (`/orgs`, `/members`,
|
|
6
|
+
* `/invitations`, `/me/*`, `/apikeys`, every product route a instantiation
|
|
7
|
+
* adds), and a cookie is attached by the browser on a cross-site POST just as
|
|
8
|
+
* happily as on a same-origin one. Better Auth's own origin check covers only
|
|
9
|
+
* its `/sign-in` paths, so without this middleware a page on any origin could
|
|
10
|
+
* drive a signed-in user's whole API.
|
|
11
|
+
*
|
|
12
|
+
* Two independent signals, both browser-set and unforgeable by page script
|
|
13
|
+
* (both are Forbidden Header Names — `fetch` cannot override them):
|
|
14
|
+
*
|
|
15
|
+
* 1. `Sec-Fetch-Site: cross-site` — a request initiated by a document on a
|
|
16
|
+
* different site. Refused outright.
|
|
17
|
+
* 2. `Origin` — present on every browser request with an unsafe method.
|
|
18
|
+
* Refused unless it is the origin we are being served on, the configured
|
|
19
|
+
* public origin, or an explicitly trusted extra.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately NOT refused:
|
|
22
|
+
*
|
|
23
|
+
* - Safe methods (GET/HEAD/OPTIONS). A cross-site read cannot be seen by the
|
|
24
|
+
* attacker — `/api/v1` sends no `Access-Control-Allow-Origin` except on the
|
|
25
|
+
* OAuth surfaces below — and refusing them would break legitimate
|
|
26
|
+
* cross-origin embeds of authenticated content.
|
|
27
|
+
* - Requests presenting an `Authorization` header. Those are API keys and
|
|
28
|
+
* OAuth bearers: not ambient credentials, so not forgeable cross-site (a
|
|
29
|
+
* page cannot attach the header without a preflight we never approve).
|
|
30
|
+
* Refusing them would break every scripted and browser-based MCP client.
|
|
31
|
+
* - The deliberate wildcard-CORS OAuth endpoints (oauth-public.ts): token,
|
|
32
|
+
* register, introspect, revoke, jwks and discovery are cookie-less by
|
|
33
|
+
* design and MUST answer any origin.
|
|
34
|
+
* - Requests with neither header. Non-browser clients (curl, the CLI, the
|
|
35
|
+
* SDK, server-to-server) send neither, and this middleware must not become
|
|
36
|
+
* a browser-only gate on a self-hosted API. The ambient-credential threat
|
|
37
|
+
* this closes is browser-only, and browsers always send at least one.
|
|
38
|
+
*/
|
|
39
|
+
export interface CrossSiteGuardOptions {
|
|
40
|
+
/** The instance's configured public origin (PUBLIC_BASE_URL). */
|
|
41
|
+
publicBaseUrl: string;
|
|
42
|
+
/**
|
|
43
|
+
* Additional origins allowed to drive the API with cookies — a separately
|
|
44
|
+
* hosted first-party dashboard, say. Empty on the template.
|
|
45
|
+
*/
|
|
46
|
+
extraTrustedOrigins?: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* Origins REFUSED even when they equal the origin this request was served
|
|
49
|
+
* on: the viewer origin (VIEWER_BASE_URL, PRDCT-1352). The host gate keeps
|
|
50
|
+
* `/api/v1` (minus the token-authed `/viewer/*` subset) off that hostname
|
|
51
|
+
* altogether, so in the shipped assembly no request here carries it as the
|
|
52
|
+
* serving origin — this is the second lock, so that a gate regression or a
|
|
53
|
+
* proxy routing the viewer hostname at the app never turns "the origin we
|
|
54
|
+
* are served on" into a trust grant for author-controlled script.
|
|
55
|
+
*/
|
|
56
|
+
deniedOrigins?: readonly string[];
|
|
57
|
+
/** Escape hatch for surfaces that must stay open (paths are `/api/v1/...`). */
|
|
58
|
+
isExempt?: (path: string) => boolean;
|
|
59
|
+
}
|
|
60
|
+
export declare function crossSiteGuard({ publicBaseUrl, extraTrustedOrigins, deniedOrigins, isExempt }: CrossSiteGuardOptions): MiddlewareHandler;
|
|
61
|
+
//# sourceMappingURL=cross-site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-site.d.ts","sourceRoot":"","sources":["../../src/middleware/cross-site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAIvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAiBD,wBAAgB,cAAc,CAAC,EAC7B,aAAa,EACb,mBAAwB,EACxB,aAAkB,EAClB,QAAQ,EACT,EAAE,qBAAqB,GAAG,iBAAiB,CAsC3C"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { apiError } from '../api/errors.js';
|
|
2
|
+
import { isPublicOauthPath } from './oauth-public.js';
|
|
3
|
+
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
4
|
+
function originOf(value) {
|
|
5
|
+
try {
|
|
6
|
+
return new URL(value).origin;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** The origin this very request was addressed to (works on localhost, previews, any domain). */
|
|
13
|
+
function servingOrigin(c) {
|
|
14
|
+
return originOf(c.req.url);
|
|
15
|
+
}
|
|
16
|
+
export function crossSiteGuard({ publicBaseUrl, extraTrustedOrigins = [], deniedOrigins = [], isExempt }) {
|
|
17
|
+
const configured = new Set();
|
|
18
|
+
const publicOrigin = originOf(publicBaseUrl);
|
|
19
|
+
if (publicOrigin)
|
|
20
|
+
configured.add(publicOrigin);
|
|
21
|
+
for (const extra of extraTrustedOrigins) {
|
|
22
|
+
const origin = originOf(extra);
|
|
23
|
+
if (origin)
|
|
24
|
+
configured.add(origin);
|
|
25
|
+
}
|
|
26
|
+
const denied = new Set();
|
|
27
|
+
for (const value of deniedOrigins) {
|
|
28
|
+
const origin = originOf(value);
|
|
29
|
+
if (origin)
|
|
30
|
+
denied.add(origin);
|
|
31
|
+
}
|
|
32
|
+
// A denied origin wins over every trust source, the serving origin included.
|
|
33
|
+
for (const origin of denied)
|
|
34
|
+
configured.delete(origin);
|
|
35
|
+
return async (c, next) => {
|
|
36
|
+
if (SAFE_METHODS.has(c.req.method))
|
|
37
|
+
return next();
|
|
38
|
+
if (c.req.header('authorization'))
|
|
39
|
+
return next();
|
|
40
|
+
if (isPublicOauthPath(c.req.path))
|
|
41
|
+
return next();
|
|
42
|
+
if (isExempt?.(c.req.path))
|
|
43
|
+
return next();
|
|
44
|
+
const secFetchSite = c.req.header('sec-fetch-site');
|
|
45
|
+
if (secFetchSite === 'cross-site') {
|
|
46
|
+
return apiError(c, 403, 'cross_site_forbidden', 'Cross-site requests are not accepted on this API');
|
|
47
|
+
}
|
|
48
|
+
const origin = c.req.header('origin');
|
|
49
|
+
if (origin) {
|
|
50
|
+
const serving = servingOrigin(c);
|
|
51
|
+
const trusted = !denied.has(origin) && (origin === serving || configured.has(origin));
|
|
52
|
+
if (!trusted) {
|
|
53
|
+
return apiError(c, 403, 'cross_site_forbidden', 'Cross-site requests are not accepted on this API');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return next();
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=cross-site.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-site.js","sourceRoot":"","sources":["../../src/middleware/cross-site.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* P7 (internal/federation.md "Hub-managed membership"): on the cloud edition,
|
|
4
|
+
* membership of a HUB-ORIGIN (projected) workspace is the hub's source of
|
|
5
|
+
* truth — invites, roles, and removals happen at the hub and flow in via
|
|
6
|
+
* SSO login + the P4 re-assertion. A local membership mutation on such a
|
|
7
|
+
* workspace would create divergence the next login/re-assertion fights, so
|
|
8
|
+
* every mutation on the local /members + /invitations surfaces answers this
|
|
9
|
+
* refusal instead. READS stay open: the projected roster is real.
|
|
10
|
+
*
|
|
11
|
+
* Why 403 (not 410): the member rows demonstrably exist (GET /members
|
|
12
|
+
* serves them), so "the resource is gone" would be false — what is denied
|
|
13
|
+
* is the OPERATION's local authority, for every caller, regardless of role
|
|
14
|
+
* or credential. That is RFC 9110 403's "forbidden for reasons unrelated to
|
|
15
|
+
* the credentials", and it keeps the platform's refusal vocabulary in one
|
|
16
|
+
* register (guest_forbidden, endpoint_not_allowed, workspace_mismatch are
|
|
17
|
+
* all 403). The `hub_managed` code + `details.manageUrl` carry the pointer.
|
|
18
|
+
*
|
|
19
|
+
* Fail-closed by construction:
|
|
20
|
+
* - Hub-origin detection keys on `principal.accountRef`, which every
|
|
21
|
+
* credential resolver (session: platform/local-identity.ts; API key:
|
|
22
|
+
* apikeys/service.ts; OAuth bearer: identity/oauth-jwt.ts) populates from
|
|
23
|
+
* a LIVE join on `workspaces.central_account_id` for the request's ONE
|
|
24
|
+
* workspace (ADR 014) — the same signal the live hub gate keys on
|
|
25
|
+
* (identity/hub-live-gate.ts). There is no principal-construction path
|
|
26
|
+
* that skips the join.
|
|
27
|
+
* - The gate is method-keyed, not route-enumerated, and mounted ONCE per
|
|
28
|
+
* subtree wildcard (`/members/*`, `/invitations/*` — in Hono the
|
|
29
|
+
* wildcard also matches the collection root): any FUTURE mutation
|
|
30
|
+
* registered anywhere under those surfaces is refused by default, with
|
|
31
|
+
* no per-path registration to remember.
|
|
32
|
+
* - It is registered only on EDITION=cloud (the `hubConfig` presence
|
|
33
|
+
* switch, like every cloud seam) — oss carries zero behavior change, and
|
|
34
|
+
* on oss `centralAccountId` is never set anyway (double cover).
|
|
35
|
+
*
|
|
36
|
+
* Principal-less requests pass through untouched: the public invitation
|
|
37
|
+
* accept/lookup segments are explicitly SKIPPED where this is mounted (their
|
|
38
|
+
* target workspace is the invitation's, not the caller's — the accept
|
|
39
|
+
* handler runs its own hub-origin check on the invitation's workspace), and
|
|
40
|
+
* every other gated route 401s in its requireAuth/requireRole gate.
|
|
41
|
+
*/
|
|
42
|
+
export declare function hubManagedMembershipGate(manageUrl: string, message?: string): MiddlewareHandler;
|
|
43
|
+
/** The teams' sentence for the same gate (PRDCT-2813): a projected team is shaped on the account site. */
|
|
44
|
+
export declare const HUB_MANAGED_TEAMS_MESSAGE = "Teams of this workspace are managed at the Antasphere hub \u2014 create, rename, and seat people there";
|
|
45
|
+
//# sourceMappingURL=hub-managed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-managed.d.ts","sourceRoot":"","sources":["../../src/middleware/hub-managed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,SAA2G,GACjH,iBAAiB,CAUnB;AAED,0GAA0G;AAC1G,eAAO,MAAM,yBAAyB,2GAC+D,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { apiError } from '../api/errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* P7 (internal/federation.md "Hub-managed membership"): on the cloud edition,
|
|
4
|
+
* membership of a HUB-ORIGIN (projected) workspace is the hub's source of
|
|
5
|
+
* truth — invites, roles, and removals happen at the hub and flow in via
|
|
6
|
+
* SSO login + the P4 re-assertion. A local membership mutation on such a
|
|
7
|
+
* workspace would create divergence the next login/re-assertion fights, so
|
|
8
|
+
* every mutation on the local /members + /invitations surfaces answers this
|
|
9
|
+
* refusal instead. READS stay open: the projected roster is real.
|
|
10
|
+
*
|
|
11
|
+
* Why 403 (not 410): the member rows demonstrably exist (GET /members
|
|
12
|
+
* serves them), so "the resource is gone" would be false — what is denied
|
|
13
|
+
* is the OPERATION's local authority, for every caller, regardless of role
|
|
14
|
+
* or credential. That is RFC 9110 403's "forbidden for reasons unrelated to
|
|
15
|
+
* the credentials", and it keeps the platform's refusal vocabulary in one
|
|
16
|
+
* register (guest_forbidden, endpoint_not_allowed, workspace_mismatch are
|
|
17
|
+
* all 403). The `hub_managed` code + `details.manageUrl` carry the pointer.
|
|
18
|
+
*
|
|
19
|
+
* Fail-closed by construction:
|
|
20
|
+
* - Hub-origin detection keys on `principal.accountRef`, which every
|
|
21
|
+
* credential resolver (session: platform/local-identity.ts; API key:
|
|
22
|
+
* apikeys/service.ts; OAuth bearer: identity/oauth-jwt.ts) populates from
|
|
23
|
+
* a LIVE join on `workspaces.central_account_id` for the request's ONE
|
|
24
|
+
* workspace (ADR 014) — the same signal the live hub gate keys on
|
|
25
|
+
* (identity/hub-live-gate.ts). There is no principal-construction path
|
|
26
|
+
* that skips the join.
|
|
27
|
+
* - The gate is method-keyed, not route-enumerated, and mounted ONCE per
|
|
28
|
+
* subtree wildcard (`/members/*`, `/invitations/*` — in Hono the
|
|
29
|
+
* wildcard also matches the collection root): any FUTURE mutation
|
|
30
|
+
* registered anywhere under those surfaces is refused by default, with
|
|
31
|
+
* no per-path registration to remember.
|
|
32
|
+
* - It is registered only on EDITION=cloud (the `hubConfig` presence
|
|
33
|
+
* switch, like every cloud seam) — oss carries zero behavior change, and
|
|
34
|
+
* on oss `centralAccountId` is never set anyway (double cover).
|
|
35
|
+
*
|
|
36
|
+
* Principal-less requests pass through untouched: the public invitation
|
|
37
|
+
* accept/lookup segments are explicitly SKIPPED where this is mounted (their
|
|
38
|
+
* target workspace is the invitation's, not the caller's — the accept
|
|
39
|
+
* handler runs its own hub-origin check on the invitation's workspace), and
|
|
40
|
+
* every other gated route 401s in its requireAuth/requireRole gate.
|
|
41
|
+
*/
|
|
42
|
+
export function hubManagedMembershipGate(manageUrl, message = 'Membership of this workspace is managed at the Antasphere hub — invite, remove, and change roles there') {
|
|
43
|
+
return async (c, next) => {
|
|
44
|
+
const method = c.req.method;
|
|
45
|
+
if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS')
|
|
46
|
+
return next();
|
|
47
|
+
const principal = c.get('principal');
|
|
48
|
+
if (principal?.accountRef) {
|
|
49
|
+
return apiError(c, 403, 'hub_managed', message, { manageUrl });
|
|
50
|
+
}
|
|
51
|
+
return next();
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** The teams' sentence for the same gate (PRDCT-2813): a projected team is shaped on the account site. */
|
|
55
|
+
export const HUB_MANAGED_TEAMS_MESSAGE = 'Teams of this workspace are managed at the Antasphere hub — create, rename, and seat people there';
|
|
56
|
+
//# sourceMappingURL=hub-managed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-managed.js","sourceRoot":"","sources":["../../src/middleware/hub-managed.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAAiB,EACjB,OAAO,GAAG,wGAAwG;IAElH,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,EAAE,CAAC;QACjF,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,SAAS,EAAE,UAAU,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED,0GAA0G;AAC1G,MAAM,CAAC,MAAM,yBAAyB,GACpC,mGAAmG,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
import { type Db } from '@antasphere/chassis-db';
|
|
3
|
+
/** Encrypt a response body for storage at rest: `iv.ciphertext.tag` base64url. */
|
|
4
|
+
export declare function seal(plain: string, authSecret: string): string;
|
|
5
|
+
/** Decrypt a sealed body; null on tamper, malformed input, or a wrong/rotated key. */
|
|
6
|
+
export declare function open(sealed: string, authSecret: string): string | null;
|
|
7
|
+
export interface IdempotencyDeps {
|
|
8
|
+
db: Db;
|
|
9
|
+
authSecret: string;
|
|
10
|
+
/** The tool's own create POSTs that take the claim (a pure predicate over the path; POST only). */
|
|
11
|
+
toolTargets?: (path: string) => boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function idempotency({ db, authSecret, toolTargets }: IdempotencyDeps): MiddlewareHandler;
|
|
14
|
+
//# sourceMappingURL=idempotency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../src/middleware/idempotency.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG9C,OAAO,EAAmB,KAAK,EAAE,EAAE,MAAM,wBAAwB,CAAC;AAkGlE,kFAAkF;AAClF,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED,sFAAsF;AACtF,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYtE;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,EAAE,CAAC;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,mGAAmG;IACnG,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACzC;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,eAAe,GAAG,iBAAiB,CAmI/F"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { and, eq } from 'drizzle-orm';
|
|
3
|
+
import { idempotencyKeys } from '@antasphere/chassis-db';
|
|
4
|
+
import { apiError } from '../api/errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Idempotency-Key middleware: an opt-in `Idempotency-Key` request header on
|
|
7
|
+
* the non-idempotent create POSTs makes a network-blip retry replay the
|
|
8
|
+
* original response instead of double-creating. Claim-first: the row is
|
|
9
|
+
* inserted BEFORE the handler runs (the unique index is the mutex), so two
|
|
10
|
+
* concurrent requests with the same key can never both execute.
|
|
11
|
+
*
|
|
12
|
+
* Explicit target list, fail-closed style — only these consult it (the
|
|
13
|
+
* lines that say "the tool's" are the TOOL's, declared through `toolTargets`):
|
|
14
|
+
* POST /api/v1/api-keys
|
|
15
|
+
* POST /api/v1/invitations
|
|
16
|
+
* POST /api/v1/members/{id}/reset-link
|
|
17
|
+
* POST /api/v1/members/{id}/change-email-link (FUZZ-7, PRDCT-1354: the
|
|
18
|
+
* SECOND secret-minting member route, and the more dangerous one — its
|
|
19
|
+
* token is sign-in-equivalent. Its contract has always declared
|
|
20
|
+
* `Idempotency-Key` and a 409, but the claim never covered it, so a
|
|
21
|
+
* retried mint silently produced a SECOND live sign-in-equivalent JWT
|
|
22
|
+
* that cannot be revoked, on top of the first. The two mint routes must
|
|
23
|
+
* stay listed together.)
|
|
24
|
+
* the tool's token mint on one of its resources
|
|
25
|
+
* the tool's duplicate of a resource (PRDCT-2279: one click mints
|
|
26
|
+
* one copy; a network-blip retry must not mint a second copy)
|
|
27
|
+
* POST /api/v1/workspaces (PRDCT-2444/2443: one click mints one workspace;
|
|
28
|
+
* on cloud the retry would otherwise create a second organization at
|
|
29
|
+
* the hub. The claim is scoped to the caller's CURRENT workspace + user;
|
|
30
|
+
* the cloud zero-membership session has no principal and runs unclaimed)
|
|
31
|
+
* the tool's upload reserve (a retried reserve must not leak a
|
|
32
|
+
* second session + reserved resource id)
|
|
33
|
+
* POST /api/v1/projects (one click mints one project) and
|
|
34
|
+
* POST /api/v1/projects/{id}/members (a retried add answers the first
|
|
35
|
+
* add's 201, not 409 `already_member`)
|
|
36
|
+
* Deliberate NON-targets:
|
|
37
|
+
* POST /api/v1/files and the tool's asset upload — content-addressed
|
|
38
|
+
* dedupe already makes them idempotent, and upload bodies must never be
|
|
39
|
+
* buffered here;
|
|
40
|
+
* POST /api/v1/setup and /api/v1/invitations/accept — one-shot by
|
|
41
|
+
* construction (retries answer 410), and they run without a principal;
|
|
42
|
+
* the tool's version commits — one-shot (session consumed / version counter)
|
|
43
|
+
* by construction: a retry answers 409.
|
|
44
|
+
*
|
|
45
|
+
* The cached response body is stored AES-256-GCM ENCRYPTED: these responses
|
|
46
|
+
* carry one-shot secrets (the full API key, the invitation acceptUrl token,
|
|
47
|
+
* the reset link) whose plaintext is deliberately never persisted anywhere
|
|
48
|
+
* else, and this cache must not become the exception. Sealed payload format:
|
|
49
|
+
* `iv.ciphertext.tag`, each part base64url; key = sha256(authSecret +
|
|
50
|
+
* ':idempotency'). Rotating AUTH_SECRET inside the 24h window is the same
|
|
51
|
+
* hard cutover it is for API keys: `open()` fails closed (null) and the
|
|
52
|
+
* stale row is dropped and re-executed.
|
|
53
|
+
*
|
|
54
|
+
* Accepted edge: a crash between the handler's commit and the response
|
|
55
|
+
* persist leaves a claim without a response — same-key retries answer 409
|
|
56
|
+
* `idempotency_in_flight` until the 24h expiry. Safe (never double-creates),
|
|
57
|
+
* mildly annoying, self-healing.
|
|
58
|
+
*/
|
|
59
|
+
/** Rows live 24h (the Stripe convention); the nightly purge deletes expired ones. */
|
|
60
|
+
const TTL_MS = 24 * 60 * 60 * 1000;
|
|
61
|
+
const KEY_MAX_LENGTH = 200;
|
|
62
|
+
const TARGET_PATHS = new Set([
|
|
63
|
+
'/api/v1/api-keys',
|
|
64
|
+
'/api/v1/invitations',
|
|
65
|
+
'/api/v1/workspaces',
|
|
66
|
+
'/api/v1/projects'
|
|
67
|
+
]);
|
|
68
|
+
// The two member routes that MINT a credential for another user. Both are
|
|
69
|
+
// covered (FUZZ-7): a replayed mint hands out a second live secret, and the
|
|
70
|
+
// change-email JWT is stateless, so it cannot even be revoked afterwards.
|
|
71
|
+
const RESET_LINK_RE = /^\/api\/v1\/members\/[^/]+\/reset-link$/;
|
|
72
|
+
const CHANGE_EMAIL_LINK_RE = /^\/api\/v1\/members\/[^/]+\/change-email-link$/;
|
|
73
|
+
const PROJECT_MEMBERS_RE = /^\/api\/v1\/projects\/[^/]+\/members$/;
|
|
74
|
+
function isTarget(method, path, toolTargets) {
|
|
75
|
+
return (method === 'POST' &&
|
|
76
|
+
(TARGET_PATHS.has(path) ||
|
|
77
|
+
RESET_LINK_RE.test(path) ||
|
|
78
|
+
CHANGE_EMAIL_LINK_RE.test(path) ||
|
|
79
|
+
PROJECT_MEMBERS_RE.test(path) ||
|
|
80
|
+
(toolTargets?.(path) ?? false)));
|
|
81
|
+
}
|
|
82
|
+
/** AES-256-GCM key derived from the server auth secret (domain-separated). */
|
|
83
|
+
function keyOf(authSecret) {
|
|
84
|
+
return createHash('sha256')
|
|
85
|
+
.update(authSecret + ':idempotency')
|
|
86
|
+
.digest();
|
|
87
|
+
}
|
|
88
|
+
/** Encrypt a response body for storage at rest: `iv.ciphertext.tag` base64url. */
|
|
89
|
+
export function seal(plain, authSecret) {
|
|
90
|
+
const iv = randomBytes(12);
|
|
91
|
+
const cipher = createCipheriv('aes-256-gcm', keyOf(authSecret), iv);
|
|
92
|
+
const ciphertext = Buffer.concat([cipher.update(plain, 'utf8'), cipher.final()]);
|
|
93
|
+
return `${iv.toString('base64url')}.${ciphertext.toString('base64url')}.${cipher.getAuthTag().toString('base64url')}`;
|
|
94
|
+
}
|
|
95
|
+
/** Decrypt a sealed body; null on tamper, malformed input, or a wrong/rotated key. */
|
|
96
|
+
export function open(sealed, authSecret) {
|
|
97
|
+
const [iv, ciphertext, tag] = sealed.split('.');
|
|
98
|
+
if (!iv || !ciphertext || !tag)
|
|
99
|
+
return null;
|
|
100
|
+
try {
|
|
101
|
+
const decipher = createDecipheriv('aes-256-gcm', keyOf(authSecret), Buffer.from(iv, 'base64url'));
|
|
102
|
+
decipher.setAuthTag(Buffer.from(tag, 'base64url'));
|
|
103
|
+
return Buffer.concat([decipher.update(Buffer.from(ciphertext, 'base64url')), decipher.final()]).toString('utf8');
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export function idempotency({ db, authSecret, toolTargets }) {
|
|
110
|
+
return async (c, next) => {
|
|
111
|
+
if (!isTarget(c.req.method, c.req.path, toolTargets))
|
|
112
|
+
return next();
|
|
113
|
+
const key = c.req.header('idempotency-key');
|
|
114
|
+
if (key === undefined)
|
|
115
|
+
return next();
|
|
116
|
+
if (key.length === 0 || key.length > KEY_MAX_LENGTH) {
|
|
117
|
+
// This middleware runs before contract validation, so the header bound
|
|
118
|
+
// is enforced here (the contract mirrors it for the OpenAPI document).
|
|
119
|
+
return apiError(c, 400, 'invalid_idempotency_key', 'Idempotency-Key must be 1–200 characters');
|
|
120
|
+
}
|
|
121
|
+
const principal = c.get('principal');
|
|
122
|
+
if (!principal)
|
|
123
|
+
return next(); // the route gates 401 downstream
|
|
124
|
+
// Hono caches the body: the zod validator's later c.req.json() re-reads
|
|
125
|
+
// from the same cache (verified on hono 4.12), so this text() is safe.
|
|
126
|
+
const bodyText = await c.req.text();
|
|
127
|
+
// Raw bytes, no canonicalization: a retry that re-serializes the same
|
|
128
|
+
// JSON differently hashes differently and 409s — by design.
|
|
129
|
+
const requestHash = createHash('sha256')
|
|
130
|
+
.update(`${c.req.method}\n${c.req.path}\n${bodyText}`)
|
|
131
|
+
.digest('hex');
|
|
132
|
+
const scope = and(eq(idempotencyKeys.workspaceId, principal.workspaceId), eq(idempotencyKeys.userId, principal.userId), eq(idempotencyKeys.key, key));
|
|
133
|
+
const claim = async () => {
|
|
134
|
+
const rows = await db
|
|
135
|
+
.insert(idempotencyKeys)
|
|
136
|
+
.values({
|
|
137
|
+
workspaceId: principal.workspaceId,
|
|
138
|
+
userId: principal.userId,
|
|
139
|
+
key,
|
|
140
|
+
requestHash,
|
|
141
|
+
expiresAt: new Date(Date.now() + TTL_MS)
|
|
142
|
+
})
|
|
143
|
+
.onConflictDoNothing({
|
|
144
|
+
target: [idempotencyKeys.workspaceId, idempotencyKeys.userId, idempotencyKeys.key]
|
|
145
|
+
})
|
|
146
|
+
.returning({ id: idempotencyKeys.id });
|
|
147
|
+
return rows[0]?.id ?? null;
|
|
148
|
+
};
|
|
149
|
+
let claimId = await claim();
|
|
150
|
+
if (claimId === null) {
|
|
151
|
+
// Claim lost: someone (possibly an earlier attempt of this very
|
|
152
|
+
// client) holds the key. Inspect the row to replay or conflict.
|
|
153
|
+
const [existing] = await db.select().from(idempotencyKeys).where(scope).limit(1);
|
|
154
|
+
if (!existing) {
|
|
155
|
+
// The row vanished between insert and select (raced the nightly
|
|
156
|
+
// purge). Claim once more; losing again means a live concurrent racer.
|
|
157
|
+
claimId = await claim();
|
|
158
|
+
if (claimId === null) {
|
|
159
|
+
return apiError(c, 409, 'idempotency_in_flight', 'A request with this Idempotency-Key is in flight — retry shortly');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else if (existing.requestHash !== requestHash) {
|
|
163
|
+
return apiError(c, 409, 'idempotency_key_reuse', 'This Idempotency-Key was already used with a different request');
|
|
164
|
+
}
|
|
165
|
+
else if (existing.responseStatus === null || existing.responseBodyEnc === null) {
|
|
166
|
+
return apiError(c, 409, 'idempotency_in_flight', 'The original request is still in flight — retry shortly');
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const plain = open(existing.responseBodyEnc, authSecret);
|
|
170
|
+
if (plain === null) {
|
|
171
|
+
// Sealed under a rotated AUTH_SECRET (documented hard cutover):
|
|
172
|
+
// unrecoverable, so drop the stale row and execute afresh.
|
|
173
|
+
await db.delete(idempotencyKeys).where(eq(idempotencyKeys.id, existing.id));
|
|
174
|
+
claimId = await claim();
|
|
175
|
+
if (claimId === null) {
|
|
176
|
+
return apiError(c, 409, 'idempotency_in_flight', 'A request with this Idempotency-Key is in flight — retry shortly');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
c.header('idempotency-replayed', 'true');
|
|
181
|
+
return c.json(JSON.parse(plain), existing.responseStatus);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Owner path: we hold the claim; the handler executes.
|
|
186
|
+
const ownedClaimId = claimId;
|
|
187
|
+
// Best-effort release: a failed request must stay retryable with the
|
|
188
|
+
// same key (release errors must not mask the real outcome).
|
|
189
|
+
const release = async () => {
|
|
190
|
+
await db
|
|
191
|
+
.delete(idempotencyKeys)
|
|
192
|
+
.where(eq(idempotencyKeys.id, ownedClaimId))
|
|
193
|
+
.catch(() => { });
|
|
194
|
+
};
|
|
195
|
+
try {
|
|
196
|
+
await next();
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
await release();
|
|
200
|
+
throw e;
|
|
201
|
+
}
|
|
202
|
+
if (c.res.status >= 200 && c.res.status < 300) {
|
|
203
|
+
// clone() tees the stream — the client still receives the original.
|
|
204
|
+
const body = await c.res.clone().text();
|
|
205
|
+
try {
|
|
206
|
+
await db
|
|
207
|
+
.update(idempotencyKeys)
|
|
208
|
+
.set({ responseStatus: c.res.status, responseBodyEnc: seal(body, authSecret) })
|
|
209
|
+
.where(eq(idempotencyKeys.id, ownedClaimId));
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// Best-effort, like audit: the handler's mutation has already
|
|
213
|
+
// committed, so a failed persist must never turn into a 500. The
|
|
214
|
+
// claim stays response-less; same-key retries 409 until expiry.
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
await release();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=idempotency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../../src/middleware/idempotency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGxF,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,eAAe,EAAW,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,qFAAqF;AACrF,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,kBAAkB;IAClB,qBAAqB;IACrB,oBAAoB;IACpB,kBAAkB;CACnB,CAAC,CAAC;AACH,0EAA0E;AAC1E,4EAA4E;AAC5E,0EAA0E;AAC1E,MAAM,aAAa,GAAG,yCAAyC,CAAC;AAChE,MAAM,oBAAoB,GAAG,gDAAgD,CAAC;AAC9E,MAAM,kBAAkB,GAAG,uCAAuC,CAAC;AAEnE,SAAS,QAAQ,CACf,MAAc,EACd,IAAY,EACZ,WAAoD;IAEpD,OAAO,CACL,MAAM,KAAK,MAAM;QACjB,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;YACrB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YACxB,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/B,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC7B,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAClC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,SAAS,KAAK,CAAC,UAAkB;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,UAAU,GAAG,cAAc,CAAC;SACnC,MAAM,EAAE,CAAC;AACd,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,IAAI,CAAC,KAAa,EAAE,UAAkB;IACpD,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACjF,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;AACxH,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,UAAkB;IACrD,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;QAClG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;QACnD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CACtG,MAAM,CACP,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AASD,MAAM,UAAU,WAAW,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAmB;IAC1E,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC;YAAE,OAAO,IAAI,EAAE,CAAC;QACpE,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAC5C,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,IAAI,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACpD,uEAAuE;YACvE,uEAAuE;YACvE,OAAO,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,yBAAyB,EAAE,0CAA0C,CAAC,CAAC;QACjG,CAAC;QACD,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,EAAE,CAAC,CAAC,iCAAiC;QAEhE,wEAAwE;QACxE,uEAAuE;QACvE,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACpC,sEAAsE;QACtE,4DAA4D;QAC5D,MAAM,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC;aACrC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;aACrD,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjB,MAAM,KAAK,GAAG,GAAG,CACf,EAAE,CAAC,eAAe,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,EACtD,EAAE,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,EAC5C,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAC7B,CAAC;QACF,MAAM,KAAK,GAAG,KAAK,IAA4B,EAAE;YAC/C,MAAM,IAAI,GAAG,MAAM,EAAE;iBAClB,MAAM,CAAC,eAAe,CAAC;iBACvB,MAAM,CAAC;gBACN,WAAW,EAAE,SAAS,CAAC,WAAW;gBAClC,MAAM,EAAE,SAAS,CAAC,MAAM;gBACxB,GAAG;gBACH,WAAW;gBACX,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC;aACzC,CAAC;iBACD,mBAAmB,CAAC;gBACnB,MAAM,EAAE,CAAC,eAAe,CAAC,WAAW,EAAE,eAAe,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC;aACnF,CAAC;iBACD,SAAS,CAAC,EAAE,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC;QAC7B,CAAC,CAAC;QAEF,IAAI,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC;QAE5B,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,gEAAgE;YAChE,gEAAgE;YAChE,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACjF,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,gEAAgE;gBAChE,uEAAuE;gBACvE,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC;gBACxB,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACrB,OAAO,QAAQ,CACb,CAAC,EACD,GAAG,EACH,uBAAuB,EACvB,kEAAkE,CACnE,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,IAAI,QAAQ,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;gBAChD,OAAO,QAAQ,CACb,CAAC,EACD,GAAG,EACH,uBAAuB,EACvB,gEAAgE,CACjE,CAAC;YACJ,CAAC;iBAAM,IAAI,QAAQ,CAAC,cAAc,KAAK,IAAI,IAAI,QAAQ,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;gBACjF,OAAO,QAAQ,CACb,CAAC,EACD,GAAG,EACH,uBAAuB,EACvB,yDAAyD,CAC1D,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;gBACzD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBACnB,gEAAgE;oBAChE,2DAA2D;oBAC3D,MAAM,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;oBAC5E,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC;oBACxB,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;wBACrB,OAAO,QAAQ,CACb,CAAC,EACD,GAAG,EACH,uBAAuB,EACvB,kEAAkE,CACnE,CAAC;oBACJ,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,CAAC,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;oBACzC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,cAAsC,CAAC,CAAC;gBACpF,CAAC;YACH,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,MAAM,YAAY,GAAG,OAAO,CAAC;QAC7B,qEAAqE;QACrE,4DAA4D;QAC5D,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,EAAE;iBACL,MAAM,CAAC,eAAe,CAAC;iBACvB,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;iBAC3C,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrB,CAAC,CAAC;QACF,IAAI,CAAC;YACH,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,OAAO,EAAE,CAAC;YAChB,MAAM,CAAC,CAAC;QACV,CAAC;QACD,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC9C,oEAAoE;YACpE,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,CAAC;gBACH,MAAM,EAAE;qBACL,MAAM,CAAC,eAAe,CAAC;qBACvB,GAAG,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;qBAC9E,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;YACjD,CAAC;YAAC,MAAM,CAAC;gBACP,8DAA8D;gBAC9D,iEAAiE;gBACjE,gEAAgE;YAClE,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,EAAE,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { type AdmitResult, type PrincipalGate, admitPrincipal, authContext, requireAuth, requireNonGuest, requireRole, resolveSessionPrincipal } from './auth-context.js';
|
|
2
|
+
export { type BucketDeclaration, type ClientIpFn, type QuotaDecision, type RateLimiters, type RequestQuotaService, createRateLimiters, createRequestQuota, emailKeyOf, makeClientIp, principalBucketKey, quotaHeaderEntries, rateLimit } from './rate-limit.js';
|
|
3
|
+
export { requestId } from './request-id.js';
|
|
4
|
+
export { type ScopeAllowlistOptions, type ScopeRule, createScopeAllowlist, looksLikeJwt } from './scopes.js';
|
|
5
|
+
export { authBodyGuard } from './auth-body.js';
|
|
6
|
+
export { crossSiteGuard } from './cross-site.js';
|
|
7
|
+
export { idempotency, open, seal } from './idempotency.js';
|
|
8
|
+
export { MAX_JSON_DEPTH, exceedsJsonDepth, jsonDepthLimit } from './json-depth.js';
|
|
9
|
+
export { noStoreAuthenticated } from './no-store.js';
|
|
10
|
+
export { isPublicOauthPath, oauthPublicEndpoints } from './oauth-public.js';
|
|
11
|
+
export { buildCsp, hstsValue, inlineScriptHashes, securityHeaders } from './security-headers.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,cAAc,EACd,WAAW,EACX,WAAW,EACX,eAAe,EACf,WAAW,EACX,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,SAAS,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { admitPrincipal, authContext, requireAuth, requireNonGuest, requireRole, resolveSessionPrincipal } from './auth-context.js';
|
|
2
|
+
export { createRateLimiters, createRequestQuota, emailKeyOf, makeClientIp, principalBucketKey, quotaHeaderEntries, rateLimit } from './rate-limit.js';
|
|
3
|
+
export { requestId } from './request-id.js';
|
|
4
|
+
export { createScopeAllowlist, looksLikeJwt } from './scopes.js';
|
|
5
|
+
export { authBodyGuard } from './auth-body.js';
|
|
6
|
+
export { crossSiteGuard } from './cross-site.js';
|
|
7
|
+
export { idempotency, open, seal } from './idempotency.js';
|
|
8
|
+
export { MAX_JSON_DEPTH, exceedsJsonDepth, jsonDepthLimit } from './json-depth.js';
|
|
9
|
+
export { noStoreAuthenticated } from './no-store.js';
|
|
10
|
+
export { isPublicOauthPath, oauthPublicEndpoints } from './oauth-public.js';
|
|
11
|
+
export { buildCsp, hstsValue, inlineScriptHashes, securityHeaders } from './security-headers.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,cAAc,EACd,WAAW,EACX,WAAW,EACX,eAAe,EACf,WAAW,EACX,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAML,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAA8C,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
/**
|
|
3
|
+
* Nesting cap for request JSON. Deliberately far above anything a contract in
|
|
4
|
+
* `@antasphere/contract` describes (the deepest is three or four levels) and far
|
|
5
|
+
* below the depth at which V8 recursion breaks.
|
|
6
|
+
*
|
|
7
|
+
* Why a cap at all: `JSON.parse` is iterative and swallows any depth, but
|
|
8
|
+
* `JSON.stringify` is RECURSIVE and blows the stack with a `RangeError` past a
|
|
9
|
+
* few thousand levels — and the exact depth depends on the V8 build, so it
|
|
10
|
+
* reproduces inside the shipped `node:22-alpine` image and not on a newer host
|
|
11
|
+
* Node. Every path that echoes, audits, logs, or persists a validated body
|
|
12
|
+
* stringifies it, so an anonymous client could turn one small request body
|
|
13
|
+
* into a 500 plus an error-level stack trace. Rejecting at the edge — before
|
|
14
|
+
* anything parses, let alone stringifies — is the only place the fix is
|
|
15
|
+
* complete.
|
|
16
|
+
*/
|
|
17
|
+
export declare const MAX_JSON_DEPTH = 100;
|
|
18
|
+
/**
|
|
19
|
+
* True when `text` nests `{`/`[` deeper than `max`. A single string-aware
|
|
20
|
+
* scan, no parsing and no allocation: brackets inside JSON string literals
|
|
21
|
+
* (and escaped quotes inside them) do not count. Returns as soon as the limit
|
|
22
|
+
* is passed, so a hostile body costs O(prefix), not O(body).
|
|
23
|
+
*/
|
|
24
|
+
export declare function exceedsJsonDepth(text: string, max: number): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Rejects over-deep JSON bodies with a 400 before any handler, parser or
|
|
27
|
+
* serializer sees them. Non-JSON and bodyless requests pass untouched, so
|
|
28
|
+
* streamed uploads and form-encoded token calls are unaffected. Mount it
|
|
29
|
+
* AFTER the body-size limit so the scan is bounded by that cap.
|
|
30
|
+
*/
|
|
31
|
+
export declare function jsonDepthLimit(maxDepth?: number): MiddlewareHandler;
|
|
32
|
+
//# sourceMappingURL=json-depth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-depth.d.ts","sourceRoot":"","sources":["../../src/middleware/json-depth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG9C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,MAAM,CAAC;AAKlC;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAmBnE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAuB,GAAG,iBAAiB,CAiBnF"}
|