@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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PKCE (Proof Key for Code Exchange) S256 implementation.
|
|
3
|
+
* Used by the OAuth plugin to secure authorization code flows.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { timingSafeEqualHex } from '../../core/auth/timing-safe';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* RFC 7636 §4.1: code_verifier = high-entropy cryptographic random
|
|
10
|
+
* STRING using the unreserved characters [A-Z]/[a-z]/[0-9]/"-"/"."/"_"/"~"
|
|
11
|
+
* with a minimum length of 43 characters and a maximum length of 128.
|
|
12
|
+
*/
|
|
13
|
+
const CODE_VERIFIER_PATTERN = /^[\w.~-]{43,128}$/;
|
|
14
|
+
|
|
15
|
+
/** Generate a cryptographically random code verifier (43-128 chars, URL-safe) */
|
|
16
|
+
export function generateCodeVerifier(): string {
|
|
17
|
+
const bytes = new Uint8Array(32);
|
|
18
|
+
crypto.getRandomValues(bytes);
|
|
19
|
+
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Generate S256 code challenge from a code verifier */
|
|
23
|
+
export async function generateCodeChallenge(verifier: string): Promise<string> {
|
|
24
|
+
const data = new TextEncoder().encode(verifier);
|
|
25
|
+
const hash = await crypto.subtle.digest('SHA-256', data);
|
|
26
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash)))
|
|
27
|
+
.replace(/\+/g, '-')
|
|
28
|
+
.replace(/\//g, '_')
|
|
29
|
+
.replace(/=/g, '');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Verify a code verifier against a stored S256 challenge.
|
|
34
|
+
*
|
|
35
|
+
* Validates the verifier against RFC 7636 §4.1 (43-128 chars, unreserved
|
|
36
|
+
* URL-safe character set) before computing the challenge — a verifier that
|
|
37
|
+
* fails this check is invalid by definition and must not unlock a code.
|
|
38
|
+
*
|
|
39
|
+
* Uses {@link timingSafeEqualHex} for the final comparison so a remote
|
|
40
|
+
* attacker can't differentiate "wrong verifier" from "wrong verifier with
|
|
41
|
+
* matching prefix" via response timing.
|
|
42
|
+
*/
|
|
43
|
+
export async function verifyCodeChallenge(
|
|
44
|
+
verifier: string,
|
|
45
|
+
challenge: string,
|
|
46
|
+
method: string,
|
|
47
|
+
): Promise<boolean> {
|
|
48
|
+
if (method !== 'S256')
|
|
49
|
+
return false;
|
|
50
|
+
|
|
51
|
+
if (!CODE_VERIFIER_PATTERN.test(verifier))
|
|
52
|
+
return false;
|
|
53
|
+
|
|
54
|
+
const computed = await generateCodeChallenge(verifier);
|
|
55
|
+
// base64url is a fixed alphabet; `timingSafeEqualHex` works for any
|
|
56
|
+
// single-byte-per-char ASCII string of equal length.
|
|
57
|
+
return timingSafeEqualHex(computed, challenge);
|
|
58
|
+
}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI 3.1 generator plugin for fortress.
|
|
3
|
+
*
|
|
4
|
+
* Walks every registered endpoint definition (auth, IAM, and any plugin
|
|
5
|
+
* routes), folds in their JSON Schema component definitions, and emits a
|
|
6
|
+
* complete OpenAPI 3.1 specification. Pairs with Scalar UI for an
|
|
7
|
+
* interactive docs page mounted by the framework adapters.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ComponentSchemas, EndpointDefinition } from '../../core/endpoint';
|
|
13
|
+
import type { ResourceFile } from '../../core/iam/resource-sync';
|
|
14
|
+
import type { JSONSchema } from '../../core/json-schema';
|
|
15
|
+
import type { FortressPlugin, PluginContext } from '../../core/plugin';
|
|
16
|
+
import type { OpenAPISpec, SpecBuilderOptions } from './spec-builder';
|
|
17
|
+
import { authComponentSchemas, authEndpoints } from '../../core/auth/auth-endpoints';
|
|
18
|
+
import { iamComponentSchemas, iamEndpoints } from '../../core/iam/iam-endpoints';
|
|
19
|
+
import { buildOpenAPISpec } from './spec-builder';
|
|
20
|
+
|
|
21
|
+
export interface OpenAPIConfig {
|
|
22
|
+
/** API title (default: 'Fortress Auth API') */
|
|
23
|
+
title?: string;
|
|
24
|
+
/** API version (default: '1.0.0') */
|
|
25
|
+
version?: string;
|
|
26
|
+
/** API description */
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Server URL(s) for the spec */
|
|
29
|
+
servers?: Array<{ url: string; description?: string }>;
|
|
30
|
+
/** Optional top-level OpenAPI tags. */
|
|
31
|
+
tags?: Array<{ name: string; description?: string }>;
|
|
32
|
+
/** Operation ID strategy. Default: historical method+path IDs. */
|
|
33
|
+
operationId?: SpecBuilderOptions['operationId'];
|
|
34
|
+
/** Path to serve the JSON spec (default: '/openapi.json') */
|
|
35
|
+
specPath?: string;
|
|
36
|
+
/** Path to serve the Scalar UI (default: '/openapi') */
|
|
37
|
+
uiPath?: string;
|
|
38
|
+
/** Disable Scalar UI (default: false) */
|
|
39
|
+
disableUI?: boolean;
|
|
40
|
+
/** Include core auth endpoints in spec (default: true) */
|
|
41
|
+
includeCoreAuth?: boolean;
|
|
42
|
+
/** Include core IAM endpoints in spec (default: true) */
|
|
43
|
+
includeCoreIam?: boolean;
|
|
44
|
+
/** Additional component schemas to include */
|
|
45
|
+
additionalSchemas?: ComponentSchemas;
|
|
46
|
+
/** Additional endpoint definitions to include in the spec (for app-specific routes) */
|
|
47
|
+
additionalEndpoints?: EndpointDefinition[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface OpenAPIMethods {
|
|
51
|
+
[key: string]: (...args: any[]) => any;
|
|
52
|
+
generateSpec: () => Promise<OpenAPISpec>;
|
|
53
|
+
getSpec: () => Promise<Record<string, unknown>>;
|
|
54
|
+
getUI: () => string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function computeRelativeUrl(fromPath: string, toPath: string): string {
|
|
58
|
+
const fromParts = fromPath.split('/').slice(0, -1);
|
|
59
|
+
const toParts = toPath.split('/');
|
|
60
|
+
let common = 0;
|
|
61
|
+
while (common < fromParts.length && common < toParts.length && fromParts[common] === toParts[common]) {
|
|
62
|
+
common++;
|
|
63
|
+
}
|
|
64
|
+
const ups = fromParts.length - common;
|
|
65
|
+
const rest = toParts.slice(common).join('/');
|
|
66
|
+
if (ups === 0)
|
|
67
|
+
return `./${rest}`;
|
|
68
|
+
return '../'.repeat(ups) + rest;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function buildScalarHTML(specPath: string, title: string): string {
|
|
72
|
+
return `<!DOCTYPE html>
|
|
73
|
+
<html>
|
|
74
|
+
<head>
|
|
75
|
+
<title>${title} — API Reference</title>
|
|
76
|
+
<meta charset="utf-8" />
|
|
77
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
78
|
+
</head>
|
|
79
|
+
<body>
|
|
80
|
+
<script id="api-reference" data-url="${specPath}"></script>
|
|
81
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
82
|
+
</body>
|
|
83
|
+
</html>`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Build a single `oneOf` branch for a resource: `resource` is `const`,
|
|
88
|
+
* `action` is `enum` over the resource's valid actions, plus shared fields.
|
|
89
|
+
*/
|
|
90
|
+
function buildResourceBranch(
|
|
91
|
+
resourceName: string,
|
|
92
|
+
actions: string[],
|
|
93
|
+
sharedProps: Record<string, JSONSchema>,
|
|
94
|
+
requiredFields: string[],
|
|
95
|
+
): JSONSchema {
|
|
96
|
+
const actionSchema: JSONSchema = actions.length > 0
|
|
97
|
+
? { type: 'string', enum: actions, description: 'Action name' }
|
|
98
|
+
: { type: 'string', description: 'Action name' };
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
type: 'object',
|
|
102
|
+
properties: {
|
|
103
|
+
resource: { type: 'string', const: resourceName, description: 'Resource name' },
|
|
104
|
+
action: actionSchema,
|
|
105
|
+
...sharedProps,
|
|
106
|
+
},
|
|
107
|
+
required: requiredFields,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Enrich `Permission` and `PermissionInput` component schemas with
|
|
113
|
+
* per-resource `oneOf` discriminated branches, and patch the `/iam/check`
|
|
114
|
+
* endpoint's inline body with flat resource/action enums.
|
|
115
|
+
*
|
|
116
|
+
* Mutates `componentSchemas` and the matching endpoint in `allEndpoints`.
|
|
117
|
+
*/
|
|
118
|
+
function enrichIamSchemas(
|
|
119
|
+
componentSchemas: ComponentSchemas,
|
|
120
|
+
allEndpoints: EndpointDefinition[],
|
|
121
|
+
resourceFile: ResourceFile,
|
|
122
|
+
): void {
|
|
123
|
+
const entries = Object.entries(resourceFile.resources);
|
|
124
|
+
if (entries.length === 0)
|
|
125
|
+
return;
|
|
126
|
+
|
|
127
|
+
// Shared fields for Permission (response schema — has id, description, conditions)
|
|
128
|
+
const permissionShared: Record<string, JSONSchema> = {
|
|
129
|
+
id: { type: 'integer', description: 'Permission ID' },
|
|
130
|
+
effect: { type: 'string', enum: ['ALLOW', 'DENY'] },
|
|
131
|
+
conditions: componentSchemas.Permission?.properties?.conditions ?? { type: 'array' },
|
|
132
|
+
description: { type: 'string', description: 'Permission description', nullable: true },
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Shared fields for PermissionInput (request schema — no id)
|
|
136
|
+
const permissionInputShared: Record<string, JSONSchema> = {
|
|
137
|
+
effect: { type: 'string', enum: ['ALLOW', 'DENY'] },
|
|
138
|
+
conditions: componentSchemas.PermissionInput?.properties?.conditions ?? { type: 'array' },
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Build oneOf branches
|
|
142
|
+
const permissionBranches: JSONSchema[] = [];
|
|
143
|
+
const permissionInputBranches: JSONSchema[] = [];
|
|
144
|
+
|
|
145
|
+
for (const [name, def] of entries) {
|
|
146
|
+
permissionBranches.push(
|
|
147
|
+
buildResourceBranch(name, def.actions, permissionShared, ['id', 'resource', 'action', 'effect']),
|
|
148
|
+
);
|
|
149
|
+
permissionInputBranches.push(
|
|
150
|
+
buildResourceBranch(name, def.actions, permissionInputShared, ['resource', 'action']),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Replace component schemas with oneOf
|
|
155
|
+
componentSchemas.Permission = { oneOf: permissionBranches };
|
|
156
|
+
componentSchemas.PermissionInput = { oneOf: permissionInputBranches };
|
|
157
|
+
|
|
158
|
+
// Patch /iam/check inline body with flat enums
|
|
159
|
+
const allResourceNames = entries.map(([name]) => name).sort();
|
|
160
|
+
const allActions = [...new Set(entries.flatMap(([, def]) => def.actions))].sort();
|
|
161
|
+
|
|
162
|
+
for (const ep of allEndpoints) {
|
|
163
|
+
if (ep.path === '/iam/check' && ep.input?.body?.properties) {
|
|
164
|
+
// Clone to avoid mutating the static endpoint definition
|
|
165
|
+
const bodyClone: JSONSchema = JSON.parse(JSON.stringify(ep.input.body));
|
|
166
|
+
if (bodyClone.properties!.resource) {
|
|
167
|
+
bodyClone.properties!.resource = { ...bodyClone.properties!.resource, enum: allResourceNames };
|
|
168
|
+
}
|
|
169
|
+
if (bodyClone.properties!.action && allActions.length > 0) {
|
|
170
|
+
bodyClone.properties!.action = { ...bodyClone.properties!.action, enum: allActions };
|
|
171
|
+
}
|
|
172
|
+
ep.input = { ...ep.input, body: bodyClone };
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* OpenAPI plugin factory. Returns a {@link FortressPlugin} that walks every
|
|
180
|
+
* registered endpoint definition and emits a complete OpenAPI 3.1 spec,
|
|
181
|
+
* pairable with Scalar UI for interactive documentation.
|
|
182
|
+
*/
|
|
183
|
+
export function openapi(config: OpenAPIConfig = {}): FortressPlugin & { readonly name: 'openapi' } {
|
|
184
|
+
const specPath = config.specPath ?? '/openapi.json';
|
|
185
|
+
const uiPath = config.uiPath ?? '/openapi';
|
|
186
|
+
const title = config.title ?? 'Fortress Auth API';
|
|
187
|
+
const version = config.version ?? '1.0.0';
|
|
188
|
+
|
|
189
|
+
let cachedSpec: OpenAPISpec | null = null;
|
|
190
|
+
|
|
191
|
+
const routes: FortressPlugin['routes'] = {
|
|
192
|
+
getSpec: {
|
|
193
|
+
method: 'GET',
|
|
194
|
+
path: specPath,
|
|
195
|
+
handler: 'getSpec',
|
|
196
|
+
meta: { summary: 'OpenAPI specification', tags: ['OpenAPI'], security: ['none'] },
|
|
197
|
+
responses: { 200: { description: 'OpenAPI 3.1 JSON spec' } },
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
if (!config.disableUI) {
|
|
202
|
+
routes.getUI = {
|
|
203
|
+
method: 'GET',
|
|
204
|
+
path: uiPath,
|
|
205
|
+
handler: 'getUI',
|
|
206
|
+
meta: { summary: 'API reference (Scalar)', tags: ['OpenAPI'], security: ['none'] },
|
|
207
|
+
responses: { 200: { description: 'Scalar API reference HTML' } },
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
name: 'openapi',
|
|
213
|
+
|
|
214
|
+
routes,
|
|
215
|
+
|
|
216
|
+
methods: (ctx: PluginContext) => {
|
|
217
|
+
async function generateSpec(): Promise<OpenAPISpec> {
|
|
218
|
+
if (cachedSpec)
|
|
219
|
+
return cachedSpec;
|
|
220
|
+
|
|
221
|
+
// Collect all endpoints from the fortress config
|
|
222
|
+
const allEndpoints: EndpointDefinition[] = [];
|
|
223
|
+
const plugins = ctx.config.plugins ?? [];
|
|
224
|
+
|
|
225
|
+
// Add core auth endpoints
|
|
226
|
+
if (config.includeCoreAuth !== false) {
|
|
227
|
+
allEndpoints.push(...Object.values(authEndpoints) as EndpointDefinition[]);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Add core IAM endpoints
|
|
231
|
+
if (config.includeCoreIam !== false) {
|
|
232
|
+
allEndpoints.push(...Object.values(iamEndpoints) as EndpointDefinition[]);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Add top-level host routes. These are synthesized into the
|
|
236
|
+
// Fortress instance at runtime, but ctx.config keeps the caller's
|
|
237
|
+
// original object; include them explicitly so the OpenAPI plugin sees
|
|
238
|
+
// `createFortress({ routes })` just like `fortress.toOpenAPI()` does.
|
|
239
|
+
if (ctx.config.routes) {
|
|
240
|
+
allEndpoints.push(...Object.values(ctx.config.routes) as EndpointDefinition[]);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Add plugin endpoints (excluding our own)
|
|
244
|
+
for (const plugin of plugins) {
|
|
245
|
+
if (plugin.name === 'openapi' || !plugin.routes)
|
|
246
|
+
continue;
|
|
247
|
+
allEndpoints.push(...Object.values(plugin.routes) as EndpointDefinition[]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Add consumer-provided endpoints
|
|
251
|
+
if (config.additionalEndpoints) {
|
|
252
|
+
allEndpoints.push(...config.additionalEndpoints);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Merge component schemas
|
|
256
|
+
const componentSchemas: ComponentSchemas = {
|
|
257
|
+
...(config.includeCoreAuth !== false ? authComponentSchemas : {}),
|
|
258
|
+
...(config.includeCoreIam !== false ? iamComponentSchemas : {}),
|
|
259
|
+
...(config.additionalSchemas ?? {}),
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// Enrich IAM schemas with dynamic resource/action enums from the DB
|
|
263
|
+
if (config.includeCoreIam !== false && ctx.iam) {
|
|
264
|
+
try {
|
|
265
|
+
const resourceFile = await ctx.iam.getResources();
|
|
266
|
+
enrichIamSchemas(componentSchemas, allEndpoints, resourceFile);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// If resource fetch fails, fall back to plain string schemas
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
cachedSpec = buildOpenAPISpec(allEndpoints, componentSchemas, {
|
|
274
|
+
title,
|
|
275
|
+
version,
|
|
276
|
+
description: config.description,
|
|
277
|
+
servers: config.servers,
|
|
278
|
+
tags: config.tags,
|
|
279
|
+
operationId: config.operationId,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return cachedSpec;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
generateSpec,
|
|
287
|
+
|
|
288
|
+
async getSpec(): Promise<Record<string, unknown>> {
|
|
289
|
+
return await generateSpec() as unknown as Record<string, unknown>;
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
getUI(): string {
|
|
293
|
+
return buildScalarHTML(computeRelativeUrl(uiPath, specPath), title);
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|