@hilbras/keystone 1.6.0 → 1.9.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/CHANGELOG.md +239 -0
- package/README.md +55 -25
- package/dist/cli.js +25 -27
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +15 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -8
- package/dist/config.js.map +1 -1
- package/dist/container.d.ts +4 -1
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js.map +1 -1
- package/dist/db/migrations/0008_flashy_firestar.sql +5 -0
- package/dist/db/migrations/0009_daffy_changeling.sql +1 -0
- package/dist/db/migrations/0010_wealthy_shadow_king.sql +37 -0
- package/dist/db/migrations/0011_overrated_vector.sql +18 -0
- package/dist/db/migrations/0012_brave_darkhawk.sql +28 -0
- package/dist/db/migrations/0013_wonderful_chimera.sql +5 -0
- package/dist/db/migrations/0014_magical_morph.sql +48 -0
- package/{src/db/migrations/meta/0007_snapshot.json → dist/db/migrations/meta/0008_snapshot.json} +136 -32
- package/{src/db/migrations/meta/0006_snapshot.json → dist/db/migrations/meta/0009_snapshot.json} +359 -30
- package/{src/db/migrations/meta/0005_snapshot.json → dist/db/migrations/meta/0010_snapshot.json} +459 -29
- package/{src/db/migrations/meta/0004_snapshot.json → dist/db/migrations/meta/0011_snapshot.json} +594 -30
- package/dist/db/migrations/meta/0012_snapshot.json +3891 -0
- package/dist/db/migrations/meta/0013_snapshot.json +3919 -0
- package/dist/db/migrations/meta/0014_snapshot.json +4311 -0
- package/dist/db/migrations/meta/_journal.json +49 -0
- package/dist/db/reencryptOidcSecrets.d.ts +2 -0
- package/dist/db/reencryptOidcSecrets.d.ts.map +1 -0
- package/dist/db/reencryptOidcSecrets.js +41 -0
- package/dist/db/reencryptOidcSecrets.js.map +1 -0
- package/dist/db/schema.d.ts +2521 -53
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +118 -3
- package/dist/db/schema.js.map +1 -1
- package/dist/db/seed.js +67 -40
- package/dist/db/seed.js.map +1 -1
- package/dist/di.d.ts.map +1 -1
- package/dist/di.js +11 -3
- package/dist/di.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/errors.d.ts +2 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +10 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/plugins/appContext.d.ts.map +1 -1
- package/dist/plugins/appContext.js +3 -12
- package/dist/plugins/appContext.js.map +1 -1
- package/dist/plugins/audit.d.ts.map +1 -1
- package/dist/plugins/audit.js +26 -6
- package/dist/plugins/audit.js.map +1 -1
- package/dist/plugins/auth.d.ts.map +1 -1
- package/dist/plugins/auth.js +32 -7
- package/dist/plugins/auth.js.map +1 -1
- package/dist/plugins/metrics.d.ts.map +1 -1
- package/dist/plugins/mtls.d.ts.map +1 -1
- package/dist/plugins/permissions.d.ts.map +1 -1
- package/dist/plugins/permissions.js +29 -9
- package/dist/plugins/permissions.js.map +1 -1
- package/dist/plugins/rateLimit.d.ts +15 -0
- package/dist/plugins/rateLimit.d.ts.map +1 -1
- package/dist/plugins/rateLimit.js +11 -1
- package/dist/plugins/rateLimit.js.map +1 -1
- package/dist/plugins/requestLogger.d.ts.map +1 -1
- package/dist/repositories/apiKey.d.ts.map +1 -1
- package/dist/repositories/application.d.ts.map +1 -1
- package/dist/repositories/application.js +1 -1
- package/dist/repositories/application.js.map +1 -1
- package/dist/repositories/audit.d.ts.map +1 -1
- package/dist/repositories/index.d.ts +3 -0
- package/dist/repositories/index.d.ts.map +1 -1
- package/dist/repositories/index.js +3 -0
- package/dist/repositories/index.js.map +1 -1
- package/dist/repositories/mfaChallenge.d.ts +23 -0
- package/dist/repositories/mfaChallenge.d.ts.map +1 -0
- package/dist/repositories/mfaChallenge.js +71 -0
- package/dist/repositories/mfaChallenge.js.map +1 -0
- package/dist/repositories/oidcConnection.d.ts +27 -43
- package/dist/repositories/oidcConnection.d.ts.map +1 -1
- package/dist/repositories/oidcConnection.js +15 -6
- package/dist/repositories/oidcConnection.js.map +1 -1
- package/dist/repositories/organization.d.ts +9 -9
- package/dist/repositories/organization.d.ts.map +1 -1
- package/dist/repositories/organization.js +91 -37
- package/dist/repositories/organization.js.map +1 -1
- package/dist/repositories/permission.d.ts.map +1 -1
- package/dist/repositories/permission.js +27 -5
- package/dist/repositories/permission.js.map +1 -1
- package/dist/repositories/samlConnection.d.ts +28 -28
- package/dist/repositories/samlConnection.d.ts.map +1 -1
- package/dist/repositories/samlConnection.js +12 -4
- package/dist/repositories/samlConnection.js.map +1 -1
- package/dist/repositories/scimConnection.d.ts +38 -0
- package/dist/repositories/scimConnection.d.ts.map +1 -0
- package/dist/repositories/scimConnection.js +123 -0
- package/dist/repositories/scimConnection.js.map +1 -0
- package/dist/repositories/scimGroup.d.ts +36 -0
- package/dist/repositories/scimGroup.d.ts.map +1 -0
- package/dist/repositories/scimGroup.js +113 -0
- package/dist/repositories/scimGroup.js.map +1 -0
- package/dist/repositories/session.d.ts +23 -13
- package/dist/repositories/session.d.ts.map +1 -1
- package/dist/repositories/session.js +13 -1
- package/dist/repositories/session.js.map +1 -1
- package/dist/repositories/types.d.ts +112 -5
- package/dist/repositories/types.d.ts.map +1 -1
- package/dist/repositories/types.js +7 -1
- package/dist/repositories/types.js.map +1 -1
- package/dist/repositories/user.d.ts +23 -1
- package/dist/repositories/user.d.ts.map +1 -1
- package/dist/repositories/user.js +180 -4
- package/dist/repositories/user.js.map +1 -1
- package/dist/routes/admin/billing.js +4 -4
- package/dist/routes/admin/billing.js.map +1 -1
- package/dist/routes/admin/helpers.d.ts +16 -20
- package/dist/routes/admin/helpers.d.ts.map +1 -1
- package/dist/routes/admin/helpers.js +53 -10
- package/dist/routes/admin/helpers.js.map +1 -1
- package/dist/routes/admin/organizations.d.ts.map +1 -1
- package/dist/routes/admin/organizations.js +76 -69
- package/dist/routes/admin/organizations.js.map +1 -1
- package/dist/routes/admin/permissions.d.ts.map +1 -1
- package/dist/routes/admin/permissions.js +48 -14
- package/dist/routes/admin/permissions.js.map +1 -1
- package/dist/routes/admin/platform.d.ts.map +1 -1
- package/dist/routes/admin/platform.js +86 -35
- package/dist/routes/admin/platform.js.map +1 -1
- package/dist/routes/admin/sso.d.ts.map +1 -1
- package/dist/routes/admin/sso.js +143 -12
- package/dist/routes/admin/sso.js.map +1 -1
- package/dist/routes/admin/webhooks.js +8 -8
- package/dist/routes/admin/webhooks.js.map +1 -1
- package/dist/routes/apiKeys.d.ts.map +1 -1
- package/dist/routes/apiKeys.js +23 -5
- package/dist/routes/apiKeys.js.map +1 -1
- package/dist/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +112 -22
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/authz.d.ts.map +1 -1
- package/dist/routes/authz.js +16 -4
- package/dist/routes/authz.js.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +16 -14
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/federation.d.ts.map +1 -1
- package/dist/routes/federation.js +17 -3
- package/dist/routes/federation.js.map +1 -1
- package/dist/routes/magicLinks.d.ts.map +1 -1
- package/dist/routes/magicLinks.js +15 -3
- package/dist/routes/magicLinks.js.map +1 -1
- package/dist/routes/oauth.d.ts.map +1 -1
- package/dist/routes/oauth.js +22 -3
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/oauth2.d.ts.map +1 -1
- package/dist/routes/oauth2.js +104 -11
- package/dist/routes/oauth2.js.map +1 -1
- package/dist/routes/oidcEnterprise.d.ts.map +1 -1
- package/dist/routes/oidcEnterprise.js +67 -21
- package/dist/routes/oidcEnterprise.js.map +1 -1
- package/dist/routes/password.d.ts.map +1 -1
- package/dist/routes/password.js.map +1 -1
- package/dist/routes/profile.js +4 -4
- package/dist/routes/profile.js.map +1 -1
- package/dist/routes/saml.d.ts +9 -0
- package/dist/routes/saml.d.ts.map +1 -1
- package/dist/routes/saml.js +187 -11
- package/dist/routes/saml.js.map +1 -1
- package/dist/routes/scim.d.ts +13 -0
- package/dist/routes/scim.d.ts.map +1 -1
- package/dist/routes/scim.js +885 -110
- package/dist/routes/scim.js.map +1 -1
- package/dist/routes/sdk.d.ts.map +1 -1
- package/dist/routes/sdk.js +24 -8
- package/dist/routes/sdk.js.map +1 -1
- package/dist/routes/serviceAccounts.d.ts.map +1 -1
- package/dist/routes/serviceAccounts.js +2 -1
- package/dist/routes/serviceAccounts.js.map +1 -1
- package/dist/routes/setup.d.ts.map +1 -1
- package/dist/routes/setup.js +15 -16
- package/dist/routes/setup.js.map +1 -1
- package/dist/routes/smsOtp.js +1 -1
- package/dist/routes/smsOtp.js.map +1 -1
- package/dist/routes/totp.d.ts.map +1 -1
- package/dist/routes/totp.js +113 -23
- package/dist/routes/totp.js.map +1 -1
- package/dist/routes/webauthn.d.ts.map +1 -1
- package/dist/routes/webauthn.js +44 -8
- package/dist/routes/webauthn.js.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/routes/workflows.js +58 -25
- package/dist/routes/workflows.js.map +1 -1
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +141 -40
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/types.d.ts +60 -29
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/services/application/authentication.d.ts +39 -1
- package/dist/services/application/authentication.d.ts.map +1 -1
- package/dist/services/application/authentication.js +43 -1
- package/dist/services/application/authentication.js.map +1 -1
- package/dist/services/application/identity.d.ts +10 -7
- package/dist/services/application/identity.d.ts.map +1 -1
- package/dist/services/application/identity.js +13 -10
- package/dist/services/application/identity.js.map +1 -1
- package/dist/services/application/organization.d.ts +11 -7
- package/dist/services/application/organization.d.ts.map +1 -1
- package/dist/services/application/organization.js +160 -12
- package/dist/services/application/organization.js.map +1 -1
- package/dist/services/applications.js +2 -2
- package/dist/services/applications.js.map +1 -1
- package/dist/services/audit.d.ts +1 -0
- package/dist/services/audit.d.ts.map +1 -1
- package/dist/services/audit.js +13 -0
- package/dist/services/audit.js.map +1 -1
- package/dist/services/cache.d.ts.map +1 -1
- package/dist/services/configuration/profiles.d.ts +4 -0
- package/dist/services/configuration/profiles.d.ts.map +1 -1
- package/dist/services/configuration/profiles.js +50 -0
- package/dist/services/configuration/profiles.js.map +1 -1
- package/dist/services/configuration.d.ts.map +1 -1
- package/dist/services/configuration.js.map +1 -1
- package/dist/services/connectors/google.d.ts.map +1 -1
- package/dist/services/connectors/google.js +3 -2
- package/dist/services/connectors/google.js.map +1 -1
- package/dist/services/connectors/oidc.d.ts.map +1 -1
- package/dist/services/connectors/oidc.js +6 -3
- package/dist/services/connectors/oidc.js.map +1 -1
- package/dist/services/connectors/zitadel.d.ts.map +1 -1
- package/dist/services/connectors/zitadel.js +4 -3
- package/dist/services/connectors/zitadel.js.map +1 -1
- package/dist/services/domain/authentication.d.ts +43 -4
- package/dist/services/domain/authentication.d.ts.map +1 -1
- package/dist/services/domain/authentication.js +82 -20
- package/dist/services/domain/authentication.js.map +1 -1
- package/dist/services/domain/authorization.d.ts +11 -0
- package/dist/services/domain/authorization.d.ts.map +1 -1
- package/dist/services/domain/authorization.js +36 -1
- package/dist/services/domain/authorization.js.map +1 -1
- package/dist/services/domain/identity.d.ts +21 -9
- package/dist/services/domain/identity.d.ts.map +1 -1
- package/dist/services/domain/identity.js +187 -10
- package/dist/services/domain/identity.js.map +1 -1
- package/dist/services/domain/organization.d.ts +6 -9
- package/dist/services/domain/organization.d.ts.map +1 -1
- package/dist/services/domain/organization.js +48 -30
- package/dist/services/domain/organization.js.map +1 -1
- package/dist/services/emailVerification.d.ts +2 -2
- package/dist/services/enterpriseSso.d.ts +13 -6
- package/dist/services/enterpriseSso.d.ts.map +1 -1
- package/dist/services/enterpriseSso.js +75 -6
- package/dist/services/enterpriseSso.js.map +1 -1
- package/dist/services/events/subscribers/auditLog.js +1 -1
- package/dist/services/events/subscribers/auditLog.js.map +1 -1
- package/dist/services/events/types.d.ts +7 -1
- package/dist/services/events/types.d.ts.map +1 -1
- package/dist/services/events/types.js.map +1 -1
- package/dist/services/events/validate.d.ts.map +1 -1
- package/dist/services/events/validate.js +27 -0
- package/dist/services/events/validate.js.map +1 -1
- package/dist/services/features.d.ts.map +1 -1
- package/dist/services/features.js.map +1 -1
- package/dist/services/federation.d.ts +6 -1
- package/dist/services/federation.d.ts.map +1 -1
- package/dist/services/federation.js +31 -4
- package/dist/services/federation.js.map +1 -1
- package/dist/services/ipControls.js +2 -2
- package/dist/services/ipControls.js.map +1 -1
- package/dist/services/magicLinks.d.ts +2 -2
- package/dist/services/mfa.d.ts +53 -0
- package/dist/services/mfa.d.ts.map +1 -0
- package/dist/services/mfa.js +157 -0
- package/dist/services/mfa.js.map +1 -0
- package/dist/services/oauth2.d.ts +16 -12
- package/dist/services/oauth2.d.ts.map +1 -1
- package/dist/services/oauth2.js +22 -13
- package/dist/services/oauth2.js.map +1 -1
- package/dist/services/oidcSecretFormat.d.ts +3 -0
- package/dist/services/oidcSecretFormat.d.ts.map +1 -0
- package/dist/services/oidcSecretFormat.js +5 -0
- package/dist/services/oidcSecretFormat.js.map +1 -0
- package/dist/services/organizations.d.ts +4 -16
- package/dist/services/organizations.d.ts.map +1 -1
- package/dist/services/organizations.js +0 -62
- package/dist/services/organizations.js.map +1 -1
- package/dist/services/permissions.d.ts.map +1 -1
- package/dist/services/permissions.js +9 -1
- package/dist/services/permissions.js.map +1 -1
- package/dist/services/plugins/registry.d.ts.map +1 -1
- package/dist/services/plugins/registry.js.map +1 -1
- package/dist/services/plugins/types.d.ts.map +1 -1
- package/dist/services/queue/bullmq.d.ts.map +1 -1
- package/dist/services/queue/inProcess.d.ts.map +1 -1
- package/dist/services/redis.d.ts +1 -1
- package/dist/services/redis.d.ts.map +1 -1
- package/dist/services/scimCredentials.d.ts +46 -0
- package/dist/services/scimCredentials.d.ts.map +1 -0
- package/dist/services/scimCredentials.js +123 -0
- package/dist/services/scimCredentials.js.map +1 -0
- package/dist/services/scimLegacyMigration.d.ts +12 -0
- package/dist/services/scimLegacyMigration.d.ts.map +1 -0
- package/dist/services/scimLegacyMigration.js +44 -0
- package/dist/services/scimLegacyMigration.js.map +1 -0
- package/dist/services/secrets/awsKms.d.ts +2 -2
- package/dist/services/secrets/awsKms.d.ts.map +1 -1
- package/dist/services/secrets/awsKms.js +3 -5
- package/dist/services/secrets/awsKms.js.map +1 -1
- package/dist/services/secrets/azureKeyVault.d.ts.map +1 -1
- package/dist/services/secrets/database.d.ts.map +1 -1
- package/dist/services/secrets/database.js.map +1 -1
- package/dist/services/secrets/environment.d.ts.map +1 -1
- package/dist/services/secrets/environment.js.map +1 -1
- package/dist/services/secrets/index.d.ts.map +1 -1
- package/dist/services/secrets/password.d.ts.map +1 -1
- package/dist/services/secrets/password.js +0 -4
- package/dist/services/secrets/password.js.map +1 -1
- package/dist/services/secrets/provider.d.ts +2 -3
- package/dist/services/secrets/provider.d.ts.map +1 -1
- package/dist/services/secrets/vault.d.ts.map +1 -1
- package/dist/services/setup/configWriter.d.ts.map +1 -1
- package/dist/services/setup/configWriter.js.map +1 -1
- package/dist/services/ssoEndpointPolicy.d.ts +8 -0
- package/dist/services/ssoEndpointPolicy.d.ts.map +1 -0
- package/dist/services/ssoEndpointPolicy.js +136 -0
- package/dist/services/ssoEndpointPolicy.js.map +1 -0
- package/dist/services/stepUp.d.ts +35 -0
- package/dist/services/stepUp.d.ts.map +1 -0
- package/dist/services/stepUp.js +65 -0
- package/dist/services/stepUp.js.map +1 -0
- package/dist/services/tokens.d.ts +37 -11
- package/dist/services/tokens.d.ts.map +1 -1
- package/dist/services/tokens.js +75 -14
- package/dist/services/tokens.js.map +1 -1
- package/dist/services/totp.d.ts +46 -0
- package/dist/services/totp.d.ts.map +1 -1
- package/dist/services/totp.js +178 -41
- package/dist/services/totp.js.map +1 -1
- package/dist/services/users.d.ts +20 -12
- package/dist/services/users.d.ts.map +1 -1
- package/dist/services/users.js +24 -51
- package/dist/services/users.js.map +1 -1
- package/dist/services/webauthn.d.ts +8 -4
- package/dist/services/webauthn.d.ts.map +1 -1
- package/dist/services/webauthn.js +4 -4
- package/dist/services/webauthn.js.map +1 -1
- package/dist/services/webhooks.d.ts +20 -20
- package/dist/services/workflows/engine.d.ts +4 -2
- package/dist/services/workflows/engine.d.ts.map +1 -1
- package/dist/services/workflows/engine.js +181 -12
- package/dist/services/workflows/engine.js.map +1 -1
- package/dist/services/workflows/steps.d.ts +2 -0
- package/dist/services/workflows/steps.d.ts.map +1 -1
- package/dist/services/workflows/steps.js +8 -75
- package/dist/services/workflows/steps.js.map +1 -1
- package/dist/setup-server.js.map +1 -1
- package/dist/types.d.ts +33 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +26 -2
- package/dist/types.js.map +1 -1
- package/package.json +26 -3
- package/dist/tests/errors.test.d.ts +0 -2
- package/dist/tests/errors.test.d.ts.map +0 -1
- package/dist/tests/errors.test.js +0 -64
- package/dist/tests/errors.test.js.map +0 -1
- package/dist/tests/events.test.d.ts +0 -2
- package/dist/tests/events.test.d.ts.map +0 -1
- package/dist/tests/events.test.js +0 -45
- package/dist/tests/events.test.js.map +0 -1
- package/dist/tests/featureFlags.test.d.ts +0 -2
- package/dist/tests/featureFlags.test.d.ts.map +0 -1
- package/dist/tests/featureFlags.test.js +0 -24
- package/dist/tests/featureFlags.test.js.map +0 -1
- package/dist/tests/integration/queue.test.d.ts +0 -2
- package/dist/tests/integration/queue.test.d.ts.map +0 -1
- package/dist/tests/integration/queue.test.js +0 -49
- package/dist/tests/integration/queue.test.js.map +0 -1
- package/dist/tests/plugins.test.d.ts +0 -2
- package/dist/tests/plugins.test.d.ts.map +0 -1
- package/dist/tests/plugins.test.js +0 -56
- package/dist/tests/plugins.test.js.map +0 -1
- package/dist/tests/result.test.d.ts +0 -2
- package/dist/tests/result.test.d.ts.map +0 -1
- package/dist/tests/result.test.js +0 -46
- package/dist/tests/result.test.js.map +0 -1
- package/dist/tests/setup/configWriter.test.d.ts +0 -2
- package/dist/tests/setup/configWriter.test.d.ts.map +0 -1
- package/dist/tests/setup/configWriter.test.js +0 -55
- package/dist/tests/setup/configWriter.test.js.map +0 -1
- package/dist/tests/setup/validation.test.d.ts +0 -2
- package/dist/tests/setup/validation.test.d.ts.map +0 -1
- package/dist/tests/setup/validation.test.js +0 -26
- package/dist/tests/setup/validation.test.js.map +0 -1
- package/dist/tests/smoke.test.d.ts +0 -2
- package/dist/tests/smoke.test.d.ts.map +0 -1
- package/dist/tests/smoke.test.js +0 -124
- package/dist/tests/smoke.test.js.map +0 -1
- package/src/cli.ts +0 -172
- package/src/config.ts +0 -143
- package/src/container.ts +0 -48
- package/src/db/index.ts +0 -53
- package/src/db/migrations/0000_skinny_ben_parker.sql +0 -553
- package/src/db/migrations/0001_brief_joseph.sql +0 -10
- package/src/db/migrations/0002_add_account_lockout.sql +0 -3
- package/src/db/migrations/0003_steep_rachel_grey.sql +0 -1
- package/src/db/migrations/0004_clever_bill_hollister.sql +0 -20
- package/src/db/migrations/0005_steep_the_call.sql +0 -2
- package/src/db/migrations/0006_ambitious_boomer.sql +0 -17
- package/src/db/migrations/0007_greedy_vindicator.sql +0 -40
- package/src/db/migrations/meta/0000_snapshot.json +0 -2964
- package/src/db/migrations/meta/0001_snapshot.json +0 -3031
- package/src/db/migrations/meta/0003_snapshot.json +0 -3051
- package/src/db/migrations/meta/_journal.json +0 -62
- package/src/db/schema.ts +0 -676
- package/src/db/seed.ts +0 -146
- package/src/di.ts +0 -81
- package/src/index.ts +0 -326
- package/src/lib/errors.ts +0 -139
- package/src/lib/result.ts +0 -44
- package/src/lib/webhookSignature.ts +0 -41
- package/src/plugins/appContext.ts +0 -76
- package/src/plugins/audit.ts +0 -42
- package/src/plugins/auth.ts +0 -230
- package/src/plugins/metrics.ts +0 -41
- package/src/plugins/mtls.ts +0 -94
- package/src/plugins/permissions.ts +0 -29
- package/src/plugins/rateLimit.ts +0 -133
- package/src/plugins/requestLogger.ts +0 -25
- package/src/plugins/tracing.ts +0 -22
- package/src/repositories/apiKey.ts +0 -158
- package/src/repositories/application.ts +0 -70
- package/src/repositories/audit.ts +0 -32
- package/src/repositories/index.ts +0 -9
- package/src/repositories/oidcConnection.ts +0 -111
- package/src/repositories/organization.ts +0 -167
- package/src/repositories/permission.ts +0 -153
- package/src/repositories/samlConnection.ts +0 -96
- package/src/repositories/session.ts +0 -86
- package/src/repositories/types.ts +0 -134
- package/src/repositories/user.ts +0 -161
- package/src/routes/admin/billing.ts +0 -48
- package/src/routes/admin/helpers.ts +0 -50
- package/src/routes/admin/index.ts +0 -16
- package/src/routes/admin/organizations.ts +0 -299
- package/src/routes/admin/permissions.ts +0 -80
- package/src/routes/admin/platform.ts +0 -335
- package/src/routes/admin/sso.ts +0 -138
- package/src/routes/admin/webhooks.ts +0 -73
- package/src/routes/admin.ts +0 -1
- package/src/routes/apiKeys.ts +0 -60
- package/src/routes/auth.ts +0 -214
- package/src/routes/authz.ts +0 -38
- package/src/routes/config.ts +0 -67
- package/src/routes/emailVerification.ts +0 -73
- package/src/routes/federation.ts +0 -156
- package/src/routes/helpers.ts +0 -17
- package/src/routes/magicLinks.ts +0 -107
- package/src/routes/oauth.ts +0 -167
- package/src/routes/oauth2.ts +0 -284
- package/src/routes/oidcEnterprise.ts +0 -166
- package/src/routes/password.ts +0 -90
- package/src/routes/profile.ts +0 -44
- package/src/routes/saml.ts +0 -209
- package/src/routes/scim.ts +0 -199
- package/src/routes/sdk.ts +0 -141
- package/src/routes/serviceAccounts.ts +0 -124
- package/src/routes/sessions.ts +0 -62
- package/src/routes/setup.ts +0 -315
- package/src/routes/smsOtp.ts +0 -67
- package/src/routes/totp.ts +0 -122
- package/src/routes/webauthn.ts +0 -147
- package/src/routes/workflows.ts +0 -157
- package/src/sdk/index.ts +0 -152
- package/src/sdk/types.ts +0 -54
- package/src/services/anomalyDetection.ts +0 -73
- package/src/services/application/authentication.ts +0 -75
- package/src/services/application/identity.ts +0 -56
- package/src/services/application/index.ts +0 -3
- package/src/services/application/organization.ts +0 -77
- package/src/services/applications.ts +0 -89
- package/src/services/audit.ts +0 -41
- package/src/services/auditExport.ts +0 -59
- package/src/services/billing.ts +0 -87
- package/src/services/cache.ts +0 -131
- package/src/services/configuration/profiles.ts +0 -115
- package/src/services/configuration.ts +0 -120
- package/src/services/connectors/google.ts +0 -92
- package/src/services/connectors/oidc.ts +0 -111
- package/src/services/connectors/registry.ts +0 -124
- package/src/services/connectors/types.ts +0 -38
- package/src/services/connectors/zitadel.ts +0 -77
- package/src/services/devices.ts +0 -76
- package/src/services/domain/authentication.ts +0 -279
- package/src/services/domain/authorization.ts +0 -49
- package/src/services/domain/identity.ts +0 -108
- package/src/services/domain/index.ts +0 -4
- package/src/services/domain/organization.ts +0 -114
- package/src/services/email.ts +0 -167
- package/src/services/emailVerification.ts +0 -75
- package/src/services/enterpriseSso.ts +0 -58
- package/src/services/events/bus.ts +0 -43
- package/src/services/events/subscribers/anomaly.ts +0 -13
- package/src/services/events/subscribers/auditLog.ts +0 -21
- package/src/services/events/subscribers/webhook.ts +0 -39
- package/src/services/events/subscribers/webhookDispatch.ts +0 -14
- package/src/services/events/types.ts +0 -106
- package/src/services/events/validate.ts +0 -118
- package/src/services/featureFlags.ts +0 -90
- package/src/services/features.ts +0 -22
- package/src/services/federation.ts +0 -30
- package/src/services/hibp.ts +0 -28
- package/src/services/ipControls.ts +0 -99
- package/src/services/magicLinks.ts +0 -51
- package/src/services/oauth2.ts +0 -216
- package/src/services/organizations.ts +0 -171
- package/src/services/permissions.ts +0 -146
- package/src/services/plugins/registry.ts +0 -242
- package/src/services/plugins/types.ts +0 -98
- package/src/services/queue/bullmq.ts +0 -104
- package/src/services/queue/inProcess.ts +0 -75
- package/src/services/queue/index.ts +0 -19
- package/src/services/queue/types.ts +0 -26
- package/src/services/redis.ts +0 -16
- package/src/services/secrets/awsKms.ts +0 -97
- package/src/services/secrets/azureKeyVault.ts +0 -171
- package/src/services/secrets/database.ts +0 -166
- package/src/services/secrets/environment.ts +0 -117
- package/src/services/secrets/index.ts +0 -50
- package/src/services/secrets/password.ts +0 -73
- package/src/services/secrets/provider.ts +0 -36
- package/src/services/secrets/vault.ts +0 -149
- package/src/services/secrets.ts +0 -2
- package/src/services/serviceAccounts.ts +0 -74
- package/src/services/setup/configWriter.ts +0 -200
- package/src/services/setup/diagnostics.ts +0 -76
- package/src/services/setup/token.ts +0 -42
- package/src/services/setup/types.ts +0 -40
- package/src/services/setup/validation.ts +0 -205
- package/src/services/sms.ts +0 -81
- package/src/services/smsOtp.ts +0 -74
- package/src/services/tokens.ts +0 -287
- package/src/services/totp.ts +0 -113
- package/src/services/users.ts +0 -239
- package/src/services/webauthn.ts +0 -193
- package/src/services/webhooks.ts +0 -190
- package/src/services/workflows/engine.ts +0 -125
- package/src/services/workflows/steps.ts +0 -129
- package/src/services/zitadel.ts +0 -277
- package/src/setup-server.ts +0 -71
- package/src/tests/errors.test.ts +0 -74
- package/src/tests/events.test.ts +0 -52
- package/src/tests/featureFlags.test.ts +0 -26
- package/src/tests/integration/queue.test.ts +0 -54
- package/src/tests/plugins.test.ts +0 -73
- package/src/tests/result.test.ts +0 -52
- package/src/tests/setup/configWriter.test.ts +0 -69
- package/src/tests/setup/validation.test.ts +0 -29
- package/src/tests/smoke.test.ts +0 -136
- package/src/types.ts +0 -70
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { Queue as BullQueue, Worker, type Job as BullJob } from "bullmq";
|
|
2
|
-
import type { Queue, Job, JobHandler, QueueStats } from "./types.js";
|
|
3
|
-
|
|
4
|
-
export class BullMQQueue implements Queue {
|
|
5
|
-
private queue: BullQueue;
|
|
6
|
-
private workers = new Map<string, Worker>();
|
|
7
|
-
private handlers = new Map<string, JobHandler>();
|
|
8
|
-
private redisUrl: string;
|
|
9
|
-
|
|
10
|
-
constructor(redisUrl: string) {
|
|
11
|
-
this.redisUrl = redisUrl;
|
|
12
|
-
this.queue = new BullQueue("keystone", {
|
|
13
|
-
connection: { url: redisUrl },
|
|
14
|
-
defaultJobOptions: {
|
|
15
|
-
removeOnComplete: 100,
|
|
16
|
-
removeOnFail: 100,
|
|
17
|
-
attempts: 3,
|
|
18
|
-
backoff: { type: "exponential", delay: 1000 },
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async enqueue<T>(job: Job<T>): Promise<void> {
|
|
24
|
-
await this.queue.add(job.type, job.payload, {
|
|
25
|
-
jobId: job.id,
|
|
26
|
-
attempts: job.attempts ?? 3,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
process(type: string, handler: JobHandler): void {
|
|
31
|
-
if (this.handlers.has(type)) {
|
|
32
|
-
console.warn(`[bullmq-queue] handler for ${type} already registered`);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
this.handlers.set(type, handler);
|
|
36
|
-
|
|
37
|
-
const worker = new Worker(
|
|
38
|
-
"keystone",
|
|
39
|
-
async (bullJob: BullJob) => {
|
|
40
|
-
const job: Job = {
|
|
41
|
-
id: bullJob.id,
|
|
42
|
-
type: bullJob.name,
|
|
43
|
-
payload: bullJob.data,
|
|
44
|
-
attempts: bullJob.attemptsMade,
|
|
45
|
-
createdAt: bullJob.timestamp ? new Date(bullJob.timestamp) : undefined,
|
|
46
|
-
};
|
|
47
|
-
await handler(job);
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
connection: { url: this.redisUrl },
|
|
51
|
-
concurrency: 5,
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
worker.on("failed", (job, err) => {
|
|
56
|
-
console.error(`[bullmq-queue] job ${job?.name} ${job?.id} failed:`, err);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
this.workers.set(type, worker);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async getStats(): Promise<QueueStats[]> {
|
|
63
|
-
const counts = await this.queue.getJobCounts("waiting", "active", "completed", "failed", "delayed");
|
|
64
|
-
return [
|
|
65
|
-
{
|
|
66
|
-
type: "all",
|
|
67
|
-
count: (counts.waiting ?? 0) + (counts.active ?? 0) + (counts.completed ?? 0),
|
|
68
|
-
failed: counts.failed ?? 0,
|
|
69
|
-
delayed: counts.delayed ?? 0,
|
|
70
|
-
},
|
|
71
|
-
];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async getFailed(limit = 50): Promise<Job[]> {
|
|
75
|
-
const jobs = await this.queue.getFailed(0, limit);
|
|
76
|
-
return jobs.map((j) => ({
|
|
77
|
-
id: String(j.id),
|
|
78
|
-
type: j.name,
|
|
79
|
-
payload: j.data,
|
|
80
|
-
attempts: j.attemptsMade,
|
|
81
|
-
createdAt: j.timestamp ? new Date(j.timestamp) : undefined,
|
|
82
|
-
}));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async retry(jobId: string): Promise<void> {
|
|
86
|
-
const job = await this.queue.getJob(jobId);
|
|
87
|
-
if (job) await job.retry();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async retryAll(): Promise<void> {
|
|
91
|
-
const jobs = await this.queue.getFailed();
|
|
92
|
-
await Promise.all(jobs.map((j) => j.retry()));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async close(): Promise<void> {
|
|
96
|
-
await Promise.all(Array.from(this.workers.values()).map((worker) => worker.close()));
|
|
97
|
-
await this.queue.close();
|
|
98
|
-
// Reset registries so a closed instance (e.g. the shared singleton after a
|
|
99
|
-
// test's app.close()) can accept process()/enqueue() again with fresh
|
|
100
|
-
// connections instead of silently reusing dead ones.
|
|
101
|
-
this.workers.clear();
|
|
102
|
-
this.handlers.clear();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { Queue, Job, JobHandler, QueueStats } from "./types.js";
|
|
2
|
-
|
|
3
|
-
const DEFAULT_ATTEMPTS = 3;
|
|
4
|
-
|
|
5
|
-
export class InProcessQueue implements Queue {
|
|
6
|
-
private handlers = new Map<string, JobHandler>();
|
|
7
|
-
private stats = new Map<string, { count: number; failed: number }>();
|
|
8
|
-
|
|
9
|
-
async enqueue<T>(job: Job<T>): Promise<void> {
|
|
10
|
-
setImmediate(() => {
|
|
11
|
-
this.run(job, 1).catch((err) => {
|
|
12
|
-
console.error(`[in-process-queue] job ${job.type} failed permanently:`, err);
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
process(type: string, handler: JobHandler): void {
|
|
18
|
-
this.handlers.set(type, handler);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async getStats(): Promise<QueueStats[]> {
|
|
22
|
-
return Array.from(this.stats.entries()).map(([type, s]) => ({
|
|
23
|
-
type,
|
|
24
|
-
count: s.count,
|
|
25
|
-
failed: s.failed,
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async getFailed(): Promise<Job[]> {
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async retry(): Promise<void> {
|
|
34
|
-
// No persisted failed jobs in the in-process queue.
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async retryAll(): Promise<void> {
|
|
38
|
-
// No persisted failed jobs in the in-process queue.
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async close(): Promise<void> {
|
|
42
|
-
this.handlers.clear();
|
|
43
|
-
this.stats.clear();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private async run(job: Job, attempt: number): Promise<void> {
|
|
47
|
-
const handler = this.handlers.get(job.type);
|
|
48
|
-
if (!handler) {
|
|
49
|
-
console.warn(`[in-process-queue] no handler registered for ${job.type}`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
this.increment(job.type, "count");
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
await handler(job);
|
|
57
|
-
} catch (err) {
|
|
58
|
-
const maxAttempts = job.attempts ?? DEFAULT_ATTEMPTS;
|
|
59
|
-
if (attempt < maxAttempts) {
|
|
60
|
-
const delay = Math.min(1000 * 2 ** (attempt - 1), 30000);
|
|
61
|
-
console.warn(`[in-process-queue] job ${job.type} failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay}ms`);
|
|
62
|
-
setTimeout(() => this.run(job, attempt + 1), delay);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
this.increment(job.type, "failed");
|
|
66
|
-
throw err;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private increment(type: string, key: "count" | "failed"): void {
|
|
71
|
-
const current = this.stats.get(type) ?? { count: 0, failed: 0 };
|
|
72
|
-
current[key]++;
|
|
73
|
-
this.stats.set(type, current);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { config } from "../../config.js";
|
|
2
|
-
import { InProcessQueue } from "./inProcess.js";
|
|
3
|
-
import { BullMQQueue } from "./bullmq.js";
|
|
4
|
-
import type { Queue } from "./types.js";
|
|
5
|
-
|
|
6
|
-
export * from "./types.js";
|
|
7
|
-
export { InProcessQueue } from "./inProcess.js";
|
|
8
|
-
export { BullMQQueue } from "./bullmq.js";
|
|
9
|
-
|
|
10
|
-
export function createQueue(): Queue {
|
|
11
|
-
const explicitProvider = config.KEYSTONE_QUEUE_PROVIDER;
|
|
12
|
-
if (explicitProvider === "in-process") return new InProcessQueue();
|
|
13
|
-
if (explicitProvider === "bullmq") return new BullMQQueue(config.REDIS_URL);
|
|
14
|
-
// Default to bullmq when Redis is available, otherwise fall back to in-process.
|
|
15
|
-
if (config.REDIS_URL) return new BullMQQueue(config.REDIS_URL);
|
|
16
|
-
return new InProcessQueue();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const queue = createQueue();
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export interface Job<T = unknown> {
|
|
2
|
-
id?: string;
|
|
3
|
-
type: string;
|
|
4
|
-
payload: T;
|
|
5
|
-
attempts?: number;
|
|
6
|
-
createdAt?: Date;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type JobHandler = (job: Job) => void | Promise<void>;
|
|
10
|
-
|
|
11
|
-
export interface QueueStats {
|
|
12
|
-
type: string;
|
|
13
|
-
count: number;
|
|
14
|
-
failed?: number;
|
|
15
|
-
delayed?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface Queue {
|
|
19
|
-
enqueue<T>(job: Job<T>): Promise<void>;
|
|
20
|
-
process(type: string, handler: JobHandler): void;
|
|
21
|
-
getStats?(): Promise<QueueStats[]>;
|
|
22
|
-
getFailed?(limit: number): Promise<Job[]>;
|
|
23
|
-
retry?(jobId: string): Promise<void>;
|
|
24
|
-
retryAll?(): Promise<void>;
|
|
25
|
-
close?(): Promise<void>;
|
|
26
|
-
}
|
package/src/services/redis.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Redis } from "ioredis";
|
|
2
|
-
import { config } from "../config.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Shared Redis connection used by rate limiting, anomaly detection, and any
|
|
6
|
-
* other distributed state in Keystone. Lazy connection means the process will
|
|
7
|
-
* not fail at import time if Redis is temporarily unavailable.
|
|
8
|
-
*/
|
|
9
|
-
export const redis = new Redis(config.REDIS_URL, {
|
|
10
|
-
maxRetriesPerRequest: 3,
|
|
11
|
-
lazyConnect: true,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export function isRedisReady(): boolean {
|
|
15
|
-
return redis.status === "ready" || redis.status === "connect";
|
|
16
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
import { importPKCS8, importSPKI, exportPKCS8, exportSPKI, generateKeyPair } from "jose";
|
|
3
|
-
import type { SecretsProvider, SigningKeyPair } from "./provider.js";
|
|
4
|
-
import { hashPassword, verifyPassword } from "./password.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* AWS KMS secrets provider reference implementation.
|
|
8
|
-
*
|
|
9
|
-
* In a real deployment this would use the AWS SDK to:
|
|
10
|
-
* - Store/retrieve JWT signing keys in AWS Secrets Manager or Parameter Store
|
|
11
|
-
* - Use KMS for envelope encryption of secrets
|
|
12
|
-
*
|
|
13
|
-
* The current implementation keeps keys in memory and encrypts the data
|
|
14
|
-
* encryption key (DEK) with a KMS key ID supplied via KMS_KEY_ID. It is
|
|
15
|
-
* intended as a starting point for a full AWS integration.
|
|
16
|
-
*/
|
|
17
|
-
export class AwsKmsSecretsProvider implements SecretsProvider {
|
|
18
|
-
readonly name = "aws-kms";
|
|
19
|
-
|
|
20
|
-
hashPassword = hashPassword;
|
|
21
|
-
verifyPassword = verifyPassword;
|
|
22
|
-
|
|
23
|
-
private kmsKeyId?: string;
|
|
24
|
-
private keyPair: SigningKeyPair | null = null;
|
|
25
|
-
|
|
26
|
-
constructor() {
|
|
27
|
-
this.kmsKeyId = process.env.KMS_KEY_ID;
|
|
28
|
-
if (!this.kmsKeyId) {
|
|
29
|
-
throw new Error("AwsKmsSecretsProvider requires KMS_KEY_ID");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
hashApiKey(key: string): string {
|
|
34
|
-
return crypto.createHash("sha256").update(key).digest("hex");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
hashClientSecret(secret: string): string {
|
|
38
|
-
return crypto.createHash("sha256").update(secret).digest("hex");
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
generateClientSecret(): string {
|
|
42
|
-
return `cs_${crypto.randomBytes(32).toString("base64url")}`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
generateApiKey(): { key: string; prefix: string } {
|
|
46
|
-
const key = `ks_${crypto.randomBytes(32).toString("base64url")}`;
|
|
47
|
-
return { key, prefix: key.slice(0, 7) };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async getActiveSigningKey(): Promise<SigningKeyPair> {
|
|
51
|
-
if (this.keyPair) return this.keyPair;
|
|
52
|
-
return this.rotateSigningKeys();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async getSigningKeyById(keyId: string): Promise<SigningKeyPair | undefined> {
|
|
56
|
-
const active = await this.getActiveSigningKey();
|
|
57
|
-
if (active.keyId === keyId) return active;
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async rotateSigningKeys(): Promise<SigningKeyPair> {
|
|
62
|
-
const pair = await generateKeyPair("RS256", { extractable: true });
|
|
63
|
-
const privatePem = await exportPKCS8(pair.privateKey);
|
|
64
|
-
const publicPem = await exportSPKI(pair.publicKey);
|
|
65
|
-
const keyId = `aws-${crypto.randomBytes(8).toString("base64url")}`;
|
|
66
|
-
|
|
67
|
-
// In production: store privatePem/publicPem in AWS Secrets Manager encrypted by KMS.
|
|
68
|
-
// eslint-disable-next-line no-console
|
|
69
|
-
console.warn(`[aws-kms] New signing key ${keyId} generated. In production, store it in AWS Secrets Manager.`);
|
|
70
|
-
|
|
71
|
-
this.keyPair = { keyId, privateKey: pair.privateKey, publicKey: pair.publicKey };
|
|
72
|
-
return this.keyPair;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async listActiveSigningKeys(): Promise<{ keyId: string; createdAt: Date; expiresAt?: Date | null }[]> {
|
|
76
|
-
const active = await this.getActiveSigningKey();
|
|
77
|
-
return [{ keyId: active.keyId, createdAt: new Date(), expiresAt: null }];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async listValidSigningKeys(): Promise<SigningKeyPair[]> {
|
|
81
|
-
const active = await this.getActiveSigningKey();
|
|
82
|
-
return [active];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async getEncryptionKey(): Promise<Buffer> {
|
|
86
|
-
// In production: decrypt a stored data key using KMS.
|
|
87
|
-
throw new Error("AwsKmsSecretsProvider.getEncryptionKey() is not yet implemented");
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async encryptSecret(plain: string): Promise<string> {
|
|
91
|
-
throw new Error("AwsKmsSecretsProvider.encryptSecret() is not yet implemented");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async decryptSecret(cipherText: string): Promise<string> {
|
|
95
|
-
throw new Error("AwsKmsSecretsProvider.decryptSecret() is not yet implemented");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
import { importPKCS8, importSPKI, exportPKCS8, exportSPKI, generateKeyPair } from "jose";
|
|
3
|
-
import type { SecretsProvider, SigningKeyPair } from "./provider.js";
|
|
4
|
-
import { hashPassword, verifyPassword } from "./password.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Azure Key Vault secrets provider.
|
|
8
|
-
*
|
|
9
|
-
* This is a reference implementation. In production it should use the Azure
|
|
10
|
-
* SDK (@azure/identity and @azure/keyvault-keys/secrets) to retrieve signing
|
|
11
|
-
* keys, encryption keys, and credentials from Azure Key Vault. Password hashing
|
|
12
|
-
* helpers are reused locally because they are compute-bound.
|
|
13
|
-
*/
|
|
14
|
-
export class AzureKeyVaultSecretsProvider implements SecretsProvider {
|
|
15
|
-
readonly name = "azure-key-vault";
|
|
16
|
-
|
|
17
|
-
hashPassword = hashPassword;
|
|
18
|
-
verifyPassword = verifyPassword;
|
|
19
|
-
|
|
20
|
-
private vaultUrl: string;
|
|
21
|
-
private tenantId: string;
|
|
22
|
-
private clientId: string;
|
|
23
|
-
private clientSecret: string;
|
|
24
|
-
|
|
25
|
-
constructor() {
|
|
26
|
-
this.vaultUrl = (process.env.AZURE_KEY_VAULT_URL || "").replace(/\/$/, "");
|
|
27
|
-
this.tenantId = process.env.AZURE_TENANT_ID || "";
|
|
28
|
-
this.clientId = process.env.AZURE_CLIENT_ID || "";
|
|
29
|
-
this.clientSecret = process.env.AZURE_CLIENT_SECRET || "";
|
|
30
|
-
|
|
31
|
-
if (!this.vaultUrl || !this.tenantId || !this.clientId || !this.clientSecret) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
"AzureKeyVaultSecretsProvider requires AZURE_KEY_VAULT_URL, AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET"
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
hashApiKey(key: string): string {
|
|
39
|
-
return crypto.createHash("sha256").update(key).digest("hex");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
hashClientSecret(secret: string): string {
|
|
43
|
-
return crypto.createHash("sha256").update(secret).digest("hex");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
generateClientSecret(): string {
|
|
47
|
-
return `cs_${crypto.randomBytes(32).toString("base64url")}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
generateApiKey(): { key: string; prefix: string } {
|
|
51
|
-
const key = `ks_${crypto.randomBytes(32).toString("base64url")}`;
|
|
52
|
-
return { key, prefix: key.slice(0, 7) };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async getActiveSigningKey(): Promise<SigningKeyPair> {
|
|
56
|
-
const stored = await this.readKey("jwt-active");
|
|
57
|
-
if (stored?.private && stored?.public) {
|
|
58
|
-
const privateKey = await importPKCS8(String(stored.private), "RS256");
|
|
59
|
-
const publicKey = await importSPKI(String(stored.public), "RS256");
|
|
60
|
-
return { keyId: String(stored.keyId ?? "azure-active"), privateKey, publicKey };
|
|
61
|
-
}
|
|
62
|
-
return this.rotateSigningKeys();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async getSigningKeyById(keyId: string): Promise<SigningKeyPair | undefined> {
|
|
66
|
-
const active = await this.getActiveSigningKey();
|
|
67
|
-
if (active.keyId === keyId) return active;
|
|
68
|
-
const stored = await this.readKey(`jwt-${keyId}`);
|
|
69
|
-
if (!stored?.private) return undefined;
|
|
70
|
-
const privateKey = await importPKCS8(String(stored.private), "RS256");
|
|
71
|
-
const publicKey = await importSPKI(String(stored.public), "RS256");
|
|
72
|
-
return { keyId, privateKey, publicKey };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async rotateSigningKeys(): Promise<SigningKeyPair> {
|
|
76
|
-
const pair = await generateKeyPair("RS256", { extractable: true });
|
|
77
|
-
const privatePem = await exportPKCS8(pair.privateKey);
|
|
78
|
-
const publicPem = await exportSPKI(pair.publicKey);
|
|
79
|
-
const keyId = `azure-${crypto.randomBytes(8).toString("base64url")}`;
|
|
80
|
-
|
|
81
|
-
await this.writeKey("jwt-active", { keyId, private: privatePem, public: publicPem, rotatedAt: new Date().toISOString() });
|
|
82
|
-
|
|
83
|
-
return { keyId, privateKey: pair.privateKey, publicKey: pair.publicKey };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async listActiveSigningKeys(): Promise<{ keyId: string; createdAt: Date; expiresAt?: Date | null }[]> {
|
|
87
|
-
const active = await this.getActiveSigningKey();
|
|
88
|
-
return [{ keyId: active.keyId, createdAt: new Date(), expiresAt: null }];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async listValidSigningKeys(): Promise<SigningKeyPair[]> {
|
|
92
|
-
return [await this.getActiveSigningKey()];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async getEncryptionKey(): Promise<Buffer> {
|
|
96
|
-
const stored = await this.readKey("encryption-key");
|
|
97
|
-
if (stored?.value) {
|
|
98
|
-
return Buffer.from(String(stored.value), "base64");
|
|
99
|
-
}
|
|
100
|
-
const key = crypto.randomBytes(32);
|
|
101
|
-
await this.writeKey("encryption-key", { value: key.toString("base64") });
|
|
102
|
-
return key;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async encryptSecret(plain: string): Promise<string> {
|
|
106
|
-
const key = await this.getEncryptionKey();
|
|
107
|
-
const iv = crypto.randomBytes(16);
|
|
108
|
-
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
|
|
109
|
-
const encrypted = Buffer.concat([cipher.update(plain, "utf-8"), cipher.final()]);
|
|
110
|
-
return `${iv.toString("base64")}:${encrypted.toString("base64")}`;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async decryptSecret(cipherText: string): Promise<string> {
|
|
114
|
-
const key = await this.getEncryptionKey();
|
|
115
|
-
const [ivBase64, encryptedBase64] = cipherText.split(":");
|
|
116
|
-
if (!ivBase64 || !encryptedBase64) throw new Error("Invalid cipher text format");
|
|
117
|
-
const iv = Buffer.from(ivBase64, "base64");
|
|
118
|
-
const encrypted = Buffer.from(encryptedBase64, "base64");
|
|
119
|
-
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
|
|
120
|
-
return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf-8");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Reference stubs for Azure Key Vault HTTP API integration.
|
|
124
|
-
private async readPath(path: string): Promise<Record<string, unknown> | undefined> {
|
|
125
|
-
const url = `${this.vaultUrl}/secrets/${path}?api-version=7.4`;
|
|
126
|
-
const token = await this.getAccessToken();
|
|
127
|
-
const response = await fetch(url, {
|
|
128
|
-
headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
|
|
129
|
-
});
|
|
130
|
-
if (response.status === 404) return undefined;
|
|
131
|
-
if (!response.ok) throw new Error(`Azure Key Vault read failed: ${response.status}`);
|
|
132
|
-
const body = await response.json();
|
|
133
|
-
return typeof body.value === "string" ? JSON.parse(body.value) : body.value;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private async readKey(name: string): Promise<Record<string, unknown> | undefined> {
|
|
137
|
-
return this.readPath(name);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private async writeKey(name: string, value: Record<string, unknown>): Promise<void> {
|
|
141
|
-
const url = `${this.vaultUrl}/secrets/${name}?api-version=7.4`;
|
|
142
|
-
const token = await this.getAccessToken();
|
|
143
|
-
const response = await fetch(url, {
|
|
144
|
-
method: "PUT",
|
|
145
|
-
headers: {
|
|
146
|
-
Authorization: `Bearer ${token}`,
|
|
147
|
-
"Content-Type": "application/json",
|
|
148
|
-
},
|
|
149
|
-
body: JSON.stringify({ value: JSON.stringify(value) }),
|
|
150
|
-
});
|
|
151
|
-
if (!response.ok) throw new Error(`Azure Key Vault write failed: ${response.status}`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
private async getAccessToken(): Promise<string> {
|
|
155
|
-
const url = `https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`;
|
|
156
|
-
const params = new URLSearchParams();
|
|
157
|
-
params.set("client_id", this.clientId);
|
|
158
|
-
params.set("client_secret", this.clientSecret);
|
|
159
|
-
params.set("scope", "https://vault.azure.net/.default");
|
|
160
|
-
params.set("grant_type", "client_credentials");
|
|
161
|
-
|
|
162
|
-
const response = await fetch(url, {
|
|
163
|
-
method: "POST",
|
|
164
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
165
|
-
body: params.toString(),
|
|
166
|
-
});
|
|
167
|
-
if (!response.ok) throw new Error(`Azure authentication failed: ${response.status}`);
|
|
168
|
-
const body = await response.json();
|
|
169
|
-
return String(body.access_token);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
import { eq, and, or, gt, isNull } from "drizzle-orm";
|
|
3
|
-
import { importPKCS8, importSPKI, exportPKCS8, exportSPKI, generateKeyPair } from "jose";
|
|
4
|
-
import { db } from "../../db/index.js";
|
|
5
|
-
import { secrets, type Secret } from "../../db/schema.js";
|
|
6
|
-
import { config } from "../../config.js";
|
|
7
|
-
import type { SecretsProvider, SigningKeyPair } from "./provider.js";
|
|
8
|
-
import { hashPassword, verifyPassword } from "./password.js";
|
|
9
|
-
|
|
10
|
-
const ENCRYPTION_ALGORITHM = "aes-256-gcm";
|
|
11
|
-
const IV_LENGTH = 16;
|
|
12
|
-
const AUTH_TAG_LENGTH = 16;
|
|
13
|
-
const KEY_ID_BYTES = 8;
|
|
14
|
-
|
|
15
|
-
export class DatabaseSecretsProvider implements SecretsProvider {
|
|
16
|
-
readonly name = "database";
|
|
17
|
-
|
|
18
|
-
hashPassword = hashPassword;
|
|
19
|
-
verifyPassword = verifyPassword;
|
|
20
|
-
|
|
21
|
-
hashApiKey(key: string): string {
|
|
22
|
-
return crypto.createHash("sha256").update(key).digest("hex");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
hashClientSecret(secret: string): string {
|
|
26
|
-
return crypto.createHash("sha256").update(secret).digest("hex");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
generateClientSecret(): string {
|
|
30
|
-
return `cs_${crypto.randomBytes(32).toString("base64url")}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
generateApiKey(): { key: string; prefix: string } {
|
|
34
|
-
const key = `ks_${crypto.randomBytes(32).toString("base64url")}`;
|
|
35
|
-
const prefix = key.slice(0, 7);
|
|
36
|
-
return { key, prefix };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async getActiveSigningKey(): Promise<SigningKeyPair> {
|
|
40
|
-
const [active] = await db
|
|
41
|
-
.select()
|
|
42
|
-
.from(secrets)
|
|
43
|
-
.where(and(eq(secrets.type, "jwt_signing"), eq(secrets.isActive, true), isNull(secrets.expiresAt)))
|
|
44
|
-
.orderBy(secrets.createdAt)
|
|
45
|
-
.limit(1);
|
|
46
|
-
|
|
47
|
-
if (active) {
|
|
48
|
-
return this.loadKeyPair(active);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return this.createSigningKey();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async getSigningKeyById(keyId: string): Promise<SigningKeyPair | undefined> {
|
|
55
|
-
const [record] = await db.select().from(secrets).where(eq(secrets.keyId, keyId)).limit(1);
|
|
56
|
-
if (!record || record.type !== "jwt_signing") return undefined;
|
|
57
|
-
return this.loadKeyPair(record);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async rotateSigningKeys(): Promise<SigningKeyPair> {
|
|
61
|
-
await db
|
|
62
|
-
.update(secrets)
|
|
63
|
-
.set({ isActive: false, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) })
|
|
64
|
-
.where(eq(secrets.type, "jwt_signing"));
|
|
65
|
-
return this.createSigningKey();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private async createSigningKey(): Promise<SigningKeyPair> {
|
|
69
|
-
const pair = await generateKeyPair("RS256", { extractable: true });
|
|
70
|
-
const privatePem = await exportPKCS8(pair.privateKey);
|
|
71
|
-
const publicPem = await exportSPKI(pair.publicKey);
|
|
72
|
-
const keyId = crypto.randomBytes(KEY_ID_BYTES).toString("base64url");
|
|
73
|
-
|
|
74
|
-
await db.insert(secrets).values({
|
|
75
|
-
keyId,
|
|
76
|
-
type: "jwt_signing",
|
|
77
|
-
value: JSON.stringify({ private: privatePem, public: publicPem }),
|
|
78
|
-
algorithm: "RS256",
|
|
79
|
-
isActive: true,
|
|
80
|
-
rotatedAt: new Date(),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return { keyId, privateKey: pair.privateKey, publicKey: pair.publicKey };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
private async loadKeyPair(record: Secret): Promise<SigningKeyPair> {
|
|
87
|
-
const parsed = JSON.parse(record.value) as { private: string; public: string };
|
|
88
|
-
const privateKey = await importPKCS8(parsed.private, "RS256");
|
|
89
|
-
const publicKey = await importSPKI(parsed.public, "RS256");
|
|
90
|
-
return { keyId: record.keyId, privateKey, publicKey };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async getEncryptionKey(): Promise<Buffer> {
|
|
94
|
-
if (config.KEYSTONE_ENCRYPTION_KEY) {
|
|
95
|
-
return crypto.createHash("sha256").update(config.KEYSTONE_ENCRYPTION_KEY).digest();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const [active] = await db
|
|
99
|
-
.select()
|
|
100
|
-
.from(secrets)
|
|
101
|
-
.where(and(eq(secrets.type, "encryption"), eq(secrets.isActive, true)))
|
|
102
|
-
.limit(1);
|
|
103
|
-
|
|
104
|
-
if (active) {
|
|
105
|
-
return Buffer.from(active.value, "base64url");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const value = crypto.randomBytes(32);
|
|
109
|
-
await db.insert(secrets).values({
|
|
110
|
-
keyId: `enc-${crypto.randomBytes(KEY_ID_BYTES).toString("base64url")}`,
|
|
111
|
-
type: "encryption",
|
|
112
|
-
value: value.toString("base64url"),
|
|
113
|
-
algorithm: "aes-256-gcm",
|
|
114
|
-
isActive: true,
|
|
115
|
-
});
|
|
116
|
-
return value;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async encryptSecret(plain: string): Promise<string> {
|
|
120
|
-
const key = await this.getEncryptionKey();
|
|
121
|
-
const iv = crypto.randomBytes(IV_LENGTH);
|
|
122
|
-
const cipher = crypto.createCipheriv(ENCRYPTION_ALGORITHM, key, iv);
|
|
123
|
-
const encrypted = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
|
|
124
|
-
const tag = cipher.getAuthTag();
|
|
125
|
-
const payload = Buffer.concat([iv, tag, encrypted]);
|
|
126
|
-
return `${ENCRYPTION_ALGORITHM}$${payload.toString("base64url")}`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async decryptSecret(cipherText: string): Promise<string> {
|
|
130
|
-
if (!cipherText.startsWith(`${ENCRYPTION_ALGORITHM}$`)) {
|
|
131
|
-
throw new Error("Unsupported cipher format");
|
|
132
|
-
}
|
|
133
|
-
const key = await this.getEncryptionKey();
|
|
134
|
-
const payload = Buffer.from(cipherText.slice(`${ENCRYPTION_ALGORITHM}$`.length), "base64url");
|
|
135
|
-
const iv = payload.subarray(0, IV_LENGTH);
|
|
136
|
-
const tag = payload.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
|
|
137
|
-
const encrypted = payload.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
|
|
138
|
-
const decipher = crypto.createDecipheriv(ENCRYPTION_ALGORITHM, key, iv);
|
|
139
|
-
decipher.setAuthTag(tag);
|
|
140
|
-
return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async listActiveSigningKeys(): Promise<{ keyId: string; createdAt: Date; expiresAt?: Date | null }[]> {
|
|
144
|
-
const rows = await db
|
|
145
|
-
.select({ keyId: secrets.keyId, createdAt: secrets.createdAt, expiresAt: secrets.expiresAt })
|
|
146
|
-
.from(secrets)
|
|
147
|
-
.where(and(eq(secrets.type, "jwt_signing"), eq(secrets.isActive, true)))
|
|
148
|
-
.orderBy(secrets.createdAt);
|
|
149
|
-
return rows;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async listValidSigningKeys(): Promise<SigningKeyPair[]> {
|
|
153
|
-
const now = new Date();
|
|
154
|
-
const rows = await db
|
|
155
|
-
.select()
|
|
156
|
-
.from(secrets)
|
|
157
|
-
.where(
|
|
158
|
-
and(
|
|
159
|
-
eq(secrets.type, "jwt_signing"),
|
|
160
|
-
or(eq(secrets.isActive, true), and(eq(secrets.isActive, false), gt(secrets.expiresAt, now)))
|
|
161
|
-
)
|
|
162
|
-
)
|
|
163
|
-
.orderBy(secrets.createdAt);
|
|
164
|
-
return Promise.all(rows.map((row) => this.loadKeyPair(row)));
|
|
165
|
-
}
|
|
166
|
-
}
|