@bajustone/fortress 1.0.0-rc.1
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/CHANGELOG.md +1011 -0
- package/LICENSE +21 -0
- package/README.md +760 -0
- package/SECURITY.md +197 -0
- package/bin/fortress.ts +667 -0
- package/dist/auth-service-BcyQ2PuZ.d.cts +307 -0
- package/dist/auth-service-BkzZkWfH.d.ts +307 -0
- package/dist/config-B2366s_G.d.ts +665 -0
- package/dist/config-GtlVt6ZD.d.cts +665 -0
- package/dist/convert-routes-BLCQT57f.d.ts +72 -0
- package/dist/convert-routes-BdMvP2_X.d.cts +72 -0
- package/dist/crypto.cjs +61 -0
- package/dist/crypto.d.cts +36 -0
- package/dist/crypto.d.ts +36 -0
- package/dist/crypto.js +35 -0
- package/dist/drift-BT1wtMDJ.d.cts +22 -0
- package/dist/drift-k9LiYpRP.d.ts +22 -0
- package/dist/drizzle/pg.cjs +481 -0
- package/dist/drizzle/pg.d.cts +15 -0
- package/dist/drizzle/pg.d.ts +15 -0
- package/dist/drizzle/pg.js +454 -0
- package/dist/drizzle.cjs +1442 -0
- package/dist/drizzle.d.cts +85 -0
- package/dist/drizzle.d.ts +85 -0
- package/dist/drizzle.js +1411 -0
- package/dist/express.cjs +1357 -0
- package/dist/express.d.cts +333 -0
- package/dist/express.d.ts +333 -0
- package/dist/express.js +1314 -0
- package/dist/fetcher.cjs +77 -0
- package/dist/fetcher.d.cts +7 -0
- package/dist/fetcher.d.ts +7 -0
- package/dist/fetcher.js +41 -0
- package/dist/fortress-BmSvFfqK.d.cts +1089 -0
- package/dist/fortress-uA-_cheR.d.ts +1089 -0
- package/dist/hono.cjs +1530 -0
- package/dist/hono.d.cts +514 -0
- package/dist/hono.d.ts +514 -0
- package/dist/hono.js +1483 -0
- package/dist/index-CxEkfCA0.d.cts +77 -0
- package/dist/index-CxEkfCA0.d.ts +77 -0
- package/dist/index-D054pcb-.d.cts +146 -0
- package/dist/index-jAMbbUAY.d.ts +146 -0
- package/dist/index.cjs +9046 -0
- package/dist/index.d.cts +717 -0
- package/dist/index.d.ts +717 -0
- package/dist/index.js +8935 -0
- package/dist/jwt.cjs +255 -0
- package/dist/jwt.d.cts +90 -0
- package/dist/jwt.d.ts +90 -0
- package/dist/jwt.js +227 -0
- package/dist/otel.cjs +108 -0
- package/dist/otel.d.cts +62 -0
- package/dist/otel.d.ts +62 -0
- package/dist/otel.js +73 -0
- package/dist/plugins/account-lockout.cjs +322 -0
- package/dist/plugins/account-lockout.d.cts +42 -0
- package/dist/plugins/account-lockout.d.ts +42 -0
- package/dist/plugins/account-lockout.js +295 -0
- package/dist/plugins/admin.cjs +2378 -0
- package/dist/plugins/admin.d.cts +72 -0
- package/dist/plugins/admin.d.ts +72 -0
- package/dist/plugins/admin.js +2351 -0
- package/dist/plugins/api-key.cjs +792 -0
- package/dist/plugins/api-key.d.cts +121 -0
- package/dist/plugins/api-key.d.ts +121 -0
- package/dist/plugins/api-key.js +765 -0
- package/dist/plugins/audit-log.cjs +493 -0
- package/dist/plugins/audit-log.d.cts +86 -0
- package/dist/plugins/audit-log.d.ts +86 -0
- package/dist/plugins/audit-log.js +468 -0
- package/dist/plugins/data-isolation.cjs +211 -0
- package/dist/plugins/data-isolation.d.cts +49 -0
- package/dist/plugins/data-isolation.d.ts +49 -0
- package/dist/plugins/data-isolation.js +186 -0
- package/dist/plugins/email-verification.cjs +273 -0
- package/dist/plugins/email-verification.d.cts +44 -0
- package/dist/plugins/email-verification.d.ts +44 -0
- package/dist/plugins/email-verification.js +246 -0
- package/dist/plugins/magic-link.cjs +231 -0
- package/dist/plugins/magic-link.d.cts +39 -0
- package/dist/plugins/magic-link.d.ts +39 -0
- package/dist/plugins/magic-link.js +204 -0
- package/dist/plugins/oauth.cjs +1696 -0
- package/dist/plugins/oauth.d.cts +406 -0
- package/dist/plugins/oauth.d.ts +406 -0
- package/dist/plugins/oauth.js +1669 -0
- package/dist/plugins/openapi.cjs +1185 -0
- package/dist/plugins/openapi.d.cts +6 -0
- package/dist/plugins/openapi.d.ts +6 -0
- package/dist/plugins/openapi.js +1158 -0
- package/dist/plugins/rate-limit/express.cjs +55 -0
- package/dist/plugins/rate-limit/express.d.cts +64 -0
- package/dist/plugins/rate-limit/express.d.ts +64 -0
- package/dist/plugins/rate-limit/express.js +30 -0
- package/dist/plugins/rate-limit/hono.cjs +51 -0
- package/dist/plugins/rate-limit/hono.d.cts +59 -0
- package/dist/plugins/rate-limit/hono.d.ts +59 -0
- package/dist/plugins/rate-limit/hono.js +26 -0
- package/dist/plugins/rate-limit/sveltekit.cjs +49 -0
- package/dist/plugins/rate-limit/sveltekit.d.cts +59 -0
- package/dist/plugins/rate-limit/sveltekit.d.ts +59 -0
- package/dist/plugins/rate-limit/sveltekit.js +24 -0
- package/dist/plugins/rate-limit.cjs +354 -0
- package/dist/plugins/rate-limit.d.cts +140 -0
- package/dist/plugins/rate-limit.d.ts +140 -0
- package/dist/plugins/rate-limit.js +325 -0
- package/dist/plugins/social-login.cjs +905 -0
- package/dist/plugins/social-login.d.cts +114 -0
- package/dist/plugins/social-login.d.ts +114 -0
- package/dist/plugins/social-login.js +880 -0
- package/dist/plugins/tenancy.cjs +780 -0
- package/dist/plugins/tenancy.d.cts +108 -0
- package/dist/plugins/tenancy.d.ts +108 -0
- package/dist/plugins/tenancy.js +753 -0
- package/dist/plugins/two-factor.cjs +555 -0
- package/dist/plugins/two-factor.d.cts +67 -0
- package/dist/plugins/two-factor.d.ts +67 -0
- package/dist/plugins/two-factor.js +526 -0
- package/dist/plugins/webauthn.cjs +786 -0
- package/dist/plugins/webauthn.d.cts +72 -0
- package/dist/plugins/webauthn.d.ts +72 -0
- package/dist/plugins/webauthn.js +766 -0
- package/dist/plugins/webhook.cjs +819 -0
- package/dist/plugins/webhook.d.cts +254 -0
- package/dist/plugins/webhook.d.ts +254 -0
- package/dist/plugins/webhook.js +789 -0
- package/dist/protect-D1v_0upK.d.cts +123 -0
- package/dist/protect-DsxV_-dJ.d.ts +123 -0
- package/dist/sveltekit.cjs +1258 -0
- package/dist/sveltekit.d.cts +420 -0
- package/dist/sveltekit.d.ts +420 -0
- package/dist/sveltekit.js +1207 -0
- package/dist/testing.cjs +4294 -0
- package/dist/testing.d.cts +197 -0
- package/dist/testing.d.ts +197 -0
- package/dist/testing.js +4264 -0
- package/dist/types-et0R8tsC.d.cts +217 -0
- package/dist/types-et0R8tsC.d.ts +217 -0
- package/docs/adapter-typed-helpers.md +192 -0
- package/docs/admin-recipes.md +227 -0
- package/docs/architecture.md +434 -0
- package/docs/ci/github-actions.yml +59 -0
- package/docs/ci.md +109 -0
- package/docs/compatibility.md +115 -0
- package/docs/deployment.md +305 -0
- package/docs/hardening.md +118 -0
- package/docs/host-owned-routes.md +154 -0
- package/docs/migrations/0001-schema-version.md +54 -0
- package/docs/migrations/0002-initial-schema.md +84 -0
- package/docs/migrations/upgrade-guide.md +160 -0
- package/docs/observability.md +394 -0
- package/docs/plugins/account-lockout.md +131 -0
- package/docs/plugins/admin.md +402 -0
- package/docs/plugins/api-key.md +327 -0
- package/docs/plugins/audit-log.md +261 -0
- package/docs/plugins/data-isolation.md +186 -0
- package/docs/plugins/email-verification.md +121 -0
- package/docs/plugins/magic-link.md +123 -0
- package/docs/plugins/oauth.md +544 -0
- package/docs/plugins/openapi.md +250 -0
- package/docs/plugins/rate-limit.md +223 -0
- package/docs/plugins/social-login.md +337 -0
- package/docs/plugins/tenancy.md +122 -0
- package/docs/plugins/two-factor.md +191 -0
- package/docs/plugins/webauthn.md +188 -0
- package/docs/plugins/webhook.md +242 -0
- package/docs/policy-as-code.md +156 -0
- package/docs/route-manifest.md +46 -0
- package/docs/security.md +261 -0
- package/docs/threat-model.md +161 -0
- package/examples/README.md +119 -0
- package/examples/express-app/index.ts +747 -0
- package/examples/hono-app/docker-compose.yml +14 -0
- package/examples/hono-app/index.ts +1009 -0
- package/examples/policy/fortress.policy.json +47 -0
- package/examples/sveltekit-app/README.md +125 -0
- package/examples/sveltekit-app/src/app.d.ts +16 -0
- package/examples/sveltekit-app/src/hooks.server.ts +23 -0
- package/examples/sveltekit-app/src/lib/server/fortress.ts +81 -0
- package/examples/sveltekit-app/src/routes/api/echo/[id]/+server.ts +32 -0
- package/examples/sveltekit-app/src/routes/api/fortress/[...path]/+server.ts +15 -0
- package/examples/sveltekit-app/src/routes/dashboard/+page.server.ts +20 -0
- package/examples/sveltekit-app/src/routes/login/+page.server.ts +48 -0
- package/examples/sveltekit-app/src/routes/oauth/consent/+page.server.ts +69 -0
- package/examples/sveltekit-app/src/routes/oauth/consent/+page.svelte +83 -0
- package/migrations/pg/0001_schema_version.down.sql +2 -0
- package/migrations/pg/0001_schema_version.sql +8 -0
- package/migrations/pg/0002_initial_schema.down.sql +36 -0
- package/migrations/pg/0002_initial_schema.sql +376 -0
- package/migrations/pg/0003_auth_continuation.down.sql +6 -0
- package/migrations/pg/0003_auth_continuation.sql +30 -0
- package/migrations/pg/0004_tenant_default_unique.down.sql +1 -0
- package/migrations/pg/0004_tenant_default_unique.sql +14 -0
- package/migrations/pg/0005_hot_indexes_timestamptz.down.sql +71 -0
- package/migrations/pg/0005_hot_indexes_timestamptz.sql +71 -0
- package/migrations/pg/0006_canonical_email.down.sql +3 -0
- package/migrations/pg/0006_canonical_email.sql +8 -0
- package/migrations/pg/0007_audit_chain_anchor.down.sql +1 -0
- package/migrations/pg/0007_audit_chain_anchor.sql +8 -0
- package/migrations/pg/0008_two_factor_hardening.down.sql +8 -0
- package/migrations/pg/0008_two_factor_hardening.sql +8 -0
- package/migrations/pg/0009_encrypt_totp_secrets.down.sql +2 -0
- package/migrations/pg/0009_encrypt_totp_secrets.sql +5 -0
- package/migrations/pg/0010_bigint_append_only_ids.down.sql +2 -0
- package/migrations/pg/0010_bigint_append_only_ids.sql +23 -0
- package/migrations/sqlite/0001_schema_version.down.sql +2 -0
- package/migrations/sqlite/0001_schema_version.sql +8 -0
- package/migrations/sqlite/0002_initial_schema.down.sql +36 -0
- package/migrations/sqlite/0002_initial_schema.sql +376 -0
- package/migrations/sqlite/0003_auth_continuation.down.sql +27 -0
- package/migrations/sqlite/0003_auth_continuation.sql +45 -0
- package/migrations/sqlite/0004_tenant_default_unique.down.sql +1 -0
- package/migrations/sqlite/0004_tenant_default_unique.sql +13 -0
- package/migrations/sqlite/0005_hot_indexes_timestamptz.down.sql +10 -0
- package/migrations/sqlite/0005_hot_indexes_timestamptz.sql +10 -0
- package/migrations/sqlite/0006_canonical_email.down.sql +3 -0
- package/migrations/sqlite/0006_canonical_email.sql +8 -0
- package/migrations/sqlite/0007_audit_chain_anchor.down.sql +1 -0
- package/migrations/sqlite/0007_audit_chain_anchor.sql +8 -0
- package/migrations/sqlite/0008_two_factor_hardening.down.sql +14 -0
- package/migrations/sqlite/0008_two_factor_hardening.sql +7 -0
- package/migrations/sqlite/0009_encrypt_totp_secrets.down.sql +2 -0
- package/migrations/sqlite/0009_encrypt_totp_secrets.sql +5 -0
- package/migrations/sqlite/0010_bigint_append_only_ids.down.sql +1 -0
- package/migrations/sqlite/0010_bigint_append_only_ids.sql +2 -0
- package/package.json +398 -0
- package/src/adapters/database/index.ts +63 -0
- package/src/adapters/database/types.ts +22 -0
- package/src/changelog-script.test.ts +21 -0
- package/src/cli.test.ts +79 -0
- package/src/core/auth/auth-admin.test.ts +247 -0
- package/src/core/auth/auth-endpoints.ts +558 -0
- package/src/core/auth/auth-observer.test.ts +191 -0
- package/src/core/auth/auth-service.ts +1464 -0
- package/src/core/auth/email.test.ts +17 -0
- package/src/core/auth/email.ts +11 -0
- package/src/core/auth/hooks.test.ts +251 -0
- package/src/core/auth/impersonation.test.ts +179 -0
- package/src/core/auth/jwt.test.ts +184 -0
- package/src/core/auth/jwt.ts +239 -0
- package/src/core/auth/login-timing.test.ts +77 -0
- package/src/core/auth/password-policy.test.ts +253 -0
- package/src/core/auth/password-policy.ts +220 -0
- package/src/core/auth/password.test.ts +42 -0
- package/src/core/auth/password.ts +62 -0
- package/src/core/auth/post-auth-gate.test.ts +258 -0
- package/src/core/auth/post-auth-gate.ts +228 -0
- package/src/core/auth/refresh-token.test.ts +86 -0
- package/src/core/auth/refresh-token.ts +105 -0
- package/src/core/auth/timing-safe.ts +23 -0
- package/src/core/config.ts +212 -0
- package/src/core/endpoint.ts +149 -0
- package/src/core/errors.ts +199 -0
- package/src/core/fetcher-interop.test.ts +106 -0
- package/src/core/fortress.test.ts +354 -0
- package/src/core/fortress.ts +550 -0
- package/src/core/http/call.test.ts +148 -0
- package/src/core/http/call.ts +149 -0
- package/src/core/http/cookie-serialize.test.ts +198 -0
- package/src/core/http/cookie-serialize.ts +107 -0
- package/src/core/http/csrf.test.ts +140 -0
- package/src/core/http/csrf.ts +173 -0
- package/src/core/http/dispatch.ts +652 -0
- package/src/core/http/error-response.test.ts +69 -0
- package/src/core/http/error-response.ts +93 -0
- package/src/core/http/fortress-rbac.test.ts +43 -0
- package/src/core/http/fortress-rbac.ts +127 -0
- package/src/core/http/handle-request.test.ts +441 -0
- package/src/core/http/handle-request.ts +354 -0
- package/src/core/http/match.test.ts +122 -0
- package/src/core/http/match.ts +126 -0
- package/src/core/http/outbound.test.ts +34 -0
- package/src/core/http/outbound.ts +105 -0
- package/src/core/http/plugin-middleware.ts +67 -0
- package/src/core/http/principal.test.ts +345 -0
- package/src/core/http/principal.ts +86 -0
- package/src/core/http/protect.test.ts +220 -0
- package/src/core/http/protect.ts +394 -0
- package/src/core/http/token-extraction.test.ts +59 -0
- package/src/core/http/token-extraction.ts +53 -0
- package/src/core/iam/explain.test.ts +177 -0
- package/src/core/iam/explain.ts +302 -0
- package/src/core/iam/iam-endpoints.ts +779 -0
- package/src/core/iam/iam-service.test.ts +829 -0
- package/src/core/iam/iam-service.ts +1137 -0
- package/src/core/iam/permission-cache.test.ts +115 -0
- package/src/core/iam/permission-cache.ts +71 -0
- package/src/core/iam/permission-check-observer.test.ts +90 -0
- package/src/core/iam/permission-evaluator.test.ts +291 -0
- package/src/core/iam/permission-evaluator.ts +198 -0
- package/src/core/iam/permission-sync.test.ts +166 -0
- package/src/core/iam/permission-sync.ts +192 -0
- package/src/core/iam/resource-sync.test.ts +70 -0
- package/src/core/iam/resource-sync.ts +182 -0
- package/src/core/iam/service-account-http.test.ts +529 -0
- package/src/core/iam/service-account.test.ts +282 -0
- package/src/core/internal-adapter.test.ts +389 -0
- package/src/core/internal-adapter.ts +435 -0
- package/src/core/json-schema.ts +50 -0
- package/src/core/manifest/__snapshots__/route-manifest.test.ts.snap +192 -0
- package/src/core/manifest/drift.ts +103 -0
- package/src/core/manifest/route-manifest.test.ts +142 -0
- package/src/core/manifest/route-manifest.ts +154 -0
- package/src/core/migrate.test.ts +72 -0
- package/src/core/migrations/engine.test.ts +308 -0
- package/src/core/migrations/engine.ts +548 -0
- package/src/core/migrations/migrations.ts +1771 -0
- package/src/core/migrations/pg-migration.integration-test.ts +353 -0
- package/src/core/migrations/upgrade-fixture.test.ts +378 -0
- package/src/core/observability/db-instrumentation.ts +205 -0
- package/src/core/observability/listener-list.test.ts +124 -0
- package/src/core/observability/listener-list.ts +73 -0
- package/src/core/observability/logger.test.ts +43 -0
- package/src/core/observability/logger.ts +49 -0
- package/src/core/observability/spans.test.ts +193 -0
- package/src/core/observability/types.ts +80 -0
- package/src/core/openapi-drift.test.ts +41 -0
- package/src/core/openapi.ts +47 -0
- package/src/core/plugin-methods-map.ts +75 -0
- package/src/core/plugin-runner.test.ts +233 -0
- package/src/core/plugin-runner.ts +276 -0
- package/src/core/plugin.ts +210 -0
- package/src/core/policy/apply.ts +272 -0
- package/src/core/policy/diff.ts +288 -0
- package/src/core/policy/loader.test.ts +63 -0
- package/src/core/policy/loader.ts +214 -0
- package/src/core/policy/policy.test.ts +232 -0
- package/src/core/policy/types.ts +105 -0
- package/src/core/schema-builder.test.ts +660 -0
- package/src/core/schema-builder.ts +881 -0
- package/src/core/standard-schema.ts +56 -0
- package/src/core/types.ts +258 -0
- package/src/core/validation.test.ts +195 -0
- package/src/core/validation.ts +192 -0
- package/src/drizzle/adapter.test.ts +425 -0
- package/src/drizzle/adapter.ts +474 -0
- package/src/drizzle/index.ts +31 -0
- package/src/drizzle/pg/adapter.integration-test.ts +456 -0
- package/src/drizzle/pg/index.ts +13 -0
- package/src/drizzle/pg/pg.integration-test.ts +1539 -0
- package/src/drizzle/pg/schema.ts +539 -0
- package/src/drizzle/pg-error-map.test.ts +218 -0
- package/src/drizzle/pg-error-map.ts +151 -0
- package/src/drizzle/schema.ts +544 -0
- package/src/drizzle/sqlite-serialization.test.ts +106 -0
- package/src/express/express-api-key-user-routes.test.ts +241 -0
- package/src/express/express.test.ts +442 -0
- package/src/express/handle.ts +191 -0
- package/src/express/index.ts +62 -0
- package/src/express/middleware.ts +551 -0
- package/src/express/protect.ts +154 -0
- package/src/express/validated.test.ts +86 -0
- package/src/express/validated.ts +99 -0
- package/src/fetcher/index.ts +81 -0
- package/src/hono/convert-routes.test.ts +220 -0
- package/src/hono/convert-routes.ts +196 -0
- package/src/hono/converters.test.ts +50 -0
- package/src/hono/converters.ts +43 -0
- package/src/hono/handle.ts +79 -0
- package/src/hono/helpers.ts +2 -0
- package/src/hono/hono-api-key-user-routes.test.ts +225 -0
- package/src/hono/hono-handlers.test.ts +861 -0
- package/src/hono/hono.test.ts +454 -0
- package/src/hono/index.ts +101 -0
- package/src/hono/middleware/auth.ts +236 -0
- package/src/hono/middleware/auth.types.test.ts +94 -0
- package/src/hono/middleware/csrf.test.ts +127 -0
- package/src/hono/middleware/csrf.ts +68 -0
- package/src/hono/middleware/error-handler.ts +12 -0
- package/src/hono/middleware/plugin-middleware.ts +35 -0
- package/src/hono/middleware/rbac.ts +131 -0
- package/src/hono/middleware/security-headers.test.ts +88 -0
- package/src/hono/middleware/security-headers.ts +68 -0
- package/src/hono/openapi.ts +237 -0
- package/src/hono/protect.ts +87 -0
- package/src/hono/validated.test.ts +123 -0
- package/src/hono/validated.ts +62 -0
- package/src/index.ts +309 -0
- package/src/integration.test.ts +718 -0
- package/src/internal/changelog.ts +56 -0
- package/src/otel/index.ts +158 -0
- package/src/otel/otel-types.test.ts +35 -0
- package/src/otel/otel.test.ts +235 -0
- package/src/plugins/account-lockout/account-lockout.test.ts +367 -0
- package/src/plugins/account-lockout/index.ts +267 -0
- package/src/plugins/admin/admin-api-key.test.ts +438 -0
- package/src/plugins/admin/index.ts +1612 -0
- package/src/plugins/api-key/api-key.test.ts +684 -0
- package/src/plugins/api-key/core.ts +336 -0
- package/src/plugins/api-key/index.ts +315 -0
- package/src/plugins/audit-log/audit-log.test.ts +749 -0
- package/src/plugins/audit-log/index.ts +680 -0
- package/src/plugins/data-isolation/data-isolation.test.ts +197 -0
- package/src/plugins/data-isolation/index.ts +157 -0
- package/src/plugins/email-verification/email-verification.test.ts +199 -0
- package/src/plugins/email-verification/index.ts +190 -0
- package/src/plugins/magic-link/index.ts +129 -0
- package/src/plugins/magic-link/magic-link.test.ts +156 -0
- package/src/plugins/oauth/id-token.ts +86 -0
- package/src/plugins/oauth/index.ts +2145 -0
- package/src/plugins/oauth/jwks.test.ts +32 -0
- package/src/plugins/oauth/jwks.ts +182 -0
- package/src/plugins/oauth/oauth.test.ts +2220 -0
- package/src/plugins/oauth/pkce.ts +58 -0
- package/src/plugins/openapi/index.ts +298 -0
- package/src/plugins/openapi/openapi.test.ts +425 -0
- package/src/plugins/openapi/spec-builder.ts +287 -0
- package/src/plugins/rate-limit/express.test.ts +89 -0
- package/src/plugins/rate-limit/express.ts +86 -0
- package/src/plugins/rate-limit/hono.test.ts +60 -0
- package/src/plugins/rate-limit/hono.ts +74 -0
- package/src/plugins/rate-limit/index.ts +383 -0
- package/src/plugins/rate-limit/memory-store.ts +61 -0
- package/src/plugins/rate-limit/rate-limit.test.ts +756 -0
- package/src/plugins/rate-limit/sveltekit.test.ts +58 -0
- package/src/plugins/rate-limit/sveltekit.ts +66 -0
- package/src/plugins/social-login/index.ts +715 -0
- package/src/plugins/social-login/providers/apple.ts +34 -0
- package/src/plugins/social-login/providers/discord.ts +26 -0
- package/src/plugins/social-login/providers/github.ts +54 -0
- package/src/plugins/social-login/providers/google.ts +23 -0
- package/src/plugins/social-login/providers/index.ts +22 -0
- package/src/plugins/social-login/providers/microsoft.ts +35 -0
- package/src/plugins/social-login/providers/oidc.ts +37 -0
- package/src/plugins/social-login/providers/providers.test.ts +211 -0
- package/src/plugins/social-login/social-login.test.ts +675 -0
- package/src/plugins/social-login/types.ts +80 -0
- package/src/plugins/tenancy/index.ts +544 -0
- package/src/plugins/tenancy/tenancy.test.ts +323 -0
- package/src/plugins/two-factor/index.ts +569 -0
- package/src/plugins/two-factor/two-factor.test.ts +235 -0
- package/src/plugins/webauthn/index.ts +554 -0
- package/src/plugins/webauthn/webauthn.test.ts +472 -0
- package/src/plugins/webhook/builtin-events.ts +29 -0
- package/src/plugins/webhook/delivery.test.ts +51 -0
- package/src/plugins/webhook/delivery.ts +154 -0
- package/src/plugins/webhook/hooks.ts +89 -0
- package/src/plugins/webhook/index.ts +445 -0
- package/src/plugins/webhook/queue/database.ts +67 -0
- package/src/plugins/webhook/queue/in-memory.test.ts +48 -0
- package/src/plugins/webhook/queue/in-memory.ts +71 -0
- package/src/plugins/webhook/queue/types.ts +51 -0
- package/src/plugins/webhook/registry.test.ts +48 -0
- package/src/plugins/webhook/registry.ts +64 -0
- package/src/plugins/webhook/signing.ts +45 -0
- package/src/plugins/webhook/ssrf.ts +198 -0
- package/src/plugins/webhook/types.ts +138 -0
- package/src/plugins/webhook/webhook.test.ts +324 -0
- package/src/sveltekit/actions.ts +233 -0
- package/src/sveltekit/catch-all.ts +43 -0
- package/src/sveltekit/cookies.ts +136 -0
- package/src/sveltekit/handle.ts +356 -0
- package/src/sveltekit/helpers.ts +69 -0
- package/src/sveltekit/index.ts +74 -0
- package/src/sveltekit/protect.ts +80 -0
- package/src/sveltekit/sveltekit-types.test.ts +31 -0
- package/src/sveltekit/sveltekit.test.ts +799 -0
- package/src/sveltekit/types.ts +134 -0
- package/src/sveltekit/validated.test.ts +117 -0
- package/src/sveltekit/validated.ts +78 -0
- package/src/testing/adapter-conformance.test.ts +408 -0
- package/src/testing/checks.test.ts +124 -0
- package/src/testing/checks.ts +304 -0
- package/src/testing/index.ts +107 -0
package/SECURITY.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a Vulnerability
|
|
4
|
+
|
|
5
|
+
If you discover a security vulnerability in Fortress, please report it responsibly.
|
|
6
|
+
|
|
7
|
+
**Do NOT open a public GitHub issue for security vulnerabilities.**
|
|
8
|
+
|
|
9
|
+
Instead, email: security@bajustone.dev
|
|
10
|
+
|
|
11
|
+
Include:
|
|
12
|
+
- Description of the vulnerability
|
|
13
|
+
- Steps to reproduce
|
|
14
|
+
- Potential impact
|
|
15
|
+
- Suggested fix (if any)
|
|
16
|
+
|
|
17
|
+
We will acknowledge receipt within 48 hours and aim to release a fix within 7 days for critical issues.
|
|
18
|
+
|
|
19
|
+
## Supported Versions
|
|
20
|
+
|
|
21
|
+
| Version | Supported |
|
|
22
|
+
|---------|-----------|
|
|
23
|
+
| 1.0.x release candidates | Yes |
|
|
24
|
+
| 0.2.x | Yes |
|
|
25
|
+
| 0.1.x | Security fixes only |
|
|
26
|
+
| 0.0.x | No (please upgrade) |
|
|
27
|
+
|
|
28
|
+
Until 1.0 final, breaking changes may ship in a release candidate or minor release. Pin deliberately and review the migration notes.
|
|
29
|
+
|
|
30
|
+
## Security Best Practices
|
|
31
|
+
|
|
32
|
+
### Route security manifest
|
|
33
|
+
|
|
34
|
+
Use `fortress.manifest` (or `fortress manifest` for the core auth/IAM surface) to review which routes are public, authenticated, RBAC-protected, OAuth self-managed, CSRF-applicable, and rate-limited. Add `detectRouteManifestDrift()` to CI when generating OpenAPI specs or mounting plugin routes so route protection metadata cannot silently drift.
|
|
35
|
+
|
|
36
|
+
For app-owned routes that call Fortress services directly, prefer `protect()` / adapter `protectedRoute()` wrappers so CSRF, auth, RBAC, validation, and plugin middleware still run from endpoint metadata. See [docs/host-owned-routes.md](docs/host-owned-routes.md).
|
|
37
|
+
|
|
38
|
+
### Input validation
|
|
39
|
+
|
|
40
|
+
Request validation runs on `@bajustone/fetcher`'s `fromJSONSchema` engine. For security-sensitive inputs:
|
|
41
|
+
- Use the **enforced** format builders (`email()`, `uuid()`, `url()`, `datetime()`) rather than the annotation-only `strFormat()` — their patterns are ReDoS-safe (linear-time) and checked at runtime.
|
|
42
|
+
- Wrap request-body objects in `strict()` (`additionalProperties: false`) to reject unknown keys and prevent over-posting / mass-assignment.
|
|
43
|
+
- Object validators are prototype-pollution-safe (null-prototype accumulation; a literal `__proto__` key is treated as an ordinary property).
|
|
44
|
+
- Note: `$ref` fields in request bodies are present-but-unconstrained at validation time — validate referenced shapes inline (or in the handler) when their contents are security-relevant.
|
|
45
|
+
|
|
46
|
+
### Outbound HTTP
|
|
47
|
+
|
|
48
|
+
Fortress's outbound calls (OAuth/OIDC token exchange, discovery, provider userinfo, GitHub profile, and the HIBP breach check) run through a shared `@bajustone/fetcher` client with a request **timeout**, so a hung or slow upstream cannot stall a login or registration. The HIBP breach check **fails open** — a timeout or error never blocks a password — and only ever sends the 5-character k-anonymity hash prefix. OIDC discovery/issuer URLs are consumer-supplied: if you accept untrusted issuer configuration, treat outbound discovery as an SSRF surface (an opt-in IP-pinning guard for outbound calls is planned, mirroring the webhook plugin's transport).
|
|
49
|
+
|
|
50
|
+
### Webhook delivery
|
|
51
|
+
|
|
52
|
+
Webhook endpoint URLs are consumer-supplied, so the **webhook plugin** treats delivery as a live SSRF surface: it delivers over HTTPS only, resolves and validates the target (rejecting private/loopback/link-local/CGNAT addresses across IPv4, IPv6, `::ffff:`-mapped, and `64:ff9b::/96` NAT64 forms), and **pins the connection to the resolved IP** to close the DNS-rebinding window between validation and connect. Overriding `delivery.fetch` bypasses this guard — only do so for targets you control. Signing secrets are CSPRNG-generated, returned only at `registerEndpoint`/`rotateSecret`, and **redacted** from `listEndpoints`/`updateEndpoint`; rotate with `rotateSecret`. Webhook payloads are HMAC-signed but **not encrypted** — never include secrets or PII in a payload. See [docs/plugins/webhook.md](docs/plugins/webhook.md).
|
|
53
|
+
|
|
54
|
+
Track Fortress-owned table/index upgrades with `fortress_schema_version`, `getMigrationStatus()`, and the bundled SQL under `migrations/{sqlite,pg}`. Auth, IAM, OAuth, API-key, tenancy, and audit-log tables are security-critical; do not skip migration drift checks during upgrades.
|
|
55
|
+
|
|
56
|
+
See [docs/security.md](docs/security.md) for comprehensive security guidance, [docs/threat-model.md](docs/threat-model.md) for the current formal threat model, [docs/hardening.md](docs/hardening.md) for the production hardening checklist, [docs/deployment.md](docs/deployment.md) for the production deployment guide (JWT secret rotation, cookies behind reverse proxies, CSRF/CORS recipes, HTTPS requirements, OAuth/OIDC RP setup), and [docs/migrations/upgrade-guide.md](docs/migrations/upgrade-guide.md) for the migration runbook.
|
|
57
|
+
|
|
58
|
+
## Registration account-enumeration tradeoff
|
|
59
|
+
|
|
60
|
+
The built-in public `POST /auth/register` endpoint intentionally returns a
|
|
61
|
+
409 when the submitted email already exists. This is useful UX for many
|
|
62
|
+
first-party apps but is an account-enumeration signal. Treat this as an
|
|
63
|
+
accepted tradeoff unless your product requires non-enumerating registration.
|
|
64
|
+
If you do, wrap registration with your own flow (e.g. always return 202 and
|
|
65
|
+
send either a verification email or an "already have an account" email).
|
|
66
|
+
|
|
67
|
+
When using the built-in endpoint publicly, mount the rate-limit plugin with
|
|
68
|
+
`register` protection enabled to slow bulk enumeration.
|
|
69
|
+
|
|
70
|
+
## Login is not an enumeration oracle
|
|
71
|
+
|
|
72
|
+
In contrast to `register`, `auth.login()` is intentionally
|
|
73
|
+
timing-equalized: the "user not found / no password set" branch runs a real
|
|
74
|
+
Argon2id verify against a well-formed reference hash produced by the
|
|
75
|
+
configured `PasswordHasher`, not a hard-coded dummy. Both that branch and
|
|
76
|
+
the "wrong password" branch take the same wall-clock time and return the
|
|
77
|
+
same generic `Invalid credentials` error, so a remote attacker cannot
|
|
78
|
+
distinguish "account exists" from "account missing" via response timing or
|
|
79
|
+
error text. The same path also covers disabled accounts to avoid leaking
|
|
80
|
+
`isActive` state. The regression test lives in
|
|
81
|
+
`src/core/auth/login-timing.test.ts`.
|
|
82
|
+
|
|
83
|
+
## Tenancy isolation model
|
|
84
|
+
|
|
85
|
+
The tenancy plugin derives the active tenant from the verified JWT custom
|
|
86
|
+
claim (`claims.customClaims.tenantId`) that is issued from `tenant_user`
|
|
87
|
+
membership, never from a client-controlled header.
|
|
88
|
+
|
|
89
|
+
Tenant schema names use the numeric tenant id (`tenant_<id>` by default), so
|
|
90
|
+
untrusted tenant codes/tax IDs are not interpolated as SQL identifiers. For
|
|
91
|
+
PostgreSQL requests with a tenant claim, the adapter wrapper pins
|
|
92
|
+
`search_path` with `set_config('search_path', ?, true)` inside the same
|
|
93
|
+
transaction and connection as the operation. Without a tenant claim, the
|
|
94
|
+
adapter is unchanged; tenant business tables should live outside `public`, so
|
|
95
|
+
missing tenant context fails closed.
|
|
96
|
+
|
|
97
|
+
Tenant access in JWTs has the normal staleness tradeoff: removing a user from
|
|
98
|
+
a tenant does not revoke already-issued access tokens until they expire or are
|
|
99
|
+
refreshed. Use short access-token lifetimes and session/token revocation when
|
|
100
|
+
immediate removal is required.
|
|
101
|
+
|
|
102
|
+
## Cookie posture (SvelteKit / `fortress.handleRequest`)
|
|
103
|
+
|
|
104
|
+
When using `fortress.handleRequest` directly or the SvelteKit adapter, auth
|
|
105
|
+
tokens are written to two `httpOnly` cookies. Defaults from
|
|
106
|
+
`FortressConfig.cookies` are now production-safe regardless of `NODE_ENV`:
|
|
107
|
+
|
|
108
|
+
| Default | Access cookie | Refresh cookie | Attributes |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| All environments | `__Host-fortress_access` | `__Host-fortress_refresh` | `HttpOnly; Secure; SameSite=Lax; Path=/` |
|
|
111
|
+
|
|
112
|
+
The `__Host-` prefix binds the cookie to the exact origin (no `Domain`, no
|
|
113
|
+
subpath, must be `Secure`) — the strongest browser-enforced isolation.
|
|
114
|
+
Many production runtimes do not reliably set `NODE_ENV=production`, so
|
|
115
|
+
Fortress no longer infers cookie security from that variable.
|
|
116
|
+
|
|
117
|
+
Local HTTP development must opt out explicitly:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
createFortress({
|
|
121
|
+
// ...
|
|
122
|
+
cookies: { secure: false }, // drops __Host- prefix; localhost HTTP only
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Override via `FortressConfig.cookies` if you need a `Domain`, `Path`,
|
|
127
|
+
custom names, or `SameSite=strict`. Note: `SameSite=strict` blocks
|
|
128
|
+
top-level cross-site navigation cookies, which breaks magic-link email
|
|
129
|
+
flows and OAuth callbacks. Stick with `lax` unless you know you don't need
|
|
130
|
+
them.
|
|
131
|
+
|
|
132
|
+
## CSRF posture
|
|
133
|
+
|
|
134
|
+
Fortress now performs its own pipeline CSRF check on Fortress-managed
|
|
135
|
+
routes (`/auth/*`, `/iam/*`, plugin paths) before dispatch. The check is on
|
|
136
|
+
by default for unsafe methods (`POST`, `PUT`, `PATCH`, `DELETE`) whenever
|
|
137
|
+
the request carries a Fortress access **or refresh** cookie:
|
|
138
|
+
|
|
139
|
+
- `Sec-Fetch-Site: cross-site` is rejected.
|
|
140
|
+
- A custom header is required (`X-Fortress-CSRF` by default).
|
|
141
|
+
- The check is not bypassed just because an `Authorization` or API-key
|
|
142
|
+
header is also present; cookies remain ambient browser credentials.
|
|
143
|
+
- Pure bearer/API-key requests with no Fortress cookies skip the check.
|
|
144
|
+
|
|
145
|
+
Configure via:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
createFortress({
|
|
149
|
+
// ...
|
|
150
|
+
csrf: {
|
|
151
|
+
enabled: true,
|
|
152
|
+
headerName: 'X-Fortress-CSRF',
|
|
153
|
+
skipPaths: [],
|
|
154
|
+
},
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Set `csrf.enabled = false` only for pure bearer/API deployments where no
|
|
159
|
+
Fortress route is reachable with ambient cookies. SvelteKit form actions
|
|
160
|
+
that go through `resolve()` remain subject to SvelteKit's own
|
|
161
|
+
`csrf.checkOrigin`; keep that enabled as defense in depth.
|
|
162
|
+
|
|
163
|
+
## Refresh-token concurrency posture
|
|
164
|
+
|
|
165
|
+
Fortress uses strict refresh-token replay semantics. When two concurrent
|
|
166
|
+
refresh attempts present the same refresh token, exactly one can rotate it;
|
|
167
|
+
the loser is treated as token reuse and the entire token family is revoked,
|
|
168
|
+
including the winner's newly issued refresh token. This favors theft
|
|
169
|
+
containment over a concurrency grace window. Applications with aggressive
|
|
170
|
+
multi-tab auto-refresh should coordinate refreshes client-side or add a
|
|
171
|
+
server-side single-flight/grace mechanism.
|
|
172
|
+
|
|
173
|
+
## SSR auto-refresh race
|
|
174
|
+
|
|
175
|
+
The SvelteKit handle hook auto-refreshes an expired access cookie when a
|
|
176
|
+
valid refresh cookie is present. Opening N tabs simultaneously triggers N
|
|
177
|
+
parallel refresh attempts; Fortress's refresh-token family rotation will
|
|
178
|
+
succeed for one and fail for the others (with `TOKEN_REUSE`). This is a
|
|
179
|
+
fundamental trade-off of the JWT + family-rotation model. If your UX
|
|
180
|
+
requires zero-friction multi-tab opens, consider:
|
|
181
|
+
|
|
182
|
+
- Adding a short grace window on rotation (`refreshTokenExpirySeconds`
|
|
183
|
+
overlap)
|
|
184
|
+
- Storing the refresh attempt in a per-user lock (custom plugin)
|
|
185
|
+
- Falling back to a server-side session table for the refresh side
|
|
186
|
+
|
|
187
|
+
## Social login hardening
|
|
188
|
+
|
|
189
|
+
Social-login callbacks verify OAuth `state` with a timing-safe comparison and keep it separate from the OIDC `nonce`. OIDC providers must return an `id_token`; Fortress verifies its JWS signature through the provider JWKS and validates issuer, audience, expiry, and nonce before account linking or provisioning. By-email account linking requires `emailVerified === true` and an active local user; provider profile mappers fail closed on an absent `email_verified` claim (including Microsoft/Entra, whose Graph `/me` and id_tokens commonly omit it), so a missing claim never satisfies the auto-link gate. Provider access and refresh tokens are stored only when `persistTokens: true` is explicitly enabled, and then are encrypted at rest with AES-256-GCM using `tokenEncryptionKey`; persistence fails closed without the key.
|
|
190
|
+
|
|
191
|
+
## Admin bootstrap hardening
|
|
192
|
+
|
|
193
|
+
The admin bootstrap endpoint is not mounted by default. Enable it explicitly with `admin({ bootstrap: { enabled: true, secret } })` (or `FORTRESS_ADMIN_BOOTSTRAP_SECRET`). It succeeds only while no `fortress-admin` role bindings exist and only when the one-time secret matches; there is no `adminUserIds` superadmin bypass.
|
|
194
|
+
|
|
195
|
+
## Tenant-less permission checks
|
|
196
|
+
|
|
197
|
+
Tenant-less permission checks match only tenant-less (`tenant_id IS NULL`) role/direct-permission bindings. Tenant-scoped grants are considered only when the check supplies the matching tenant id.
|