@wildo-ai/saas-backend-lib 1.0.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/dist/esm/__tests__/setup.d.ts +7 -0
- package/dist/esm/__tests__/setup.d.ts.map +1 -0
- package/dist/esm/__tests__/setup.js +14 -0
- package/dist/esm/__tests__/setup.js.map +1 -0
- package/dist/esm/__tests__/test-container.d.ts +39 -0
- package/dist/esm/__tests__/test-container.d.ts.map +1 -0
- package/dist/esm/__tests__/test-container.js +94 -0
- package/dist/esm/__tests__/test-container.js.map +1 -0
- package/dist/esm/applications/models/applications.backend.schemas.d.ts +11 -0
- package/dist/esm/applications/models/applications.backend.schemas.d.ts.map +1 -0
- package/dist/esm/applications/models/applications.backend.schemas.js +15 -0
- package/dist/esm/applications/models/applications.backend.schemas.js.map +1 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts +12 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +30 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.d.ts +98 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.d.ts.map +1 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.js +11 -0
- package/dist/esm/base-classes/models/repositories.backend.schemas.js.map +1 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.d.ts +31 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.js +52 -0
- package/dist/esm/base-classes/services/__tests__/mock-resource-operation-helper.service.js.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.d.ts +56 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.js +52 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-custom-execution.service.js.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.d.ts +33 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.js +125 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-executor.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.d.ts +20 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.js +45 -0
- package/dist/esm/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.d.ts +133 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.js +280 -0
- package/dist/esm/base-classes/services/controllers/abstract-controller.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts +147 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js +1320 -0
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts +107 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js +369 -0
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.d.ts +194 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.js +417 -0
- package/dist/esm/base-classes/services/controllers/validate-field-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.d.ts +9 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.js +35 -0
- package/dist/esm/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +107 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js +800 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts +181 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js +529 -0
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts +245 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js +1509 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.d.ts +134 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.js +388 -0
- package/dist/esm/base-classes/services/resource-operations-helper.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.d.ts +9 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.js +26 -0
- package/dist/esm/base-classes/services/services/__tests__/mock-services-registry-handler.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts +144 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.js +49 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts +84 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js +156 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts +42 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js +94 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js.map +1 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +593 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +4015 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -0
- package/dist/esm/base-classes/utils/backend-type-utils.d.ts +43 -0
- package/dist/esm/base-classes/utils/backend-type-utils.d.ts.map +1 -0
- package/dist/esm/base-classes/utils/backend-type-utils.js +10 -0
- package/dist/esm/base-classes/utils/backend-type-utils.js.map +1 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.d.ts +44 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.js +94 -0
- package/dist/esm/billing/services/back-office/abstract-billing.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.d.ts +102 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.js +405 -0
- package/dist/esm/billing/services/back-office/billing-feature-sync.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.d.ts +55 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.js +268 -0
- package/dist/esm/billing/services/back-office/billing-state.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts +83 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js +371 -0
- package/dist/esm/billing/services/back-office/product-catalog-sync.backend.service.js.map +1 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts +80 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.js +255 -0
- package/dist/esm/billing/services/back-office/usage-metering.backend.service.js.map +1 -0
- package/dist/esm/billing/services/billing.utils.d.ts +17 -0
- package/dist/esm/billing/services/billing.utils.d.ts.map +1 -0
- package/dist/esm/billing/services/billing.utils.js +25 -0
- package/dist/esm/billing/services/billing.utils.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.d.ts +50 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js +290 -0
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts +92 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js +193 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-impl-utils.backend.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts +66 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js +180 -0
- package/dist/esm/billing/services/custom-impl/billing-custom-implementations.backend.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.d.ts +31 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.js +100 -0
- package/dist/esm/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts +33 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js +200 -0
- package/dist/esm/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.d.ts +58 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js +362 -0
- package/dist/esm/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.d.ts +19 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.js +50 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-adapter.backend.service.js.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.d.ts +21 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.js +32 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-capability-handler.backend.service.js.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts +114 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.d.ts.map +1 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js +569 -0
- package/dist/esm/billing/services/webhooks/billing-webhook-event-router.backend.service.js.map +1 -0
- package/dist/esm/billing/testing/billing-test-fixtures.d.ts +109 -0
- package/dist/esm/billing/testing/billing-test-fixtures.d.ts.map +1 -0
- package/dist/esm/billing/testing/billing-test-fixtures.js +200 -0
- package/dist/esm/billing/testing/billing-test-fixtures.js.map +1 -0
- package/dist/esm/billing/testing/mock-billing-provider.d.ts +152 -0
- package/dist/esm/billing/testing/mock-billing-provider.d.ts.map +1 -0
- package/dist/esm/billing/testing/mock-billing-provider.js +394 -0
- package/dist/esm/billing/testing/mock-billing-provider.js.map +1 -0
- package/dist/esm/charts/controllers/chart.backend.controller.d.ts +46 -0
- package/dist/esm/charts/controllers/chart.backend.controller.d.ts.map +1 -0
- package/dist/esm/charts/controllers/chart.backend.controller.js +214 -0
- package/dist/esm/charts/controllers/chart.backend.controller.js.map +1 -0
- package/dist/esm/charts/services/chart-registry.backend.service.d.ts +55 -0
- package/dist/esm/charts/services/chart-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/charts/services/chart-registry.backend.service.js +102 -0
- package/dist/esm/charts/services/chart-registry.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.d.ts +9 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.js +80 -0
- package/dist/esm/compliance/audit-trails/audit-logs.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.d.ts +23 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.js +46 -0
- package/dist/esm/compliance/audit-trails/services/__tests__/mock-audit-logs.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts +73 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js +291 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts +447 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js +898 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts +127 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js +462 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js.map +1 -0
- package/dist/esm/compliance/index.d.ts +2 -0
- package/dist/esm/compliance/index.d.ts.map +1 -0
- package/dist/esm/compliance/index.js +1 -0
- package/dist/esm/compliance/index.js.map +1 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts +31 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.js +112 -0
- package/dist/esm/config/custom/application-config-controller.backend.service.js.map +1 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.d.ts +29 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.d.ts.map +1 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.js +143 -0
- package/dist/esm/config/models/app-config-overrides.backend.definitions.js.map +1 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.d.ts +56 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.js +121 -0
- package/dist/esm/config/models/app-config-secrets.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.d.ts +35 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.d.ts.map +1 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.js +89 -0
- package/dist/esm/config/models/app-config.backend-authored.definitions.js.map +1 -0
- package/dist/esm/config/models/app-config.backend.schemas.d.ts +1651 -0
- package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/app-config.backend.schemas.js +478 -0
- package/dist/esm/config/models/app-config.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.d.ts +74 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.js +115 -0
- package/dist/esm/config/models/app-env-config.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.d.ts +11 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.d.ts.map +1 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.js +50 -0
- package/dist/esm/config/models/config-mutation-boundary.utils.js.map +1 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.d.ts +48 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.d.ts.map +1 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.js +106 -0
- package/dist/esm/config/models/postgresql-env-config.backend.schemas.js.map +1 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.d.ts +12 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.d.ts.map +1 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.js +23 -0
- package/dist/esm/config/models/runtime-topology.backend.contracts.js.map +1 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.d.ts +39 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.d.ts.map +1 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.js +124 -0
- package/dist/esm/config/services/__tests__/mock-app-configuration.service.js.map +1 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts +76 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.d.ts.map +1 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.js +375 -0
- package/dist/esm/config/services/app-configuration-loader.backend.service.js.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.service.d.ts +148 -0
- package/dist/esm/config/services/app-configuration.backend.service.d.ts.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.service.js +494 -0
- package/dist/esm/config/services/app-configuration.backend.service.js.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts +17 -0
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts.map +1 -0
- package/dist/esm/config/services/app-configuration.backend.utils.js +61 -0
- package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts +70 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.js +470 -0
- package/dist/esm/config/services/application-startup-config-validator.backend.service.js.map +1 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.d.ts +136 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.js +9 -0
- package/dist/esm/databases/models/aggregation.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/databases.backend.schemas.d.ts +32 -0
- package/dist/esm/databases/models/databases.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/databases.backend.schemas.js +60 -0
- package/dist/esm/databases/models/databases.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/filter.backend.schemas.d.ts +83 -0
- package/dist/esm/databases/models/filter.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/filter.backend.schemas.js +27 -0
- package/dist/esm/databases/models/filter.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/sql.backend.schemas.d.ts +75 -0
- package/dist/esm/databases/models/sql.backend.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/sql.backend.schemas.js +31 -0
- package/dist/esm/databases/models/sql.backend.schemas.js.map +1 -0
- package/dist/esm/databases/models/transaction.shared.schemas.d.ts +120 -0
- package/dist/esm/databases/models/transaction.shared.schemas.d.ts.map +1 -0
- package/dist/esm/databases/models/transaction.shared.schemas.js +30 -0
- package/dist/esm/databases/models/transaction.shared.schemas.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.d.ts +15 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.js +60 -0
- package/dist/esm/databases/services/__tests__/mock-mongo-transaction-registry.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.d.ts +19 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.js +69 -0
- package/dist/esm/databases/services/__tests__/mock-mongodb.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.d.ts +11 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.js +315 -0
- package/dist/esm/databases/services/__tests__/mock-mongoose-model.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.d.ts +29 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.js +65 -0
- package/dist/esm/databases/services/__tests__/mock-redis.service.js.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.d.ts +19 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.d.ts.map +1 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.js +44 -0
- package/dist/esm/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts +74 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js +369 -0
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.d.ts +110 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.js +444 -0
- package/dist/esm/databases/services/aggregation/aggregation-query.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.d.ts +38 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.js +180 -0
- package/dist/esm/databases/services/aggregation/computed-measure-evaluator.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.d.ts +42 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.js +183 -0
- package/dist/esm/databases/services/aggregation/field-access-validator.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.d.ts +48 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.js +320 -0
- package/dist/esm/databases/services/aggregation/time-series-densifier.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.d.ts +47 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.js +187 -0
- package/dist/esm/databases/services/aggregation/topn-processor.backend.service.js.map +1 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.d.ts +47 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.js +250 -0
- package/dist/esm/databases/services/aggregation/window-function-processor.backend.service.js.map +1 -0
- package/dist/esm/databases/services/db-utils.d.ts +56 -0
- package/dist/esm/databases/services/db-utils.d.ts.map +1 -0
- package/dist/esm/databases/services/db-utils.js +66 -0
- package/dist/esm/databases/services/db-utils.js.map +1 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.d.ts +91 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.js +652 -0
- package/dist/esm/databases/services/mongo-aggregation.backend.service.js.map +1 -0
- package/dist/esm/databases/services/mongodb.service.d.ts +132 -0
- package/dist/esm/databases/services/mongodb.service.d.ts.map +1 -0
- package/dist/esm/databases/services/mongodb.service.js +630 -0
- package/dist/esm/databases/services/mongodb.service.js.map +1 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.d.ts +113 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.js +635 -0
- package/dist/esm/databases/services/postgresql-aggregation.backend.service.js.map +1 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.d.ts +75 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.js +255 -0
- package/dist/esm/databases/services/postgresql-database.backend.service.js.map +1 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.d.ts +116 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.js +624 -0
- package/dist/esm/databases/services/postgresql-filter.backend.service.js.map +1 -0
- package/dist/esm/databases/services/redis.service.d.ts +143 -0
- package/dist/esm/databases/services/redis.service.d.ts.map +1 -0
- package/dist/esm/databases/services/redis.service.js +429 -0
- package/dist/esm/databases/services/redis.service.js.map +1 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.d.ts +302 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.d.ts.map +1 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.js +1787 -0
- package/dist/esm/databases/services/zod-to-mongoose-schema-convertor.backend.service.js.map +1 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.d.ts +65 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.d.ts.map +1 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.js +237 -0
- package/dist/esm/databases/services/zod-to-sql-hybrid-schema.planner.js.map +1 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.d.ts +339 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.d.ts.map +1 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.js +209 -0
- package/dist/esm/errors/services/__tests__/mock-error-builder.service.js.map +1 -0
- package/dist/esm/errors/services/error-builder.backend.service.d.ts +95 -0
- package/dist/esm/errors/services/error-builder.backend.service.d.ts.map +1 -0
- package/dist/esm/errors/services/error-builder.backend.service.js +334 -0
- package/dist/esm/errors/services/error-builder.backend.service.js.map +1 -0
- package/dist/esm/errors/services/error-handler.backend.service.d.ts +43 -0
- package/dist/esm/errors/services/error-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/errors/services/error-handler.backend.service.js +219 -0
- package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -0
- package/dist/esm/errors/services/rate-limit.backend.service.d.ts +23 -0
- package/dist/esm/errors/services/rate-limit.backend.service.d.ts.map +1 -0
- package/dist/esm/errors/services/rate-limit.backend.service.js +59 -0
- package/dist/esm/errors/services/rate-limit.backend.service.js.map +1 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.d.ts +135 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.d.ts.map +1 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.js +129 -0
- package/dist/esm/external-providers/models/external-providers.backend.schemas.js.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts +18 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js +38 -0
- package/dist/esm/external-providers/services/__tests__/mock-external-providers-registry.service.js.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.d.ts +20 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.js +44 -0
- package/dist/esm/external-providers/services/__tests__/mock-lazy-provider-registry.service.js.map +1 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.d.ts +9 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.js +36 -0
- package/dist/esm/external-providers/services/external-api-handler.backend.service.js.map +1 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +83 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +422 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.d.ts +102 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.js +352 -0
- package/dist/esm/external-providers/services/feature-bindings.backend.service.js.map +1 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.d.ts +141 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.js +391 -0
- package/dist/esm/external-providers/services/lazy-provider-registry.backend.service.js.map +1 -0
- package/dist/esm/features/controllers/features.backend.controller.d.ts +35 -0
- package/dist/esm/features/controllers/features.backend.controller.d.ts.map +1 -0
- package/dist/esm/features/controllers/features.backend.controller.js +179 -0
- package/dist/esm/features/controllers/features.backend.controller.js.map +1 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.d.ts +8 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.d.ts.map +1 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.js +31 -0
- package/dist/esm/features/services/__tests__/mock-capability-bindings.service.js.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.d.ts +22 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.d.ts.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.js +52 -0
- package/dist/esm/features/services/__tests__/mock-feature-definition-registry.service.js.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.d.ts +13 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.d.ts.map +1 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.js +36 -0
- package/dist/esm/features/services/__tests__/mock-feature-resolution.service.js.map +1 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.d.ts +111 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.js +437 -0
- package/dist/esm/features/services/feature-definition-registry.backend.service.js.map +1 -0
- package/dist/esm/features/services/feature-gate.backend.service.d.ts +110 -0
- package/dist/esm/features/services/feature-gate.backend.service.d.ts.map +1 -0
- package/dist/esm/features/services/feature-gate.backend.service.js +414 -0
- package/dist/esm/features/services/feature-gate.backend.service.js.map +1 -0
- package/dist/esm/features/services/feature-resolution.backend.service.d.ts +163 -0
- package/dist/esm/features/services/feature-resolution.backend.service.d.ts.map +1 -0
- package/dist/esm/features/services/feature-resolution.backend.service.js +550 -0
- package/dist/esm/features/services/feature-resolution.backend.service.js.map +1 -0
- package/dist/esm/features/testing/feature-test-utils.d.ts +85 -0
- package/dist/esm/features/testing/feature-test-utils.d.ts.map +1 -0
- package/dist/esm/features/testing/feature-test-utils.js +127 -0
- package/dist/esm/features/testing/feature-test-utils.js.map +1 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.d.ts +34 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.js +226 -0
- package/dist/esm/files/batches/files-cleanup.batch.backend.service.js.map +1 -0
- package/dist/esm/files/constraints/file-analyzers.types.d.ts +76 -0
- package/dist/esm/files/constraints/file-analyzers.types.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-analyzers.types.js +16 -0
- package/dist/esm/files/constraints/file-analyzers.types.js.map +1 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.d.ts +38 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.js +99 -0
- package/dist/esm/files/constraints/file-constraint-resolver-chain.backend.service.js.map +1 -0
- package/dist/esm/files/constraints/file-constraint.types.d.ts +77 -0
- package/dist/esm/files/constraints/file-constraint.types.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-constraint.types.js +16 -0
- package/dist/esm/files/constraints/file-constraint.types.js.map +1 -0
- package/dist/esm/files/constraints/file-validation.backend.service.d.ts +63 -0
- package/dist/esm/files/constraints/file-validation.backend.service.d.ts.map +1 -0
- package/dist/esm/files/constraints/file-validation.backend.service.js +317 -0
- package/dist/esm/files/constraints/file-validation.backend.service.js.map +1 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.d.ts +33 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.js +126 -0
- package/dist/esm/files/constraints/resource-field-constraint-resolver.backend.service.js.map +1 -0
- package/dist/esm/files/controllers/file.controller.d.ts +145 -0
- package/dist/esm/files/controllers/file.controller.d.ts.map +1 -0
- package/dist/esm/files/controllers/file.controller.js +806 -0
- package/dist/esm/files/controllers/file.controller.js.map +1 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts +85 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js +512 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.d.ts +84 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.d.ts.map +1 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.js +224 -0
- package/dist/esm/files/rag/weaviate-vector-store.backend.service.js.map +1 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.d.ts +55 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.d.ts.map +1 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.js +202 -0
- package/dist/esm/files/scanning/clamav-scanner.backend.service.js.map +1 -0
- package/dist/esm/files/scanning/file-scan.types.d.ts +17 -0
- package/dist/esm/files/scanning/file-scan.types.d.ts.map +1 -0
- package/dist/esm/files/scanning/file-scan.types.js +7 -0
- package/dist/esm/files/scanning/file-scan.types.js.map +1 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.d.ts +73 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.d.ts.map +1 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.js +184 -0
- package/dist/esm/files/scanning/yara-scanner.backend.service.js.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.d.ts +12 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.d.ts.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.js +41 -0
- package/dist/esm/files/services/__tests__/mock-file-field-detection.service.js.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.d.ts +33 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.d.ts.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.js +71 -0
- package/dist/esm/files/services/__tests__/mock-file-operation-handler.service.js.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.d.ts +16 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.d.ts.map +1 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.js +95 -0
- package/dist/esm/files/services/__tests__/mock-file-repository.service.js.map +1 -0
- package/dist/esm/files/services/file-field-detection.backend.service.d.ts +57 -0
- package/dist/esm/files/services/file-field-detection.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-field-detection.backend.service.js +145 -0
- package/dist/esm/files/services/file-field-detection.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts +103 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.js +604 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-population.backend.service.d.ts +73 -0
- package/dist/esm/files/services/file-population.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-population.backend.service.js +367 -0
- package/dist/esm/files/services/file-population.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.d.ts +64 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.js +188 -0
- package/dist/esm/files/services/file-rag-indexing.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-scanning.backend.service.d.ts +97 -0
- package/dist/esm/files/services/file-scanning.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-scanning.backend.service.js +323 -0
- package/dist/esm/files/services/file-scanning.backend.service.js.map +1 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.d.ts +52 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.js +168 -0
- package/dist/esm/files/services/file-text-extraction.backend.service.js.map +1 -0
- package/dist/esm/files/services/files.backend.service.d.ts +235 -0
- package/dist/esm/files/services/files.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/files.backend.service.js +987 -0
- package/dist/esm/files/services/files.backend.service.js.map +1 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.d.ts +50 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.js +253 -0
- package/dist/esm/files/storage/file-storage-path-resolver.backend.service.js.map +1 -0
- package/dist/esm/files/storage/file-storage-provider.types.d.ts +156 -0
- package/dist/esm/files/storage/file-storage-provider.types.d.ts.map +1 -0
- package/dist/esm/files/storage/file-storage-provider.types.js +10 -0
- package/dist/esm/files/storage/file-storage-provider.types.js.map +1 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.d.ts +68 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.js +168 -0
- package/dist/esm/files/storage/file-storage-router.backend.service.js.map +1 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts +57 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js +307 -0
- package/dist/esm/files/storage/local-directory-storage-provider.backend.service.js.map +1 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.d.ts +41 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.d.ts.map +1 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js +397 -0
- package/dist/esm/files/storage/wildo-managed-storage-provider.backend.service.js.map +1 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.d.ts +30 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.js +251 -0
- package/dist/esm/files/utils/file-field-schema-path.backend.utils.js.map +1 -0
- package/dist/esm/files/utils/file-upload.utils.d.ts +74 -0
- package/dist/esm/files/utils/file-upload.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-upload.utils.js +116 -0
- package/dist/esm/files/utils/file-upload.utils.js.map +1 -0
- package/dist/esm/files/utils/file-uploader.utils.d.ts +15 -0
- package/dist/esm/files/utils/file-uploader.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-uploader.utils.js +47 -0
- package/dist/esm/files/utils/file-uploader.utils.js.map +1 -0
- package/dist/esm/files/utils/file-validation.utils.d.ts +111 -0
- package/dist/esm/files/utils/file-validation.utils.d.ts.map +1 -0
- package/dist/esm/files/utils/file-validation.utils.js +516 -0
- package/dist/esm/files/utils/file-validation.utils.js.map +1 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.d.ts +222 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.d.ts.map +1 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.js +320 -0
- package/dist/esm/flows-actors/agent-catalogs.backend.js.map +1 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.d.ts +33 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.d.ts.map +1 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.js +96 -0
- package/dist/esm/flows-actors/controllers/flows-actors.controller.js.map +1 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts +225 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js +323 -0
- package/dist/esm/flows-actors/models/agent-catalogs.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.d.ts +77 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.js +28 -0
- package/dist/esm/flows-actors/models/agent-facets.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.d.ts +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.js +1 -0
- package/dist/esm/flows-actors/models/agents.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts +52 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.js +307 -0
- package/dist/esm/flows-actors/models/core-facets.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.d.ts +7 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.js +8 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.definitions.js.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts +30 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.d.ts.map +1 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.js +7 -0
- package/dist/esm/flows-actors/models/flows-actors.backend.schemas.js.map +1 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.d.ts +72 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.js +229 -0
- package/dist/esm/flows-actors/services/actors-system.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.d.ts +95 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.js +276 -0
- package/dist/esm/flows-actors/services/agent-facets.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +183 -0
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/agents.backend.service.js +2095 -0
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.d.ts +64 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.js +180 -0
- package/dist/esm/flows-actors/services/context-curation.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +101 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js +313 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -0
- package/dist/esm/flows-actors/services/flows.backend.services.d.ts +64 -0
- package/dist/esm/flows-actors/services/flows.backend.services.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/flows.backend.services.js +203 -0
- package/dist/esm/flows-actors/services/flows.backend.services.js.map +1 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts +91 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.d.ts.map +1 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js +629 -0
- package/dist/esm/flows-actors/services/prompt-compiler.backend.service.js.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.d.ts +15 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.js +55 -0
- package/dist/esm/flows-actors/utils/cli-runtime-operation-support.backend.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.d.ts +22 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.js +131 -0
- package/dist/esm/flows-actors/utils/cli-runtime-runner.backend.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.d.ts +15 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.js +43 -0
- package/dist/esm/flows-actors/utils/flows-actors-frontend-extractor.utils.js.map +1 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.d.ts +66 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.d.ts.map +1 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.js +219 -0
- package/dist/esm/flows-actors/utils/prompt-ir-adapters.backend.utils.js.map +1 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.d.ts +17 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.js +110 -0
- package/dist/esm/guidance/batches/dormancy-detection.batch.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.d.ts +41 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.js +135 -0
- package/dist/esm/guidance/services/guidance-trigger-evaluator.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.d.ts +33 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.js +105 -0
- package/dist/esm/guidance/services/lifecycle-custom-implementations.backend.js.map +1 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.d.ts +103 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.js +685 -0
- package/dist/esm/guidance/services/lifecycle-evaluator.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.d.ts +23 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.js +57 -0
- package/dist/esm/guidance/services/milestone-condition-registry.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.d.ts +49 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.js +248 -0
- package/dist/esm/guidance/services/milestone-definition-registry.backend.service.js.map +1 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts +64 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.d.ts.map +1 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.js +487 -0
- package/dist/esm/guidance/services/milestone-evaluator.backend.service.js.map +1 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts +55 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.js +208 -0
- package/dist/esm/i18n/controllers/i18n-controller.backend.service.js.map +1 -0
- package/dist/esm/i18n/services/i18n.backend.service.d.ts +43 -0
- package/dist/esm/i18n/services/i18n.backend.service.d.ts.map +1 -0
- package/dist/esm/i18n/services/i18n.backend.service.js +83 -0
- package/dist/esm/i18n/services/i18n.backend.service.js.map +1 -0
- package/dist/esm/index.d.ts +203 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +239 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/inject/models/container.d.ts +44 -0
- package/dist/esm/inject/models/container.d.ts.map +1 -0
- package/dist/esm/inject/models/container.js +489 -0
- package/dist/esm/inject/models/container.js.map +1 -0
- package/dist/esm/inject/models/service-types.d.ts +198 -0
- package/dist/esm/inject/models/service-types.d.ts.map +1 -0
- package/dist/esm/inject/models/service-types.js +226 -0
- package/dist/esm/inject/models/service-types.js.map +1 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.d.ts +34 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.d.ts.map +1 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js +122 -0
- package/dist/esm/monitoring/analytics/controllers/analytics.backend.controller.js.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts +41 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.d.ts.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js +62 -0
- package/dist/esm/monitoring/analytics/services/value-moment-engine.backend.service.js.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts +18 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.js +43 -0
- package/dist/esm/monitoring/analytics/services/value-moment-handler-registry.backend.service.js.map +1 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.d.ts +12 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.js +25 -0
- package/dist/esm/monitoring/logger/middleware/logging.middleware.js.map +1 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts +41 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.js +29 -0
- package/dist/esm/monitoring/logger/models/logger.backend.schemas.js.map +1 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.d.ts +22 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.js +53 -0
- package/dist/esm/monitoring/logger/services/__tests__/mock-logger.service.js.map +1 -0
- package/dist/esm/monitoring/logger/services/logger.service.d.ts +37 -0
- package/dist/esm/monitoring/logger/services/logger.service.d.ts.map +1 -0
- package/dist/esm/monitoring/logger/services/logger.service.js +189 -0
- package/dist/esm/monitoring/logger/services/logger.service.js.map +1 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.d.ts +38 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.js +147 -0
- package/dist/esm/monitoring/observability/middleware/metrics.middleware.js.map +1 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.d.ts +26 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.js +117 -0
- package/dist/esm/monitoring/observability/middleware/telemetry.middleware.js.map +1 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.d.ts +28 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.js +182 -0
- package/dist/esm/monitoring/observability/middleware/tracing.middleware.js.map +1 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +86 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js +1 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.d.ts +57 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.js +77 -0
- package/dist/esm/monitoring/observability/services/instrumentations/custom.instrumentations.js.map +1 -0
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts +27 -0
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/metrics.service.js +236 -0
- package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.d.ts +28 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.js +144 -0
- package/dist/esm/monitoring/observability/services/telemetry.service.js.map +1 -0
- package/dist/esm/monitoring/observability/services/tracer.service.d.ts +24 -0
- package/dist/esm/monitoring/observability/services/tracer.service.d.ts.map +1 -0
- package/dist/esm/monitoring/observability/services/tracer.service.js +287 -0
- package/dist/esm/monitoring/observability/services/tracer.service.js.map +1 -0
- package/dist/esm/notifications/email/components/email-components.d.ts +90 -0
- package/dist/esm/notifications/email/components/email-components.d.ts.map +1 -0
- package/dist/esm/notifications/email/components/email-components.js +171 -0
- package/dist/esm/notifications/email/components/email-components.js.map +1 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts +80 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.js +25 -0
- package/dist/esm/notifications/email/models/email-context-provider.interface.js.map +1 -0
- package/dist/esm/notifications/email/models/email-template-definition.d.ts +68 -0
- package/dist/esm/notifications/email/models/email-template-definition.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email-template-definition.js +12 -0
- package/dist/esm/notifications/email/models/email-template-definition.js.map +1 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.d.ts +19 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.js +66 -0
- package/dist/esm/notifications/email/models/email-template.actors-system.backend.definitions.js.map +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.d.ts +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.d.ts.map +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.js +1 -0
- package/dist/esm/notifications/email/models/email.backend.scheamas.js.map +1 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.d.ts +74 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.js +196 -0
- package/dist/esm/notifications/email/services/email-batch-send.batch.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts +49 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js +141 -0
- package/dist/esm/notifications/email/services/email-context-provider-registry.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.d.ts +74 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.js +215 -0
- package/dist/esm/notifications/email/services/email-renderer.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts +37 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js +121 -0
- package/dist/esm/notifications/email/services/email-template-compiler.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.d.ts +115 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.js +634 -0
- package/dist/esm/notifications/email/services/email-template-generation.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts +48 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.js +146 -0
- package/dist/esm/notifications/email/services/email-template-registry.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts +58 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js +223 -0
- package/dist/esm/notifications/email/services/email-template-sandbox.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.d.ts +49 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.js +204 -0
- package/dist/esm/notifications/email/services/email-template-validator.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/services/email.backend.service.d.ts +76 -0
- package/dist/esm/notifications/email/services/email.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/email/services/email.backend.service.js +294 -0
- package/dist/esm/notifications/email/services/email.backend.service.js.map +1 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts +56 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.d.ts.map +1 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.js +108 -0
- package/dist/esm/notifications/email/utils/color-conversion.utils.js.map +1 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.d.ts +8 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.d.ts.map +1 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.js +15 -0
- package/dist/esm/notifications/email/utils/interpolate-email-label.utils.js.map +1 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.d.ts +50 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.d.ts.map +1 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.js +281 -0
- package/dist/esm/notifications/email/utils/zod-to-typescript.utils.js.map +1 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.d.ts +94 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.js +292 -0
- package/dist/esm/notifications/services/notification-badge.backend.service.js.map +1 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts +202 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js +1290 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js.map +1 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.d.ts +50 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.js +209 -0
- package/dist/esm/notifications/sms/services/sms.backend.service.js.map +1 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +58 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +184 -0
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.d.ts +56 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.js +109 -0
- package/dist/esm/notifications/webhooks/services/polymorphic-lookup.backend.service.js.map +1 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts +96 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js +396 -0
- package/dist/esm/notifications/webhooks/services/webhook-handler.backend.service.js.map +1 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.d.ts +39 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.js +73 -0
- package/dist/esm/organizations/services/org-creation-on-registration.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.d.ts +22 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.js +35 -0
- package/dist/esm/organizations/services/org-member-roles-validation.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.d.ts +10 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.d.ts.map +1 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js +77 -0
- package/dist/esm/organizations/services/organization-custom-implementation.backend.service.js.map +1 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.d.ts +10 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.d.ts.map +1 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.js +131 -0
- package/dist/esm/organizations/services/organization-member-custom-implementation.backend.service.js.map +1 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.d.ts +22 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.js +21 -0
- package/dist/esm/organizations/services/scim-provisioning-gate.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.d.ts +25 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.js +34 -0
- package/dist/esm/organizations/services/user-org-type-grant.backend.utils.js.map +1 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.d.ts +32 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.d.ts.map +1 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.js +66 -0
- package/dist/esm/organizations/services/user-type-revocation-on-org-leave.backend.utils.js.map +1 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts +126 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js +370 -0
- package/dist/esm/queue/adapters/rabbitmq-adapter.backend.service.js.map +1 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.d.ts +86 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.js +176 -0
- package/dist/esm/queue/apps-crontabs-manager.backend.service.js.map +1 -0
- package/dist/esm/queue/cron-job-sync.backend.service.d.ts +42 -0
- package/dist/esm/queue/cron-job-sync.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/cron-job-sync.backend.service.js +181 -0
- package/dist/esm/queue/cron-job-sync.backend.service.js.map +1 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts +84 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.js +275 -0
- package/dist/esm/queue/domain-queue-consumer.backend.service.js.map +1 -0
- package/dist/esm/queue/job-completion-registry.backend.service.d.ts +111 -0
- package/dist/esm/queue/job-completion-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-completion-registry.backend.service.js +237 -0
- package/dist/esm/queue/job-completion-registry.backend.service.js.map +1 -0
- package/dist/esm/queue/job-consumer.backend.service.d.ts +109 -0
- package/dist/esm/queue/job-consumer.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-consumer.backend.service.js +515 -0
- package/dist/esm/queue/job-consumer.backend.service.js.map +1 -0
- package/dist/esm/queue/job-executor.backend.service.d.ts +53 -0
- package/dist/esm/queue/job-executor.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-executor.backend.service.js +278 -0
- package/dist/esm/queue/job-executor.backend.service.js.map +1 -0
- package/dist/esm/queue/job-payload-storage.backend.service.d.ts +86 -0
- package/dist/esm/queue/job-payload-storage.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-payload-storage.backend.service.js +250 -0
- package/dist/esm/queue/job-payload-storage.backend.service.js.map +1 -0
- package/dist/esm/queue/job-status-tracking.backend.service.d.ts +97 -0
- package/dist/esm/queue/job-status-tracking.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/job-status-tracking.backend.service.js +281 -0
- package/dist/esm/queue/job-status-tracking.backend.service.js.map +1 -0
- package/dist/esm/queue/queue-monitoring.backend.service.d.ts +71 -0
- package/dist/esm/queue/queue-monitoring.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/queue-monitoring.backend.service.js +297 -0
- package/dist/esm/queue/queue-monitoring.backend.service.js.map +1 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts +63 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.js +171 -0
- package/dist/esm/queue/queue-worker-initializer.backend.service.js.map +1 -0
- package/dist/esm/queue/queue.backend.service.d.ts +108 -0
- package/dist/esm/queue/queue.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/queue.backend.service.js +419 -0
- package/dist/esm/queue/queue.backend.service.js.map +1 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.d.ts +74 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.js +189 -0
- package/dist/esm/queue/scheduled-message-verifier.backend.service.js.map +1 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts +124 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.d.ts.map +1 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.js +250 -0
- package/dist/esm/queue/worker-shutdown-manager.backend.service.js.map +1 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.d.ts +34 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.d.ts.map +1 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.js +42 -0
- package/dist/esm/requests/models/api-routes.backend.defintions.js.map +1 -0
- package/dist/esm/requests/models/requests.backend.schemas.d.ts +48 -0
- package/dist/esm/requests/models/requests.backend.schemas.d.ts.map +1 -0
- package/dist/esm/requests/models/requests.backend.schemas.js +7 -0
- package/dist/esm/requests/models/requests.backend.schemas.js.map +1 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.d.ts +6 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.d.ts.map +1 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.js +20 -0
- package/dist/esm/requests/service/__tests__/mock-apps-shared-resources-gateway.service.js.map +1 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.d.ts +84 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.js +462 -0
- package/dist/esm/requests/service/apps-shared-resources-gateway.backend.service.js.map +1 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.d.ts +9 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.js +36 -0
- package/dist/esm/requests/service/platform-mutualized-handler.backend.service.js.map +1 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.d.ts +6 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.d.ts.map +1 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.js +47 -0
- package/dist/esm/requests/service/platform-requests.backend.utils.js.map +1 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.d.ts +111 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.js +354 -0
- package/dist/esm/requests/service/remote-client-base.backend.service.js.map +1 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.d.ts +9 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.js +36 -0
- package/dist/esm/requests/service/serverless-services-handler.backend.service.js.map +1 -0
- package/dist/esm/requests/service/websocket.service.d.ts +507 -0
- package/dist/esm/requests/service/websocket.service.d.ts.map +1 -0
- package/dist/esm/requests/service/websocket.service.js +2222 -0
- package/dist/esm/requests/service/websocket.service.js.map +1 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts +3 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts.map +1 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js +17 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js.map +1 -0
- package/dist/esm/resources/models/index.d.ts +7 -0
- package/dist/esm/resources/models/index.d.ts.map +1 -0
- package/dist/esm/resources/models/index.js +7 -0
- package/dist/esm/resources/models/index.js.map +1 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.d.ts +4 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.d.ts.map +1 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.js +7 -0
- package/dist/esm/resources/models/resources-operations.backend.definitions.js.map +1 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.d.ts +3 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.d.ts.map +1 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.js +19 -0
- package/dist/esm/resources/models/resources-relationships.backend.definitions.js.map +1 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.d.ts +13 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.d.ts.map +1 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.js +14 -0
- package/dist/esm/resources/models/resources-types.backend.schemas.js.map +1 -0
- package/dist/esm/resources/models/resources.backend.schemas.d.ts +7 -0
- package/dist/esm/resources/models/resources.backend.schemas.d.ts.map +1 -0
- package/dist/esm/resources/models/resources.backend.schemas.js +8 -0
- package/dist/esm/resources/models/resources.backend.schemas.js.map +1 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.d.ts +121 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.d.ts.map +1 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.js +10 -0
- package/dist/esm/resources/models/virtual-fields.backend.types.js.map +1 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.d.ts +25 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.d.ts.map +1 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.js +59 -0
- package/dist/esm/resources/services/__tests__/mock-resources-registry.service.js.map +1 -0
- package/dist/esm/resources/services/resource-context.backend.service.d.ts +321 -0
- package/dist/esm/resources/services/resource-context.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resource-context.backend.service.js +723 -0
- package/dist/esm/resources/services/resource-context.backend.service.js.map +1 -0
- package/dist/esm/resources/services/resource-id.backend.service.d.ts +110 -0
- package/dist/esm/resources/services/resource-id.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resource-id.backend.service.js +267 -0
- package/dist/esm/resources/services/resource-id.backend.service.js.map +1 -0
- package/dist/esm/resources/services/resource-population.backend.service.d.ts +149 -0
- package/dist/esm/resources/services/resource-population.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resource-population.backend.service.js +543 -0
- package/dist/esm/resources/services/resource-population.backend.service.js.map +1 -0
- package/dist/esm/resources/services/resources-registry.backend.service.d.ts +151 -0
- package/dist/esm/resources/services/resources-registry.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/resources-registry.backend.service.js +867 -0
- package/dist/esm/resources/services/resources-registry.backend.service.js.map +1 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.d.ts +72 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.d.ts.map +1 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.js +254 -0
- package/dist/esm/resources/services/virtual-fields.backend.service.js.map +1 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts +73 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.js +275 -0
- package/dist/esm/runtime/controllers/health-controller.backend.service.js.map +1 -0
- package/dist/esm/runtime/domain-module.backend.definitions.d.ts +43 -0
- package/dist/esm/runtime/domain-module.backend.definitions.d.ts.map +1 -0
- package/dist/esm/runtime/domain-module.backend.definitions.js +70 -0
- package/dist/esm/runtime/domain-module.backend.definitions.js.map +1 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.d.ts +253 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.d.ts.map +1 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.js +329 -0
- package/dist/esm/runtime/models/execution-context.backend.schemas.js.map +1 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.d.ts +45 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.d.ts.map +1 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.js +73 -0
- package/dist/esm/runtime/models/runtime.backend.schemas.js.map +1 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts +315 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js +1525 -0
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js.map +1 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.d.ts +60 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.js +150 -0
- package/dist/esm/runtime/services/execution-context-handler.backend.service.js.map +1 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts +11 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.d.ts.map +1 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.js +1 -0
- package/dist/esm/runtime/services/health-readiness-contributor.backend.interface.js.map +1 -0
- package/dist/esm/runtime/services/http-server.backend.service.d.ts +188 -0
- package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/http-server.backend.service.js +755 -0
- package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -0
- package/dist/esm/runtime/services/start-application.backend.service.d.ts +240 -0
- package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -0
- package/dist/esm/runtime/services/start-application.backend.service.js +977 -0
- package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.d.ts +10 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.d.ts.map +1 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.js +13 -0
- package/dist/esm/runtime/testing/execution-context-test-fixtures.js.map +1 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.d.ts +15 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.d.ts.map +1 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.js +42 -0
- package/dist/esm/runtime/testing/mock-execution-context-creator.service.js.map +1 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.d.ts +85 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.d.ts.map +1 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.js +171 -0
- package/dist/esm/runtime/utils/scan-default-exports.backend.utils.js.map +1 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts +19 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js +59 -0
- package/dist/esm/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.d.ts +31 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.js +215 -0
- package/dist/esm/security/authentications/controllers/auth-method-management-controller.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts +493 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js +2371 -0
- package/dist/esm/security/authentications/controllers/authentication-controller.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.d.ts +83 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.js +113 -0
- package/dist/esm/security/authentications/models/auth-constants.backend.js.map +1 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.d.ts +98 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.js +59 -0
- package/dist/esm/security/authentications/models/authentications.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts +42 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js +98 -0
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts +163 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.js +12 -0
- package/dist/esm/security/authentications/models/oauth2-connection.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.d.ts +102 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.js +7 -0
- package/dist/esm/security/authentications/models/saml-authentication.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.d.ts +88 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.js +17 -0
- package/dist/esm/security/authentications/models/sso-connection.backend.schemas.js.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.d.ts +27 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.js +66 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.js.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.d.ts +30 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.js +44 -0
- package/dist/esm/security/authentications/services/__tests__/mock-auth-token-issuer.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.d.ts +19 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.js +43 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.d.ts +37 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.js +58 -0
- package/dist/esm/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts +85 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js +379 -0
- package/dist/esm/security/authentications/services/admin-config/auth-organization-configuration.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts +79 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js +205 -0
- package/dist/esm/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts +59 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js +179 -0
- package/dist/esm/security/authentications/services/admin-config/domain-verification.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts +116 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js +436 -0
- package/dist/esm/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.d.ts +67 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.js +222 -0
- package/dist/esm/security/authentications/services/admin-config/oidc-discovery.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts +80 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.js +368 -0
- package/dist/esm/security/authentications/services/anonymous-session.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.d.ts +75 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.js +139 -0
- package/dist/esm/security/authentications/services/auth-credential-verifier.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.d.ts +72 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.js +127 -0
- package/dist/esm/security/authentications/services/auth-execution-context-factory.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts +57 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js +459 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts +44 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js +131 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts +58 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js +209 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.d.ts +46 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.js +124 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-phone-verification.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts +165 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js +816 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-registration.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts +218 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js +1026 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-authentication.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts +150 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js +737 -0
- package/dist/esm/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.d.ts +224 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.js +593 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.d.ts +267 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.js +1376 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-authentication.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.d.ts +93 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.js +396 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-metadata.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.d.ts +40 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.js +92 -0
- package/dist/esm/security/authentications/services/auth-methods/saml-replay-guard.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts +82 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js +325 -0
- package/dist/esm/security/authentications/services/auth-methods/webauthn.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.d.ts +66 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.js +198 -0
- package/dist/esm/security/authentications/services/auth-session-store.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts +108 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js +406 -0
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts +366 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js +2631 -0
- package/dist/esm/security/authentications/services/authentication-orchestrator.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.d.ts +13 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js +53 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-custom-implementations.backend.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.d.ts +12 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.js +41 -0
- package/dist/esm/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.d.ts +18 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.js +140 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.d.ts +16 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.js +112 -0
- package/dist/esm/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts +16 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js +101 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.d.ts +18 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.js +136 -0
- package/dist/esm/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts +19 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js +154 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.d.ts +26 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.js +657 -0
- package/dist/esm/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.d.ts +27 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.js +60 -0
- package/dist/esm/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.d.ts +23 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.js +44 -0
- package/dist/esm/security/authentications/services/utils/auth-controller.utils.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.d.ts +89 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.js +192 -0
- package/dist/esm/security/authentications/services/utils/auth-credential-ops.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.d.ts +20 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.js +55 -0
- package/dist/esm/security/authentications/services/utils/auth-response-helper.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.d.ts +50 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js +135 -0
- package/dist/esm/security/authentications/services/utils/auth-user-lookup.backend.service.js.map +1 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.d.ts +26 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.d.ts.map +1 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.js +59 -0
- package/dist/esm/security/authentications/services/utils/saml-java-availability.js.map +1 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +137 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js +723 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts +28 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js +156 -0
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts +4 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js +72 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.d.ts +125 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.js +69 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.shared.schemas.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/index.d.ts +3 -0
- package/dist/esm/security/consumable-tokens/models/index.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/models/index.js +3 -0
- package/dist/esm/security/consumable-tokens/models/index.js.map +1 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.d.ts +26 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.js +55 -0
- package/dist/esm/security/consumable-tokens/services/__tests__/mock-consumable-token.service.js.map +1 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts +142 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js +446 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.d.ts +46 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.d.ts.map +1 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.js +147 -0
- package/dist/esm/security/jwt/services/auth-jwt-guard.backend.service.js.map +1 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts +75 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts.map +1 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.js +368 -0
- package/dist/esm/security/jwt/services/jwt.backend.service.js.map +1 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.d.ts +71 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.d.ts.map +1 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.js +863 -0
- package/dist/esm/security/scim/controllers/scim.backend.controller.js.map +1 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts +275 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.d.ts.map +1 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js +139 -0
- package/dist/esm/security/scim/models/scim-protocol.backend.schemas.js.map +1 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.d.ts +35 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.d.ts.map +1 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.js +232 -0
- package/dist/esm/security/scim/utils/scim-filter-parser.js.map +1 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.d.ts +42 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.d.ts.map +1 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.js +89 -0
- package/dist/esm/security/scim/utils/scim-response-formatter.js.map +1 -0
- package/dist/esm/testing.d.ts +31 -0
- package/dist/esm/testing.d.ts.map +1 -0
- package/dist/esm/testing.js +31 -0
- package/dist/esm/testing.js.map +1 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts +9 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.js +48 -0
- package/dist/esm/users/services/user-self-custom-implementations.backend.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +163 -0
- package/src/__tests__/integration/bulk-repository-write-contract.integration.test.ts +373 -0
- package/src/__tests__/integration/custom-batch-job-execution.integration.test.ts +147 -0
- package/src/__tests__/integration/delete-file-rollback-persistence.integration.test.ts +551 -0
- package/src/__tests__/integration/file-management-nested-persistence.integration.test.ts +487 -0
- package/src/__tests__/integration/file-management-postgresql-persistence.integration.test.ts +466 -0
- package/src/__tests__/integration/files-cleanup-persistence.integration.test.ts +335 -0
- package/src/__tests__/integration/generated-bulk-relationship-runtime.integration.test.ts +545 -0
- package/src/__tests__/integration/lifecycle-delete-rollback-persistence.integration.test.ts +537 -0
- package/src/__tests__/integration/postgresql-contextual-filter-enforcement.integration.test.ts +170 -0
- package/src/__tests__/integration/postgresql-delete-best-effort-boundary.integration.test.ts +604 -0
- package/src/__tests__/integration/prompt-compiler.integration.test.ts +723 -0
- package/src/__tests__/integration/relationship-service-semantics.integration.test.ts +2086 -0
- package/src/__tests__/integration/repositories-registry.integration.test.ts +296 -0
- package/src/__tests__/integration/resource-factory-pipeline.integration.test.ts +556 -0
- package/src/__tests__/integration/resource-services.integration.test.ts +265 -0
- package/src/__tests__/integration/resources-registry.integration.test.ts +327 -0
- package/src/__tests__/integration/services-registry.integration.test.ts +231 -0
- package/src/__tests__/integration/update-many-runtime-guards.integration.test.ts +290 -0
- package/src/__tests__/setup.ts +15 -0
- package/src/__tests__/test-container.ts +120 -0
- package/src/applications/models/applications.backend.schemas.ts +18 -0
- package/src/base-classes/__tests__/batches-cronjobs-executor.test.ts +63 -0
- package/src/base-classes/__tests__/bulk-delete-child-file-guard.test.ts +152 -0
- package/src/base-classes/__tests__/bulk-nested-file-update-coordination.test.ts +171 -0
- package/src/base-classes/__tests__/delete-file-coordination.test.ts +185 -0
- package/src/base-classes/__tests__/postgresql-file-transaction-coordination.test.ts +424 -0
- package/src/base-classes/__tests__/postgresql-repository-contextual-filter-enforcement.test.ts +88 -0
- package/src/base-classes/__tests__/repository-contextual-filter-enforcement.test.ts +87 -0
- package/src/base-classes/__tests__/resource-operation-helper-context-enforcement.test.ts +74 -0
- package/src/base-classes/__tests__/transaction-boundaries.test.ts +153 -0
- package/src/base-classes/models/manual-controllers.backend.definition.ts +56 -0
- package/src/base-classes/models/repositories.backend.schemas.ts +105 -0
- package/src/base-classes/services/__tests__/mock-resource-operation-helper.service.ts +61 -0
- package/src/base-classes/services/batches/batches-cronjobs-custom-execution.service.ts +148 -0
- package/src/base-classes/services/batches/batches-cronjobs-executor.backend.service.ts +115 -0
- package/src/base-classes/services/batches/batches-cronjobs-resource-execution.backend.service.ts +58 -0
- package/src/base-classes/services/controllers/__tests__/controller-request-validation.utils.test.ts +292 -0
- package/src/base-classes/services/controllers/__tests__/controller-resource-file-upload-routes.test.ts +1335 -0
- package/src/base-classes/services/controllers/__tests__/controller-resource.version-conflict.test.ts +372 -0
- package/src/base-classes/services/controllers/abstract-controller.backend.service.ts +302 -0
- package/src/base-classes/services/controllers/controller-resource.backend.service.ts +1833 -0
- package/src/base-classes/services/controllers/controllers-registry-handler.backend.service.ts +494 -0
- package/src/base-classes/services/controllers/validate-field-handler.backend.service.ts +613 -0
- package/src/base-classes/services/repositories/__tests__/mock-repositories-registry-handler.service.ts +31 -0
- package/src/base-classes/services/repositories/__tests__/repository-resource.singleton-read.test.ts +50 -0
- package/src/base-classes/services/repositories/postgresql-resource-repository.backend.service.ts +1207 -0
- package/src/base-classes/services/repositories/repositories-registry-handler.backend.service.ts +804 -0
- package/src/base-classes/services/repositories/repository-resource.backend.service.ts +2186 -0
- package/src/base-classes/services/resource-operations-helper.backend.service.ts +468 -0
- package/src/base-classes/services/services/__tests__/mock-services-registry-handler.service.ts +21 -0
- package/src/base-classes/services/services/__tests__/services-registry-handler.notifications.test.ts +65 -0
- package/src/base-classes/services/services/resource-operation-custom-implementation-base.backend.service.ts +305 -0
- package/src/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.ts +224 -0
- package/src/base-classes/services/services/resource-operation-custom-implementation.factory.backend.ts +331 -0
- package/src/base-classes/services/services/services-registry-handler.backend.service.ts +6288 -0
- package/src/base-classes/utils/backend-type-utils.ts +64 -0
- package/src/billing/services/back-office/__tests__/billing-feature-sync.backend.service.test.ts +132 -0
- package/src/billing/services/back-office/__tests__/billing-state.backend.service.test.ts +245 -0
- package/src/billing/services/back-office/__tests__/product-catalog-sync.backend.service.test.ts +238 -0
- package/src/billing/services/back-office/abstract-billing.backend.service.ts +89 -0
- package/src/billing/services/back-office/billing-feature-sync.backend.service.ts +473 -0
- package/src/billing/services/back-office/billing-state.backend.service.ts +348 -0
- package/src/billing/services/back-office/product-catalog-sync.backend.service.ts +415 -0
- package/src/billing/services/back-office/usage-metering.backend.service.ts +326 -0
- package/src/billing/services/billing.utils.ts +26 -0
- package/src/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.ts +342 -0
- package/src/billing/services/custom-impl/billing-custom-impl-utils.backend.ts +274 -0
- package/src/billing/services/custom-impl/billing-custom-implementations.backend.ts +236 -0
- package/src/billing/services/custom-impl/credit-pool.custom-ops.custom-impl.backend.service.ts +133 -0
- package/src/billing/services/custom-impl/promotion.custom-ops.custom-impl.backend.service.ts +242 -0
- package/src/billing/services/custom-impl/subscription.mutations.custom-impl.backend.service.ts +434 -0
- package/src/billing/services/webhooks/billing-webhook-adapter.backend.service.ts +70 -0
- package/src/billing/services/webhooks/billing-webhook-capability-handler.backend.service.ts +46 -0
- package/src/billing/services/webhooks/billing-webhook-event-router.backend.service.ts +727 -0
- package/src/billing/testing/billing-test-fixtures.ts +296 -0
- package/src/billing/testing/mock-billing-provider.ts +548 -0
- package/src/charts/controllers/__tests__/chart.backend.controller.test.ts +403 -0
- package/src/charts/controllers/chart.backend.controller.ts +238 -0
- package/src/charts/services/__tests__/chart-registry.backend.service.test.ts +120 -0
- package/src/charts/services/chart-registry.backend.service.ts +109 -0
- package/src/compliance/audit-trails/audit-logs.custom-impl.backend.service.ts +104 -0
- package/src/compliance/audit-trails/services/__tests__/mock-audit-logs.service.ts +48 -0
- package/src/compliance/audit-trails/services/audit-event-dispatcher.backend.service.ts +325 -0
- package/src/compliance/audit-trails/services/audit-logs.backend.service.ts +1313 -0
- package/src/compliance/audit-trails/services/siem-webhook-delivery.backend.service.ts +542 -0
- package/src/compliance/index.ts +1 -0
- package/src/config/custom/application-config-controller.backend.service.ts +119 -0
- package/src/config/models/__tests__/app-config-secrets.boundaries.test.ts +56 -0
- package/src/config/models/__tests__/app-config.backend-authored.definitions.test.ts +286 -0
- package/src/config/models/app-config-secrets.backend.schemas.ts +154 -0
- package/src/config/models/app-config.backend-authored.definitions.ts +165 -0
- package/src/config/models/app-config.backend.schemas.ts +614 -0
- package/src/config/models/app-env-config.backend.schemas.ts +135 -0
- package/src/config/models/config-mutation-boundary.utils.ts +76 -0
- package/src/config/models/postgresql-env-config.backend.schemas.ts +126 -0
- package/src/config/models/runtime-topology.backend.contracts.ts +42 -0
- package/src/config/services/__tests__/app-configuration-loader.backend.service.test.ts +118 -0
- package/src/config/services/__tests__/app-configuration.backend.service.test.ts +40 -0
- package/src/config/services/__tests__/app-configuration.backend.utils.test.ts +72 -0
- package/src/config/services/__tests__/application-startup-config-validator.backend.service.test.ts +404 -0
- package/src/config/services/__tests__/mock-app-configuration.service.ts +131 -0
- package/src/config/services/app-configuration-loader.backend.service.ts +443 -0
- package/src/config/services/app-configuration.backend.service.ts +570 -0
- package/src/config/services/app-configuration.backend.utils.ts +94 -0
- package/src/config/services/application-startup-config-validator.backend.service.ts +611 -0
- package/src/databases/models/aggregation.backend.schemas.ts +174 -0
- package/src/databases/models/databases.backend.schemas.ts +70 -0
- package/src/databases/models/filter.backend.schemas.ts +101 -0
- package/src/databases/models/sql.backend.schemas.ts +111 -0
- package/src/databases/models/transaction.shared.schemas.ts +172 -0
- package/src/databases/services/__tests__/mock-mongo-transaction-registry.service.ts +90 -0
- package/src/databases/services/__tests__/mock-mongodb.service.ts +86 -0
- package/src/databases/services/__tests__/mock-mongoose-model.service.ts +411 -0
- package/src/databases/services/__tests__/mock-redis.service.ts +72 -0
- package/src/databases/services/__tests__/mock-zod-mongoose-schema-convertor.service.ts +41 -0
- package/src/databases/services/__tests__/mongo-aggregation-compiler.test.ts +918 -0
- package/src/databases/services/__tests__/postgresql-filter.backend.service.test.ts +180 -0
- package/src/databases/services/__tests__/sql-hybrid-transform.test.ts +73 -0
- package/src/databases/services/aggregation/__tests__/aggregation-authorization.backend.service.test.ts +444 -0
- package/src/databases/services/aggregation/__tests__/aggregation-query.backend.service.test.ts +150 -0
- package/src/databases/services/aggregation/__tests__/computed-measure-evaluator.test.ts +525 -0
- package/src/databases/services/aggregation/__tests__/field-access-validator.test.ts +458 -0
- package/src/databases/services/aggregation/__tests__/time-series-densifier.test.ts +631 -0
- package/src/databases/services/aggregation/__tests__/window-function-processor.test.ts +598 -0
- package/src/databases/services/aggregation/aggregation-authorization.backend.service.ts +516 -0
- package/src/databases/services/aggregation/aggregation-query.backend.service.ts +514 -0
- package/src/databases/services/aggregation/computed-measure-evaluator.backend.service.ts +196 -0
- package/src/databases/services/aggregation/field-access-validator.backend.service.ts +225 -0
- package/src/databases/services/aggregation/time-series-densifier.backend.service.ts +389 -0
- package/src/databases/services/aggregation/topn-processor.backend.service.ts +221 -0
- package/src/databases/services/aggregation/window-function-processor.backend.service.ts +301 -0
- package/src/databases/services/db-utils.ts +96 -0
- package/src/databases/services/mongo-aggregation.backend.service.ts +762 -0
- package/src/databases/services/mongodb.service.ts +736 -0
- package/src/databases/services/postgresql-aggregation.backend.service.ts +794 -0
- package/src/databases/services/postgresql-database.backend.service.ts +288 -0
- package/src/databases/services/postgresql-filter.backend.service.ts +673 -0
- package/src/databases/services/redis.service.ts +531 -0
- package/src/databases/services/zod-to-mongoose-schema-convertor.backend.service.ts +2486 -0
- package/src/databases/services/zod-to-sql-hybrid-schema.planner.ts +312 -0
- package/src/errors/services/__tests__/error-builder.backend.service.test.ts +31 -0
- package/src/errors/services/__tests__/error-handler.backend.service.test.ts +82 -0
- package/src/errors/services/__tests__/mock-error-builder.service.ts +288 -0
- package/src/errors/services/error-builder.backend.service.ts +403 -0
- package/src/errors/services/error-handler.backend.service.ts +236 -0
- package/src/errors/services/rate-limit.backend.service.ts +45 -0
- package/src/external-providers/models/external-providers.backend.schemas.ts +243 -0
- package/src/external-providers/services/__tests__/external-providers-registry.backend.service.test.ts +136 -0
- package/src/external-providers/services/__tests__/feature-bindings.backend.service.test.ts +40 -0
- package/src/external-providers/services/__tests__/mock-external-providers-registry.service.ts +33 -0
- package/src/external-providers/services/__tests__/mock-lazy-provider-registry.service.ts +45 -0
- package/src/external-providers/services/external-api-handler.backend.service.ts +19 -0
- package/src/external-providers/services/external-providers-registry.backend.service.ts +534 -0
- package/src/external-providers/services/feature-bindings.backend.service.ts +422 -0
- package/src/external-providers/services/lazy-provider-registry.backend.service.ts +486 -0
- package/src/features/__tests__/feature-builders.test.ts +152 -0
- package/src/features/controllers/__tests__/features.backend.controller.test.ts +173 -0
- package/src/features/controllers/features.backend.controller.ts +200 -0
- package/src/features/services/__tests__/feature-definition-registry.backend.service.test.ts +152 -0
- package/src/features/services/__tests__/feature-gate.test.ts +484 -0
- package/src/features/services/__tests__/feature-resolution.backend.service.test.ts +203 -0
- package/src/features/services/__tests__/mock-capability-bindings.service.ts +26 -0
- package/src/features/services/__tests__/mock-feature-definition-registry.service.ts +56 -0
- package/src/features/services/__tests__/mock-feature-resolution.service.ts +36 -0
- package/src/features/services/feature-definition-registry.backend.service.ts +537 -0
- package/src/features/services/feature-gate.backend.service.ts +522 -0
- package/src/features/services/feature-resolution.backend.service.ts +652 -0
- package/src/features/testing/feature-test-utils.ts +200 -0
- package/src/files/batches/__tests__/files-cleanup.batch.backend.service.test.ts +186 -0
- package/src/files/batches/files-cleanup.batch.backend.service.ts +259 -0
- package/src/files/constraints/file-analyzers.types.ts +85 -0
- package/src/files/constraints/file-constraint-resolver-chain.backend.service.ts +99 -0
- package/src/files/constraints/file-constraint.types.ts +104 -0
- package/src/files/constraints/file-validation.backend.service.ts +359 -0
- package/src/files/constraints/resource-field-constraint-resolver.backend.service.ts +138 -0
- package/src/files/controllers/__tests__/file.controller.behavior.test.ts +655 -0
- package/src/files/controllers/file.controller.ts +1030 -0
- package/src/files/handlers/__tests__/resource-file-upload-handler.backend.service.test.ts +392 -0
- package/src/files/handlers/resource-file-upload-handler.backend.service.ts +605 -0
- package/src/files/rag/weaviate-vector-store.backend.service.ts +271 -0
- package/src/files/scanning/clamav-scanner.backend.service.ts +214 -0
- package/src/files/scanning/file-scan.types.ts +17 -0
- package/src/files/scanning/yara-scanner.backend.service.ts +212 -0
- package/src/files/services/__tests__/file-field-detection.backend.service.test.ts +91 -0
- package/src/files/services/__tests__/file-operation-handler.backend.service.test.ts +272 -0
- package/src/files/services/__tests__/file-population.backend.service.test.ts +120 -0
- package/src/files/services/__tests__/file-scanning.backend.service.test.ts +163 -0
- package/src/files/services/__tests__/files.backend.service.test.ts +885 -0
- package/src/files/services/__tests__/mock-file-field-detection.service.ts +43 -0
- package/src/files/services/__tests__/mock-file-operation-handler.service.ts +113 -0
- package/src/files/services/__tests__/mock-file-repository.service.ts +104 -0
- package/src/files/services/file-field-detection.backend.service.ts +156 -0
- package/src/files/services/file-operation-handler.backend.service.ts +861 -0
- package/src/files/services/file-population.backend.service.ts +485 -0
- package/src/files/services/file-rag-indexing.backend.service.ts +229 -0
- package/src/files/services/file-scanning.backend.service.ts +373 -0
- package/src/files/services/file-text-extraction.backend.service.ts +193 -0
- package/src/files/services/files.backend.service.ts +1356 -0
- package/src/files/storage/file-storage-path-resolver.backend.service.ts +289 -0
- package/src/files/storage/file-storage-provider.types.ts +188 -0
- package/src/files/storage/file-storage-router.backend.service.ts +172 -0
- package/src/files/storage/local-directory-storage-provider.backend.service.ts +417 -0
- package/src/files/storage/wildo-managed-storage-provider.backend.service.ts +530 -0
- package/src/files/utils/__tests__/file-field-schema-path.backend.utils.test.ts +44 -0
- package/src/files/utils/__tests__/file-uploader.utils.test.ts +57 -0
- package/src/files/utils/__tests__/file-validation.utils.test.ts +559 -0
- package/src/files/utils/file-field-schema-path.backend.utils.ts +385 -0
- package/src/files/utils/file-upload.utils.ts +146 -0
- package/src/files/utils/file-uploader.utils.ts +65 -0
- package/src/files/utils/file-validation.utils.ts +753 -0
- package/src/flows-actors/agent-catalogs.backend.ts +427 -0
- package/src/flows-actors/controllers/flows-actors.controller.ts +91 -0
- package/src/flows-actors/models/agent-catalogs.backend.definitions.ts +430 -0
- package/src/flows-actors/models/agent-facets.backend.definitions.ts +120 -0
- package/src/flows-actors/models/agents.backend.definitions.ts +4 -0
- package/src/flows-actors/models/core-facets.backend.definitions.ts +348 -0
- package/src/flows-actors/models/flows-actors.backend.definitions.ts +13 -0
- package/src/flows-actors/models/flows-actors.backend.schemas.ts +44 -0
- package/src/flows-actors/services/__tests__/agent-facets-catalogs.test.ts +544 -0
- package/src/flows-actors/services/__tests__/agents.backend.service.cli-runtime.test.ts +234 -0
- package/src/flows-actors/services/actors-system.backend.service.ts +270 -0
- package/src/flows-actors/services/agent-facets.backend.service.ts +350 -0
- package/src/flows-actors/services/agents.backend.service.ts +2730 -0
- package/src/flows-actors/services/context-curation.backend.service.ts +203 -0
- package/src/flows-actors/services/flows-actors-registry.service.ts +374 -0
- package/src/flows-actors/services/flows.backend.services.ts +237 -0
- package/src/flows-actors/services/prompt-compiler.backend.service.ts +734 -0
- package/src/flows-actors/utils/__tests__/cli-runtime-operation-support.backend.utils.test.ts +95 -0
- package/src/flows-actors/utils/cli-runtime-operation-support.backend.utils.ts +87 -0
- package/src/flows-actors/utils/cli-runtime-runner.backend.utils.ts +171 -0
- package/src/flows-actors/utils/flows-actors-frontend-extractor.utils.ts +63 -0
- package/src/flows-actors/utils/prompt-ir-adapters.backend.utils.ts +257 -0
- package/src/guidance/batches/dormancy-detection.batch.backend.service.ts +126 -0
- package/src/guidance/services/__tests__/guidance-trigger-evaluator.backend.service.test.ts +49 -0
- package/src/guidance/services/__tests__/lifecycle-evaluator.backend.service.test.ts +85 -0
- package/src/guidance/services/__tests__/milestone-definition-registry.backend.service.test.ts +211 -0
- package/src/guidance/services/__tests__/milestone-evaluator.backend.service.test.ts +561 -0
- package/src/guidance/services/guidance-trigger-evaluator.backend.service.ts +151 -0
- package/src/guidance/services/lifecycle-custom-implementations.backend.ts +139 -0
- package/src/guidance/services/lifecycle-evaluator.backend.service.ts +908 -0
- package/src/guidance/services/milestone-condition-registry.backend.service.ts +57 -0
- package/src/guidance/services/milestone-definition-registry.backend.service.ts +265 -0
- package/src/guidance/services/milestone-evaluator.backend.service.ts +611 -0
- package/src/i18n/controllers/i18n-controller.backend.service.ts +227 -0
- package/src/i18n/services/i18n.backend.service.ts +88 -0
- package/src/index.ts +286 -0
- package/src/inject/models/container.ts +586 -0
- package/src/inject/models/service-types.ts +488 -0
- package/src/monitoring/analytics/controllers/analytics.backend.controller.ts +114 -0
- package/src/monitoring/analytics/services/value-moment-engine.backend.service.ts +53 -0
- package/src/monitoring/analytics/services/value-moment-handler-registry.backend.service.ts +38 -0
- package/src/monitoring/logger/middleware/logging.middleware.ts +40 -0
- package/src/monitoring/logger/models/logger.backend.schemas.ts +56 -0
- package/src/monitoring/logger/services/__tests__/mock-logger.service.ts +49 -0
- package/src/monitoring/logger/services/logger.service.ts +214 -0
- package/src/monitoring/observability/middleware/metrics.middleware.ts +205 -0
- package/src/monitoring/observability/middleware/telemetry.middleware.ts +188 -0
- package/src/monitoring/observability/middleware/tracing.middleware.ts +265 -0
- package/src/monitoring/observability/models/observability.backend.schemas.ts +96 -0
- package/src/monitoring/observability/services/instrumentations/custom.instrumentations.ts +132 -0
- package/src/monitoring/observability/services/metrics.service.ts +266 -0
- package/src/monitoring/observability/services/telemetry.service.ts +157 -0
- package/src/monitoring/observability/services/tracer.service.ts +334 -0
- package/src/notifications/email/components/email-components.ts +341 -0
- package/src/notifications/email/models/email-context-provider.interface.ts +107 -0
- package/src/notifications/email/models/email-template-definition.ts +74 -0
- package/src/notifications/email/models/email-template.actors-system.backend.definitions.ts +80 -0
- package/src/notifications/email/models/email.backend.scheamas.ts +0 -0
- package/src/notifications/email/services/email-batch-send.batch.backend.service.ts +236 -0
- package/src/notifications/email/services/email-context-provider-registry.backend.service.ts +157 -0
- package/src/notifications/email/services/email-renderer.backend.service.ts +274 -0
- package/src/notifications/email/services/email-template-compiler.backend.service.ts +136 -0
- package/src/notifications/email/services/email-template-generation.backend.service.ts +811 -0
- package/src/notifications/email/services/email-template-registry.backend.service.ts +166 -0
- package/src/notifications/email/services/email-template-sandbox.backend.service.ts +255 -0
- package/src/notifications/email/services/email-template-validator.backend.service.ts +229 -0
- package/src/notifications/email/services/email.backend.service.ts +429 -0
- package/src/notifications/email/utils/color-conversion.utils.ts +142 -0
- package/src/notifications/email/utils/interpolate-email-label.utils.ts +16 -0
- package/src/notifications/email/utils/zod-to-typescript.utils.ts +352 -0
- package/src/notifications/services/__tests__/notifications-dispatcher.operation-semantics.test.ts +773 -0
- package/src/notifications/services/__tests__/notifications-dispatcher.websocket-integration.test.ts +173 -0
- package/src/notifications/services/notification-badge.backend.service.ts +412 -0
- package/src/notifications/services/notifications-dispatcher.backend.service.ts +1696 -0
- package/src/notifications/sms/services/sms.backend.service.ts +283 -0
- package/src/notifications/webhooks/controllers/webhook-auto-controller.backend.service.ts +220 -0
- package/src/notifications/webhooks/services/polymorphic-lookup.backend.service.ts +131 -0
- package/src/notifications/webhooks/services/webhook-handler.backend.service.ts +481 -0
- package/src/organizations/services/__tests__/org-creation-on-registration.backend.utils.test.ts +193 -0
- package/src/organizations/services/__tests__/org-member-roles-validation.backend.utils.test.ts +101 -0
- package/src/organizations/services/__tests__/organization-custom-implementation.backend.service.test.ts +113 -0
- package/src/organizations/services/__tests__/scim-provisioning-gate.backend.utils.test.ts +94 -0
- package/src/organizations/services/__tests__/user-org-type-grant.backend.utils.test.ts +164 -0
- package/src/organizations/services/__tests__/user-type-revocation-on-org-leave.backend.utils.test.ts +161 -0
- package/src/organizations/services/org-creation-on-registration.backend.utils.ts +119 -0
- package/src/organizations/services/org-member-roles-validation.backend.utils.ts +51 -0
- package/src/organizations/services/organization-custom-implementation.backend.service.ts +106 -0
- package/src/organizations/services/organization-member-custom-implementation.backend.service.ts +150 -0
- package/src/organizations/services/scim-provisioning-gate.backend.utils.ts +34 -0
- package/src/organizations/services/user-org-type-grant.backend.utils.ts +49 -0
- package/src/organizations/services/user-type-revocation-on-org-leave.backend.utils.ts +102 -0
- package/src/queue/adapters/rabbitmq-adapter.backend.service.ts +494 -0
- package/src/queue/apps-crontabs-manager.backend.service.ts +258 -0
- package/src/queue/cron-job-sync.backend.service.ts +184 -0
- package/src/queue/domain-queue-consumer.backend.service.ts +333 -0
- package/src/queue/job-completion-registry.backend.service.ts +342 -0
- package/src/queue/job-consumer.backend.service.ts +646 -0
- package/src/queue/job-executor.backend.service.ts +315 -0
- package/src/queue/job-payload-storage.backend.service.ts +297 -0
- package/src/queue/job-status-tracking.backend.service.ts +376 -0
- package/src/queue/queue-monitoring.backend.service.ts +333 -0
- package/src/queue/queue-worker-initializer.backend.service.ts +179 -0
- package/src/queue/queue.backend.service.ts +530 -0
- package/src/queue/scheduled-message-verifier.backend.service.ts +228 -0
- package/src/queue/worker-shutdown-manager.backend.service.ts +298 -0
- package/src/requests/models/api-routes.backend.defintions.ts +45 -0
- package/src/requests/models/requests.backend.schemas.ts +73 -0
- package/src/requests/service/__tests__/websocket.service.auth-refresh.test.ts +361 -0
- package/src/requests/service/__tests__/websocket.service.resource-room-validation.test.ts +234 -0
- package/src/requests/service/__tests__/websocket.service.variant-authorization.test.ts +94 -0
- package/src/requests/service/platform-mutualized-handler.backend.service.ts +19 -0
- package/src/requests/service/platform-requests.backend.utils.ts +54 -0
- package/src/requests/service/remote-client-base.backend.service.ts +485 -0
- package/src/requests/service/serverless-services-handler.backend.service.ts +19 -0
- package/src/requests/service/websocket.service.ts +2844 -0
- package/src/resources/models/custom-service-implementations.backend.definition.ts +22 -0
- package/src/resources/models/index.ts +7 -0
- package/src/resources/models/resources-operations.backend.definitions.ts +9 -0
- package/src/resources/models/resources-relationships.backend.definitions.ts +30 -0
- package/src/resources/models/resources-types.backend.schemas.ts +14 -0
- package/src/resources/models/resources.backend.schemas.ts +6 -0
- package/src/resources/models/virtual-fields.backend.types.ts +132 -0
- package/src/resources/services/__tests__/mock-resources-registry.service.ts +69 -0
- package/src/resources/services/__tests__/resource-id.backend.service.test.ts +69 -0
- package/src/resources/services/resource-context.backend.service.ts +1107 -0
- package/src/resources/services/resource-id.backend.service.ts +280 -0
- package/src/resources/services/resource-population.backend.service.ts +761 -0
- package/src/resources/services/resources-registry.backend.service.ts +1126 -0
- package/src/resources/services/virtual-fields.backend.service.ts +303 -0
- package/src/runtime/__tests__/execution-context-creator.backend.service.test.ts +469 -0
- package/src/runtime/controllers/health-controller.backend.service.ts +297 -0
- package/src/runtime/domain-module.backend.definitions.test.ts +83 -0
- package/src/runtime/domain-module.backend.definitions.ts +161 -0
- package/src/runtime/models/execution-context.backend.schemas.ts +456 -0
- package/src/runtime/models/runtime.backend.schemas.ts +82 -0
- package/src/runtime/services/execution-context-creator.backend.service.ts +2102 -0
- package/src/runtime/services/execution-context-handler.backend.service.ts +224 -0
- package/src/runtime/services/health-readiness-contributor.backend.interface.ts +11 -0
- package/src/runtime/services/http-server.backend.service.ts +870 -0
- package/src/runtime/services/start-application.backend.service.ts +1109 -0
- package/src/runtime/testing/execution-context-test-fixtures.ts +14 -0
- package/src/runtime/testing/mock-execution-context-creator.service.ts +46 -0
- package/src/runtime/utils/scan-default-exports.backend.utils.ts +247 -0
- package/src/security/authentications/__tests__/auth-registration.test.ts +338 -0
- package/src/security/authentications/__tests__/authentication-controller.test.ts +31 -0
- package/src/security/authentications/__tests__/authentication-orchestrator.test.ts +27 -0
- package/src/security/authentications/__tests__/saml-assertion-validator.test.ts +631 -0
- package/src/security/authentications/__tests__/saml-authentication.test.ts +126 -0
- package/src/security/authentications/__tests__/saml-integration-test-helpers.test.ts +234 -0
- package/src/security/authentications/__tests__/saml-metadata.test.ts +185 -0
- package/src/security/authentications/__tests__/saml-replay-guard.test.ts +99 -0
- package/src/security/authentications/__tests__/saml-sso-flow.integration.test.ts +355 -0
- package/src/security/authentications/__tests__/saml-test-fixtures.test.ts +433 -0
- package/src/security/authentications/__tests__/saml-test-parser.test.ts +117 -0
- package/src/security/authentications/__tests__/sso-connection-custom-ops.integration.test.ts +236 -0
- package/src/security/authentications/batches/anonymous-session-cleanup.batch.backend.service.ts +71 -0
- package/src/security/authentications/controllers/auth-method-management-controller.backend.service.ts +205 -0
- package/src/security/authentications/controllers/authentication-controller.backend.service.ts +2712 -0
- package/src/security/authentications/models/auth-constants.backend.ts +141 -0
- package/src/security/authentications/models/authentications.backend.schemas.ts +106 -0
- package/src/security/authentications/models/jwt.backend.schemas.ts +107 -0
- package/src/security/authentications/models/oauth2-connection.backend.schemas.ts +196 -0
- package/src/security/authentications/models/saml-authentication.backend.schemas.ts +124 -0
- package/src/security/authentications/models/sso-connection.backend.schemas.ts +104 -0
- package/src/security/authentications/services/__tests__/mock-auth-execution-context-factory.service.ts +73 -0
- package/src/security/authentications/services/__tests__/mock-auth-token-issuer.service.ts +46 -0
- package/src/security/authentications/services/admin-config/__tests__/mock-domain-to-org-lookup.service.ts +40 -0
- package/src/security/authentications/services/admin-config/__tests__/mock-enterprise-user-provisioning.service.ts +67 -0
- package/src/security/authentications/services/admin-config/auth-organization-configuration.service.ts +424 -0
- package/src/security/authentications/services/admin-config/domain-to-org-lookup.backend.service.ts +244 -0
- package/src/security/authentications/services/admin-config/domain-verification.backend.service.ts +215 -0
- package/src/security/authentications/services/admin-config/enterprise-user-provisioning.backend.service.ts +509 -0
- package/src/security/authentications/services/admin-config/oidc-discovery.backend.service.ts +250 -0
- package/src/security/authentications/services/anonymous-session.backend.service.ts +442 -0
- package/src/security/authentications/services/auth-credential-verifier.backend.service.ts +147 -0
- package/src/security/authentications/services/auth-execution-context-factory.backend.service.ts +132 -0
- package/src/security/authentications/services/auth-methods/auth-method-management.backend.service.ts +532 -0
- package/src/security/authentications/services/auth-methods/auth-mfa.backend.service.ts +141 -0
- package/src/security/authentications/services/auth-methods/auth-password-reset.backend.service.ts +215 -0
- package/src/security/authentications/services/auth-methods/auth-phone-verification.backend.service.ts +136 -0
- package/src/security/authentications/services/auth-methods/auth-registration.backend.service.ts +994 -0
- package/src/security/authentications/services/auth-methods/oauth2-authentication.backend.service.ts +1210 -0
- package/src/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service.ts +903 -0
- package/src/security/authentications/services/auth-methods/saml-assertion-validator.backend.service.ts +791 -0
- package/src/security/authentications/services/auth-methods/saml-authentication.backend.service.ts +1727 -0
- package/src/security/authentications/services/auth-methods/saml-metadata.backend.service.ts +432 -0
- package/src/security/authentications/services/auth-methods/saml-replay-guard.backend.service.ts +90 -0
- package/src/security/authentications/services/auth-methods/webauthn.backend.service.ts +393 -0
- package/src/security/authentications/services/auth-session-store.backend.service.ts +211 -0
- package/src/security/authentications/services/auth-token-issuer.backend.service.ts +496 -0
- package/src/security/authentications/services/authentication-orchestrator.backend.service.ts +3156 -0
- package/src/security/authentications/services/custom-impls/auth-custom-implementations.backend.ts +88 -0
- package/src/security/authentications/services/custom-impls/auth-policy.custom-impl.backend.service.ts +54 -0
- package/src/security/authentications/services/custom-impls/scim-provisioning-config.custom-impl.backend.service.ts +167 -0
- package/src/security/authentications/services/custom-impls/scim-tokens.custom-impl.backend.service.ts +136 -0
- package/src/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.ts +123 -0
- package/src/security/authentications/services/custom-impls/siem-export-config.custom-impl.backend.service.ts +161 -0
- package/src/security/authentications/services/custom-impls/sso-config.custom-impl.backend.service.ts +185 -0
- package/src/security/authentications/services/custom-impls/sso-connection.custom-impl.backend.service.ts +792 -0
- package/src/security/authentications/services/utils/__tests__/mock-auth-user-lookup.service.ts +62 -0
- package/src/security/authentications/services/utils/auth-controller.utils.ts +51 -0
- package/src/security/authentications/services/utils/auth-credential-ops.backend.service.ts +202 -0
- package/src/security/authentications/services/utils/auth-response-helper.backend.service.ts +38 -0
- package/src/security/authentications/services/utils/auth-user-lookup.backend.service.ts +128 -0
- package/src/security/authentications/services/utils/saml-java-availability.ts +64 -0
- package/src/security/authorizations/__tests__/authorizations.backend.service.test.ts +82 -0
- package/src/security/authorizations/services/authorizations.backend.service.ts +934 -0
- package/src/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.ts +168 -0
- package/src/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.ts +92 -0
- package/src/security/consumable-tokens/models/consumable-tokens.shared.schemas.ts +86 -0
- package/src/security/consumable-tokens/models/index.ts +3 -0
- package/src/security/consumable-tokens/services/__tests__/mock-consumable-token.service.ts +63 -0
- package/src/security/consumable-tokens/services/consumable-token.backend.service.ts +568 -0
- package/src/security/jwt/services/auth-jwt-guard.backend.service.ts +137 -0
- package/src/security/jwt/services/jwt.backend.service.ts +397 -0
- package/src/security/scim/__tests__/scim-filter-parser.test.ts +121 -0
- package/src/security/scim/controllers/scim.backend.controller.ts +1066 -0
- package/src/security/scim/models/scim-protocol.backend.schemas.ts +258 -0
- package/src/security/scim/utils/scim-filter-parser.ts +289 -0
- package/src/security/scim/utils/scim-response-formatter.ts +122 -0
- package/src/testing.ts +30 -0
- package/src/types/xmldom.d.ts +9 -0
- package/src/users/services/user-self-custom-implementations.backend.ts +62 -0
|
@@ -0,0 +1,3156 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { inject, injectable } from 'inversify';
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
import { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';
|
|
5
|
+
import { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';
|
|
6
|
+
import { ErrorBuilderBackendService } from '~wildo-backend-lib/errors/services/error-builder.backend.service';
|
|
7
|
+
import type { ServicesRegistryHandlerBackendService } from '~wildo-backend-lib/base-classes/services/services/services-registry-handler.backend.service';
|
|
8
|
+
import { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';
|
|
9
|
+
import {
|
|
10
|
+
AuthIdentificationRequest,
|
|
11
|
+
AvailableMethod,
|
|
12
|
+
CoreConsumableTokenTypes,
|
|
13
|
+
ConsumableToken_ConsumptionMode,
|
|
14
|
+
ErrorCustomMessageReference,
|
|
15
|
+
ErrorType,
|
|
16
|
+
isWildoBackendError,
|
|
17
|
+
PasswordAuthRequest,
|
|
18
|
+
User,
|
|
19
|
+
UserStatus,
|
|
20
|
+
} from '@wildo-ai/saas-models';
|
|
21
|
+
import { CoreResourceType } from '@wildo-ai/saas-models';
|
|
22
|
+
import {
|
|
23
|
+
AuthUtils,
|
|
24
|
+
AuthIdentificationResponseSchema,
|
|
25
|
+
AuthMethod,
|
|
26
|
+
AuthFactorLevel,
|
|
27
|
+
AuthenticationResponseSchema,
|
|
28
|
+
AuthIdentificationResponse,
|
|
29
|
+
AuthenticationRequest,
|
|
30
|
+
AuthenticationResponse,
|
|
31
|
+
AuthenticationSession,
|
|
32
|
+
AuthenticationSessionSchema,
|
|
33
|
+
AuthenticationSessionState,
|
|
34
|
+
AuthNextStep,
|
|
35
|
+
AuthScopeType,
|
|
36
|
+
} from '@wildo-ai/saas-models';
|
|
37
|
+
import { AuthSessionPurpose, MfaEnrollmentState } from '@wildo-ai/saas-models';
|
|
38
|
+
import type { EmailOTPAuthRequest, TOTPAuthRequest, PasskeyAuthRequest, SMSOTPAuthRequest, UserCredentials, MagicLinkSendRequest, MagicLinkVerifyRequest, UserTypeAuthPolicy, UserTypesConfig } from '@wildo-ai/saas-models';
|
|
39
|
+
import { RegistrationMode, EmailVerificationMode } from '@wildo-ai/saas-models';
|
|
40
|
+
import { DurationUnit } from '@wildo-ai/zod-decorators';
|
|
41
|
+
import { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';
|
|
42
|
+
import { AuditLogsBackendService } from '~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service';
|
|
43
|
+
import { createOrgOnRegistration } from '~wildo-backend-lib/organizations/services/org-creation-on-registration.backend.utils';
|
|
44
|
+
import { grantUserTypesOnOrgJoin } from '~wildo-backend-lib/organizations/services/user-org-type-grant.backend.utils';
|
|
45
|
+
|
|
46
|
+
// New decomposed services
|
|
47
|
+
import { AuthSessionStoreBackendService } from '~wildo-backend-lib/security/authentications/services/auth-session-store.backend.service';
|
|
48
|
+
import { AuthCredentialVerifierBackendService } from '~wildo-backend-lib/security/authentications/services/auth-credential-verifier.backend.service';
|
|
49
|
+
import { AuthTokenIssuerBackendService, type AuthTokens } from '~wildo-backend-lib/security/authentications/services/auth-token-issuer.backend.service';
|
|
50
|
+
import { WebAuthnBackendService } from '~wildo-backend-lib/security/authentications/services/auth-methods/webauthn.backend.service';
|
|
51
|
+
import type { OtpOperational, MagicLinkOperational, TotpOperational } from '~wildo-backend-lib/config/models/app-config.backend.schemas';
|
|
52
|
+
import type { LockoutPolicyConfig } from '@wildo-ai/saas-models';
|
|
53
|
+
import { ConsumableTokenBackendService } from '~wildo-backend-lib/security/consumable-tokens/services/consumable-token.backend.service';
|
|
54
|
+
import { RedisService } from '~wildo-backend-lib/databases/services/redis.service';
|
|
55
|
+
import { RateLimitBackendService } from '~wildo-backend-lib/errors/services/rate-limit.backend.service';
|
|
56
|
+
import { DomainToOrgLookupBackendService } from '~wildo-backend-lib/security/authentications/services/admin-config/domain-to-org-lookup.backend.service';
|
|
57
|
+
import type { DomainOrgLookupResult } from '~wildo-backend-lib/security/authentications/services/admin-config/domain-to-org-lookup.backend.service';
|
|
58
|
+
import { AuthOrganizationConfigurationService } from '~wildo-backend-lib/security/authentications/services/admin-config/auth-organization-configuration.service';
|
|
59
|
+
import { AUTH_REDIS_KEYS } from '~wildo-backend-lib/security/authentications/models/auth-constants.backend';
|
|
60
|
+
import { OAuth2ConnectionResolverBackendService } from '~wildo-backend-lib/security/authentications/services/auth-methods/oauth2-connection-resolver.backend.service';
|
|
61
|
+
import { AuthUserLookupBackendService } from '~wildo-backend-lib/security/authentications/services/utils/auth-user-lookup.backend.service';
|
|
62
|
+
import { AuthCredentialOpsBackendService } from '~wildo-backend-lib/security/authentications/services/utils/auth-credential-ops.backend.service';
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* AuthenticationOrchestratorBackendService
|
|
66
|
+
*
|
|
67
|
+
* Orchestrates the authentication flow: identify → authenticate → tokens.
|
|
68
|
+
*
|
|
69
|
+
* Decomposed from the original AuthenticationBackendService (1900 lines → ~400 lines).
|
|
70
|
+
* Session storage, credential verification, and token issuance are delegated to
|
|
71
|
+
* focused sub-services (AuthSessionStore, AuthCredentialVerifier, AuthTokenIssuer).
|
|
72
|
+
*
|
|
73
|
+
* Public API preserved:
|
|
74
|
+
* - identify(request) → AuthIdentificationResponse
|
|
75
|
+
* - authenticate(request) → AuthenticationResponse
|
|
76
|
+
* - authenticatePassword(request) → AuthenticationResponse
|
|
77
|
+
* - getAuthenticationSessionState(sessionId) → AuthenticationSession | null
|
|
78
|
+
*
|
|
79
|
+
* TRAP 2: The controller calls exactly these methods. Signatures accept EC as the first parameter.
|
|
80
|
+
* TRAP 9: Dependency arrows flow one way: Orchestrator → Services → Infrastructure.
|
|
81
|
+
* TRAP 13: Audit logging stays here (not in sub-services).
|
|
82
|
+
*/
|
|
83
|
+
@injectable()
|
|
84
|
+
export class AuthenticationOrchestratorBackendService {
|
|
85
|
+
/** L11: Default session duration in minutes (absolute TTL). Overridden by userTypes[t].auth.sessionDurationMinutes. */
|
|
86
|
+
private static readonly DEFAULT_SESSION_DURATION_MINUTES = 30;
|
|
87
|
+
/** Idle timeout in minutes — session is deleted if lastActivity exceeds this. Must be < SESSION_DURATION_MINUTES. */
|
|
88
|
+
private static readonly AUTH_SESSION_IDLE_TIMEOUT_MINUTES = 5;
|
|
89
|
+
/** Default number of MFA methods required (for future MFA support). */
|
|
90
|
+
private static readonly DEFAULT_MFA_METHODS_REQUIRED = 1;
|
|
91
|
+
|
|
92
|
+
private readonly logDebug: (message: string, context?: Record<string, unknown>) => void;
|
|
93
|
+
|
|
94
|
+
constructor(
|
|
95
|
+
@inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,
|
|
96
|
+
@inject(SAAS_SERVICE_TYPES.AppConfigService) private readonly appConfigService: AppConfigurationService,
|
|
97
|
+
@inject(SAAS_SERVICE_TYPES.ErrorBuilderService) private readonly errorBuilder: ErrorBuilderBackendService,
|
|
98
|
+
@inject(SAAS_SERVICE_TYPES.ServicesRegistryHandlerService) private readonly servicesRegistryHandler: ServicesRegistryHandlerBackendService,
|
|
99
|
+
@inject(SAAS_SERVICE_TYPES.AuditLogsService) private readonly auditLogsService: AuditLogsBackendService,
|
|
100
|
+
// New decomposed services
|
|
101
|
+
@inject(SAAS_SERVICE_TYPES.AuthSessionStore) private readonly sessionStore: AuthSessionStoreBackendService,
|
|
102
|
+
@inject(SAAS_SERVICE_TYPES.AuthCredentialVerifier) private readonly credentialVerifier: AuthCredentialVerifierBackendService,
|
|
103
|
+
@inject(SAAS_SERVICE_TYPES.AuthTokenIssuer) private readonly tokenIssuer: AuthTokenIssuerBackendService,
|
|
104
|
+
// MFA services (Step 10-11)
|
|
105
|
+
@inject(SAAS_SERVICE_TYPES.ConsumableTokenService) private readonly consumableTokenService: ConsumableTokenBackendService,
|
|
106
|
+
@inject(SAAS_SERVICE_TYPES.RedisService) private readonly redisService: RedisService,
|
|
107
|
+
@inject(SAAS_SERVICE_TYPES.RateLimitBackendService) private readonly rateLimitService: RateLimitBackendService,
|
|
108
|
+
// Domain-to-org lookup service (Step 14 — enterprise SSO domain routing)
|
|
109
|
+
@inject(SAAS_SERVICE_TYPES.DomainToOrgLookupService) private readonly domainToOrgLookup: DomainToOrgLookupBackendService,
|
|
110
|
+
// Organization configuration (M12 — org-level auth policy enforcement)
|
|
111
|
+
@inject(SAAS_SERVICE_TYPES.AuthOrganizationConfigurationService) private readonly orgConfigService: AuthOrganizationConfigurationService,
|
|
112
|
+
// WebAuthn/Passkey ceremony service (Phase G1)
|
|
113
|
+
@inject(SAAS_SERVICE_TYPES.WebAuthnService) private readonly webAuthnService: WebAuthnBackendService,
|
|
114
|
+
// G3: OAuth2 connection resolver — for filtering providers by org restrictions
|
|
115
|
+
@inject(SAAS_SERVICE_TYPES.OAuth2ConnectionResolverService) private readonly oauth2Resolver: OAuth2ConnectionResolverBackendService,
|
|
116
|
+
// AUTH-14: User lookup + effective auth policy resolution with org overrides
|
|
117
|
+
@inject(SAAS_SERVICE_TYPES.AuthUserLookupService) private readonly userLookup: AuthUserLookupBackendService,
|
|
118
|
+
// Centralized credential read/update operations via service registry
|
|
119
|
+
@inject(SAAS_SERVICE_TYPES.AuthCredentialOpsService) private readonly credentialOps: AuthCredentialOpsBackendService,
|
|
120
|
+
) {
|
|
121
|
+
this.logDebug = this.logger.debugByType('AuthenticationOrchestrator');
|
|
122
|
+
this.logger.setDebugTypeLogging('AuthenticationOrchestrator', false);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Global lockout policy for email-scoped rate limiting (pre-authentication, user type unknown).
|
|
127
|
+
* Computed as the most-restrictive lockout across all configured user types:
|
|
128
|
+
* lowest maxLoginAttempts, longest lockoutDuration, progressive if any type uses it.
|
|
129
|
+
*/
|
|
130
|
+
private get lockoutPolicy(): LockoutPolicyConfig {
|
|
131
|
+
const userTypes = this.appConfigService.config.userTypes;
|
|
132
|
+
const policies = Object.values(userTypes).map(ut => ut.auth.lockoutPolicy);
|
|
133
|
+
if (policies.length === 0) {
|
|
134
|
+
return { maxLoginAttempts: 5, lockoutDurationMinutes: 30, progressiveLockout: false, maxProgressiveLockoutHours: 24 };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
maxLoginAttempts: Math.min(...policies.map(p => p.maxLoginAttempts)),
|
|
138
|
+
lockoutDurationMinutes: Math.max(...policies.map(p => p.lockoutDurationMinutes)),
|
|
139
|
+
progressiveLockout: policies.some(p => p.progressiveLockout),
|
|
140
|
+
maxProgressiveLockoutHours: Math.max(...policies.map(p => p.maxProgressiveLockoutHours)),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private get otpConfig(): OtpOperational {
|
|
145
|
+
return this.appConfigService.config.auth.otpOperational;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private get magicLinkConfig(): MagicLinkOperational {
|
|
149
|
+
return this.appConfigService.config.auth.magicLinkOperational;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private get totpConfig(): TotpOperational {
|
|
153
|
+
return this.appConfigService.config.auth.totpOperational;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ===============================
|
|
157
|
+
// PER-USER-TYPE AUTH CONFIG RESOLUTION (W3.1)
|
|
158
|
+
// ===============================
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Resolve the effective auth policy for a given user type.
|
|
162
|
+
* If the user type exists in config.userTypes, returns its auth policy.
|
|
163
|
+
* Falls back to FALLBACK_AUTH_POLICY when no user type is configured.
|
|
164
|
+
*/
|
|
165
|
+
private _resolveAuthPolicy(activeUserType?: string | null): UserTypeAuthPolicy {
|
|
166
|
+
if (activeUserType) {
|
|
167
|
+
const policy = this.appConfigService.getUserTypeAuthPolicy(activeUserType);
|
|
168
|
+
if (policy) return policy;
|
|
169
|
+
}
|
|
170
|
+
return AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* W6.8: Safe default auth policy when no user type is resolved.
|
|
175
|
+
* All values are restrictive-safe. Applications MUST configure userTypes for full control.
|
|
176
|
+
*/
|
|
177
|
+
private static readonly FALLBACK_AUTH_POLICY: UserTypeAuthPolicy = {
|
|
178
|
+
authMethodsEnabled: { [AuthMethod.PASSWORD]: true },
|
|
179
|
+
mfaPolicy: {
|
|
180
|
+
requireMFA: false,
|
|
181
|
+
requireStrongMFA: false,
|
|
182
|
+
enrollmentGracePeriodDays: 0,
|
|
183
|
+
passkeyExemptFromMFA: true,
|
|
184
|
+
},
|
|
185
|
+
registration: {
|
|
186
|
+
mode: RegistrationMode.OPEN,
|
|
187
|
+
allowedMethods: [AuthMethod.PASSWORD],
|
|
188
|
+
requirePasswordOnRegister: true,
|
|
189
|
+
emailVerification: EmailVerificationMode.REQUIRED_BEFORE_ACCESS,
|
|
190
|
+
blockForSSODomains: false,
|
|
191
|
+
},
|
|
192
|
+
passwordPolicy: {
|
|
193
|
+
minLength: 8,
|
|
194
|
+
maxLength: 128,
|
|
195
|
+
requireUppercase: true,
|
|
196
|
+
requireLowercase: true,
|
|
197
|
+
requireNumbers: true,
|
|
198
|
+
requireSpecialChars: false,
|
|
199
|
+
expiryDays: 0,
|
|
200
|
+
},
|
|
201
|
+
sessionDurationMinutes: AuthenticationOrchestratorBackendService.DEFAULT_SESSION_DURATION_MINUTES,
|
|
202
|
+
lockoutPolicy: {
|
|
203
|
+
maxLoginAttempts: 5,
|
|
204
|
+
lockoutDurationMinutes: 30,
|
|
205
|
+
progressiveLockout: false,
|
|
206
|
+
maxProgressiveLockoutHours: 24,
|
|
207
|
+
},
|
|
208
|
+
autoLinkByEmail: true,
|
|
209
|
+
methodManagement: {
|
|
210
|
+
allowUserMethodRemoval: true,
|
|
211
|
+
requireReauthForMethodChanges: false,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* AUTH-14: Resolve auth policy with org override merging for a known user.
|
|
217
|
+
* Use this instead of _resolveAuthPolicy when userId is available.
|
|
218
|
+
* Falls back to raw user-type policy if org resolution fails.
|
|
219
|
+
*/
|
|
220
|
+
private async _resolveAuthPolicyWithOrgOverrides(
|
|
221
|
+
ec: ExecutionContext<any>,
|
|
222
|
+
activeUserType: string | null | undefined,
|
|
223
|
+
userId: string,
|
|
224
|
+
): Promise<UserTypeAuthPolicy> {
|
|
225
|
+
if (!activeUserType) return AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
226
|
+
const effective = await this.userLookup.resolveEffectiveAuthPolicy(ec, userId, activeUserType);
|
|
227
|
+
return effective ?? AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* W6.8: Check if an auth method is enabled in ANY configured user type.
|
|
232
|
+
* Used for pre-identification guards (sendMagicLink, sendSMSOTP) where
|
|
233
|
+
* the user type is not yet known.
|
|
234
|
+
*/
|
|
235
|
+
private _isMethodEnabledGlobally(method: AuthMethod): boolean {
|
|
236
|
+
const userTypes: UserTypesConfig = this.appConfigService.config.userTypes ?? {};
|
|
237
|
+
for (const [, typeDef] of Object.entries(userTypes)) {
|
|
238
|
+
if (typeDef?.auth?.authMethodsEnabled?.[method]) return true;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Resolve auth policy from a session's activeUserType. Convenience wrapper.
|
|
245
|
+
*/
|
|
246
|
+
private _resolveAuthPolicyFromSession(session: AuthenticationSession): UserTypeAuthPolicy {
|
|
247
|
+
return this._resolveAuthPolicy(session.activeUserType);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private _assertFrontendServiceAuthAllowed(frontendServiceName: string | undefined, userType: string | null | undefined): void {
|
|
251
|
+
if (!frontendServiceName || !userType) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const userManagement = this.appConfigService.getFrontendServiceUserManagementEntry(frontendServiceName, userType);
|
|
256
|
+
if (!userManagement?.auth) {
|
|
257
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined, {
|
|
258
|
+
customMessageReference: ErrorCustomMessageReference.AUTHORIZATION,
|
|
259
|
+
context: {
|
|
260
|
+
message: `Authentication is disabled for frontend service "${frontendServiceName}" and user type "${userType}"`,
|
|
261
|
+
frontendServiceName,
|
|
262
|
+
activeUserType: userType,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ===============================
|
|
269
|
+
// SESSION HELPERS (delegate to AuthSessionStore)
|
|
270
|
+
// ===============================
|
|
271
|
+
|
|
272
|
+
private _getSessionTtlSeconds(activeUserType?: string | null): number {
|
|
273
|
+
const policy = this._resolveAuthPolicy(activeUserType);
|
|
274
|
+
return policy.sessionDurationMinutes * 60;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Create a new authentication session in the store.
|
|
280
|
+
*/
|
|
281
|
+
/** W4: Registration sessions get longer TTL (24h) to match email verification token expiry. */
|
|
282
|
+
private static readonly REGISTRATION_SESSION_TTL_SECONDS = 24 * 60 * 60;
|
|
283
|
+
|
|
284
|
+
private async createSession(
|
|
285
|
+
sessionId: string,
|
|
286
|
+
initialState: AuthenticationSessionState = AuthenticationSessionState.CREATED,
|
|
287
|
+
options: {
|
|
288
|
+
deviceInfo?: { userAgent?: string; ipAddress?: string };
|
|
289
|
+
activeUserType?: string;
|
|
290
|
+
purpose?: AuthSessionPurpose;
|
|
291
|
+
email?: string;
|
|
292
|
+
userId?: string;
|
|
293
|
+
pendingOrgType?: string;
|
|
294
|
+
} = {},
|
|
295
|
+
): Promise<AuthenticationSession> {
|
|
296
|
+
const authPolicy = this._resolveAuthPolicy(options.activeUserType);
|
|
297
|
+
const isRegistrationFlow = options.purpose === AuthSessionPurpose.REGISTRATION || options.purpose === AuthSessionPurpose.INVITATION;
|
|
298
|
+
const ttlSeconds = isRegistrationFlow
|
|
299
|
+
? AuthenticationOrchestratorBackendService.REGISTRATION_SESSION_TTL_SECONDS
|
|
300
|
+
: authPolicy.sessionDurationMinutes * 60;
|
|
301
|
+
const now = new Date();
|
|
302
|
+
const expiresAt = new Date(now.getTime() + ttlSeconds * 1000);
|
|
303
|
+
|
|
304
|
+
const session: AuthenticationSession = {
|
|
305
|
+
sessionId,
|
|
306
|
+
state: initialState,
|
|
307
|
+
activeUserType: options.activeUserType,
|
|
308
|
+
purpose: options.purpose ?? AuthSessionPurpose.LOGIN,
|
|
309
|
+
email: options.email,
|
|
310
|
+
userId: options.userId,
|
|
311
|
+
createdAt: now,
|
|
312
|
+
expiresAt,
|
|
313
|
+
lastActivity: now,
|
|
314
|
+
completedFactors: [],
|
|
315
|
+
availableFirstFactorMethods: [],
|
|
316
|
+
availableSecondFactorMethods: [],
|
|
317
|
+
availableEnrollmentMethods: [],
|
|
318
|
+
enrolledSecondFactorMethods: [],
|
|
319
|
+
usableSecondFactorMethods: [],
|
|
320
|
+
requiresMFA: false,
|
|
321
|
+
requireStrongMFA: false,
|
|
322
|
+
mfaMethodsRequired: AuthenticationOrchestratorBackendService.DEFAULT_MFA_METHODS_REQUIRED,
|
|
323
|
+
attempts: 0,
|
|
324
|
+
maxAttempts: authPolicy.lockoutPolicy.maxLoginAttempts,
|
|
325
|
+
requestedIntegrations: [],
|
|
326
|
+
deviceInfo: options.deviceInfo,
|
|
327
|
+
pendingOrgType: options.pendingOrgType,
|
|
328
|
+
version: 0,
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
await this.sessionStore.set(sessionId, session, ttlSeconds);
|
|
332
|
+
this.logDebug(`Created new authentication session: ${sessionId}`, { purpose: session.purpose });
|
|
333
|
+
|
|
334
|
+
return session;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Get and validate a session. Returns null if not found, expired, or idle-timed-out.
|
|
339
|
+
*/
|
|
340
|
+
private async getSession(sessionId: string): Promise<AuthenticationSession | null> {
|
|
341
|
+
const session = await this.sessionStore.get(sessionId);
|
|
342
|
+
|
|
343
|
+
if (!session) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Check expiry (Redis TTL handles this too, but defensive check)
|
|
348
|
+
if (session.expiresAt < new Date()) {
|
|
349
|
+
await this.sessionStore.delete(sessionId);
|
|
350
|
+
this.logDebug(`Session expired and removed: ${sessionId}`);
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// M15 fix: Idle timeout — delete session if lastActivity is stale
|
|
355
|
+
if (session.lastActivity) {
|
|
356
|
+
const idleLimitMs = AuthenticationOrchestratorBackendService.AUTH_SESSION_IDLE_TIMEOUT_MINUTES * 60 * 1000;
|
|
357
|
+
const idleDuration = Date.now() - session.lastActivity.getTime();
|
|
358
|
+
if (idleDuration > idleLimitMs) {
|
|
359
|
+
await this.sessionStore.delete(sessionId);
|
|
360
|
+
this.logDebug(`Session idle-timed-out and removed: ${sessionId}`, {
|
|
361
|
+
idleMinutes: Math.round(idleDuration / 60000),
|
|
362
|
+
limitMinutes: AuthenticationOrchestratorBackendService.AUTH_SESSION_IDLE_TIMEOUT_MINUTES,
|
|
363
|
+
});
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return session;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Maximum retries for atomic session updates before falling back to non-atomic write. */
|
|
372
|
+
private static readonly ATOMIC_UPDATE_MAX_RETRIES = 3;
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Update a session in the store using atomic compare-and-swap (M1 fix).
|
|
376
|
+
*
|
|
377
|
+
* Uses the session `version` field for optimistic concurrency control.
|
|
378
|
+
* On version mismatch (concurrent writer), re-reads and retries up to MAX_RETRIES.
|
|
379
|
+
* Falls back to a non-atomic write only if all retries are exhausted.
|
|
380
|
+
*/
|
|
381
|
+
private async updateSession(
|
|
382
|
+
sessionId: string,
|
|
383
|
+
updates: Partial<AuthenticationSession>,
|
|
384
|
+
): Promise<AuthenticationSession | null> {
|
|
385
|
+
for (let attempt = 0; attempt <= AuthenticationOrchestratorBackendService.ATOMIC_UPDATE_MAX_RETRIES; attempt++) {
|
|
386
|
+
const session = await this.getSession(sessionId);
|
|
387
|
+
if (!session) {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const expectedVersion = session.version ?? 0;
|
|
392
|
+
const updatedSession = AuthenticationSessionSchema.parse({
|
|
393
|
+
...session,
|
|
394
|
+
...updates,
|
|
395
|
+
lastActivity: new Date(),
|
|
396
|
+
version: expectedVersion + 1,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Try atomic update via Lua compare-and-swap
|
|
400
|
+
const result = await this.sessionStore.atomicUpdate(
|
|
401
|
+
sessionId,
|
|
402
|
+
updatedSession,
|
|
403
|
+
expectedVersion,
|
|
404
|
+
this._getSessionTtlSeconds(updatedSession.activeUserType),
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
if (result) {
|
|
408
|
+
this.logDebug(`Updated authentication session: ${sessionId}`, {
|
|
409
|
+
state: updatedSession.state,
|
|
410
|
+
version: updatedSession.version,
|
|
411
|
+
});
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Version mismatch — another writer beat us. Retry with fresh read.
|
|
416
|
+
this.logDebug(`Session update version conflict (attempt ${attempt + 1}): ${sessionId}`);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// All retries exhausted — return null to signal failure rather than falling back
|
|
420
|
+
// to a non-atomic write that could silently overwrite a concurrent writer's update.
|
|
421
|
+
this.logger.warn?.('Session atomic update retries exhausted, returning failure', { sessionId });
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Remove a session from the store.
|
|
427
|
+
*/
|
|
428
|
+
private async removeSession(sessionId: string): Promise<void> {
|
|
429
|
+
await this.sessionStore.delete(sessionId);
|
|
430
|
+
this.logDebug(`Removed authentication session: ${sessionId}`);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Increment session attempts and check for lockout.
|
|
435
|
+
* W3.1: Uses per-user-type lockout policy from session's activeUserType.
|
|
436
|
+
*/
|
|
437
|
+
private async incrementSessionAttempts(
|
|
438
|
+
ec: ExecutionContext<any>,
|
|
439
|
+
sessionId: string,
|
|
440
|
+
): Promise<{ session: AuthenticationSession | null; locked: boolean }> {
|
|
441
|
+
const session = await this.getSession(sessionId);
|
|
442
|
+
if (!session) {
|
|
443
|
+
return { session: null, locked: false };
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const sessionPolicy = this._resolveAuthPolicyFromSession(session);
|
|
447
|
+
const sessionLockout = sessionPolicy.lockoutPolicy;
|
|
448
|
+
const attempts = session.attempts + 1;
|
|
449
|
+
const locked = attempts >= session.maxAttempts;
|
|
450
|
+
|
|
451
|
+
let effectiveLockoutMinutes = sessionLockout.lockoutDurationMinutes;
|
|
452
|
+
|
|
453
|
+
// W2.3: Progressive lockout — double duration for each consecutive lockout, capped at maxProgressiveLockoutHours
|
|
454
|
+
if (locked && sessionLockout.progressiveLockout && session.userId) {
|
|
455
|
+
try {
|
|
456
|
+
const { previousCount } = await this.credentialOps.incrementLockout(ec, session.userId!);
|
|
457
|
+
const maxMinutes = (sessionLockout.maxProgressiveLockoutHours ?? 24) * 60;
|
|
458
|
+
effectiveLockoutMinutes = Math.min(
|
|
459
|
+
sessionLockout.lockoutDurationMinutes * Math.pow(2, previousCount),
|
|
460
|
+
maxMinutes,
|
|
461
|
+
);
|
|
462
|
+
} catch {
|
|
463
|
+
// Fallback to base duration if credential lookup fails
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const updates: Partial<AuthenticationSession> = {
|
|
468
|
+
attempts,
|
|
469
|
+
state: locked ? AuthenticationSessionState.LOCKED : session.state,
|
|
470
|
+
lockoutUntil: locked
|
|
471
|
+
? new Date(Date.now() + effectiveLockoutMinutes * 60 * 1000)
|
|
472
|
+
: undefined,
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const updatedSession = await this.updateSession(sessionId, updates);
|
|
476
|
+
|
|
477
|
+
if (locked && updatedSession?.userId) {
|
|
478
|
+
const deviceInfo = updatedSession.deviceInfo;
|
|
479
|
+
await this.auditLogsService.logUserAccountLocked({
|
|
480
|
+
userId: updatedSession.userId,
|
|
481
|
+
email: updatedSession.email || 'unknown',
|
|
482
|
+
authMethod: AuthMethod.PASSWORD,
|
|
483
|
+
lockoutDuration: effectiveLockoutMinutes,
|
|
484
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
485
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
486
|
+
sessionId,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return { session: updatedSession, locked };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// ===============================
|
|
494
|
+
// GLOBAL LOCKOUT (C1 fix — per-email, Redis-based)
|
|
495
|
+
// ===============================
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Get the current global attempt count for an email address.
|
|
499
|
+
*/
|
|
500
|
+
private async _getGlobalAttempts(email: string): Promise<number> {
|
|
501
|
+
const key = `${AUTH_REDIS_KEYS.GLOBAL_LOCKOUT}${email.toLowerCase()}`;
|
|
502
|
+
return this.redisService.getRateLimitCount(key);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Increment the global attempt counter for an email.
|
|
507
|
+
* Returns the new count and whether the account is locked.
|
|
508
|
+
* The key auto-expires after the lockout duration.
|
|
509
|
+
*/
|
|
510
|
+
private async _incrementGlobalAttempts(email: string): Promise<{ count: number; locked: boolean }> {
|
|
511
|
+
const key = `${AUTH_REDIS_KEYS.GLOBAL_LOCKOUT}${email.toLowerCase()}`;
|
|
512
|
+
const count = await this.redisService.incrementRateLimit(key, this.lockoutPolicy.lockoutDurationMinutes * 60);
|
|
513
|
+
return { count, locked: count >= this.lockoutPolicy.maxLoginAttempts };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Reset the global attempt counter on successful authentication.
|
|
518
|
+
*/
|
|
519
|
+
private async _resetGlobalAttempts(email: string): Promise<void> {
|
|
520
|
+
const key = `${AUTH_REDIS_KEYS.GLOBAL_LOCKOUT}${email.toLowerCase()}`;
|
|
521
|
+
await this.redisService.del(`rate_limit:${key}`);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Check if an email is globally locked out. If so, throw an error.
|
|
526
|
+
*/
|
|
527
|
+
private async _checkGlobalLockout(email: string): Promise<void> {
|
|
528
|
+
const attempts = await this._getGlobalAttempts(email);
|
|
529
|
+
if (attempts >= this.lockoutPolicy.maxLoginAttempts) {
|
|
530
|
+
this.logDebug('Global lockout active', { email, attempts, max: this.lockoutPolicy.maxLoginAttempts });
|
|
531
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
532
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_ACCOUNT_LOCKED,
|
|
533
|
+
context: {
|
|
534
|
+
message: 'Account temporarily locked due to too many failed attempts. Please try again later.',
|
|
535
|
+
lockoutDurationMinutes: this.lockoutPolicy.lockoutDurationMinutes,
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ===============================
|
|
542
|
+
// INTERNAL HELPERS
|
|
543
|
+
// ===============================
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Resolve user for authentication by email.
|
|
547
|
+
*/
|
|
548
|
+
private async _resolveUserForAuthentication(
|
|
549
|
+
ec: ExecutionContext<any>,
|
|
550
|
+
_session: AuthenticationSession,
|
|
551
|
+
email: string,
|
|
552
|
+
sessionId: string,
|
|
553
|
+
): Promise<User> {
|
|
554
|
+
this.logDebug(`Resolving user for authentication: sessionId=${sessionId}, email=${email}`);
|
|
555
|
+
|
|
556
|
+
const user = await this.userLookup.findAnyUserByEmail(ec, email);
|
|
557
|
+
|
|
558
|
+
if (!user) {
|
|
559
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
560
|
+
const authResponse = this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.FIRST, { retryAllowed: !locked });
|
|
561
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
562
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_USER_NOT_FOUND,
|
|
563
|
+
context: { email, authResponse },
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
this._enforceUserStatus(user, sessionId);
|
|
568
|
+
return user;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
private _enforceUserStatus(user: User, sessionId: string): void {
|
|
572
|
+
if (user.status === UserStatus.ACTIVE) return;
|
|
573
|
+
|
|
574
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
575
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_ACCOUNT_LOCKED,
|
|
576
|
+
context: { userStatus: user.status, sessionId },
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Update session after successful method authentication.
|
|
582
|
+
* Sets the correct session state based on whether this is a first or second factor completion.
|
|
583
|
+
*/
|
|
584
|
+
private async _updateSessionAfterSuccessfulAuth(
|
|
585
|
+
ec: ExecutionContext<any>,
|
|
586
|
+
sessionId: string,
|
|
587
|
+
userId: string,
|
|
588
|
+
authMethod: AuthMethod,
|
|
589
|
+
): Promise<void> {
|
|
590
|
+
const session = await this.getSession(sessionId);
|
|
591
|
+
if (!session) {
|
|
592
|
+
throw this.errorBuilder.buildError(ErrorType.NOT_FOUND, undefined, {
|
|
593
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_INVALID,
|
|
594
|
+
context: { sessionId, operation: 'update' },
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const currentFactors = session.completedFactors || [];
|
|
599
|
+
const newCompletedFactors = currentFactors.includes(authMethod)
|
|
600
|
+
? currentFactors
|
|
601
|
+
: [...currentFactors, authMethod];
|
|
602
|
+
|
|
603
|
+
// Determine correct session state: second-factor methods get COMPLETED (not FIRST_FACTOR_COMPLETED)
|
|
604
|
+
const isSecondFactor = AuthUtils.canBeSecondFactor(authMethod) && currentFactors.length > 0;
|
|
605
|
+
|
|
606
|
+
// Backend enforcement: reject second-factor methods not in usableSecondFactorMethods.
|
|
607
|
+
// Prevents API-level bypass of requireStrongMFA (e.g. submitting EMAIL_OTP directly).
|
|
608
|
+
if (isSecondFactor && session.usableSecondFactorMethods && session.usableSecondFactorMethods.length > 0) {
|
|
609
|
+
if (!session.usableSecondFactorMethods.includes(authMethod)) {
|
|
610
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined, {
|
|
611
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_METHOD_NOT_SUPPORTED,
|
|
612
|
+
context: { method: authMethod, reason: 'METHOD_NOT_IN_USABLE_LIST' },
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const newState = isSecondFactor
|
|
618
|
+
? AuthenticationSessionState.COMPLETED
|
|
619
|
+
: AuthenticationSessionState.FIRST_FACTOR_COMPLETED;
|
|
620
|
+
|
|
621
|
+
// AUTH-14: Use org-override-aware policy when userId is known
|
|
622
|
+
const sessionPolicy = userId
|
|
623
|
+
? await this._resolveAuthPolicyWithOrgOverrides(ec, session.activeUserType, userId)
|
|
624
|
+
: this._resolveAuthPolicyFromSession(session);
|
|
625
|
+
|
|
626
|
+
const sessionUpdate: Partial<AuthenticationSession> = {
|
|
627
|
+
state: newState,
|
|
628
|
+
completedFactors: newCompletedFactors,
|
|
629
|
+
attempts: 0, // Reset attempts on successful authentication
|
|
630
|
+
userId: userId,
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// After first-factor success, determine if MFA is required for this session.
|
|
634
|
+
// W3.1: Resolve per-user-type auth policy from session's activeUserType.
|
|
635
|
+
if (!isSecondFactor) {
|
|
636
|
+
const mfaCheck = await this._shouldRequireMFA(ec, userId, session.organizationId, authMethod, sessionPolicy);
|
|
637
|
+
if (mfaCheck.required) {
|
|
638
|
+
const hasEnrolledStrongFactor = mfaCheck.enrolledMethods.some(m => m !== AuthMethod.EMAIL_OTP);
|
|
639
|
+
|
|
640
|
+
if (!hasEnrolledStrongFactor) {
|
|
641
|
+
// W4.5: MFA required but no strong factor enrolled — route to enrollment
|
|
642
|
+
const secondFactorMethods = AuthUtils.getSecondFactorMethods();
|
|
643
|
+
const availableEnrollment = secondFactorMethods.filter(
|
|
644
|
+
m => sessionPolicy.authMethodsEnabled?.[m],
|
|
645
|
+
);
|
|
646
|
+
|
|
647
|
+
sessionUpdate.state = AuthenticationSessionState.MFA_ENROLLMENT_REQUIRED;
|
|
648
|
+
sessionUpdate.requiresMFA = true;
|
|
649
|
+
sessionUpdate.requireStrongMFA = sessionPolicy.mfaPolicy?.requireStrongMFA ?? false;
|
|
650
|
+
sessionUpdate.nextStep = AuthNextStep.MFA_ENROLLMENT;
|
|
651
|
+
sessionUpdate.availableEnrollmentMethods = availableEnrollment;
|
|
652
|
+
} else {
|
|
653
|
+
const mfaResolution = await this._resolveUsableMfaMethods(mfaCheck.enrolledMethods, sessionPolicy);
|
|
654
|
+
|
|
655
|
+
sessionUpdate.requiresMFA = true;
|
|
656
|
+
sessionUpdate.requireStrongMFA = mfaResolution.requireStrongMFA;
|
|
657
|
+
sessionUpdate.availableSecondFactorMethods = mfaResolution.availableMethods;
|
|
658
|
+
sessionUpdate.enrolledSecondFactorMethods = mfaCheck.enrolledMethods;
|
|
659
|
+
sessionUpdate.usableSecondFactorMethods = mfaResolution.usableMethods;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
await this.updateSession(sessionId, sessionUpdate);
|
|
665
|
+
|
|
666
|
+
// W2.3: Reset progressive lockout counter on successful auth
|
|
667
|
+
if (sessionPolicy.lockoutPolicy.progressiveLockout && userId) {
|
|
668
|
+
try {
|
|
669
|
+
await this.credentialOps.resetLockout(ec, userId);
|
|
670
|
+
} catch {
|
|
671
|
+
// Non-critical: lockout counter reset failure should not block auth
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// ===============================
|
|
677
|
+
// AUTHENTICATION FLOW METHODS
|
|
678
|
+
// ===============================
|
|
679
|
+
|
|
680
|
+
public async identify(
|
|
681
|
+
ec: ExecutionContext<any>,
|
|
682
|
+
identificationRequest: AuthIdentificationRequest,
|
|
683
|
+
activeUserType?: string,
|
|
684
|
+
frontendServiceName?: string,
|
|
685
|
+
): Promise<AuthIdentificationResponse> {
|
|
686
|
+
const { email, deviceInfo } = identificationRequest;
|
|
687
|
+
|
|
688
|
+
this.logDebug(`User identification request: email=${email}`);
|
|
689
|
+
|
|
690
|
+
// H1 fix: Rate limit identify() — 10 req/min per IP, 10 req/min per email
|
|
691
|
+
if (deviceInfo?.ipAddress) {
|
|
692
|
+
await this.rateLimitService.checkRateLimit(`${AUTH_REDIS_KEYS.IDENTIFY_IP}${deviceInfo.ipAddress}`, 10, 60);
|
|
693
|
+
}
|
|
694
|
+
await this.rateLimitService.checkRateLimit(`${AUTH_REDIS_KEYS.IDENTIFY_EMAIL}${email.toLowerCase()}`, 10, 60);
|
|
695
|
+
|
|
696
|
+
// C1 fix: Check global lockout before creating a session
|
|
697
|
+
await this._checkGlobalLockout(email);
|
|
698
|
+
|
|
699
|
+
const user = await this.userLookup.findAnyUserByEmail(ec, email);
|
|
700
|
+
|
|
701
|
+
this.logDebug(`User lookup result: userExists=${!!user}, email=${email}`);
|
|
702
|
+
|
|
703
|
+
// AUTH-10 FIX: When the user exists in DB, trust their stored userTypes over
|
|
704
|
+
// the client-provided X-Frontend-Service-Name-derived hint. The header is only used as a
|
|
705
|
+
// hint when the user is unknown (pre-registration UI).
|
|
706
|
+
const dbUserTypes = user ? (user as User & { userTypes?: string[] }).userTypes : undefined;
|
|
707
|
+
const resolvedUserType = (dbUserTypes?.length ? dbUserTypes[0] : undefined) ?? activeUserType;
|
|
708
|
+
|
|
709
|
+
// ─── Step 14: Domain-based SSO routing ───
|
|
710
|
+
// Extract email domain and check if an org claims it for SSO
|
|
711
|
+
const emailDomain = email.split('@')[1]?.toLowerCase();
|
|
712
|
+
let domainOrgLookup: DomainOrgLookupResult | null = null;
|
|
713
|
+
|
|
714
|
+
if (emailDomain) {
|
|
715
|
+
try {
|
|
716
|
+
domainOrgLookup = await this.domainToOrgLookup.findOrgByDomain(ec, emailDomain);
|
|
717
|
+
} catch {
|
|
718
|
+
this.logDebug('Domain-to-org lookup failed (non-fatal)', { emailDomain });
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Generate cryptographically secure session ID (Section 6.5 fix)
|
|
723
|
+
const sessionId = this.sessionStore.generateSessionId();
|
|
724
|
+
|
|
725
|
+
// AUTH-14: Use org-override-aware policy when user is known, raw policy for unknown users
|
|
726
|
+
this._assertFrontendServiceAuthAllowed(frontendServiceName, resolvedUserType);
|
|
727
|
+
|
|
728
|
+
const authPolicy = (user && resolvedUserType)
|
|
729
|
+
? await this._resolveAuthPolicyWithOrgOverrides(ec, resolvedUserType, user._id)
|
|
730
|
+
: this._resolveAuthPolicy(resolvedUserType);
|
|
731
|
+
const firstFactorMethods = await this._getAvailableFirstFactorMethods(ec, domainOrgLookup, authPolicy);
|
|
732
|
+
|
|
733
|
+
// G1: Filter PASSKEY from firstFactorMethods if the user has no registered passkeys.
|
|
734
|
+
// Also enrich the PASSKEY method config with the registered passkey count for UI hints.
|
|
735
|
+
if (user) {
|
|
736
|
+
try {
|
|
737
|
+
const userId = user._id;
|
|
738
|
+
const cred = await this.credentialVerifier.resolveCredentials(ec, userId);
|
|
739
|
+
const passkeyCount = (cred as UserCredentials)?.passkeyCredentials?.length ?? 0;
|
|
740
|
+
|
|
741
|
+
if (passkeyCount === 0) {
|
|
742
|
+
// Remove PASSKEY from available first factor methods since user has none registered
|
|
743
|
+
const passkeyIdx = firstFactorMethods.findIndex(m => m.method === AuthMethod.PASSKEY);
|
|
744
|
+
if (passkeyIdx >= 0) {
|
|
745
|
+
firstFactorMethods.splice(passkeyIdx, 1);
|
|
746
|
+
}
|
|
747
|
+
} else {
|
|
748
|
+
// Enrich PASSKEY config with credential count for UI hinting
|
|
749
|
+
const passkeyMethod = firstFactorMethods.find(m => m.method === AuthMethod.PASSKEY);
|
|
750
|
+
if (passkeyMethod) {
|
|
751
|
+
passkeyMethod.config = {
|
|
752
|
+
...passkeyMethod.config,
|
|
753
|
+
registeredPasskeyCount: passkeyCount,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
} catch {
|
|
758
|
+
// If credential lookup fails, just leave PASSKEY as-is from app config
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// If org requires SSO and disallows password fallback, filter out password
|
|
763
|
+
if (domainOrgLookup?.enforcement?.requireSSO && !domainOrgLookup.enforcement.allowPasswordFallback) {
|
|
764
|
+
const ssoOnlyMethods = firstFactorMethods.filter(
|
|
765
|
+
m => m.method === AuthMethod.ORG_OPENID_CONNECT || m.method === AuthMethod.ORG_SAML,
|
|
766
|
+
);
|
|
767
|
+
if (ssoOnlyMethods.length > 0) {
|
|
768
|
+
firstFactorMethods.length = 0;
|
|
769
|
+
firstFactorMethods.push(...ssoOnlyMethods);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Create session (W3.5: activeUserType stored on session, W3.1: per-user-type TTL + lockout)
|
|
774
|
+
// AUTH-10: Store the DB-resolved user type, not the raw header value
|
|
775
|
+
const session = await this.createSession(sessionId, AuthenticationSessionState.IDENTIFIED, {
|
|
776
|
+
deviceInfo,
|
|
777
|
+
activeUserType: resolvedUserType,
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
await this.updateSession(sessionId, {
|
|
781
|
+
email: email.toLowerCase(),
|
|
782
|
+
userExists: !!user,
|
|
783
|
+
userId: user?._id,
|
|
784
|
+
availableFirstFactorMethods: firstFactorMethods,
|
|
785
|
+
organizationId: domainOrgLookup?.scopeId,
|
|
786
|
+
scopeType: domainOrgLookup?.scopeType,
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
// Build organization branding if domain matched an org
|
|
790
|
+
const organizationBranding = domainOrgLookup
|
|
791
|
+
? { organizationName: domainOrgLookup.matchedProvider?.displayName }
|
|
792
|
+
: undefined;
|
|
793
|
+
|
|
794
|
+
// H2 fix: Always return userExists: true to prevent email enumeration.
|
|
795
|
+
// If no user was found, still advertise PASSWORD as available method so the
|
|
796
|
+
// response shape is identical regardless of email existence.
|
|
797
|
+
if (!user && firstFactorMethods.length === 0) {
|
|
798
|
+
const passwordMethod = await this._buildAvailableMethodObject(undefined, AuthMethod.PASSWORD, undefined, authPolicy);
|
|
799
|
+
if (passwordMethod) {
|
|
800
|
+
firstFactorMethods.push(passwordMethod);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// #13g Step 3: Flag ssoMigrationRequired when user's domain matches enforced SSO
|
|
805
|
+
// but they haven't linked yet — signals the frontend to show migration messaging.
|
|
806
|
+
let ssoMigrationRequired = false;
|
|
807
|
+
if (user && domainOrgLookup?.enforcement?.requireSSO && domainOrgLookup.matchedProvider) {
|
|
808
|
+
try {
|
|
809
|
+
const matchedConnectionId = (domainOrgLookup.matchedProvider._id as string) || (domainOrgLookup.matchedProvider.connectionId as string);
|
|
810
|
+
if (matchedConnectionId) {
|
|
811
|
+
const existingLink = await this.servicesRegistryHandler.read<{ _id: string }>(CoreResourceType.USER_IDENTITY_LINKS, ec, {
|
|
812
|
+
userId: (user as User)._id,
|
|
813
|
+
connectionId: matchedConnectionId,
|
|
814
|
+
});
|
|
815
|
+
if (!existingLink) {
|
|
816
|
+
ssoMigrationRequired = true;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
} catch {
|
|
820
|
+
this.logger.warn('SSO migration check failed (non-fatal)', { email });
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const payload = {
|
|
825
|
+
sessionId,
|
|
826
|
+
email: email.toLowerCase(),
|
|
827
|
+
userExists: true, // H2 fix: always true to prevent enumeration
|
|
828
|
+
firstFactorMethods,
|
|
829
|
+
defaultFirstFactorMethod: firstFactorMethods.length > 0 ? firstFactorMethods[0].method : undefined,
|
|
830
|
+
secondFactorMethods: [],
|
|
831
|
+
requiresMFA: false,
|
|
832
|
+
mfaMethodsRequired: AuthenticationOrchestratorBackendService.DEFAULT_MFA_METHODS_REQUIRED,
|
|
833
|
+
organizationBranding,
|
|
834
|
+
availableIntegrations: [],
|
|
835
|
+
ssoMigrationRequired,
|
|
836
|
+
};
|
|
837
|
+
return AuthIdentificationResponseSchema.parse(payload);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// ===============================
|
|
841
|
+
// AVAILABLE METHODS LOGIC
|
|
842
|
+
// ===============================
|
|
843
|
+
|
|
844
|
+
private async _getAvailableFirstFactorMethods(ec: ExecutionContext<any>, domainOrgLookup?: DomainOrgLookupResult | null, authPolicy?: UserTypeAuthPolicy): Promise<AvailableMethod[]> {
|
|
845
|
+
const policy = authPolicy ?? AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
846
|
+
const methods: AvailableMethod[] = [];
|
|
847
|
+
for (const method of AuthUtils.getFirstFactorMethods()) {
|
|
848
|
+
const availableMethod = await this._buildAvailableMethodObject(ec, method, domainOrgLookup, policy);
|
|
849
|
+
if (availableMethod) {
|
|
850
|
+
methods.push(availableMethod);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return methods;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
private async _getAvailableSecondFactorMethods(authPolicy?: UserTypeAuthPolicy): Promise<AvailableMethod[]> {
|
|
857
|
+
const policy = authPolicy ?? AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
858
|
+
const methods: AvailableMethod[] = [];
|
|
859
|
+
for (const method of AuthUtils.getSecondFactorMethods()) {
|
|
860
|
+
const availableMethod = await this._buildAvailableMethodObject(undefined, method, undefined, policy);
|
|
861
|
+
if (availableMethod) {
|
|
862
|
+
methods.push(availableMethod);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const acceptable = policy.mfaPolicy?.acceptableMFAMethods ?? [];
|
|
867
|
+
if (acceptable.length > 0) {
|
|
868
|
+
return methods.filter(m => acceptable.includes(m.method));
|
|
869
|
+
}
|
|
870
|
+
return methods;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Intersects available methods with enrolled methods, applying requireStrongMFA filtering.
|
|
875
|
+
* Returns { availableMethods, usableMethods, requireStrongMFA } for session population.
|
|
876
|
+
*/
|
|
877
|
+
private async _resolveUsableMfaMethods(enrolledMethods: AuthMethod[], authPolicy?: UserTypeAuthPolicy): Promise<{
|
|
878
|
+
availableMethods: AvailableMethod[];
|
|
879
|
+
usableMethods: AuthMethod[];
|
|
880
|
+
requireStrongMFA: boolean;
|
|
881
|
+
}> {
|
|
882
|
+
const policy = authPolicy ?? AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
883
|
+
const availableMethods = await this._getAvailableSecondFactorMethods(policy);
|
|
884
|
+
const enrolledSet = new Set<AuthMethod>(enrolledMethods);
|
|
885
|
+
const requireStrongMFA = !!policy.mfaPolicy?.requireStrongMFA;
|
|
886
|
+
let usableMethods: AuthMethod[] = availableMethods
|
|
887
|
+
.filter(m => enrolledSet.has(m.method))
|
|
888
|
+
.map(m => m.method);
|
|
889
|
+
if (requireStrongMFA) {
|
|
890
|
+
usableMethods = usableMethods.filter(m => m !== AuthMethod.EMAIL_OTP);
|
|
891
|
+
}
|
|
892
|
+
return { availableMethods, usableMethods, requireStrongMFA };
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// ===============================
|
|
896
|
+
// PASSWORD AUTHENTICATION
|
|
897
|
+
// ===============================
|
|
898
|
+
|
|
899
|
+
public async authenticatePassword(ec: ExecutionContext<any>, passwordAuthRequest: PasswordAuthRequest): Promise<AuthenticationResponse> {
|
|
900
|
+
const { sessionId, password } = passwordAuthRequest;
|
|
901
|
+
this.logDebug('Password authentication started', { sessionId, hasPassword: !!password });
|
|
902
|
+
|
|
903
|
+
// Get and validate session
|
|
904
|
+
const session = await this.getSession(sessionId);
|
|
905
|
+
if (!session) {
|
|
906
|
+
this.logDebug('Session not found', { sessionId });
|
|
907
|
+
const authResponse = this._buildIdentificationErrorResponse(sessionId, passwordAuthRequest.factorLevel, false, session);
|
|
908
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
909
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_INVALID,
|
|
910
|
+
context: { sessionId, authResponse },
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Check session-level lockout
|
|
915
|
+
if (session.state === AuthenticationSessionState.LOCKED) {
|
|
916
|
+
const authResponse = this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.FIRST, {
|
|
917
|
+
retryAllowed: false,
|
|
918
|
+
lockoutUntil: session.lockoutUntil,
|
|
919
|
+
});
|
|
920
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
921
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_ACCOUNT_LOCKED,
|
|
922
|
+
context: { sessionId, authResponse },
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// M2 fix: State machine guard — only allow password auth from valid states
|
|
927
|
+
const validPasswordStates = new Set([
|
|
928
|
+
AuthenticationSessionState.IDENTIFIED,
|
|
929
|
+
AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS,
|
|
930
|
+
]);
|
|
931
|
+
if (!validPasswordStates.has(session.state)) {
|
|
932
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
933
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_INVALID,
|
|
934
|
+
context: { message: 'Invalid session state for password authentication' },
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const { email } = session;
|
|
939
|
+
|
|
940
|
+
// H1 fix: Rate limit authenticatePassword() — 5 req/min per email+IP
|
|
941
|
+
const ipAddress = session.deviceInfo?.ipAddress;
|
|
942
|
+
await this.rateLimitService.checkRateLimit(`${AUTH_REDIS_KEYS.PASSWORD_EMAIL}${email.toLowerCase()}`, 5, 60);
|
|
943
|
+
if (ipAddress) {
|
|
944
|
+
await this.rateLimitService.checkRateLimit(`${AUTH_REDIS_KEYS.PASSWORD_IP}${ipAddress}`, 10, 60);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// C1 fix: Check global lockout (per-email, survives session recreation)
|
|
948
|
+
await this._checkGlobalLockout(email);
|
|
949
|
+
|
|
950
|
+
// M14 fix: If user's scope requires SSO, check grace login allowance before proceeding.
|
|
951
|
+
if (session.organizationId) {
|
|
952
|
+
await this._checkSSOGraceLoginAllowed(ec, (session.scopeType as AuthScopeType) || AuthScopeType.ORGANIZATION, session.organizationId, session.userId || '');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Update session state
|
|
956
|
+
await this.updateSession(sessionId, {
|
|
957
|
+
state: AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS,
|
|
958
|
+
currentFactor: AuthFactorLevel.FIRST,
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
// Resolve user
|
|
962
|
+
const user = await this._resolveUserForAuthentication(ec, session, email, sessionId);
|
|
963
|
+
const userId = (user as User)._id;
|
|
964
|
+
|
|
965
|
+
// Resolve credentials via AuthCredentialVerifier
|
|
966
|
+
const cred = await this.credentialVerifier.resolveCredentials(ec, userId);
|
|
967
|
+
|
|
968
|
+
if (!cred) {
|
|
969
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
970
|
+
const authResponse = this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.FIRST, {
|
|
971
|
+
authMethod: AuthMethod.PASSWORD,
|
|
972
|
+
retryAllowed: !locked,
|
|
973
|
+
});
|
|
974
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
975
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_USER_CREDENTIALS_NOT_FOUND,
|
|
976
|
+
context: { email, authResponse },
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// Verify password via AuthCredentialVerifier
|
|
981
|
+
this.logDebug('Verifying password', { sessionId });
|
|
982
|
+
const ok = await this.credentialVerifier.verifyPassword(cred.passwordHash, password);
|
|
983
|
+
this.logDebug('Password verification result', { sessionId, passwordMatch: ok });
|
|
984
|
+
|
|
985
|
+
if (!ok) {
|
|
986
|
+
this.logDebug('Password verification failed', { sessionId });
|
|
987
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
988
|
+
|
|
989
|
+
// C1 fix: Also increment global counter (survives session recreation)
|
|
990
|
+
const { locked: globalLocked } = await this._incrementGlobalAttempts(email);
|
|
991
|
+
const effectivelyLocked = locked || globalLocked;
|
|
992
|
+
|
|
993
|
+
// Audit log authentication failure (TRAP 13: audit stays in orchestrator)
|
|
994
|
+
const deviceInfo = session.deviceInfo;
|
|
995
|
+
await this.auditLogsService.logUserLoginFailed({
|
|
996
|
+
email,
|
|
997
|
+
authMethod: AuthMethod.PASSWORD,
|
|
998
|
+
failureReason: 'Invalid credentials',
|
|
999
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
1000
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
1001
|
+
attemptsRemaining: session.maxAttempts - session.attempts - 1,
|
|
1002
|
+
sessionId,
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
const authResponse = this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.FIRST, {
|
|
1006
|
+
authMethod: AuthMethod.PASSWORD,
|
|
1007
|
+
retryAllowed: !effectivelyLocked,
|
|
1008
|
+
});
|
|
1009
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1010
|
+
customMessageReference: effectivelyLocked
|
|
1011
|
+
? ErrorCustomMessageReference.AUTHENTICATION_ACCOUNT_LOCKED
|
|
1012
|
+
: ErrorCustomMessageReference.AUTHENTICATION_USER_CREDENTIALS_INVALID,
|
|
1013
|
+
context: { email, authResponse },
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Password verified — update session
|
|
1018
|
+
this.logDebug('Password authentication successful', { sessionId, userId });
|
|
1019
|
+
|
|
1020
|
+
// C1 fix: Reset global lockout counter on successful authentication
|
|
1021
|
+
await this._resetGlobalAttempts(email);
|
|
1022
|
+
|
|
1023
|
+
// M14 fix: Increment SSO grace login counter after successful password auth.
|
|
1024
|
+
if (session.organizationId) {
|
|
1025
|
+
await this._incrementSSOGraceLogin(ec, (session.scopeType as AuthScopeType) || AuthScopeType.ORGANIZATION, session.organizationId, userId);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
await this._updateSessionAfterSuccessfulAuth(ec, sessionId, userId, AuthMethod.PASSWORD);
|
|
1029
|
+
|
|
1030
|
+
const updatedSession = await this.getSession(sessionId);
|
|
1031
|
+
return this._buildAuthenticationSuccessMethod(
|
|
1032
|
+
sessionId,
|
|
1033
|
+
AuthFactorLevel.FIRST,
|
|
1034
|
+
AuthMethod.PASSWORD,
|
|
1035
|
+
'', // No access token yet — tokens issued after completion check in authenticate()
|
|
1036
|
+
{
|
|
1037
|
+
completedFactors: updatedSession?.completedFactors || [],
|
|
1038
|
+
requiresMFA: updatedSession?.requiresMFA || false,
|
|
1039
|
+
availableMFAMethods: updatedSession?.availableSecondFactorMethods || [],
|
|
1040
|
+
mfaMethodsRequired: updatedSession?.mfaMethodsRequired,
|
|
1041
|
+
enrolledSecondFactorMethods: updatedSession?.enrolledSecondFactorMethods || [],
|
|
1042
|
+
usableSecondFactorMethods: updatedSession?.usableSecondFactorMethods || [],
|
|
1043
|
+
nextStep: updatedSession?.nextStep,
|
|
1044
|
+
availableEnrollmentMethods: updatedSession?.availableEnrollmentMethods || [],
|
|
1045
|
+
},
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// ===============================
|
|
1050
|
+
// NATIVE SDK FIRST-FACTOR (S0.9)
|
|
1051
|
+
// ===============================
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Handle a native SDK token exchange as a completed first factor.
|
|
1055
|
+
* Creates a session, checks MFA requirement, and either issues tokens or returns MFA-required.
|
|
1056
|
+
* User status is enforced before any token issuance.
|
|
1057
|
+
*/
|
|
1058
|
+
public async handleNativeSDKFirstFactor(
|
|
1059
|
+
ec: ExecutionContext<any>,
|
|
1060
|
+
userId: string,
|
|
1061
|
+
email: string,
|
|
1062
|
+
deviceInfo?: { ipAddress?: string; userAgent?: string },
|
|
1063
|
+
activeUserType?: string,
|
|
1064
|
+
frontendServiceName?: string,
|
|
1065
|
+
): Promise<{ mfaRequired: false; tokens: AuthTokens } | { mfaRequired: true; sessionId: string; enrolledMethods: AuthMethod[] }> {
|
|
1066
|
+
const user = await this.userLookup.findUserById(ec, userId);
|
|
1067
|
+
if (!user || user.status !== UserStatus.ACTIVE) {
|
|
1068
|
+
this._enforceUserStatus(user || { status: UserStatus.DELETED } as User, `native-sdk:${userId}`);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// AUTH-10 FIX: Trust DB user type over header. The user already exists (provisioned above).
|
|
1072
|
+
const nativeDbUserTypes = (user as User & { userTypes?: string[] })?.userTypes ?? [];
|
|
1073
|
+
const nativeResolvedUserType = nativeDbUserTypes[0] ?? activeUserType;
|
|
1074
|
+
|
|
1075
|
+
// W3.1b: Validate header-claimed type matches DB if both are present
|
|
1076
|
+
if (activeUserType && nativeDbUserTypes.length > 0 && !nativeDbUserTypes.includes(activeUserType)) {
|
|
1077
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined, {
|
|
1078
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_USER_TYPE_MISMATCH,
|
|
1079
|
+
context: { message: 'Your account is not registered for this application.', activeUserType },
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
this._assertFrontendServiceAuthAllowed(frontendServiceName, nativeResolvedUserType);
|
|
1084
|
+
|
|
1085
|
+
// AUTH-14: Use org-override-aware policy for native SDK flows
|
|
1086
|
+
const nativeSdkPolicy = await this._resolveAuthPolicyWithOrgOverrides(ec, nativeResolvedUserType, userId);
|
|
1087
|
+
const mfaCheck = await this._shouldRequireMFA(ec, userId, undefined, AuthMethod.EXTERNAL_OAUTH2, nativeSdkPolicy);
|
|
1088
|
+
|
|
1089
|
+
if (mfaCheck.required) {
|
|
1090
|
+
const hasEnrolledStrongFactor = mfaCheck.enrolledMethods.some(m => m !== AuthMethod.EMAIL_OTP);
|
|
1091
|
+
|
|
1092
|
+
if (hasEnrolledStrongFactor) {
|
|
1093
|
+
const sessionId = this.sessionStore.generateSessionId();
|
|
1094
|
+
await this.createSession(sessionId, AuthenticationSessionState.FIRST_FACTOR_COMPLETED, { deviceInfo, activeUserType: nativeResolvedUserType });
|
|
1095
|
+
const mfaResolution = await this._resolveUsableMfaMethods(mfaCheck.enrolledMethods, nativeSdkPolicy);
|
|
1096
|
+
|
|
1097
|
+
await this.updateSession(sessionId, {
|
|
1098
|
+
userId,
|
|
1099
|
+
email,
|
|
1100
|
+
completedFactors: [AuthMethod.EXTERNAL_OAUTH2],
|
|
1101
|
+
requiresMFA: true,
|
|
1102
|
+
requireStrongMFA: mfaResolution.requireStrongMFA,
|
|
1103
|
+
availableSecondFactorMethods: mfaResolution.availableMethods,
|
|
1104
|
+
enrolledSecondFactorMethods: mfaCheck.enrolledMethods,
|
|
1105
|
+
usableSecondFactorMethods: mfaResolution.usableMethods,
|
|
1106
|
+
});
|
|
1107
|
+
return { mfaRequired: true, sessionId, enrolledMethods: mfaCheck.enrolledMethods };
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// W4.5: MFA required but no strong factor enrolled — block token issuance, require enrollment
|
|
1111
|
+
const sessionId = this.sessionStore.generateSessionId();
|
|
1112
|
+
const secondFactorMethods = AuthUtils.getSecondFactorMethods();
|
|
1113
|
+
const availableEnrollment = secondFactorMethods.filter(
|
|
1114
|
+
m => nativeSdkPolicy.authMethodsEnabled?.[m],
|
|
1115
|
+
);
|
|
1116
|
+
|
|
1117
|
+
await this.createSession(sessionId, AuthenticationSessionState.MFA_ENROLLMENT_REQUIRED, { deviceInfo, activeUserType: nativeResolvedUserType });
|
|
1118
|
+
await this.updateSession(sessionId, {
|
|
1119
|
+
userId,
|
|
1120
|
+
email,
|
|
1121
|
+
completedFactors: [AuthMethod.EXTERNAL_OAUTH2],
|
|
1122
|
+
requiresMFA: true,
|
|
1123
|
+
requireStrongMFA: nativeSdkPolicy.mfaPolicy?.requireStrongMFA ?? false,
|
|
1124
|
+
nextStep: AuthNextStep.MFA_ENROLLMENT,
|
|
1125
|
+
availableEnrollmentMethods: availableEnrollment,
|
|
1126
|
+
});
|
|
1127
|
+
return { mfaRequired: true, sessionId, enrolledMethods: [] };
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const tokens = await this.tokenIssuer.issueTokensForUser(userId, undefined, {
|
|
1131
|
+
lastAuthenticatedAt: Math.floor(Date.now() / 1000),
|
|
1132
|
+
});
|
|
1133
|
+
return { mfaRequired: false, tokens };
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// ===============================
|
|
1137
|
+
// W4: REGISTRATION PIPELINE
|
|
1138
|
+
// ===============================
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* W4.1: Create a registration session after user account creation.
|
|
1142
|
+
* Called by `registerUser()` instead of returning a generic success message.
|
|
1143
|
+
* The session tracks the registration pipeline state (email verify → MFA enrollment → complete).
|
|
1144
|
+
*/
|
|
1145
|
+
public async createRegistrationSession(
|
|
1146
|
+
userId: string,
|
|
1147
|
+
email: string,
|
|
1148
|
+
options: {
|
|
1149
|
+
activeUserType?: string;
|
|
1150
|
+
purpose?: AuthSessionPurpose;
|
|
1151
|
+
deviceInfo?: { userAgent?: string; ipAddress?: string };
|
|
1152
|
+
pendingOrgType?: string;
|
|
1153
|
+
} = {},
|
|
1154
|
+
): Promise<AuthenticationSession> {
|
|
1155
|
+
const sessionId = this.sessionStore.generateSessionId();
|
|
1156
|
+
const session = await this.createSession(sessionId, AuthenticationSessionState.REGISTERED, {
|
|
1157
|
+
activeUserType: options.activeUserType,
|
|
1158
|
+
purpose: options.purpose ?? AuthSessionPurpose.REGISTRATION,
|
|
1159
|
+
email,
|
|
1160
|
+
userId,
|
|
1161
|
+
deviceInfo: options.deviceInfo,
|
|
1162
|
+
pendingOrgType: options.pendingOrgType,
|
|
1163
|
+
});
|
|
1164
|
+
return session;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/**
|
|
1168
|
+
* W4.1: Process email verification through the registration pipeline.
|
|
1169
|
+
* Instead of issuing tokens directly, transitions the session through:
|
|
1170
|
+
* EMAIL_VERIFIED → check MFA → MFA_ENROLLMENT_REQUIRED / MFA_ENROLLMENT_GRACE / COMPLETED.
|
|
1171
|
+
*
|
|
1172
|
+
* Returns the updated session with `nextStep` indicating what the frontend should do.
|
|
1173
|
+
*/
|
|
1174
|
+
public async processEmailVerification(
|
|
1175
|
+
ec: ExecutionContext<any>,
|
|
1176
|
+
userId: string,
|
|
1177
|
+
email: string,
|
|
1178
|
+
activeUserType?: string,
|
|
1179
|
+
deviceInfo?: { userAgent?: string; ipAddress?: string },
|
|
1180
|
+
purpose?: AuthSessionPurpose,
|
|
1181
|
+
): Promise<AuthenticationSession> {
|
|
1182
|
+
const authPolicy = activeUserType
|
|
1183
|
+
? await this._resolveAuthPolicyWithOrgOverrides(ec, activeUserType, userId)
|
|
1184
|
+
: AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
1185
|
+
|
|
1186
|
+
const sessionId = this.sessionStore.generateSessionId();
|
|
1187
|
+
const session = await this.createSession(sessionId, AuthenticationSessionState.EMAIL_VERIFIED, {
|
|
1188
|
+
activeUserType,
|
|
1189
|
+
purpose: purpose ?? AuthSessionPurpose.REGISTRATION,
|
|
1190
|
+
email,
|
|
1191
|
+
userId,
|
|
1192
|
+
deviceInfo,
|
|
1193
|
+
});
|
|
1194
|
+
|
|
1195
|
+
return this._advanceRegistrationPipeline(ec, session, authPolicy, userId);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* W4: Advance a registration session through the pipeline after a state transition.
|
|
1200
|
+
* Checks MFA requirements, grace period, and onboarding to determine next state.
|
|
1201
|
+
*/
|
|
1202
|
+
private async _advanceRegistrationPipeline(
|
|
1203
|
+
ec: ExecutionContext<any>,
|
|
1204
|
+
session: AuthenticationSession,
|
|
1205
|
+
authPolicy: UserTypeAuthPolicy,
|
|
1206
|
+
userId: string,
|
|
1207
|
+
): Promise<AuthenticationSession> {
|
|
1208
|
+
if (session.state !== AuthenticationSessionState.EMAIL_VERIFIED) {
|
|
1209
|
+
return session;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const mfaResult = await this._shouldRequireMFA(ec, userId, undefined, undefined, authPolicy);
|
|
1213
|
+
|
|
1214
|
+
const cred = await this.credentialOps.readByUserId(ec, userId);
|
|
1215
|
+
|
|
1216
|
+
if (mfaResult.required) {
|
|
1217
|
+
const hasEnrolledStrongFactor = mfaResult.enrolledMethods.some(m => m !== AuthMethod.EMAIL_OTP);
|
|
1218
|
+
|
|
1219
|
+
if (hasEnrolledStrongFactor) {
|
|
1220
|
+
if (cred && cred.mfaEnrollmentState !== MfaEnrollmentState.ENROLLED) {
|
|
1221
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.ENROLLED } as Partial<UserCredentials>);
|
|
1222
|
+
}
|
|
1223
|
+
return this._completeRegistrationSession(session);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
const gracePeriodDays = authPolicy.mfaPolicy?.enrollmentGracePeriodDays ?? 0;
|
|
1227
|
+
if (gracePeriodDays > 0) {
|
|
1228
|
+
const graceExpiresAt = new Date();
|
|
1229
|
+
graceExpiresAt.setDate(graceExpiresAt.getDate() + gracePeriodDays);
|
|
1230
|
+
|
|
1231
|
+
if (cred) {
|
|
1232
|
+
await this.credentialOps.updateById(ec, cred._id, {
|
|
1233
|
+
mfaEnrollmentState: MfaEnrollmentState.GRACE,
|
|
1234
|
+
firstMfaPromptAt: cred.firstMfaPromptAt ?? new Date(),
|
|
1235
|
+
} as Partial<UserCredentials>);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
const updated = await this.updateSession(session.sessionId, {
|
|
1239
|
+
state: AuthenticationSessionState.MFA_ENROLLMENT_GRACE,
|
|
1240
|
+
nextStep: AuthNextStep.COMPLETE,
|
|
1241
|
+
mfaGraceExpiresAt: graceExpiresAt.toISOString(),
|
|
1242
|
+
requiresMFA: true,
|
|
1243
|
+
});
|
|
1244
|
+
return updated ?? session;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
if (cred) {
|
|
1248
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.PENDING } as Partial<UserCredentials>);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const secondFactorMethods = AuthUtils.getSecondFactorMethods();
|
|
1252
|
+
const availableEnrollment = secondFactorMethods.filter(
|
|
1253
|
+
m => authPolicy.authMethodsEnabled?.[m],
|
|
1254
|
+
);
|
|
1255
|
+
|
|
1256
|
+
const updated = await this.updateSession(session.sessionId, {
|
|
1257
|
+
state: AuthenticationSessionState.MFA_ENROLLMENT_REQUIRED,
|
|
1258
|
+
nextStep: AuthNextStep.MFA_ENROLLMENT,
|
|
1259
|
+
requiresMFA: true,
|
|
1260
|
+
requireStrongMFA: authPolicy.mfaPolicy?.requireStrongMFA ?? false,
|
|
1261
|
+
availableEnrollmentMethods: availableEnrollment,
|
|
1262
|
+
});
|
|
1263
|
+
return updated ?? session;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
if (cred && cred.mfaEnrollmentState !== MfaEnrollmentState.NOT_REQUIRED && cred.mfaEnrollmentState !== MfaEnrollmentState.ENROLLED) {
|
|
1267
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.NOT_REQUIRED } as Partial<UserCredentials>);
|
|
1268
|
+
}
|
|
1269
|
+
return this._completeRegistrationSession(session);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* W4: Complete a registration session — transition to COMPLETED or ONBOARDING_PENDING state.
|
|
1274
|
+
* W5.7: When pendingOrgType is set, route to ONBOARDING_PENDING instead of COMPLETED.
|
|
1275
|
+
*/
|
|
1276
|
+
private async _completeRegistrationSession(session: AuthenticationSession): Promise<AuthenticationSession> {
|
|
1277
|
+
if (session.pendingOrgType) {
|
|
1278
|
+
const updated = await this.updateSession(session.sessionId, {
|
|
1279
|
+
state: AuthenticationSessionState.ONBOARDING_PENDING,
|
|
1280
|
+
nextStep: AuthNextStep.ONBOARDING,
|
|
1281
|
+
});
|
|
1282
|
+
return updated ?? session;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
const updated = await this.updateSession(session.sessionId, {
|
|
1286
|
+
state: AuthenticationSessionState.COMPLETED,
|
|
1287
|
+
nextStep: AuthNextStep.COMPLETE,
|
|
1288
|
+
});
|
|
1289
|
+
return updated ?? session;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* W4.3: Complete MFA enrollment during registration pipeline.
|
|
1294
|
+
* Called after the user successfully enrolls an MFA method during registration.
|
|
1295
|
+
* Transitions from MFA_ENROLLMENT_REQUIRED → COMPLETED and issues tokens.
|
|
1296
|
+
*/
|
|
1297
|
+
public async completeRegistrationMfaEnrollment(
|
|
1298
|
+
ec: ExecutionContext<any>,
|
|
1299
|
+
sessionId: string,
|
|
1300
|
+
): Promise<AuthenticationSession> {
|
|
1301
|
+
const session = await this.getSession(sessionId);
|
|
1302
|
+
if (!session) {
|
|
1303
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1304
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_EXPIRED,
|
|
1305
|
+
context: { message: 'Registration session not found or expired' },
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
if (session.state !== AuthenticationSessionState.MFA_ENROLLMENT_REQUIRED &&
|
|
1310
|
+
session.state !== AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS) {
|
|
1311
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1312
|
+
context: { message: `Cannot complete MFA enrollment from state: ${session.state}` },
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// W4.9 SEC FIX: Verify that a strong MFA method was actually enrolled before completing
|
|
1317
|
+
if (!session.userId) {
|
|
1318
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1319
|
+
context: { message: 'Session missing userId — cannot complete MFA enrollment' },
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
const cred = await this.credentialOps.readByUserId(ec, session.userId);
|
|
1324
|
+
const enrolledMethods = AuthUtils.getEnrolledSecondFactorMethods(cred);
|
|
1325
|
+
const hasStrongFactor = enrolledMethods.some(m => m !== AuthMethod.EMAIL_OTP);
|
|
1326
|
+
|
|
1327
|
+
if (!hasStrongFactor) {
|
|
1328
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1329
|
+
context: { message: 'No MFA method has been enrolled yet. Complete MFA setup before continuing.' },
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
if (cred && cred.mfaEnrollmentState !== MfaEnrollmentState.ENROLLED) {
|
|
1334
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.ENROLLED } as Partial<UserCredentials>);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
return this._completeRegistrationSession(session);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
/**
|
|
1341
|
+
* W5.7: Complete org onboarding — create the deferred organization and transition to COMPLETED.
|
|
1342
|
+
* Called by the guidance/onboarding flow after collecting the org name from the user.
|
|
1343
|
+
*/
|
|
1344
|
+
public async completeOrgOnboarding(
|
|
1345
|
+
ec: ExecutionContext<any>,
|
|
1346
|
+
sessionId: string,
|
|
1347
|
+
organizationName: string,
|
|
1348
|
+
): Promise<AuthenticationSession> {
|
|
1349
|
+
const session = await this.getSession(sessionId);
|
|
1350
|
+
if (!session) {
|
|
1351
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1352
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_EXPIRED,
|
|
1353
|
+
context: { message: 'Session not found or expired' },
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
if (session.state !== AuthenticationSessionState.ONBOARDING_PENDING) {
|
|
1358
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1359
|
+
context: { message: `Cannot complete org onboarding from state: ${session.state}` },
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
if (!session.pendingOrgType || !session.userId || !session.email) {
|
|
1364
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1365
|
+
context: { message: 'Session missing pendingOrgType, userId, or email' },
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
const trimmedName = organizationName.trim();
|
|
1370
|
+
if (!trimmedName) {
|
|
1371
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, undefined, {
|
|
1372
|
+
context: { message: 'Organization name is required' },
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
const orgTypeDef = (this.appConfigService.config as any)?.organizationTypes?.[session.pendingOrgType];
|
|
1377
|
+
const policy = orgTypeDef?.creationPolicy;
|
|
1378
|
+
|
|
1379
|
+
const orgResult = await createOrgOnRegistration(ec, {
|
|
1380
|
+
userId: session.userId,
|
|
1381
|
+
userEmail: session.email,
|
|
1382
|
+
activeUserType: session.activeUserType ?? '',
|
|
1383
|
+
organizationName: trimmedName,
|
|
1384
|
+
organizationTypes: {
|
|
1385
|
+
[session.pendingOrgType]: {
|
|
1386
|
+
creationPolicy: {
|
|
1387
|
+
createOnUserTypeRegistration: [session.activeUserType ?? ''],
|
|
1388
|
+
orgNameSource: 'ask' as const,
|
|
1389
|
+
defaultOwnerRole: policy?.defaultOwnerRole,
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
},
|
|
1393
|
+
servicesRegistryHandler: this.servicesRegistryHandler,
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
if (orgResult.created && orgResult.organizationId) {
|
|
1397
|
+
const organizationTypes = (this.appConfigService.config as any)?.organizationTypes;
|
|
1398
|
+
await grantUserTypesOnOrgJoin(ec, {
|
|
1399
|
+
userId: session.userId,
|
|
1400
|
+
organizationId: orgResult.organizationId,
|
|
1401
|
+
organizationTypes,
|
|
1402
|
+
servicesRegistryHandler: this.servicesRegistryHandler,
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
const updated = await this.updateSession(session.sessionId, {
|
|
1407
|
+
state: AuthenticationSessionState.COMPLETED,
|
|
1408
|
+
nextStep: AuthNextStep.COMPLETE,
|
|
1409
|
+
pendingOrgType: undefined,
|
|
1410
|
+
organizationId: orgResult.organizationId,
|
|
1411
|
+
});
|
|
1412
|
+
return updated ?? session;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// ===============================
|
|
1416
|
+
// MAIN AUTHENTICATE DISPATCH
|
|
1417
|
+
// ===============================
|
|
1418
|
+
|
|
1419
|
+
public async authenticate(ec: ExecutionContext<any>, request: AuthenticationRequest): Promise<AuthenticationResponse> {
|
|
1420
|
+
this.logDebug('Main authenticate method called', {
|
|
1421
|
+
sessionId: request.sessionId,
|
|
1422
|
+
method: request.method,
|
|
1423
|
+
factorLevel: request.factorLevel,
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
let authResponse: AuthenticationResponse;
|
|
1427
|
+
|
|
1428
|
+
// Step 1: Dispatch to the method-specific handler.
|
|
1429
|
+
// Capture discriminant before switch to preserve type information for error fallback.
|
|
1430
|
+
const method = request.method;
|
|
1431
|
+
switch (method) {
|
|
1432
|
+
case AuthMethod.PASSWORD: {
|
|
1433
|
+
const session = await this.getSession(request.sessionId);
|
|
1434
|
+
if (!session) {
|
|
1435
|
+
return this.__buildAuthenticationErrorMethod(request.sessionId, request.factorLevel, { retryAllowed: false });
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
const email = session.email;
|
|
1439
|
+
if (!email) {
|
|
1440
|
+
return this.__buildAuthenticationErrorMethod(request.sessionId, request.factorLevel, { retryAllowed: true });
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
try {
|
|
1444
|
+
authResponse = await this.authenticatePassword(ec, request as PasswordAuthRequest);
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
throw error;
|
|
1447
|
+
}
|
|
1448
|
+
break;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
case AuthMethod.EMAIL_OTP: {
|
|
1452
|
+
authResponse = await this.authenticateEmailOTP(ec, request as EmailOTPAuthRequest);
|
|
1453
|
+
break;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
case AuthMethod.TOTP: {
|
|
1457
|
+
authResponse = await this.authenticateTOTP(ec, request as TOTPAuthRequest);
|
|
1458
|
+
break;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
case AuthMethod.PASSKEY: {
|
|
1462
|
+
authResponse = await this.authenticatePasskey(ec, request as PasskeyAuthRequest);
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
case AuthMethod.SMS_OTP: {
|
|
1467
|
+
authResponse = await this.authenticateSMSOTP(ec, request as SMSOTPAuthRequest);
|
|
1468
|
+
break;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
default:
|
|
1472
|
+
// Unimplemented methods return a clean error.
|
|
1473
|
+
// sessionId and factorLevel exist on BaseAuthRequestSchema — shared by all union variants.
|
|
1474
|
+
return this.__buildAuthenticationErrorMethod(
|
|
1475
|
+
request.sessionId,
|
|
1476
|
+
request.factorLevel ?? AuthFactorLevel.FIRST,
|
|
1477
|
+
{ retryAllowed: true },
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
this.logDebug('Authentication method result', {
|
|
1482
|
+
sessionId: request.sessionId,
|
|
1483
|
+
method: request.method,
|
|
1484
|
+
success: authResponse.success,
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
// Step 2: If method succeeded, check if overall authentication is complete.
|
|
1488
|
+
if (authResponse.success) {
|
|
1489
|
+
const session = await this.getSession(request.sessionId);
|
|
1490
|
+
if (!session) {
|
|
1491
|
+
return this.__buildAuthenticationErrorMethod(request.sessionId, request.factorLevel, { retryAllowed: false });
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
const isComplete = this._isAuthenticationComplete(session, request.factorLevel, request.method);
|
|
1495
|
+
|
|
1496
|
+
if (isComplete) {
|
|
1497
|
+
this.logDebug('Authentication complete, issuing tokens', { sessionId: request.sessionId });
|
|
1498
|
+
|
|
1499
|
+
// S0.7 Layer 1: Re-check user status before token issuance (catches race conditions and all auth paths)
|
|
1500
|
+
if (session.userId) {
|
|
1501
|
+
const currentUser = await this.userLookup.findUserById(ec, session.userId);
|
|
1502
|
+
if (!currentUser || currentUser.status !== UserStatus.ACTIVE) {
|
|
1503
|
+
await this.updateSession(request.sessionId, { state: AuthenticationSessionState.FAILED });
|
|
1504
|
+
this._enforceUserStatus(currentUser || { status: UserStatus.DELETED } as User, request.sessionId);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// W3.1b: Validate user-type membership — user's userTypes[] must include the session's activeUserType
|
|
1508
|
+
if (session.activeUserType && currentUser) {
|
|
1509
|
+
const userTypes = (currentUser as User & { userTypes?: string[] }).userTypes ?? [];
|
|
1510
|
+
if (!userTypes.includes(session.activeUserType)) {
|
|
1511
|
+
await this.updateSession(request.sessionId, { state: AuthenticationSessionState.FAILED });
|
|
1512
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined, {
|
|
1513
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_USER_TYPE_MISMATCH,
|
|
1514
|
+
context: { message: 'Your account is not registered for this application.', activeUserType: session.activeUserType },
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// W2.2 + W3.1 + AUTH-14: Password expiry check with org overrides
|
|
1521
|
+
const sessionAuthPolicy = session.userId
|
|
1522
|
+
? await this._resolveAuthPolicyWithOrgOverrides(ec, session.activeUserType, session.userId)
|
|
1523
|
+
: this._resolveAuthPolicyFromSession(session);
|
|
1524
|
+
const expiryDays = sessionAuthPolicy.passwordPolicy?.expiryDays ?? 0;
|
|
1525
|
+
if (expiryDays > 0 && session.userId) {
|
|
1526
|
+
const expired = await this.credentialOps.isPasswordExpired(ec, session.userId, expiryDays);
|
|
1527
|
+
if (expired) {
|
|
1528
|
+
await this.updateSession(request.sessionId, { state: AuthenticationSessionState.PASSWORD_EXPIRED });
|
|
1529
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1530
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_PASSWORD_EXPIRED,
|
|
1531
|
+
context: { sessionId: request.sessionId, reason: 'PASSWORD_EXPIRED' },
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
const tokens = await this.tokenIssuer.issueTokens(session, {
|
|
1537
|
+
includeRefreshToken: true,
|
|
1538
|
+
lastAuthenticatedAt: Math.floor(Date.now() / 1000),
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
// Update session to completed
|
|
1542
|
+
await this.updateSession(request.sessionId, { state: AuthenticationSessionState.COMPLETED });
|
|
1543
|
+
|
|
1544
|
+
// Get final session for audit log
|
|
1545
|
+
const finalSession = await this.getSession(request.sessionId);
|
|
1546
|
+
const completedFactors = finalSession?.completedFactors || session.completedFactors || [];
|
|
1547
|
+
|
|
1548
|
+
// Audit log successful authentication (TRAP 13)
|
|
1549
|
+
const deviceInfo = finalSession?.deviceInfo;
|
|
1550
|
+
if (finalSession?.userId) {
|
|
1551
|
+
await this.auditLogsService.logUserLogin({
|
|
1552
|
+
userId: finalSession.userId,
|
|
1553
|
+
email: finalSession.email || 'unknown',
|
|
1554
|
+
authMethod: request.method,
|
|
1555
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
1556
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
1557
|
+
sessionId: request.sessionId,
|
|
1558
|
+
organizationId: finalSession.organizationId,
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// Clean up session after successful authentication
|
|
1563
|
+
await this.removeSession(request.sessionId);
|
|
1564
|
+
|
|
1565
|
+
return this._buildAuthenticationSuccessMethod(
|
|
1566
|
+
request.sessionId,
|
|
1567
|
+
request.factorLevel,
|
|
1568
|
+
request.method,
|
|
1569
|
+
tokens.accessToken,
|
|
1570
|
+
{
|
|
1571
|
+
refreshToken: tokens.refreshToken,
|
|
1572
|
+
completedFactors,
|
|
1573
|
+
},
|
|
1574
|
+
);
|
|
1575
|
+
} else {
|
|
1576
|
+
// Method succeeded but overall auth is not complete (e.g., MFA required)
|
|
1577
|
+
return authResponse;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
return authResponse;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
// ===============================
|
|
1585
|
+
// PUBLIC API: SESSION STATE
|
|
1586
|
+
// ===============================
|
|
1587
|
+
|
|
1588
|
+
/**
|
|
1589
|
+
* Get the current state of an authentication session.
|
|
1590
|
+
*
|
|
1591
|
+
* TRAP 2 (async change): This method is now async because Redis lookups are Promise-based.
|
|
1592
|
+
* The controller must add `await` to this call — this is the one allowed controller modification.
|
|
1593
|
+
*/
|
|
1594
|
+
public async getAuthenticationSessionState(ec: ExecutionContext<any>, sessionId: string): Promise<AuthenticationSession | null> {
|
|
1595
|
+
const session = await this.getSession(sessionId);
|
|
1596
|
+
if (!session) {
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
// Return a copy to avoid external modifications
|
|
1600
|
+
return { ...session };
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// ===============================
|
|
1604
|
+
// EMAIL OTP AUTHENTICATION (Step 10)
|
|
1605
|
+
// ===============================
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Send an Email OTP to the user's email address.
|
|
1609
|
+
*
|
|
1610
|
+
* Called from the auth controller (POST /auth/mfa/email-otp/send).
|
|
1611
|
+
* Generates a 6-digit OTP, stores it as a consumable token, and returns
|
|
1612
|
+
* the session state. The actual email sending is done by the controller.
|
|
1613
|
+
*
|
|
1614
|
+
* Rate limiting: Redis INCR with TTL. Values from config.auth.otpOperational.
|
|
1615
|
+
*/
|
|
1616
|
+
public async sendEmailOTP(ec: ExecutionContext<any>, sessionId: string): Promise<{ otpToken: string; email: string; expiryMinutes: number }> {
|
|
1617
|
+
const session = await this.getSession(sessionId);
|
|
1618
|
+
if (!session) {
|
|
1619
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1620
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_INVALID,
|
|
1621
|
+
context: { sessionId },
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// Must have completed first factor before MFA
|
|
1626
|
+
if (session.state !== AuthenticationSessionState.FIRST_FACTOR_COMPLETED &&
|
|
1627
|
+
session.state !== AuthenticationSessionState.MFA_REQUIRED) {
|
|
1628
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1629
|
+
context: { message: 'First factor authentication must be completed before requesting Email OTP' },
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
const email = session.email;
|
|
1634
|
+
if (!email) {
|
|
1635
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1636
|
+
context: { message: 'No email associated with this session' },
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
const userId = session.userId;
|
|
1641
|
+
if (!userId) {
|
|
1642
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
1643
|
+
context: { message: 'No user associated with this session' },
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// Rate limiting — Redis INCR with 60s window. Values from config.auth.otpOperational.
|
|
1648
|
+
const rateLimitKey = `${AUTH_REDIS_KEYS.EMAIL_OTP}${userId}:email_otp`;
|
|
1649
|
+
const currentCount = await this.redisService.incrementRateLimit(rateLimitKey, 60);
|
|
1650
|
+
if (currentCount > this.otpConfig.emailOtp.rateLimitPerMinute) {
|
|
1651
|
+
throw this.errorBuilder.buildError(ErrorType.RATE_LIMIT, undefined, {
|
|
1652
|
+
context: {
|
|
1653
|
+
message: 'Too many OTP requests. Please wait before requesting another code.',
|
|
1654
|
+
retryAfterSeconds: 60,
|
|
1655
|
+
},
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
// Revoke any existing EMAIL_OTP tokens for this user to ensure only one valid OTP at a time
|
|
1660
|
+
await this.consumableTokenService.revokeTokensByRelatedId(userId, CoreConsumableTokenTypes.EMAIL_OTP);
|
|
1661
|
+
|
|
1662
|
+
// Generate OTP — cryptographically random N-digit code
|
|
1663
|
+
const otpLength = this.otpConfig.emailOtp.otpLength;
|
|
1664
|
+
const otpCode = this._generateOTP(otpLength);
|
|
1665
|
+
|
|
1666
|
+
// Store as consumable token (SINGLE_USE, configurable TTL)
|
|
1667
|
+
const expiryMinutes = this.otpConfig.emailOtp.expiryMinutes;
|
|
1668
|
+
await this.consumableTokenService.createToken({
|
|
1669
|
+
tokenType: CoreConsumableTokenTypes.EMAIL_OTP,
|
|
1670
|
+
consumptionMode: ConsumableToken_ConsumptionMode.SINGLE_USE,
|
|
1671
|
+
expiresIn: { value: expiryMinutes, unit: DurationUnit.MINUTES },
|
|
1672
|
+
userId: userId,
|
|
1673
|
+
resourceIdentifier: CoreResourceType.USERS,
|
|
1674
|
+
relatedId: userId,
|
|
1675
|
+
metadata: {
|
|
1676
|
+
otpCode,
|
|
1677
|
+
sessionId,
|
|
1678
|
+
email,
|
|
1679
|
+
},
|
|
1680
|
+
});
|
|
1681
|
+
|
|
1682
|
+
// Update session to MFA_REQUIRED state
|
|
1683
|
+
await this.updateSession(sessionId, {
|
|
1684
|
+
state: AuthenticationSessionState.MFA_REQUIRED,
|
|
1685
|
+
currentFactor: AuthFactorLevel.SECOND,
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
this.logDebug('Email OTP generated and stored', { sessionId, userId });
|
|
1689
|
+
|
|
1690
|
+
return { otpToken: otpCode, email, expiryMinutes };
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
/**
|
|
1694
|
+
* Verify an Email OTP code submitted by the user.
|
|
1695
|
+
*
|
|
1696
|
+
* Called from authenticate() dispatch when method=EMAIL_OTP,
|
|
1697
|
+
* or directly from the auth controller (POST /auth/mfa/email-otp/verify).
|
|
1698
|
+
*/
|
|
1699
|
+
public async authenticateEmailOTP(ec: ExecutionContext<any>, request: EmailOTPAuthRequest): Promise<AuthenticationResponse> {
|
|
1700
|
+
const { sessionId, token } = request;
|
|
1701
|
+
|
|
1702
|
+
const session = await this.getSession(sessionId);
|
|
1703
|
+
if (!session) {
|
|
1704
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, { retryAllowed: false });
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// Must be in MFA_REQUIRED, SECOND_FACTOR_IN_PROGRESS, or FIRST_FACTOR_COMPLETED state.
|
|
1708
|
+
// FIRST_FACTOR_COMPLETED is accepted because the MFA flow may not have explicitly
|
|
1709
|
+
// transitioned to MFA_REQUIRED yet (consistent with TOTP which has no "send" step).
|
|
1710
|
+
if (session.state !== AuthenticationSessionState.MFA_REQUIRED &&
|
|
1711
|
+
session.state !== AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS &&
|
|
1712
|
+
session.state !== AuthenticationSessionState.FIRST_FACTOR_COMPLETED) {
|
|
1713
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, {
|
|
1714
|
+
retryAllowed: true,
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
if (!token) {
|
|
1719
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, {
|
|
1720
|
+
retryAllowed: true,
|
|
1721
|
+
authMethod: AuthMethod.EMAIL_OTP,
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
// Update session to in-progress
|
|
1726
|
+
await this.updateSession(sessionId, {
|
|
1727
|
+
state: AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS,
|
|
1728
|
+
currentFactor: AuthFactorLevel.SECOND,
|
|
1729
|
+
});
|
|
1730
|
+
|
|
1731
|
+
const userId = session.userId;
|
|
1732
|
+
if (!userId) {
|
|
1733
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, { retryAllowed: false });
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// Find matching consumable token by looking up EMAIL_OTP tokens for this user.
|
|
1737
|
+
// We verify the OTP code matches the stored metadata.
|
|
1738
|
+
const isValid = await this._verifyEmailOTP(userId, sessionId, token);
|
|
1739
|
+
|
|
1740
|
+
if (!isValid) {
|
|
1741
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
1742
|
+
|
|
1743
|
+
// Audit log MFA failure
|
|
1744
|
+
const deviceInfo = session.deviceInfo;
|
|
1745
|
+
await this.auditLogsService.logUserLoginFailed({
|
|
1746
|
+
email: session.email || 'unknown',
|
|
1747
|
+
authMethod: AuthMethod.EMAIL_OTP,
|
|
1748
|
+
failureReason: 'Invalid OTP code',
|
|
1749
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
1750
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
1751
|
+
attemptsRemaining: session.maxAttempts - session.attempts - 1,
|
|
1752
|
+
sessionId,
|
|
1753
|
+
});
|
|
1754
|
+
|
|
1755
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, {
|
|
1756
|
+
authMethod: AuthMethod.EMAIL_OTP,
|
|
1757
|
+
retryAllowed: !locked,
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// OTP verified — update session
|
|
1762
|
+
await this._updateSessionAfterSuccessfulAuth(ec, sessionId, userId, AuthMethod.EMAIL_OTP);
|
|
1763
|
+
|
|
1764
|
+
const updatedSession = await this.getSession(sessionId);
|
|
1765
|
+
return this._buildAuthenticationSuccessMethod(
|
|
1766
|
+
sessionId,
|
|
1767
|
+
AuthFactorLevel.SECOND,
|
|
1768
|
+
AuthMethod.EMAIL_OTP,
|
|
1769
|
+
'', // Tokens issued by authenticate() after completion check
|
|
1770
|
+
{ completedFactors: updatedSession?.completedFactors || [] },
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
/**
|
|
1775
|
+
* Verify the OTP code against stored consumable tokens for this user and session.
|
|
1776
|
+
* Attempts to consume the token atomically to prevent replay.
|
|
1777
|
+
*/
|
|
1778
|
+
private async _verifyEmailOTP(userId: string, sessionId: string, code: string): Promise<boolean> {
|
|
1779
|
+
try {
|
|
1780
|
+
// Find unconsumed EMAIL_OTP tokens for this user
|
|
1781
|
+
const tokens = await this.consumableTokenService.findTokensByRelatedId(
|
|
1782
|
+
userId,
|
|
1783
|
+
CoreConsumableTokenTypes.EMAIL_OTP,
|
|
1784
|
+
);
|
|
1785
|
+
|
|
1786
|
+
for (const tokenDoc of tokens) {
|
|
1787
|
+
const metadata = tokenDoc.metadata as Record<string, unknown> | undefined;
|
|
1788
|
+
if (!metadata?.otpCode || !metadata?.sessionId) continue;
|
|
1789
|
+
|
|
1790
|
+
// L1 fix: constant-time comparison to prevent timing side-channel on OTP
|
|
1791
|
+
const storedCode = String(metadata.otpCode);
|
|
1792
|
+
const storedSession = String(metadata.sessionId);
|
|
1793
|
+
if (storedCode.length !== code.length || storedSession.length !== sessionId.length) continue;
|
|
1794
|
+
|
|
1795
|
+
const codeMatch = crypto.timingSafeEqual(Buffer.from(storedCode), Buffer.from(code));
|
|
1796
|
+
const sessionMatch = crypto.timingSafeEqual(Buffer.from(storedSession), Buffer.from(sessionId));
|
|
1797
|
+
|
|
1798
|
+
if (codeMatch && sessionMatch) {
|
|
1799
|
+
// Consume the token atomically
|
|
1800
|
+
try {
|
|
1801
|
+
await this.consumableTokenService.consumeToken(tokenDoc.token);
|
|
1802
|
+
return true;
|
|
1803
|
+
} catch {
|
|
1804
|
+
// Token already consumed or expired — try next
|
|
1805
|
+
continue;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
return false;
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
if (isWildoBackendError(error)) {
|
|
1813
|
+
throw error;
|
|
1814
|
+
}
|
|
1815
|
+
this.logger.error('Failed to verify Email OTP', {
|
|
1816
|
+
userId,
|
|
1817
|
+
sessionId,
|
|
1818
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1819
|
+
});
|
|
1820
|
+
return false;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
// ===============================
|
|
1825
|
+
// TOTP AUTHENTICATION (Step 11)
|
|
1826
|
+
// ===============================
|
|
1827
|
+
|
|
1828
|
+
/**
|
|
1829
|
+
* Verify a TOTP code submitted by the user.
|
|
1830
|
+
*
|
|
1831
|
+
* Called from authenticate() dispatch when method=TOTP.
|
|
1832
|
+
* Reads the user's verified TOTP secret from their credential record,
|
|
1833
|
+
* validates the code using the otpauth library.
|
|
1834
|
+
*/
|
|
1835
|
+
public async authenticateTOTP(ec: ExecutionContext<any>, request: TOTPAuthRequest): Promise<AuthenticationResponse> {
|
|
1836
|
+
const { sessionId, token } = request;
|
|
1837
|
+
|
|
1838
|
+
const session = await this.getSession(sessionId);
|
|
1839
|
+
if (!session) {
|
|
1840
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, { retryAllowed: false });
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// Must be in MFA_REQUIRED or SECOND_FACTOR_IN_PROGRESS state
|
|
1844
|
+
if (session.state !== AuthenticationSessionState.MFA_REQUIRED &&
|
|
1845
|
+
session.state !== AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS &&
|
|
1846
|
+
session.state !== AuthenticationSessionState.FIRST_FACTOR_COMPLETED) {
|
|
1847
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, {
|
|
1848
|
+
retryAllowed: true,
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// Update session to in-progress
|
|
1853
|
+
await this.updateSession(sessionId, {
|
|
1854
|
+
state: AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS,
|
|
1855
|
+
currentFactor: AuthFactorLevel.SECOND,
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1858
|
+
const userId = session.userId;
|
|
1859
|
+
if (!userId) {
|
|
1860
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, { retryAllowed: false });
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
const cred = await this.credentialOps.readByUserId(ec, userId);
|
|
1864
|
+
|
|
1865
|
+
if (!cred || !cred.totpVerified || !cred.secretBase32) {
|
|
1866
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, {
|
|
1867
|
+
authMethod: AuthMethod.TOTP,
|
|
1868
|
+
retryAllowed: true,
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
const { TOTP } = await import('otpauth');
|
|
1873
|
+
const { algorithm, digits, period, window } = this.totpConfig;
|
|
1874
|
+
const totp = new TOTP({
|
|
1875
|
+
secret: cred.secretBase32,
|
|
1876
|
+
algorithm,
|
|
1877
|
+
digits,
|
|
1878
|
+
period,
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
const delta = totp.validate({ token, window });
|
|
1882
|
+
let isValidTOTP = delta !== null;
|
|
1883
|
+
|
|
1884
|
+
// M7 fix: TOTP anti-replay — reject codes at or before the last used time step (RFC 6238 §5.2)
|
|
1885
|
+
// Store the absolute time step counter (current period + delta) instead of relative delta,
|
|
1886
|
+
// so comparisons remain valid across time period boundaries.
|
|
1887
|
+
if (isValidTOTP) {
|
|
1888
|
+
const currentTimeStep = Math.floor(Date.now() / (period * 1000));
|
|
1889
|
+
const absoluteStep = currentTimeStep + delta!;
|
|
1890
|
+
const replayKey = `${AUTH_REDIS_KEYS.TOTP_USED}${userId}`;
|
|
1891
|
+
const lastUsedStep = await this.redisService.get<string>(replayKey);
|
|
1892
|
+
if (lastUsedStep !== null && absoluteStep <= parseInt(lastUsedStep as string, 10)) {
|
|
1893
|
+
isValidTOTP = false;
|
|
1894
|
+
} else {
|
|
1895
|
+
await this.redisService.set(replayKey, String(absoluteStep), { ttl: 90 });
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// If TOTP code fails, try backup codes
|
|
1900
|
+
let usedBackupCode = false;
|
|
1901
|
+
if (!isValidTOTP && cred.backupCodesHashed?.length > 0) {
|
|
1902
|
+
const inputHash = crypto.createHash('sha256').update(token).digest('hex');
|
|
1903
|
+
const inputBuf = Buffer.from(inputHash, 'hex');
|
|
1904
|
+
|
|
1905
|
+
// L2 fix: constant-time comparison iterating ALL hashes to prevent timing leak
|
|
1906
|
+
let matchIndex = -1;
|
|
1907
|
+
for (let i = 0; i < cred.backupCodesHashed.length; i++) {
|
|
1908
|
+
const storedBuf = Buffer.from(cred.backupCodesHashed[i], 'hex');
|
|
1909
|
+
if (inputBuf.length === storedBuf.length && crypto.timingSafeEqual(inputBuf, storedBuf)) {
|
|
1910
|
+
matchIndex = i;
|
|
1911
|
+
// Don't break — always compare all to prevent timing leak
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
if (matchIndex >= 0) {
|
|
1916
|
+
const updatedCodes = [...cred.backupCodesHashed];
|
|
1917
|
+
updatedCodes.splice(matchIndex, 1);
|
|
1918
|
+
await this.credentialOps.updateBackupCodes(ec, cred._id, updatedCodes);
|
|
1919
|
+
usedBackupCode = true;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
if (!isValidTOTP && !usedBackupCode) {
|
|
1924
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
1925
|
+
|
|
1926
|
+
// Audit log MFA failure
|
|
1927
|
+
const deviceInfo = session.deviceInfo;
|
|
1928
|
+
await this.auditLogsService.logUserLoginFailed({
|
|
1929
|
+
email: session.email || 'unknown',
|
|
1930
|
+
authMethod: AuthMethod.TOTP,
|
|
1931
|
+
failureReason: 'Invalid TOTP code',
|
|
1932
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
1933
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
1934
|
+
attemptsRemaining: session.maxAttempts - session.attempts - 1,
|
|
1935
|
+
sessionId,
|
|
1936
|
+
});
|
|
1937
|
+
|
|
1938
|
+
return this.__buildAuthenticationErrorMethod(sessionId, AuthFactorLevel.SECOND, {
|
|
1939
|
+
authMethod: AuthMethod.TOTP,
|
|
1940
|
+
retryAllowed: !locked,
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
// TOTP verified — update session
|
|
1945
|
+
await this._updateSessionAfterSuccessfulAuth(ec, sessionId, userId, AuthMethod.TOTP);
|
|
1946
|
+
|
|
1947
|
+
const updatedSession = await this.getSession(sessionId);
|
|
1948
|
+
return this._buildAuthenticationSuccessMethod(
|
|
1949
|
+
sessionId,
|
|
1950
|
+
AuthFactorLevel.SECOND,
|
|
1951
|
+
AuthMethod.TOTP,
|
|
1952
|
+
'', // Tokens issued by authenticate() after completion check
|
|
1953
|
+
{
|
|
1954
|
+
completedFactors: updatedSession?.completedFactors || [],
|
|
1955
|
+
challengeData: usedBackupCode ? { usedBackupCode: true } : undefined,
|
|
1956
|
+
},
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
// ===============================
|
|
1961
|
+
// PASSKEY AUTHENTICATION (Phase G1)
|
|
1962
|
+
// ===============================
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* Verify a WebAuthn/Passkey authentication response.
|
|
1966
|
+
*
|
|
1967
|
+
* Called from authenticate() dispatch when method=PASSKEY.
|
|
1968
|
+
* Supports both first factor (passwordless) and second factor (MFA) usage.
|
|
1969
|
+
* Delegates to WebAuthnBackendService for cryptographic verification.
|
|
1970
|
+
*/
|
|
1971
|
+
public async authenticatePasskey(ec: ExecutionContext<any>, request: PasskeyAuthRequest): Promise<AuthenticationResponse> {
|
|
1972
|
+
const { sessionId, factorLevel, response } = request;
|
|
1973
|
+
|
|
1974
|
+
const session = await this.getSession(sessionId);
|
|
1975
|
+
if (!session) {
|
|
1976
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, { retryAllowed: false });
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// State machine guard — valid states depend on factor level
|
|
1980
|
+
const validStates = factorLevel === AuthFactorLevel.FIRST
|
|
1981
|
+
? new Set([AuthenticationSessionState.IDENTIFIED, AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS])
|
|
1982
|
+
: new Set([AuthenticationSessionState.MFA_REQUIRED, AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS, AuthenticationSessionState.FIRST_FACTOR_COMPLETED]);
|
|
1983
|
+
|
|
1984
|
+
if (!validStates.has(session.state)) {
|
|
1985
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, {
|
|
1986
|
+
authMethod: AuthMethod.PASSKEY,
|
|
1987
|
+
retryAllowed: true,
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
const userId = session.userId;
|
|
1992
|
+
if (!userId) {
|
|
1993
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, { retryAllowed: false });
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
// Update session to in-progress
|
|
1997
|
+
await this.updateSession(sessionId, {
|
|
1998
|
+
state: factorLevel === AuthFactorLevel.FIRST
|
|
1999
|
+
? AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS
|
|
2000
|
+
: AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS,
|
|
2001
|
+
currentFactor: factorLevel,
|
|
2002
|
+
});
|
|
2003
|
+
|
|
2004
|
+
// Delegate to WebAuthn service for cryptographic verification
|
|
2005
|
+
let verified = false;
|
|
2006
|
+
let credentialId = response.id;
|
|
2007
|
+
try {
|
|
2008
|
+
const result = await this.webAuthnService.verifyAuthenticationResponse(ec, userId, response as any);
|
|
2009
|
+
verified = result.verified;
|
|
2010
|
+
credentialId = result.credentialId;
|
|
2011
|
+
} catch (error) {
|
|
2012
|
+
this.logger.warn('WebAuthn verification threw an error', {
|
|
2013
|
+
userId,
|
|
2014
|
+
sessionId,
|
|
2015
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2016
|
+
});
|
|
2017
|
+
verified = false;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
if (!verified) {
|
|
2021
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
2022
|
+
|
|
2023
|
+
// Audit log passkey auth failure
|
|
2024
|
+
const deviceInfo = session.deviceInfo;
|
|
2025
|
+
await this.auditLogsService.logUserPasskeyAuthFailure({
|
|
2026
|
+
email: session.email || 'unknown',
|
|
2027
|
+
failureReason: 'WebAuthn verification failed',
|
|
2028
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2029
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2030
|
+
sessionId,
|
|
2031
|
+
});
|
|
2032
|
+
|
|
2033
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, {
|
|
2034
|
+
authMethod: AuthMethod.PASSKEY,
|
|
2035
|
+
retryAllowed: !locked,
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// Passkey verified — audit log success
|
|
2040
|
+
const deviceInfo = session.deviceInfo;
|
|
2041
|
+
await this.auditLogsService.logUserPasskeyAuthSuccess({
|
|
2042
|
+
userId: userId,
|
|
2043
|
+
email: session.email || 'unknown',
|
|
2044
|
+
credentialId,
|
|
2045
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2046
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2047
|
+
sessionId,
|
|
2048
|
+
});
|
|
2049
|
+
|
|
2050
|
+
// C1 fix: Reset global lockout counter on successful authentication
|
|
2051
|
+
if (session.email) {
|
|
2052
|
+
await this._resetGlobalAttempts(session.email);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
// Update session state
|
|
2056
|
+
await this._updateSessionAfterSuccessfulAuth(ec, sessionId, userId, AuthMethod.PASSKEY);
|
|
2057
|
+
|
|
2058
|
+
const updatedSession = await this.getSession(sessionId);
|
|
2059
|
+
return this._buildAuthenticationSuccessMethod(
|
|
2060
|
+
sessionId,
|
|
2061
|
+
factorLevel,
|
|
2062
|
+
AuthMethod.PASSKEY,
|
|
2063
|
+
'', // Tokens issued by authenticate() after completion check
|
|
2064
|
+
{
|
|
2065
|
+
completedFactors: updatedSession?.completedFactors || [],
|
|
2066
|
+
requiresMFA: updatedSession?.requiresMFA || false,
|
|
2067
|
+
availableMFAMethods: updatedSession?.availableSecondFactorMethods || [],
|
|
2068
|
+
mfaMethodsRequired: updatedSession?.mfaMethodsRequired,
|
|
2069
|
+
},
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// ===============================
|
|
2074
|
+
// MFA HELPERS
|
|
2075
|
+
// ===============================
|
|
2076
|
+
|
|
2077
|
+
/**
|
|
2078
|
+
* Determine if MFA is required for this user/session after first-factor success.
|
|
2079
|
+
*
|
|
2080
|
+
* M12+M13 fix: Now checks org-level auth policy in addition to app-level.
|
|
2081
|
+
* Effective policy = max(app_policy, org_policy) — org can only tighten, never weaken.
|
|
2082
|
+
*
|
|
2083
|
+
* Returns true if:
|
|
2084
|
+
* - The effective policy requires MFA for all users, OR
|
|
2085
|
+
* - The effective policy requires MFA for admins, OR
|
|
2086
|
+
* - The org's minimumAuthLevel is 'mfa' or 'sso', OR
|
|
2087
|
+
* - The user has enrolled a verified TOTP secret (user opted in to MFA)
|
|
2088
|
+
*/
|
|
2089
|
+
private async _shouldRequireMFA(ec: ExecutionContext<any>, userId: string, organizationId?: string, firstFactorMethod?: AuthMethod, authPolicy?: UserTypeAuthPolicy): Promise<{ required: boolean; enrolledMethods: AuthMethod[] }> {
|
|
2090
|
+
const policy = authPolicy ?? AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
2091
|
+
const mfaPolicy = policy.mfaPolicy;
|
|
2092
|
+
const NOT_REQUIRED = { required: false, enrolledMethods: [] as AuthMethod[] };
|
|
2093
|
+
|
|
2094
|
+
// G1 + W2.5: Passkey exemption — passkeys are multi-factor by nature (possession + biometric/PIN).
|
|
2095
|
+
if (firstFactorMethod === AuthMethod.PASSKEY) {
|
|
2096
|
+
const passkeyExemptFromMFA = mfaPolicy?.passkeyExemptFromMFA ?? true;
|
|
2097
|
+
if (passkeyExemptFromMFA) {
|
|
2098
|
+
return NOT_REQUIRED;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
const policyRequiresMFA = !!mfaPolicy?.requireMFA;
|
|
2103
|
+
|
|
2104
|
+
try {
|
|
2105
|
+
const cred = await this.credentialOps.readByUserId(ec, userId);
|
|
2106
|
+
|
|
2107
|
+
const enrolledMethods = AuthUtils.getEnrolledSecondFactorMethods(cred);
|
|
2108
|
+
|
|
2109
|
+
if (policyRequiresMFA) {
|
|
2110
|
+
const hasStrongSecondFactor = enrolledMethods.some(
|
|
2111
|
+
(m) => m !== AuthMethod.EMAIL_OTP,
|
|
2112
|
+
);
|
|
2113
|
+
|
|
2114
|
+
if (hasStrongSecondFactor) {
|
|
2115
|
+
if (cred && cred.mfaEnrollmentState !== MfaEnrollmentState.ENROLLED) {
|
|
2116
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.ENROLLED } as Partial<UserCredentials>);
|
|
2117
|
+
}
|
|
2118
|
+
return { required: true, enrolledMethods };
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
const graceDays = mfaPolicy?.enrollmentGracePeriodDays ?? 0;
|
|
2122
|
+
if (graceDays > 0 && cred) {
|
|
2123
|
+
if (!cred.firstMfaPromptAt) {
|
|
2124
|
+
await this.credentialOps.updateById(ec, cred._id, { firstMfaPromptAt: new Date(), mfaEnrollmentState: MfaEnrollmentState.GRACE } as Partial<UserCredentials>);
|
|
2125
|
+
} else if (cred.mfaEnrollmentState !== MfaEnrollmentState.GRACE) {
|
|
2126
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.GRACE } as Partial<UserCredentials>);
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
const graceStart = cred.firstMfaPromptAt ?? new Date();
|
|
2130
|
+
const graceEnd = new Date(graceStart.getTime() + graceDays * 86_400_000);
|
|
2131
|
+
if (new Date() < graceEnd) {
|
|
2132
|
+
return NOT_REQUIRED;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
await this.credentialOps.updateById(ec, cred._id, { mfaEnrollmentState: MfaEnrollmentState.PENDING } as Partial<UserCredentials>);
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
return { required: true, enrolledMethods };
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
if (cred?.totpVerified) {
|
|
2142
|
+
return { required: true, enrolledMethods };
|
|
2143
|
+
}
|
|
2144
|
+
} catch {
|
|
2145
|
+
if (policyRequiresMFA) {
|
|
2146
|
+
return { required: true, enrolledMethods: [] };
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
return NOT_REQUIRED;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
// ===============================
|
|
2154
|
+
// AUTH POLICY MERGE (M13)
|
|
2155
|
+
// ===============================
|
|
2156
|
+
|
|
2157
|
+
// W2.10: _mergeAuthPolicies removed — runtime AuthPolicyBase deprecated.
|
|
2158
|
+
// All MFA requirements now come solely from config (mfaPolicy).
|
|
2159
|
+
|
|
2160
|
+
// ===============================
|
|
2161
|
+
// SSO GRACE LOGIN TRACKING (M14)
|
|
2162
|
+
// ===============================
|
|
2163
|
+
|
|
2164
|
+
/** Redis key prefix for SSO grace login counters — scope-aware format: sso_grace_logins:{scopeType}:{scopeId}:{userId} */
|
|
2165
|
+
|
|
2166
|
+
/**
|
|
2167
|
+
* M14: Check if password login is allowed under SSO grace policy.
|
|
2168
|
+
* If the scope requires SSO and grace logins are exhausted, throws AUTHENTICATION error.
|
|
2169
|
+
*/
|
|
2170
|
+
private async _checkSSOGraceLoginAllowed(ec: ExecutionContext<any>, scopeType: AuthScopeType, scopeId: string, userId: string): Promise<void> {
|
|
2171
|
+
try {
|
|
2172
|
+
const ssoConfig = await this.orgConfigService.loadSSOConfig(ec, scopeType, scopeId);
|
|
2173
|
+
if (!ssoConfig) return;
|
|
2174
|
+
|
|
2175
|
+
const { enforcement } = ssoConfig;
|
|
2176
|
+
if (!enforcement.requireSSO) return;
|
|
2177
|
+
if (!enforcement.allowPasswordFallback) {
|
|
2178
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2179
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SSO_REQUIRED,
|
|
2180
|
+
context: { message: 'SSO is required. Password login is not allowed.' },
|
|
2181
|
+
});
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
const maxGrace = enforcement.graceLoginAttempts;
|
|
2185
|
+
if (maxGrace <= 0) {
|
|
2186
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2187
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SSO_REQUIRED,
|
|
2188
|
+
context: { message: 'SSO is required. Password login grace period exhausted.' },
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
if (!userId) return;
|
|
2193
|
+
|
|
2194
|
+
const identifier = `${AUTH_REDIS_KEYS.SSO_GRACE_LOGINS}${scopeType}:${scopeId}:${userId}`;
|
|
2195
|
+
const currentCount = await this.redisService.getRateLimitCount(identifier);
|
|
2196
|
+
|
|
2197
|
+
if (currentCount >= maxGrace) {
|
|
2198
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2199
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SSO_REQUIRED,
|
|
2200
|
+
context: {
|
|
2201
|
+
message: 'Password login grace period exhausted. Please use SSO.',
|
|
2202
|
+
graceLoginsUsed: currentCount,
|
|
2203
|
+
graceLoginsMax: maxGrace,
|
|
2204
|
+
},
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
} catch (error) {
|
|
2208
|
+
if (isWildoBackendError(error)) throw error;
|
|
2209
|
+
this.logDebug('SSO grace login check failed (non-fatal)', {
|
|
2210
|
+
scopeType,
|
|
2211
|
+
scopeId,
|
|
2212
|
+
userId,
|
|
2213
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
/** 1 year in seconds — effectively permanent for grace counter, but avoids orphaned keys */
|
|
2219
|
+
private static readonly SSO_GRACE_TTL_SECONDS = 365 * 24 * 60 * 60;
|
|
2220
|
+
|
|
2221
|
+
/**
|
|
2222
|
+
* M14: Atomically increment SSO grace login counter after successful password auth.
|
|
2223
|
+
* Uses Redis INCR (via incrementRateLimit) for atomic increment — no TOCTOU race.
|
|
2224
|
+
* TTL is 1 year (effectively permanent but avoids orphaned keys if scope config changes).
|
|
2225
|
+
*/
|
|
2226
|
+
private async _incrementSSOGraceLogin(ec: ExecutionContext<any>, scopeType: AuthScopeType, scopeId: string, userId: string): Promise<void> {
|
|
2227
|
+
try {
|
|
2228
|
+
const ssoConfig = await this.orgConfigService.loadSSOConfig(ec, scopeType, scopeId);
|
|
2229
|
+
if (!ssoConfig?.enforcement.requireSSO) return;
|
|
2230
|
+
|
|
2231
|
+
const identifier = `${AUTH_REDIS_KEYS.SSO_GRACE_LOGINS}${scopeType}:${scopeId}:${userId}`;
|
|
2232
|
+
const newCount = await this.redisService.incrementRateLimit(
|
|
2233
|
+
identifier,
|
|
2234
|
+
AuthenticationOrchestratorBackendService.SSO_GRACE_TTL_SECONDS,
|
|
2235
|
+
);
|
|
2236
|
+
|
|
2237
|
+
this.logDebug('SSO grace login counter incremented', {
|
|
2238
|
+
scopeType,
|
|
2239
|
+
scopeId,
|
|
2240
|
+
userId,
|
|
2241
|
+
graceLoginsUsed: newCount,
|
|
2242
|
+
graceLoginsMax: ssoConfig.enforcement.graceLoginAttempts,
|
|
2243
|
+
});
|
|
2244
|
+
} catch {
|
|
2245
|
+
// Non-fatal — don't block auth if counter update fails
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
// ===============================
|
|
2250
|
+
// MAGIC LINK (Phase G2)
|
|
2251
|
+
// ===============================
|
|
2252
|
+
|
|
2253
|
+
/**
|
|
2254
|
+
* Send a magic link email to the user.
|
|
2255
|
+
* Anti-enumeration: always returns success regardless of whether the user exists.
|
|
2256
|
+
* Rate limited per email.
|
|
2257
|
+
*/
|
|
2258
|
+
public async sendMagicLink(ec: ExecutionContext<any>, request: MagicLinkSendRequest, deviceInfo?: { ipAddress?: string; userAgent?: string }): Promise<{ success: true; token?: string; email?: string; userId?: string; expiresInMinutes?: number }> {
|
|
2259
|
+
if (!this._isMethodEnabledGlobally(AuthMethod.MAGIC_LINK)) {
|
|
2260
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2261
|
+
context: { message: 'Magic link authentication is not enabled' },
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
const { email } = request;
|
|
2266
|
+
|
|
2267
|
+
// Rate limiting — dual window (per minute + per hour)
|
|
2268
|
+
await this.rateLimitService.checkRateLimit(
|
|
2269
|
+
`${AUTH_REDIS_KEYS.MAGIC_LINK_MIN}${email}:min`,
|
|
2270
|
+
this.magicLinkConfig.rateLimitPerMinute,
|
|
2271
|
+
60
|
|
2272
|
+
);
|
|
2273
|
+
await this.rateLimitService.checkRateLimit(
|
|
2274
|
+
`${AUTH_REDIS_KEYS.MAGIC_LINK_MIN}${email}:hour`,
|
|
2275
|
+
this.magicLinkConfig.rateLimitPerHour,
|
|
2276
|
+
3600
|
|
2277
|
+
);
|
|
2278
|
+
|
|
2279
|
+
// Look up the user (same pattern as identify())
|
|
2280
|
+
let user: User | null = null;
|
|
2281
|
+
try {
|
|
2282
|
+
user = await this.userLookup.findUserByEmail(ec, email);
|
|
2283
|
+
} catch {
|
|
2284
|
+
// Suppress — anti-enumeration (also covers non-active users)
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
// Audit the send (even if user doesn't exist or is inactive)
|
|
2288
|
+
await this.auditLogsService.logMagicLinkSent({
|
|
2289
|
+
email,
|
|
2290
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2291
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2292
|
+
});
|
|
2293
|
+
|
|
2294
|
+
// If user doesn't exist or is not active, return success silently (anti-enumeration)
|
|
2295
|
+
if (!user) {
|
|
2296
|
+
return { success: true };
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
const userId = user._id;
|
|
2300
|
+
|
|
2301
|
+
// Revoke any existing MAGIC_LINK tokens for this user
|
|
2302
|
+
await this.consumableTokenService.revokeTokensByRelatedId(userId, CoreConsumableTokenTypes.MAGIC_LINK);
|
|
2303
|
+
|
|
2304
|
+
// Store as consumable token (createToken auto-generates a crypto-random token value)
|
|
2305
|
+
const createdToken = await this.consumableTokenService.createToken({
|
|
2306
|
+
tokenType: CoreConsumableTokenTypes.MAGIC_LINK,
|
|
2307
|
+
consumptionMode: ConsumableToken_ConsumptionMode.SINGLE_USE,
|
|
2308
|
+
expiresIn: { value: this.magicLinkConfig.tokenExpiryMinutes, unit: DurationUnit.MINUTES },
|
|
2309
|
+
userId: userId,
|
|
2310
|
+
resourceIdentifier: CoreResourceType.USERS,
|
|
2311
|
+
relatedId: userId,
|
|
2312
|
+
metadata: { email },
|
|
2313
|
+
});
|
|
2314
|
+
|
|
2315
|
+
this.logDebug('Magic link token created', { email, userId });
|
|
2316
|
+
|
|
2317
|
+
return { success: true, token: createdToken.token, email, userId, expiresInMinutes: this.magicLinkConfig.tokenExpiryMinutes };
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
/**
|
|
2321
|
+
* Verify a magic link token.
|
|
2322
|
+
* Returns an auth response with tokens on success.
|
|
2323
|
+
*/
|
|
2324
|
+
public async verifyMagicLink(ec: ExecutionContext<any>, request: MagicLinkVerifyRequest, deviceInfo?: { ipAddress?: string; userAgent?: string }, activeUserType?: string): Promise<AuthenticationResponse> {
|
|
2325
|
+
if (!this._isMethodEnabledGlobally(AuthMethod.MAGIC_LINK)) {
|
|
2326
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2327
|
+
context: { message: 'Magic link authentication is not enabled' },
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
const { token } = request;
|
|
2332
|
+
|
|
2333
|
+
// Validate the token (checks expiry, revocation, consumption)
|
|
2334
|
+
let validatedToken: Awaited<ReturnType<typeof this.consumableTokenService.validateToken>> | null = null;
|
|
2335
|
+
try {
|
|
2336
|
+
validatedToken = await this.consumableTokenService.validateToken(token, [CoreConsumableTokenTypes.MAGIC_LINK]);
|
|
2337
|
+
} catch {
|
|
2338
|
+
// Token invalid, expired, or already consumed
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
if (!validatedToken) {
|
|
2342
|
+
await this.auditLogsService.logMagicLinkFailed({
|
|
2343
|
+
failureReason: 'Invalid or expired magic link token',
|
|
2344
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2345
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2346
|
+
});
|
|
2347
|
+
|
|
2348
|
+
return {
|
|
2349
|
+
success: false,
|
|
2350
|
+
sessionId: '',
|
|
2351
|
+
userExists: false,
|
|
2352
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2353
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2354
|
+
error: 'Invalid or expired magic link',
|
|
2355
|
+
errorCode: 'MAGIC_LINK_INVALID',
|
|
2356
|
+
retryAllowed: false,
|
|
2357
|
+
integrationTokens: [],
|
|
2358
|
+
requiresMFA: false,
|
|
2359
|
+
} as AuthenticationResponse;
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2362
|
+
// Consume the token atomically — wrap in try/catch for concurrent double-click race
|
|
2363
|
+
try {
|
|
2364
|
+
await this.consumableTokenService.consumeToken(token);
|
|
2365
|
+
} catch {
|
|
2366
|
+
// Token already consumed by concurrent request — return same error as invalid token
|
|
2367
|
+
await this.auditLogsService.logMagicLinkFailed({
|
|
2368
|
+
failureReason: 'Magic link token already consumed (concurrent request)',
|
|
2369
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2370
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2371
|
+
});
|
|
2372
|
+
return {
|
|
2373
|
+
success: false,
|
|
2374
|
+
sessionId: '',
|
|
2375
|
+
userExists: false,
|
|
2376
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2377
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2378
|
+
error: 'Invalid or expired magic link',
|
|
2379
|
+
errorCode: 'MAGIC_LINK_INVALID',
|
|
2380
|
+
retryAllowed: false,
|
|
2381
|
+
integrationTokens: [],
|
|
2382
|
+
requiresMFA: false,
|
|
2383
|
+
} as AuthenticationResponse;
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
const userId = validatedToken.relatedId;
|
|
2387
|
+
if (!userId) {
|
|
2388
|
+
await this.auditLogsService.logMagicLinkFailed({
|
|
2389
|
+
failureReason: 'Magic link token has no associated user',
|
|
2390
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2391
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2392
|
+
});
|
|
2393
|
+
return {
|
|
2394
|
+
success: false,
|
|
2395
|
+
sessionId: '',
|
|
2396
|
+
userExists: false,
|
|
2397
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2398
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2399
|
+
error: 'Invalid magic link token',
|
|
2400
|
+
errorCode: 'MAGIC_LINK_INVALID',
|
|
2401
|
+
retryAllowed: false,
|
|
2402
|
+
integrationTokens: [],
|
|
2403
|
+
requiresMFA: false,
|
|
2404
|
+
} as AuthenticationResponse;
|
|
2405
|
+
}
|
|
2406
|
+
const tokenMetadata = validatedToken.metadata as Record<string, unknown> | undefined;
|
|
2407
|
+
const email = tokenMetadata?.email as string;
|
|
2408
|
+
|
|
2409
|
+
// Defense-in-depth: constant-time compare request email vs token email.
|
|
2410
|
+
// Prevents URL-tampering attacks where an attacker changes the email in the
|
|
2411
|
+
// magic link URL while keeping a stolen/intercepted token value.
|
|
2412
|
+
if (!email) {
|
|
2413
|
+
this.logger.warn('Magic link token metadata missing email — token integrity issue', {
|
|
2414
|
+
userId,
|
|
2415
|
+
tokenType: CoreConsumableTokenTypes.MAGIC_LINK,
|
|
2416
|
+
});
|
|
2417
|
+
await this.auditLogsService.logMagicLinkFailed({
|
|
2418
|
+
failureReason: 'Token metadata missing email (data integrity issue)',
|
|
2419
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2420
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2421
|
+
});
|
|
2422
|
+
return {
|
|
2423
|
+
success: false,
|
|
2424
|
+
sessionId: '',
|
|
2425
|
+
userExists: false,
|
|
2426
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2427
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2428
|
+
error: 'Invalid or expired magic link',
|
|
2429
|
+
errorCode: 'MAGIC_LINK_INVALID',
|
|
2430
|
+
retryAllowed: false,
|
|
2431
|
+
integrationTokens: [],
|
|
2432
|
+
requiresMFA: false,
|
|
2433
|
+
} as AuthenticationResponse;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
const tokenEmailBuf = Buffer.from(email.toLowerCase());
|
|
2437
|
+
const requestEmailBuf = Buffer.from(request.email.toLowerCase());
|
|
2438
|
+
if (tokenEmailBuf.length !== requestEmailBuf.length || !crypto.timingSafeEqual(tokenEmailBuf, requestEmailBuf)) {
|
|
2439
|
+
this.logger.warn('Magic link email mismatch — possible URL tampering or token theft', {
|
|
2440
|
+
userId,
|
|
2441
|
+
requestEmail: request.email,
|
|
2442
|
+
});
|
|
2443
|
+
await this.auditLogsService.logMagicLinkFailed({
|
|
2444
|
+
failureReason: 'Email mismatch between request and token',
|
|
2445
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2446
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2447
|
+
});
|
|
2448
|
+
return {
|
|
2449
|
+
success: false,
|
|
2450
|
+
sessionId: '',
|
|
2451
|
+
userExists: false,
|
|
2452
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2453
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2454
|
+
error: 'Invalid or expired magic link',
|
|
2455
|
+
errorCode: 'MAGIC_LINK_INVALID',
|
|
2456
|
+
retryAllowed: false,
|
|
2457
|
+
integrationTokens: [],
|
|
2458
|
+
requiresMFA: false,
|
|
2459
|
+
} as AuthenticationResponse;
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
// Load the user
|
|
2463
|
+
let user: User | null = null;
|
|
2464
|
+
try {
|
|
2465
|
+
user = await this.userLookup.findUserById(ec, userId);
|
|
2466
|
+
} catch {
|
|
2467
|
+
// Suppress
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
if (!user) {
|
|
2471
|
+
return {
|
|
2472
|
+
success: false,
|
|
2473
|
+
sessionId: '',
|
|
2474
|
+
userExists: false,
|
|
2475
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2476
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2477
|
+
error: 'User not found',
|
|
2478
|
+
errorCode: 'USER_NOT_FOUND',
|
|
2479
|
+
retryAllowed: false,
|
|
2480
|
+
integrationTokens: [],
|
|
2481
|
+
requiresMFA: false,
|
|
2482
|
+
} as AuthenticationResponse;
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
// Verify user is active — reject suspended/locked/pending users
|
|
2486
|
+
const userStatus = (user as Record<string, unknown>).status as string | undefined;
|
|
2487
|
+
if (userStatus && userStatus !== UserStatus.ACTIVE) {
|
|
2488
|
+
await this.auditLogsService.logMagicLinkFailed({
|
|
2489
|
+
failureReason: `Account is not active (status: ${userStatus})`,
|
|
2490
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2491
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2492
|
+
});
|
|
2493
|
+
return {
|
|
2494
|
+
success: false,
|
|
2495
|
+
sessionId: '',
|
|
2496
|
+
userExists: true,
|
|
2497
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2498
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2499
|
+
error: 'Account is not active',
|
|
2500
|
+
errorCode: 'ACCOUNT_INACTIVE',
|
|
2501
|
+
retryAllowed: false,
|
|
2502
|
+
integrationTokens: [],
|
|
2503
|
+
requiresMFA: false,
|
|
2504
|
+
} as AuthenticationResponse;
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
// Resolve scope via domain lookup (mirrors identify() pattern)
|
|
2508
|
+
let resolvedOrganizationId: string | undefined;
|
|
2509
|
+
if (email) {
|
|
2510
|
+
const emailDomain = email.split('@')[1]?.toLowerCase();
|
|
2511
|
+
if (emailDomain) {
|
|
2512
|
+
try {
|
|
2513
|
+
const domainOrgLookup = await this.domainToOrgLookup.findOrgByDomain(ec, emailDomain);
|
|
2514
|
+
resolvedOrganizationId = domainOrgLookup?.scopeId;
|
|
2515
|
+
} catch {
|
|
2516
|
+
this.logDebug('Domain-to-org lookup failed during magic link verify (non-fatal)', { emailDomain });
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
// Create a session for this auth flow
|
|
2522
|
+
const sessionId = this.sessionStore.generateSessionId();
|
|
2523
|
+
await this.createSession(sessionId, AuthenticationSessionState.FIRST_FACTOR_COMPLETED, {
|
|
2524
|
+
deviceInfo,
|
|
2525
|
+
activeUserType,
|
|
2526
|
+
});
|
|
2527
|
+
|
|
2528
|
+
// Update session with user info (including organizationId for downstream MFA/SSO checks)
|
|
2529
|
+
await this.updateSession(sessionId, {
|
|
2530
|
+
email,
|
|
2531
|
+
userExists: true,
|
|
2532
|
+
userId: userId,
|
|
2533
|
+
completedFactors: [AuthMethod.MAGIC_LINK],
|
|
2534
|
+
currentFactor: AuthFactorLevel.FIRST,
|
|
2535
|
+
organizationId: resolvedOrganizationId,
|
|
2536
|
+
});
|
|
2537
|
+
|
|
2538
|
+
// Audit success
|
|
2539
|
+
await this.auditLogsService.logMagicLinkVerified({
|
|
2540
|
+
userId: userId,
|
|
2541
|
+
email,
|
|
2542
|
+
sessionId,
|
|
2543
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2544
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2545
|
+
});
|
|
2546
|
+
|
|
2547
|
+
// Reset global lockout counter — magic link proves email ownership (high assurance)
|
|
2548
|
+
if (email) {
|
|
2549
|
+
await this._resetGlobalAttempts(email);
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
// AUTH-14: Use org-override-aware policy for magic link flows
|
|
2553
|
+
const magicLinkPolicy = await this._resolveAuthPolicyWithOrgOverrides(ec, activeUserType, userId);
|
|
2554
|
+
const mfaCheck = await this._shouldRequireMFA(ec, userId, resolvedOrganizationId, AuthMethod.MAGIC_LINK, magicLinkPolicy);
|
|
2555
|
+
|
|
2556
|
+
if (mfaCheck.required) {
|
|
2557
|
+
const mfaResolution = await this._resolveUsableMfaMethods(mfaCheck.enrolledMethods, magicLinkPolicy);
|
|
2558
|
+
|
|
2559
|
+
await this.updateSession(sessionId, {
|
|
2560
|
+
state: AuthenticationSessionState.MFA_REQUIRED,
|
|
2561
|
+
requiresMFA: true,
|
|
2562
|
+
requireStrongMFA: mfaResolution.requireStrongMFA,
|
|
2563
|
+
availableSecondFactorMethods: mfaResolution.availableMethods,
|
|
2564
|
+
enrolledSecondFactorMethods: mfaCheck.enrolledMethods,
|
|
2565
|
+
usableSecondFactorMethods: mfaResolution.usableMethods,
|
|
2566
|
+
});
|
|
2567
|
+
|
|
2568
|
+
return {
|
|
2569
|
+
success: false,
|
|
2570
|
+
sessionId,
|
|
2571
|
+
userExists: true,
|
|
2572
|
+
factorLevel: AuthFactorLevel.FIRST,
|
|
2573
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2574
|
+
requiresMFA: true,
|
|
2575
|
+
availableMFAMethods: mfaResolution.availableMethods,
|
|
2576
|
+
mfaMethodsRequired: AuthenticationOrchestratorBackendService.DEFAULT_MFA_METHODS_REQUIRED,
|
|
2577
|
+
enrolledSecondFactorMethods: mfaCheck.enrolledMethods,
|
|
2578
|
+
usableSecondFactorMethods: mfaResolution.usableMethods,
|
|
2579
|
+
completedFactors: [AuthMethod.MAGIC_LINK],
|
|
2580
|
+
retryAllowed: true,
|
|
2581
|
+
integrationTokens: [],
|
|
2582
|
+
} as AuthenticationResponse;
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
// Complete authentication — issue tokens
|
|
2586
|
+
await this.updateSession(sessionId, {
|
|
2587
|
+
state: AuthenticationSessionState.COMPLETED,
|
|
2588
|
+
});
|
|
2589
|
+
|
|
2590
|
+
const updatedSession = await this.getSession(sessionId);
|
|
2591
|
+
if (!updatedSession) {
|
|
2592
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2593
|
+
context: { message: 'Session lost after magic link verification' },
|
|
2594
|
+
});
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
const tokens = await this.tokenIssuer.issueTokens(updatedSession, {
|
|
2598
|
+
includeRefreshToken: true,
|
|
2599
|
+
lastAuthenticatedAt: Math.floor(Date.now() / 1000),
|
|
2600
|
+
});
|
|
2601
|
+
|
|
2602
|
+
// Audit login
|
|
2603
|
+
await this.auditLogsService.logUserLogin({
|
|
2604
|
+
userId: userId,
|
|
2605
|
+
ipAddress: deviceInfo?.ipAddress || 'unknown',
|
|
2606
|
+
userAgent: deviceInfo?.userAgent || 'unknown',
|
|
2607
|
+
authMethod: AuthMethod.MAGIC_LINK,
|
|
2608
|
+
email,
|
|
2609
|
+
sessionId,
|
|
2610
|
+
});
|
|
2611
|
+
|
|
2612
|
+
// Clean up session
|
|
2613
|
+
await this.removeSession(sessionId);
|
|
2614
|
+
|
|
2615
|
+
return this._buildAuthenticationSuccessMethod(
|
|
2616
|
+
sessionId,
|
|
2617
|
+
AuthFactorLevel.FIRST,
|
|
2618
|
+
AuthMethod.MAGIC_LINK,
|
|
2619
|
+
tokens.accessToken,
|
|
2620
|
+
{
|
|
2621
|
+
refreshToken: tokens.refreshToken,
|
|
2622
|
+
completedFactors: [AuthMethod.MAGIC_LINK],
|
|
2623
|
+
},
|
|
2624
|
+
);
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
// ===============================
|
|
2628
|
+
// SMS OTP (Phase G2)
|
|
2629
|
+
// ===============================
|
|
2630
|
+
|
|
2631
|
+
/**
|
|
2632
|
+
* Send an SMS OTP code to the user's verified phone number.
|
|
2633
|
+
* Can be used as first factor or second factor depending on config.
|
|
2634
|
+
* Rate limited with dual-window (burst + hourly).
|
|
2635
|
+
*/
|
|
2636
|
+
public async sendSMSOTP(ec: ExecutionContext<any>, sessionId: string, phoneNumber?: string): Promise<{ sent: true; otpCode: string; targetPhone: string }> {
|
|
2637
|
+
if (!this._isMethodEnabledGlobally(AuthMethod.SMS_OTP)) {
|
|
2638
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2639
|
+
context: { message: 'SMS OTP authentication is not enabled' },
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
const session = await this.getSession(sessionId);
|
|
2643
|
+
if (!session) {
|
|
2644
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2645
|
+
customMessageReference: ErrorCustomMessageReference.AUTHENTICATION_SESSION_INVALID,
|
|
2646
|
+
context: { sessionId },
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
// Validate session state — allow states valid for first-factor or second-factor OTP send
|
|
2651
|
+
const validSendStates = [
|
|
2652
|
+
AuthenticationSessionState.IDENTIFIED,
|
|
2653
|
+
AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS,
|
|
2654
|
+
AuthenticationSessionState.FIRST_FACTOR_COMPLETED,
|
|
2655
|
+
AuthenticationSessionState.MFA_REQUIRED,
|
|
2656
|
+
];
|
|
2657
|
+
if (!validSendStates.includes(session.state as AuthenticationSessionState)) {
|
|
2658
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2659
|
+
context: { message: 'Session is not in a valid state for SMS OTP send' },
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
// Determine the phone number to send to
|
|
2664
|
+
let targetPhone = phoneNumber;
|
|
2665
|
+
|
|
2666
|
+
if (!targetPhone) {
|
|
2667
|
+
const userId = session.userId;
|
|
2668
|
+
if (userId) {
|
|
2669
|
+
try {
|
|
2670
|
+
targetPhone = await this.credentialOps.getVerifiedPhone(ec, userId);
|
|
2671
|
+
} catch {
|
|
2672
|
+
// Suppress
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
if (!targetPhone) {
|
|
2678
|
+
throw this.errorBuilder.buildError(ErrorType.VALIDATION, undefined, {
|
|
2679
|
+
context: { message: 'No verified phone number available for SMS OTP' },
|
|
2680
|
+
});
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
// Dual-window rate limiting
|
|
2684
|
+
await this.rateLimitService.checkRateLimit(
|
|
2685
|
+
`${AUTH_REDIS_KEYS.SMS_OTP_BURST}${targetPhone}:burst`,
|
|
2686
|
+
this.otpConfig.smsOtp.rateLimitBurst,
|
|
2687
|
+
60
|
|
2688
|
+
);
|
|
2689
|
+
await this.rateLimitService.checkRateLimit(
|
|
2690
|
+
`${AUTH_REDIS_KEYS.SMS_OTP_BURST}${targetPhone}:hourly`,
|
|
2691
|
+
this.otpConfig.smsOtp.rateLimitHourly,
|
|
2692
|
+
3600
|
|
2693
|
+
);
|
|
2694
|
+
|
|
2695
|
+
const userId = session.userId;
|
|
2696
|
+
if (userId) {
|
|
2697
|
+
// Revoke existing SMS_OTP tokens
|
|
2698
|
+
await this.consumableTokenService.revokeTokensByRelatedId(userId, CoreConsumableTokenTypes.SMS_OTP);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
// Generate OTP code
|
|
2702
|
+
const otpCode = this._generateOTP(this.otpConfig.smsOtp.otpLength);
|
|
2703
|
+
|
|
2704
|
+
// Store as consumable token
|
|
2705
|
+
await this.consumableTokenService.createToken({
|
|
2706
|
+
tokenType: CoreConsumableTokenTypes.SMS_OTP,
|
|
2707
|
+
consumptionMode: ConsumableToken_ConsumptionMode.SINGLE_USE,
|
|
2708
|
+
expiresIn: { value: this.otpConfig.smsOtp.expiryMinutes, unit: DurationUnit.MINUTES },
|
|
2709
|
+
userId: userId,
|
|
2710
|
+
resourceIdentifier: CoreResourceType.USERS,
|
|
2711
|
+
relatedId: userId || targetPhone,
|
|
2712
|
+
metadata: {
|
|
2713
|
+
otpCode,
|
|
2714
|
+
sessionId,
|
|
2715
|
+
phoneNumber: targetPhone,
|
|
2716
|
+
},
|
|
2717
|
+
});
|
|
2718
|
+
|
|
2719
|
+
// Audit
|
|
2720
|
+
await this.auditLogsService.logSMSOTPSent({
|
|
2721
|
+
phoneNumber: targetPhone,
|
|
2722
|
+
factorLevel: session.currentFactor || AuthFactorLevel.FIRST,
|
|
2723
|
+
sessionId,
|
|
2724
|
+
ipAddress: session.deviceInfo?.ipAddress || 'unknown',
|
|
2725
|
+
userAgent: session.deviceInfo?.userAgent || 'unknown',
|
|
2726
|
+
});
|
|
2727
|
+
|
|
2728
|
+
// Update session state to reflect pending OTP verification
|
|
2729
|
+
const isSecondFactor = session.state === AuthenticationSessionState.FIRST_FACTOR_COMPLETED
|
|
2730
|
+
|| session.state === AuthenticationSessionState.MFA_REQUIRED;
|
|
2731
|
+
await this.updateSession(sessionId, {
|
|
2732
|
+
state: isSecondFactor
|
|
2733
|
+
? AuthenticationSessionState.MFA_REQUIRED
|
|
2734
|
+
: AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS,
|
|
2735
|
+
currentFactor: isSecondFactor ? AuthFactorLevel.SECOND : AuthFactorLevel.FIRST,
|
|
2736
|
+
});
|
|
2737
|
+
|
|
2738
|
+
this.logDebug('SMS OTP generated', { sessionId, phoneNumber: targetPhone });
|
|
2739
|
+
|
|
2740
|
+
return { sent: true, otpCode, targetPhone };
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
/**
|
|
2744
|
+
* Verify an SMS OTP code. Supports both first and second factor.
|
|
2745
|
+
* Called from authenticate() dispatch — does NOT issue tokens (authenticate() handles completion).
|
|
2746
|
+
* Uses constant-time comparison for the OTP code.
|
|
2747
|
+
*/
|
|
2748
|
+
public async authenticateSMSOTP(ec: ExecutionContext<any>, request: SMSOTPAuthRequest): Promise<AuthenticationResponse> {
|
|
2749
|
+
if (!this._isMethodEnabledGlobally(AuthMethod.SMS_OTP)) {
|
|
2750
|
+
throw this.errorBuilder.buildError(ErrorType.AUTHENTICATION, undefined, {
|
|
2751
|
+
context: { message: 'SMS OTP authentication is not enabled' },
|
|
2752
|
+
});
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
const { sessionId, token, factorLevel } = request;
|
|
2756
|
+
|
|
2757
|
+
const session = await this.getSession(sessionId);
|
|
2758
|
+
if (!session) {
|
|
2759
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, { retryAllowed: false });
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
// Allow-list: SMS OTP can be first or second factor, so accept states valid for either.
|
|
2763
|
+
// Reject unexpected states (COMPLETED, LOCKED, CREATED) to prevent replay or abuse.
|
|
2764
|
+
const validSMSOTPStates = [
|
|
2765
|
+
AuthenticationSessionState.IDENTIFIED,
|
|
2766
|
+
AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS,
|
|
2767
|
+
AuthenticationSessionState.FIRST_FACTOR_COMPLETED,
|
|
2768
|
+
AuthenticationSessionState.MFA_REQUIRED,
|
|
2769
|
+
AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS,
|
|
2770
|
+
];
|
|
2771
|
+
if (!validSMSOTPStates.includes(session.state as AuthenticationSessionState)) {
|
|
2772
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, {
|
|
2773
|
+
retryAllowed: false,
|
|
2774
|
+
authMethod: AuthMethod.SMS_OTP,
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
if (!token) {
|
|
2779
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, {
|
|
2780
|
+
retryAllowed: true,
|
|
2781
|
+
authMethod: AuthMethod.SMS_OTP,
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
// Update session to in-progress
|
|
2786
|
+
const inProgressState = factorLevel === AuthFactorLevel.SECOND
|
|
2787
|
+
? AuthenticationSessionState.SECOND_FACTOR_IN_PROGRESS
|
|
2788
|
+
: AuthenticationSessionState.FIRST_FACTOR_IN_PROGRESS;
|
|
2789
|
+
await this.updateSession(sessionId, {
|
|
2790
|
+
state: inProgressState,
|
|
2791
|
+
currentFactor: factorLevel,
|
|
2792
|
+
});
|
|
2793
|
+
|
|
2794
|
+
const userId = session.userId;
|
|
2795
|
+
if (!userId) {
|
|
2796
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, { retryAllowed: false });
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
// Find matching SMS_OTP token and verify with constant-time comparison
|
|
2800
|
+
const isValid = await this._verifySMSOTP(userId, sessionId, token);
|
|
2801
|
+
|
|
2802
|
+
if (!isValid) {
|
|
2803
|
+
const { locked } = await this.incrementSessionAttempts(ec, sessionId);
|
|
2804
|
+
|
|
2805
|
+
await this.auditLogsService.logSMSOTPFailed({
|
|
2806
|
+
phoneNumber: request.phoneNumber,
|
|
2807
|
+
factorLevel,
|
|
2808
|
+
failureReason: locked ? 'Account locked after too many attempts' : 'Invalid OTP code',
|
|
2809
|
+
sessionId,
|
|
2810
|
+
ipAddress: session.deviceInfo?.ipAddress || 'unknown',
|
|
2811
|
+
userAgent: session.deviceInfo?.userAgent || 'unknown',
|
|
2812
|
+
});
|
|
2813
|
+
|
|
2814
|
+
return this.__buildAuthenticationErrorMethod(sessionId, factorLevel, {
|
|
2815
|
+
retryAllowed: !locked,
|
|
2816
|
+
authMethod: AuthMethod.SMS_OTP,
|
|
2817
|
+
});
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
// Audit success
|
|
2821
|
+
await this.auditLogsService.logSMSOTPVerified({
|
|
2822
|
+
userId: userId,
|
|
2823
|
+
phoneNumber: request.phoneNumber || 'unknown',
|
|
2824
|
+
factorLevel,
|
|
2825
|
+
sessionId,
|
|
2826
|
+
ipAddress: session.deviceInfo?.ipAddress || 'unknown',
|
|
2827
|
+
userAgent: session.deviceInfo?.userAgent || 'unknown',
|
|
2828
|
+
});
|
|
2829
|
+
|
|
2830
|
+
// Update session (mirrors authenticateEmailOTP pattern)
|
|
2831
|
+
await this._updateSessionAfterSuccessfulAuth(ec, sessionId, userId, AuthMethod.SMS_OTP);
|
|
2832
|
+
|
|
2833
|
+
const updatedSession = await this.getSession(sessionId);
|
|
2834
|
+
return this._buildAuthenticationSuccessMethod(
|
|
2835
|
+
sessionId,
|
|
2836
|
+
factorLevel,
|
|
2837
|
+
AuthMethod.SMS_OTP,
|
|
2838
|
+
'', // Tokens issued by authenticate() after completion check
|
|
2839
|
+
{ completedFactors: updatedSession?.completedFactors || [] },
|
|
2840
|
+
);
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
/**
|
|
2844
|
+
* Verify an SMS OTP code using constant-time comparison.
|
|
2845
|
+
* Mirrors the _verifyEmailOTP pattern.
|
|
2846
|
+
*/
|
|
2847
|
+
private async _verifySMSOTP(userId: string, sessionId: string, submittedCode: string): Promise<boolean> {
|
|
2848
|
+
try {
|
|
2849
|
+
const tokens = await this.consumableTokenService.findTokensByRelatedId(
|
|
2850
|
+
userId,
|
|
2851
|
+
CoreConsumableTokenTypes.SMS_OTP,
|
|
2852
|
+
);
|
|
2853
|
+
|
|
2854
|
+
for (const tokenDoc of tokens) {
|
|
2855
|
+
const metadata = tokenDoc.metadata as Record<string, unknown> | undefined;
|
|
2856
|
+
if (!metadata?.otpCode || !metadata?.sessionId) continue;
|
|
2857
|
+
|
|
2858
|
+
const storedCode = String(metadata.otpCode);
|
|
2859
|
+
const storedSession = String(metadata.sessionId);
|
|
2860
|
+
if (storedCode.length !== submittedCode.length || storedSession.length !== sessionId.length) continue;
|
|
2861
|
+
|
|
2862
|
+
const codeMatch = crypto.timingSafeEqual(Buffer.from(storedCode), Buffer.from(submittedCode));
|
|
2863
|
+
const sessionMatch = crypto.timingSafeEqual(Buffer.from(storedSession), Buffer.from(sessionId));
|
|
2864
|
+
|
|
2865
|
+
if (codeMatch && sessionMatch) {
|
|
2866
|
+
try {
|
|
2867
|
+
await this.consumableTokenService.consumeToken(tokenDoc.token);
|
|
2868
|
+
return true;
|
|
2869
|
+
} catch {
|
|
2870
|
+
continue;
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2875
|
+
return false;
|
|
2876
|
+
} catch (error) {
|
|
2877
|
+
if (isWildoBackendError(error)) {
|
|
2878
|
+
throw error;
|
|
2879
|
+
}
|
|
2880
|
+
this.logger.error('Failed to verify SMS OTP', {
|
|
2881
|
+
userId,
|
|
2882
|
+
sessionId,
|
|
2883
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2884
|
+
});
|
|
2885
|
+
return false;
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
/**
|
|
2890
|
+
* Generate a cryptographically random N-digit numeric OTP.
|
|
2891
|
+
*/
|
|
2892
|
+
private _generateOTP(length: number): string {
|
|
2893
|
+
const max = Math.pow(10, length);
|
|
2894
|
+
const min = Math.pow(10, length - 1);
|
|
2895
|
+
// Use crypto.randomInt for unbiased random number generation
|
|
2896
|
+
const { randomInt } = crypto;
|
|
2897
|
+
return String(randomInt(min, max));
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2900
|
+
// ===============================
|
|
2901
|
+
// COMPLETION LOGIC
|
|
2902
|
+
// ===============================
|
|
2903
|
+
|
|
2904
|
+
private _isAuthenticationComplete(
|
|
2905
|
+
session: AuthenticationSession,
|
|
2906
|
+
currentFactorLevel: AuthFactorLevel,
|
|
2907
|
+
authMethod: AuthMethod,
|
|
2908
|
+
): boolean {
|
|
2909
|
+
const completedFactors = session.completedFactors || [];
|
|
2910
|
+
|
|
2911
|
+
const hasFirstFactor = completedFactors.some((factor) => AuthUtils.canBeFirstFactor(factor));
|
|
2912
|
+
const hasSecondFactor = completedFactors.some((factor) => AuthUtils.canBeSecondFactor(factor));
|
|
2913
|
+
|
|
2914
|
+
switch (currentFactorLevel) {
|
|
2915
|
+
case AuthFactorLevel.FIRST:
|
|
2916
|
+
// If MFA is required for this session (set during first-factor success based on
|
|
2917
|
+
// app MFA policy + user's enrolled second-factor methods), first factor alone is not enough.
|
|
2918
|
+
if (session.requiresMFA) {
|
|
2919
|
+
return false;
|
|
2920
|
+
}
|
|
2921
|
+
return session.state === AuthenticationSessionState.FIRST_FACTOR_COMPLETED && hasFirstFactor;
|
|
2922
|
+
case AuthFactorLevel.SECOND:
|
|
2923
|
+
return hasFirstFactor && hasSecondFactor && completedFactors.length >= 2;
|
|
2924
|
+
default:
|
|
2925
|
+
return false;
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
// ===============================
|
|
2930
|
+
// RESPONSE BUILDERS
|
|
2931
|
+
// ===============================
|
|
2932
|
+
|
|
2933
|
+
private _buildIdentificationErrorResponse(
|
|
2934
|
+
sessionId: string,
|
|
2935
|
+
factorLevel: AuthFactorLevel,
|
|
2936
|
+
retryAllowed: boolean = true,
|
|
2937
|
+
session?: AuthenticationSession | null,
|
|
2938
|
+
): AuthenticationResponse {
|
|
2939
|
+
return AuthenticationResponseSchema.parse({
|
|
2940
|
+
success: false,
|
|
2941
|
+
sessionId,
|
|
2942
|
+
userExists: session?.userExists ?? false,
|
|
2943
|
+
factorLevel,
|
|
2944
|
+
retryAllowed,
|
|
2945
|
+
remainingAttempts: session ? session.maxAttempts - session.attempts : undefined,
|
|
2946
|
+
lockoutUntil: session?.lockoutUntil,
|
|
2947
|
+
requiresMFA: false,
|
|
2948
|
+
integrationTokens: [],
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
private _buildAuthenticationSuccessMethod(
|
|
2953
|
+
sessionId: string,
|
|
2954
|
+
factorLevel: AuthFactorLevel,
|
|
2955
|
+
authMethod: AuthMethod,
|
|
2956
|
+
accessToken: string,
|
|
2957
|
+
options: {
|
|
2958
|
+
refreshToken?: string;
|
|
2959
|
+
expiresIn?: number;
|
|
2960
|
+
user?: any;
|
|
2961
|
+
integrationTokens?: Array<{
|
|
2962
|
+
integrationId: string;
|
|
2963
|
+
accessToken: string;
|
|
2964
|
+
refreshToken?: string;
|
|
2965
|
+
expiresIn?: number;
|
|
2966
|
+
scopes: string[];
|
|
2967
|
+
}>;
|
|
2968
|
+
requiresMFA?: boolean;
|
|
2969
|
+
availableMFAMethods?: AvailableMethod[];
|
|
2970
|
+
mfaMethodsRequired?: number;
|
|
2971
|
+
enrolledSecondFactorMethods?: AuthMethod[];
|
|
2972
|
+
usableSecondFactorMethods?: AuthMethod[];
|
|
2973
|
+
completedFactors?: AuthMethod[];
|
|
2974
|
+
challengeData?: Record<string, any>;
|
|
2975
|
+
redirectUrl?: string;
|
|
2976
|
+
nextStep?: string;
|
|
2977
|
+
availableEnrollmentMethods?: AuthMethod[];
|
|
2978
|
+
} = {},
|
|
2979
|
+
): AuthenticationResponse {
|
|
2980
|
+
return AuthenticationResponseSchema.parse({
|
|
2981
|
+
success: !options.requiresMFA,
|
|
2982
|
+
sessionId,
|
|
2983
|
+
userExists: true,
|
|
2984
|
+
factorLevel,
|
|
2985
|
+
authMethod,
|
|
2986
|
+
accessToken,
|
|
2987
|
+
refreshToken: options.refreshToken,
|
|
2988
|
+
expiresIn: options.expiresIn,
|
|
2989
|
+
user: options.user,
|
|
2990
|
+
integrationTokens: options.integrationTokens || [],
|
|
2991
|
+
requiresMFA: options.requiresMFA || false,
|
|
2992
|
+
availableMFAMethods: options.availableMFAMethods,
|
|
2993
|
+
mfaMethodsRequired: options.mfaMethodsRequired,
|
|
2994
|
+
enrolledSecondFactorMethods: options.enrolledSecondFactorMethods || [],
|
|
2995
|
+
usableSecondFactorMethods: options.usableSecondFactorMethods || [],
|
|
2996
|
+
completedFactors: options.completedFactors || [authMethod],
|
|
2997
|
+
retryAllowed: true,
|
|
2998
|
+
challengeData: options.challengeData,
|
|
2999
|
+
redirectUrl: options.redirectUrl,
|
|
3000
|
+
nextStep: options.nextStep,
|
|
3001
|
+
availableEnrollmentMethods: options.availableEnrollmentMethods || [],
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
private __buildAuthenticationErrorMethod(
|
|
3006
|
+
sessionId: string,
|
|
3007
|
+
factorLevel: AuthFactorLevel,
|
|
3008
|
+
options: {
|
|
3009
|
+
authMethod?: AuthMethod;
|
|
3010
|
+
retryAllowed?: boolean;
|
|
3011
|
+
remainingAttempts?: number;
|
|
3012
|
+
lockoutUntil?: Date;
|
|
3013
|
+
requiresMFA?: boolean;
|
|
3014
|
+
availableMFAMethods?: AvailableMethod[];
|
|
3015
|
+
mfaMethodsRequired?: number;
|
|
3016
|
+
completedFactors?: AuthMethod[];
|
|
3017
|
+
challengeData?: Record<string, any>;
|
|
3018
|
+
redirectUrl?: string;
|
|
3019
|
+
} = {},
|
|
3020
|
+
): AuthenticationResponse {
|
|
3021
|
+
// Note: we don't call getSession here synchronously because this is used in sync error builders.
|
|
3022
|
+
// The session data is passed through options when available.
|
|
3023
|
+
return AuthenticationResponseSchema.parse({
|
|
3024
|
+
success: false,
|
|
3025
|
+
sessionId,
|
|
3026
|
+
userExists: false,
|
|
3027
|
+
factorLevel,
|
|
3028
|
+
authMethod: options.authMethod,
|
|
3029
|
+
retryAllowed: options.retryAllowed ?? true,
|
|
3030
|
+
remainingAttempts: options.remainingAttempts,
|
|
3031
|
+
lockoutUntil: options.lockoutUntil,
|
|
3032
|
+
requiresMFA: options.requiresMFA ?? false,
|
|
3033
|
+
availableMFAMethods: options.availableMFAMethods,
|
|
3034
|
+
mfaMethodsRequired: options.mfaMethodsRequired,
|
|
3035
|
+
completedFactors: options.completedFactors || [],
|
|
3036
|
+
integrationTokens: [],
|
|
3037
|
+
challengeData: options.challengeData,
|
|
3038
|
+
redirectUrl: options.redirectUrl,
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
private async _buildAvailableMethodObject(
|
|
3043
|
+
ec: ExecutionContext<any> | undefined,
|
|
3044
|
+
method: AuthMethod,
|
|
3045
|
+
domainOrgLookup?: DomainOrgLookupResult | null,
|
|
3046
|
+
authPolicy?: UserTypeAuthPolicy,
|
|
3047
|
+
): Promise<AvailableMethod | null> {
|
|
3048
|
+
const globalAuth = this.appConfigService.config.auth;
|
|
3049
|
+
const policy = authPolicy ?? AuthenticationOrchestratorBackendService.FALLBACK_AUTH_POLICY;
|
|
3050
|
+
|
|
3051
|
+
const isEnabled = policy.authMethodsEnabled[method];
|
|
3052
|
+
if (!isEnabled) {
|
|
3053
|
+
return null;
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
const factorType = AuthUtils.getFactorType(method);
|
|
3057
|
+
const category = AuthUtils.getMethodCategory(method);
|
|
3058
|
+
const canBeFirstFactor = AuthUtils.canBeFirstFactor(method);
|
|
3059
|
+
const canBeSecondFactor = AuthUtils.canBeSecondFactor(method);
|
|
3060
|
+
const organizationRestricted = AuthUtils.isOrganizationRestricted(method);
|
|
3061
|
+
const supportsIntegrations = AuthUtils.supportsIntegrationAccess(method);
|
|
3062
|
+
|
|
3063
|
+
let required = false;
|
|
3064
|
+
if (canBeSecondFactor && policy.mfaPolicy.requireMFA) {
|
|
3065
|
+
required = true;
|
|
3066
|
+
}
|
|
3067
|
+
let oauth2ProviderRefs: string[] = [];
|
|
3068
|
+
let ssoIds: string[] = [];
|
|
3069
|
+
let availableIntegrations: string[] = [];
|
|
3070
|
+
let config: Record<string, any> | undefined;
|
|
3071
|
+
|
|
3072
|
+
switch (method) {
|
|
3073
|
+
case AuthMethod.EXTERNAL_OAUTH2: {
|
|
3074
|
+
let oauth2Providers = Object.keys(globalAuth.ssoProviders || {});
|
|
3075
|
+
if (domainOrgLookup && ec) {
|
|
3076
|
+
oauth2Providers = await this.oauth2Resolver.filterProviders(
|
|
3077
|
+
ec,
|
|
3078
|
+
domainOrgLookup.scopeType,
|
|
3079
|
+
domainOrgLookup.scopeId,
|
|
3080
|
+
oauth2Providers,
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3083
|
+
if (oauth2Providers.length === 0) return null;
|
|
3084
|
+
availableIntegrations = oauth2Providers;
|
|
3085
|
+
oauth2ProviderRefs = oauth2Providers;
|
|
3086
|
+
break;
|
|
3087
|
+
}
|
|
3088
|
+
case AuthMethod.MAGIC_LINK:
|
|
3089
|
+
case AuthMethod.SMS_OTP:
|
|
3090
|
+
break;
|
|
3091
|
+
case AuthMethod.PASSKEY:
|
|
3092
|
+
config = globalAuth.passkeyConfig
|
|
3093
|
+
? { rpName: globalAuth.passkeyConfig.rpName, rpId: globalAuth.passkeyConfig.rpId }
|
|
3094
|
+
: undefined;
|
|
3095
|
+
break;
|
|
3096
|
+
case AuthMethod.ORG_OPENID_CONNECT: {
|
|
3097
|
+
if (!domainOrgLookup || domainOrgLookup.matchedProviderType !== 'oidc') {
|
|
3098
|
+
return null;
|
|
3099
|
+
}
|
|
3100
|
+
const providerInfo = this.domainToOrgLookup.getSSOProviderInfo(domainOrgLookup);
|
|
3101
|
+
if (!providerInfo) return null;
|
|
3102
|
+
ssoIds = [providerInfo.connectionId];
|
|
3103
|
+
config = {
|
|
3104
|
+
displayName: providerInfo.displayName,
|
|
3105
|
+
providerRef: providerInfo.providerRef,
|
|
3106
|
+
connectionId: providerInfo.connectionId,
|
|
3107
|
+
scopeType: domainOrgLookup.scopeType,
|
|
3108
|
+
scopeId: domainOrgLookup.scopeId,
|
|
3109
|
+
organizationId: domainOrgLookup.organizationId,
|
|
3110
|
+
};
|
|
3111
|
+
if (domainOrgLookup.enforcement?.requireSSO) {
|
|
3112
|
+
required = true;
|
|
3113
|
+
}
|
|
3114
|
+
break;
|
|
3115
|
+
}
|
|
3116
|
+
case AuthMethod.ORG_SAML: {
|
|
3117
|
+
if (!domainOrgLookup || domainOrgLookup.matchedProviderType !== 'saml') {
|
|
3118
|
+
return null;
|
|
3119
|
+
}
|
|
3120
|
+
const samlProviderInfo = this.domainToOrgLookup.getSSOProviderInfo(domainOrgLookup);
|
|
3121
|
+
if (!samlProviderInfo) return null;
|
|
3122
|
+
ssoIds = [samlProviderInfo.connectionId];
|
|
3123
|
+
config = {
|
|
3124
|
+
displayName: samlProviderInfo.displayName,
|
|
3125
|
+
providerRef: samlProviderInfo.providerRef,
|
|
3126
|
+
connectionId: samlProviderInfo.connectionId,
|
|
3127
|
+
loginUrl: `/auth/saml/login/${samlProviderInfo.connectionId}`,
|
|
3128
|
+
scopeType: domainOrgLookup.scopeType,
|
|
3129
|
+
scopeId: domainOrgLookup.scopeId,
|
|
3130
|
+
organizationId: domainOrgLookup.organizationId,
|
|
3131
|
+
};
|
|
3132
|
+
if (domainOrgLookup.enforcement?.requireSSO) {
|
|
3133
|
+
required = true;
|
|
3134
|
+
}
|
|
3135
|
+
break;
|
|
3136
|
+
}
|
|
3137
|
+
default:
|
|
3138
|
+
break;
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
return {
|
|
3142
|
+
method,
|
|
3143
|
+
factorType,
|
|
3144
|
+
category,
|
|
3145
|
+
canBeFirstFactor,
|
|
3146
|
+
canBeSecondFactor,
|
|
3147
|
+
required,
|
|
3148
|
+
oauth2ProviderRefs,
|
|
3149
|
+
ssoIds,
|
|
3150
|
+
organizationRestricted,
|
|
3151
|
+
supportsIntegrations,
|
|
3152
|
+
availableIntegrations,
|
|
3153
|
+
config,
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
}
|