@solidxai/core 0.1.2 → 0.1.5-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +8 -0
- package/dist/commands/run-tests.command.d.ts +37 -0
- package/dist/commands/run-tests.command.d.ts.map +1 -0
- package/dist/commands/run-tests.command.js +345 -0
- package/dist/commands/run-tests.command.js.map +1 -0
- package/dist/commands/test-data.command.d.ts +6 -6
- package/dist/commands/test-data.command.d.ts.map +1 -1
- package/dist/commands/test-data.command.js +25 -25
- package/dist/commands/test-data.command.js.map +1 -1
- package/dist/commands/test.command.d.ts +5 -0
- package/dist/commands/test.command.d.ts.map +1 -0
- package/dist/commands/test.command.js +26 -0
- package/dist/commands/test.command.js.map +1 -0
- package/dist/constants/error-messages.d.ts +1 -0
- package/dist/constants/error-messages.d.ts.map +1 -1
- package/dist/constants/error-messages.js +1 -0
- package/dist/constants/error-messages.js.map +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +12 -12
- package/dist/constants.js.map +1 -1
- package/dist/controllers/otp-authentication.controller.d.ts +1 -4
- package/dist/controllers/otp-authentication.controller.d.ts.map +1 -1
- package/dist/controllers/otp-authentication.controller.js +1 -1
- package/dist/controllers/role-metadata.controller.d.ts +1 -0
- package/dist/controllers/role-metadata.controller.d.ts.map +1 -1
- package/dist/controllers/role-metadata.controller.js +15 -0
- package/dist/controllers/role-metadata.controller.js.map +1 -1
- package/dist/controllers/service.controller.d.ts +0 -9
- package/dist/controllers/service.controller.d.ts.map +1 -1
- package/dist/controllers/service.controller.js +0 -45
- package/dist/controllers/service.controller.js.map +1 -1
- package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
- package/dist/dtos/basic-filters.dto.js.map +1 -1
- package/dist/dtos/create-email-template.dto.d.ts.map +1 -1
- package/dist/dtos/create-email-template.dto.js.map +1 -1
- package/dist/dtos/create-list-of-values.dto.d.ts.map +1 -1
- package/dist/dtos/create-list-of-values.dto.js.map +1 -1
- package/dist/dtos/create-menu-item-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-menu-item-metadata.dto.js.map +1 -1
- package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-role-metadata.dto.js.map +1 -1
- package/dist/dtos/create-scheduled-job.dto.d.ts.map +1 -1
- package/dist/dtos/create-scheduled-job.dto.js.map +1 -1
- package/dist/dtos/create-security-rule.dto.d.ts.map +1 -1
- package/dist/dtos/create-security-rule.dto.js.map +1 -1
- package/dist/dtos/create-sms-template.dto.d.ts.map +1 -1
- package/dist/dtos/create-sms-template.dto.js.map +1 -1
- package/dist/dtos/create-user.dto.d.ts +1 -0
- package/dist/dtos/create-user.dto.d.ts.map +1 -1
- package/dist/dtos/create-user.dto.js +2 -1
- package/dist/dtos/create-user.dto.js.map +1 -1
- package/dist/dtos/create-view-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-view-metadata.dto.js.map +1 -1
- package/dist/dtos/otp-sign-in.dto.d.ts +1 -1
- package/dist/dtos/otp-sign-in.dto.d.ts.map +1 -1
- package/dist/dtos/otp-sign-in.dto.js +2 -2
- package/dist/dtos/otp-sign-in.dto.js.map +1 -1
- package/dist/dtos/otp-sign-up.dto.d.ts +2 -2
- package/dist/dtos/otp-sign-up.dto.d.ts.map +1 -1
- package/dist/dtos/otp-sign-up.dto.js +2 -2
- package/dist/dtos/otp-sign-up.dto.js.map +1 -1
- package/dist/dtos/resolve-s3-url.dto.d.ts +2 -5
- package/dist/dtos/resolve-s3-url.dto.d.ts.map +1 -1
- package/dist/dtos/resolve-s3-url.dto.js +1 -13
- package/dist/dtos/resolve-s3-url.dto.js.map +1 -1
- package/dist/dtos/sign-up.dto.d.ts.map +1 -1
- package/dist/dtos/sign-up.dto.js.map +1 -1
- package/dist/dtos/update-email-template.dto.d.ts.map +1 -1
- package/dist/dtos/update-email-template.dto.js.map +1 -1
- package/dist/dtos/update-list-of-values.dto.d.ts.map +1 -1
- package/dist/dtos/update-list-of-values.dto.js.map +1 -1
- package/dist/dtos/update-menu-item-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/update-menu-item-metadata.dto.js.map +1 -1
- package/dist/dtos/update-scheduled-job.dto.d.ts.map +1 -1
- package/dist/dtos/update-scheduled-job.dto.js.map +1 -1
- package/dist/dtos/update-security-rule.dto.d.ts.map +1 -1
- package/dist/dtos/update-security-rule.dto.js.map +1 -1
- package/dist/dtos/update-sms-template.dto.d.ts.map +1 -1
- package/dist/dtos/update-sms-template.dto.js.map +1 -1
- package/dist/dtos/update-view-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/update-view-metadata.dto.js.map +1 -1
- package/dist/entities/user.entity.d.ts +1 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +6 -1
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts +2 -0
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js +33 -23
- package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js.map +1 -1
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts +3 -0
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js +36 -23
- package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js.map +1 -1
- package/dist/helpers/security.helper.js +1 -0
- package/dist/helpers/security.helper.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/repository/solid-base.repository.d.ts +10 -1
- package/dist/repository/solid-base.repository.d.ts.map +1 -1
- package/dist/repository/solid-base.repository.js +109 -0
- package/dist/repository/solid-base.repository.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts +2 -0
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +142 -91
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/module-test-data.service.d.ts.map +1 -1
- package/dist/seeders/module-test-data.service.js +3 -3
- package/dist/seeders/module-test-data.service.js.map +1 -1
- package/dist/seeders/permission-metadata-seeder.service.d.ts +1 -1
- package/dist/seeders/permission-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/permission-metadata-seeder.service.js +1 -1
- package/dist/seeders/permission-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +12 -25
- package/dist/services/authentication.service.d.ts +22 -8
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +228 -214
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts +2 -0
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +18 -2
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts +4 -0
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +66 -32
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +7 -4
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/field-metadata.service.d.ts.map +1 -1
- package/dist/services/field-metadata.service.js.map +1 -1
- package/dist/services/file/disk-file.service.d.ts +0 -2
- package/dist/services/file/disk-file.service.d.ts.map +1 -1
- package/dist/services/file/disk-file.service.js +7 -16
- package/dist/services/file/disk-file.service.js.map +1 -1
- package/dist/services/file/index.d.ts +1 -0
- package/dist/services/file/index.d.ts.map +1 -1
- package/dist/services/file/index.js +1 -0
- package/dist/services/file/index.js.map +1 -1
- package/dist/services/file/storage-path-builder.d.ts +17 -0
- package/dist/services/file/storage-path-builder.d.ts.map +1 -0
- package/dist/{seeders/sms-template-seeder.service.js → services/file/storage-path-builder.js} +45 -35
- package/dist/services/file/storage-path-builder.js.map +1 -0
- package/dist/services/media.service.d.ts +1 -1
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +45 -6
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.js +46 -7
- package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts +4 -6
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +16 -14
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/queues/common.d.ts +3 -0
- package/dist/services/queues/common.d.ts.map +1 -0
- package/dist/services/queues/common.js +39 -0
- package/dist/services/queues/common.js.map +1 -0
- package/dist/services/queues/database-publisher.service.d.ts.map +1 -1
- package/dist/services/queues/database-publisher.service.js +3 -1
- package/dist/services/queues/database-publisher.service.js.map +1 -1
- package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
- package/dist/services/queues/database-subscriber.service.js +5 -2
- package/dist/services/queues/database-subscriber.service.js.map +1 -1
- package/dist/services/queues/rabbitmq-publisher.service.d.ts.map +1 -1
- package/dist/services/queues/rabbitmq-publisher.service.js +13 -6
- package/dist/services/queues/rabbitmq-publisher.service.js.map +1 -1
- package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
- package/dist/services/queues/rabbitmq-subscriber.service.js +9 -5
- package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
- package/dist/services/setting.service.d.ts +3 -2
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +7 -4
- package/dist/services/setting.service.js.map +1 -1
- package/dist/services/settings/default-settings-provider.service.d.ts +24 -2
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +8 -6
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/solid-core.module.d.ts +3 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +49 -9
- package/dist/solid-core.module.js.map +1 -1
- package/dist/testing/__examples__/register-example-specs.d.ts +3 -0
- package/dist/testing/__examples__/register-example-specs.d.ts.map +1 -0
- package/dist/testing/__examples__/register-example-specs.js +8 -0
- package/dist/testing/__examples__/register-example-specs.js.map +1 -0
- package/dist/testing/__examples__/specs/custom-health.spec.d.ts +17 -0
- package/dist/testing/__examples__/specs/custom-health.spec.d.ts.map +1 -0
- package/dist/testing/__examples__/specs/custom-health.spec.js +30 -0
- package/dist/testing/__examples__/specs/custom-health.spec.js.map +1 -0
- package/dist/testing/adapters/api/api-adapter.d.ts +9 -0
- package/dist/testing/adapters/api/api-adapter.d.ts.map +1 -0
- package/dist/testing/adapters/api/api-adapter.js +76 -0
- package/dist/testing/adapters/api/api-adapter.js.map +1 -0
- package/dist/testing/adapters/api/api.types.d.ts +14 -0
- package/dist/testing/adapters/api/api.types.d.ts.map +1 -0
- package/dist/testing/adapters/api/api.types.js +3 -0
- package/dist/testing/adapters/api/api.types.js.map +1 -0
- package/dist/testing/adapters/ui/playwright-adapter.d.ts +14 -0
- package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -0
- package/dist/testing/adapters/ui/playwright-adapter.js +80 -0
- package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -0
- package/dist/testing/adapters/ui/ui.types.d.ts +5 -0
- package/dist/testing/adapters/ui/ui.types.d.ts.map +1 -0
- package/dist/testing/adapters/ui/ui.types.js +3 -0
- package/dist/testing/adapters/ui/ui.types.js.map +1 -0
- package/dist/testing/contracts/runtime-context.types.d.ts +35 -0
- package/dist/testing/contracts/runtime-context.types.d.ts.map +1 -0
- package/dist/testing/contracts/runtime-context.types.js +3 -0
- package/dist/testing/contracts/runtime-context.types.js.map +1 -0
- package/dist/testing/contracts/test-spec.types.d.ts +21 -0
- package/dist/testing/contracts/test-spec.types.d.ts.map +1 -0
- package/dist/testing/contracts/test-spec.types.js +3 -0
- package/dist/testing/contracts/test-spec.types.js.map +1 -0
- package/dist/testing/contracts/testing-metadata.types.d.ts +41 -0
- package/dist/testing/contracts/testing-metadata.types.d.ts.map +1 -0
- package/dist/testing/contracts/testing-metadata.types.js +3 -0
- package/dist/testing/contracts/testing-metadata.types.js.map +1 -0
- package/dist/testing/core/interpolation.d.ts +4 -0
- package/dist/testing/core/interpolation.d.ts.map +1 -0
- package/dist/testing/core/interpolation.js +180 -0
- package/dist/testing/core/interpolation.js.map +1 -0
- package/dist/testing/core/normalize-steps.d.ts +7 -0
- package/dist/testing/core/normalize-steps.d.ts.map +1 -0
- package/dist/testing/core/normalize-steps.js +20 -0
- package/dist/testing/core/normalize-steps.js.map +1 -0
- package/dist/testing/core/resource-store.d.ts +8 -0
- package/dist/testing/core/resource-store.d.ts.map +1 -0
- package/dist/testing/core/resource-store.js +41 -0
- package/dist/testing/core/resource-store.js.map +1 -0
- package/dist/testing/core/spec-registry.d.ts +10 -0
- package/dist/testing/core/spec-registry.d.ts.map +1 -0
- package/dist/testing/core/spec-registry.js +32 -0
- package/dist/testing/core/spec-registry.js.map +1 -0
- package/dist/testing/core/step-registry.d.ts +10 -0
- package/dist/testing/core/step-registry.d.ts.map +1 -0
- package/dist/testing/core/step-registry.js +26 -0
- package/dist/testing/core/step-registry.js.map +1 -0
- package/dist/testing/core/testing-engine.d.ts +14 -0
- package/dist/testing/core/testing-engine.d.ts.map +1 -0
- package/dist/testing/core/testing-engine.js +97 -0
- package/dist/testing/core/testing-engine.js.map +1 -0
- package/dist/testing/core/timeout.d.ts +2 -0
- package/dist/testing/core/timeout.d.ts.map +1 -0
- package/dist/testing/core/timeout.js +18 -0
- package/dist/testing/core/timeout.js.map +1 -0
- package/dist/testing/reporter/attachments.d.ts +4 -0
- package/dist/testing/reporter/attachments.d.ts.map +1 -0
- package/dist/testing/reporter/attachments.js +25 -0
- package/dist/testing/reporter/attachments.js.map +1 -0
- package/dist/testing/reporter/console-reporter.d.ts +45 -0
- package/dist/testing/reporter/console-reporter.d.ts.map +1 -0
- package/dist/testing/reporter/console-reporter.js +189 -0
- package/dist/testing/reporter/console-reporter.js.map +1 -0
- package/dist/testing/reporter/reporter.types.d.ts +37 -0
- package/dist/testing/reporter/reporter.types.d.ts.map +1 -0
- package/dist/testing/reporter/reporter.types.js +3 -0
- package/dist/testing/reporter/reporter.types.js.map +1 -0
- package/dist/testing/runner/lifecycle.d.ts +9 -0
- package/dist/testing/runner/lifecycle.d.ts.map +1 -0
- package/dist/testing/runner/lifecycle.js +33 -0
- package/dist/testing/runner/lifecycle.js.map +1 -0
- package/dist/testing/runner/run-from-metadata.d.ts +24 -0
- package/dist/testing/runner/run-from-metadata.d.ts.map +1 -0
- package/dist/testing/runner/run-from-metadata.js +70 -0
- package/dist/testing/runner/run-from-metadata.js.map +1 -0
- package/dist/testing/runner/scenario-filter.d.ts +9 -0
- package/dist/testing/runner/scenario-filter.d.ts.map +1 -0
- package/dist/testing/runner/scenario-filter.js +22 -0
- package/dist/testing/runner/scenario-filter.js.map +1 -0
- package/dist/testing/steps/api/auth.step.d.ts +3 -0
- package/dist/testing/steps/api/auth.step.d.ts.map +1 -0
- package/dist/testing/steps/api/auth.step.js +38 -0
- package/dist/testing/steps/api/auth.step.js.map +1 -0
- package/dist/testing/steps/api/index.d.ts +3 -0
- package/dist/testing/steps/api/index.d.ts.map +1 -0
- package/dist/testing/steps/api/index.js +10 -0
- package/dist/testing/steps/api/index.js.map +1 -0
- package/dist/testing/steps/api/request.step.d.ts +3 -0
- package/dist/testing/steps/api/request.step.d.ts.map +1 -0
- package/dist/testing/steps/api/request.step.js +281 -0
- package/dist/testing/steps/api/request.step.js.map +1 -0
- package/dist/testing/steps/assert/http.step.d.ts +3 -0
- package/dist/testing/steps/assert/http.step.d.ts.map +1 -0
- package/dist/testing/steps/assert/http.step.js +27 -0
- package/dist/testing/steps/assert/http.step.js.map +1 -0
- package/dist/testing/steps/assert/index.d.ts +3 -0
- package/dist/testing/steps/assert/index.d.ts.map +1 -0
- package/dist/testing/steps/assert/index.js +12 -0
- package/dist/testing/steps/assert/index.js.map +1 -0
- package/dist/testing/steps/assert/jsonpath.step.d.ts +3 -0
- package/dist/testing/steps/assert/jsonpath.step.d.ts.map +1 -0
- package/dist/testing/steps/assert/jsonpath.step.js +40 -0
- package/dist/testing/steps/assert/jsonpath.step.js.map +1 -0
- package/dist/testing/steps/assert/primitives.step.d.ts +3 -0
- package/dist/testing/steps/assert/primitives.step.d.ts.map +1 -0
- package/dist/testing/steps/assert/primitives.step.js +43 -0
- package/dist/testing/steps/assert/primitives.step.js.map +1 -0
- package/dist/testing/steps/test/index.d.ts +3 -0
- package/dist/testing/steps/test/index.d.ts.map +1 -0
- package/dist/testing/steps/test/index.js +8 -0
- package/dist/testing/steps/test/index.js.map +1 -0
- package/dist/testing/steps/test/test-spec.step.d.ts +3 -0
- package/dist/testing/steps/test/test-spec.step.d.ts.map +1 -0
- package/dist/testing/steps/test/test-spec.step.js +41 -0
- package/dist/testing/steps/test/test-spec.step.js.map +1 -0
- package/dist/testing/steps/ui/actions.step.d.ts +3 -0
- package/dist/testing/steps/ui/actions.step.d.ts.map +1 -0
- package/dist/testing/steps/ui/actions.step.js +31 -0
- package/dist/testing/steps/ui/actions.step.js.map +1 -0
- package/dist/testing/steps/ui/assertions.step.d.ts +3 -0
- package/dist/testing/steps/ui/assertions.step.d.ts.map +1 -0
- package/dist/testing/steps/ui/assertions.step.js +41 -0
- package/dist/testing/steps/ui/assertions.step.js.map +1 -0
- package/dist/testing/steps/ui/form.step.d.ts +3 -0
- package/dist/testing/steps/ui/form.step.d.ts.map +1 -0
- package/dist/testing/steps/ui/form.step.js +34 -0
- package/dist/testing/steps/ui/form.step.js.map +1 -0
- package/dist/testing/steps/ui/index.d.ts +3 -0
- package/dist/testing/steps/ui/index.d.ts.map +1 -0
- package/dist/testing/steps/ui/index.js +14 -0
- package/dist/testing/steps/ui/index.js.map +1 -0
- package/dist/testing/steps/ui/navigation.step.d.ts +3 -0
- package/dist/testing/steps/ui/navigation.step.d.ts.map +1 -0
- package/dist/testing/steps/ui/navigation.step.js +39 -0
- package/dist/testing/steps/ui/navigation.step.js.map +1 -0
- package/dist/testing/steps/util/index.d.ts +3 -0
- package/dist/testing/steps/util/index.d.ts.map +1 -0
- package/dist/testing/steps/util/index.js +12 -0
- package/dist/testing/steps/util/index.js.map +1 -0
- package/dist/testing/steps/util/log.step.d.ts +3 -0
- package/dist/testing/steps/util/log.step.d.ts.map +1 -0
- package/dist/testing/steps/util/log.step.js +18 -0
- package/dist/testing/steps/util/log.step.js.map +1 -0
- package/dist/testing/steps/util/require.step.d.ts +3 -0
- package/dist/testing/steps/util/require.step.d.ts.map +1 -0
- package/dist/testing/steps/util/require.step.js +16 -0
- package/dist/testing/steps/util/require.step.js.map +1 -0
- package/dist/testing/steps/util/sleep.step.d.ts +3 -0
- package/dist/testing/steps/util/sleep.step.d.ts.map +1 -0
- package/dist/testing/steps/util/sleep.step.js +13 -0
- package/dist/testing/steps/util/sleep.step.js.map +1 -0
- package/docs/test-data-workflow.md +51 -11
- package/package.json +10 -2
- package/src/commands/run-tests.command.ts +278 -0
- package/src/commands/test-data.command.ts +26 -26
- package/src/commands/test.command.ts +14 -0
- package/src/constants/error-messages.ts +1 -0
- package/src/constants.ts +3 -3
- package/src/controllers/role-metadata.controller.ts +26 -18
- package/src/controllers/service.controller.ts +58 -59
- package/src/dtos/basic-filters.dto.ts +0 -2
- package/src/dtos/create-email-template.dto.ts +7 -0
- package/src/dtos/create-list-of-values.dto.ts +7 -0
- package/src/dtos/create-menu-item-metadata.dto.ts +12 -1
- package/src/dtos/create-role-metadata.dto.ts +9 -0
- package/src/dtos/create-scheduled-job.dto.ts +14 -0
- package/src/dtos/create-security-rule.dto.ts +6 -0
- package/src/dtos/create-sms-template.dto.ts +6 -0
- package/src/dtos/create-user.dto.ts +1 -0
- package/src/dtos/create-view-metadata.dto.ts +11 -0
- package/src/dtos/otp-sign-in.dto.ts +3 -3
- package/src/dtos/otp-sign-up.dto.ts +3 -3
- package/src/dtos/resolve-s3-url.dto.ts +2 -12
- package/src/dtos/sign-up.dto.ts +0 -2
- package/src/dtos/update-email-template.dto.ts +6 -0
- package/src/dtos/update-list-of-values.dto.ts +8 -0
- package/src/dtos/update-menu-item-metadata.dto.ts +12 -0
- package/src/dtos/update-scheduled-job.dto.ts +15 -0
- package/src/dtos/update-security-rule.dto.ts +7 -0
- package/src/dtos/update-sms-template.dto.ts +32 -32
- package/src/dtos/update-view-metadata.dto.ts +12 -0
- package/src/entities/user.entity.ts +3 -0
- package/src/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.ts +43 -32
- package/src/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.ts +45 -33
- package/src/helpers/security.helper.ts +1 -1
- package/src/index.ts +3 -4
- package/src/repository/solid-base.repository.ts +172 -1
- package/src/seeders/module-metadata-seeder.service.ts +191 -150
- package/src/seeders/module-test-data.service.ts +5 -3
- package/src/seeders/permission-metadata-seeder.service.ts +1 -4
- package/src/seeders/seed-data/solid-core-metadata.json +12 -25
- package/src/services/authentication.service.ts +268 -266
- package/src/services/chatter-message.service.ts +18 -1
- package/src/services/crud-helper.service.ts +79 -36
- package/src/services/crud.service.ts +10 -4
- package/src/services/field-metadata.service.ts +0 -71
- package/src/services/file/disk-file.service.ts +8 -18
- package/src/services/file/index.ts +1 -0
- package/src/services/file/storage-path-builder.ts +56 -0
- package/src/services/media.service.ts +13 -7
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +1 -1
- package/src/services/mediaStorageProviders/file-storage-provider.ts +13 -8
- package/src/services/module-metadata.service.ts +18 -15
- package/src/services/queues/common.ts +75 -0
- package/src/services/queues/database-publisher.service.ts +4 -1
- package/src/services/queues/database-subscriber.service.ts +5 -3
- package/src/services/queues/rabbitmq-publisher.service.ts +17 -7
- package/src/services/queues/rabbitmq-subscriber.service.ts +9 -5
- package/src/services/setting.service.ts +5 -3
- package/src/services/settings/default-settings-provider.service.ts +5 -3
- package/src/solid-core.module.ts +20 -12
- package/src/testing/README.md +364 -0
- package/src/testing/__examples__/register-example-specs.ts +6 -0
- package/src/testing/__examples__/specs/custom-health.spec.ts +29 -0
- package/src/testing/__examples__/testing.sample.json +82 -0
- package/src/testing/adapters/api/api-adapter.ts +85 -0
- package/src/testing/adapters/api/api.types.ts +15 -0
- package/src/testing/adapters/ui/playwright-adapter.ts +54 -0
- package/src/testing/adapters/ui/ui.types.ts +4 -0
- package/src/testing/contracts/runtime-context.types.ts +36 -0
- package/src/testing/contracts/test-spec.types.ts +24 -0
- package/src/testing/contracts/testing-metadata.types.ts +46 -0
- package/src/testing/core/interpolation.ts +189 -0
- package/src/testing/core/normalize-steps.ts +21 -0
- package/src/testing/core/resource-store.ts +38 -0
- package/src/testing/core/spec-registry.ts +33 -0
- package/src/testing/core/step-registry.ts +27 -0
- package/src/testing/core/testing-engine.ts +127 -0
- package/src/testing/core/timeout.ts +19 -0
- package/src/testing/reporter/attachments.ts +25 -0
- package/src/testing/reporter/console-reporter.ts +229 -0
- package/src/testing/reporter/reporter.types.ts +36 -0
- package/src/testing/runner/lifecycle.ts +31 -0
- package/src/testing/runner/run-from-metadata.ts +87 -0
- package/src/testing/runner/scenario-filter.ts +33 -0
- package/src/testing/steps/api/auth.step.ts +66 -0
- package/src/testing/steps/api/index.ts +10 -0
- package/src/testing/steps/api/request.step.ts +358 -0
- package/src/testing/steps/assert/http.step.ts +33 -0
- package/src/testing/steps/assert/index.ts +12 -0
- package/src/testing/steps/assert/jsonpath.step.ts +50 -0
- package/src/testing/steps/assert/primitives.step.ts +69 -0
- package/src/testing/steps/test/index.ts +8 -0
- package/src/testing/steps/test/test-spec.step.ts +52 -0
- package/src/testing/steps/ui/actions.step.ts +36 -0
- package/src/testing/steps/ui/assertions.step.ts +54 -0
- package/src/testing/steps/ui/form.step.ts +39 -0
- package/src/testing/steps/ui/index.ts +12 -0
- package/src/testing/steps/ui/navigation.step.ts +53 -0
- package/src/testing/steps/util/index.ts +10 -0
- package/src/testing/steps/util/log.step.ts +19 -0
- package/src/testing/steps/util/require.step.ts +16 -0
- package/src/testing/steps/util/sleep.step.ts +15 -0
- package/tsconfig.json +35 -25
- package/tsconfig.tests.json +14 -0
- package/dist/passport-strategies/local.strategy.d.ts +0 -15
- package/dist/passport-strategies/local.strategy.d.ts.map +0 -1
- package/dist/passport-strategies/local.strategy.js +0 -44
- package/dist/passport-strategies/local.strategy.js.map +0 -1
- package/dist/seeders/email-template-seeder.service.d.ts +0 -10
- package/dist/seeders/email-template-seeder.service.d.ts.map +0 -1
- package/dist/seeders/email-template-seeder.service.js +0 -84
- package/dist/seeders/email-template-seeder.service.js.map +0 -1
- package/dist/seeders/sms-template-seeder.service.d.ts +0 -10
- package/dist/seeders/sms-template-seeder.service.d.ts.map +0 -1
- package/dist/seeders/sms-template-seeder.service.js.map +0 -1
- package/dist/seeders/user-seeder.service.d.ts +0 -10
- package/dist/seeders/user-seeder.service.d.ts.map +0 -1
- package/dist/seeders/user-seeder.service.js +0 -44
- package/dist/seeders/user-seeder.service.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/passport-strategies/local.strategy.ts +0 -28
- package/src/seeders/email-template-seeder.service.ts +0 -49
- package/src/seeders/sms-template-seeder.service.ts +0 -50
- package/src/seeders/user-seeder.service.ts +0 -33
|
@@ -3,6 +3,7 @@ import type { SolidCoreSetting } from "src/services/settings/default-settings-pr
|
|
|
3
3
|
import {
|
|
4
4
|
BadRequestException,
|
|
5
5
|
ConflictException,
|
|
6
|
+
ForbiddenException,
|
|
6
7
|
Inject,
|
|
7
8
|
Injectable,
|
|
8
9
|
InternalServerErrorException,
|
|
@@ -26,8 +27,8 @@ import { DataSource, Repository } from 'typeorm';
|
|
|
26
27
|
import { v4 as uuidv4 } from 'uuid';
|
|
27
28
|
import {
|
|
28
29
|
ForgotPasswordSendVerificationTokenOn,
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
PasswordlessLoginValidateWhatSources,
|
|
31
|
+
PasswordlessRegistrationValidateWhatSources
|
|
31
32
|
} from "../constants";
|
|
32
33
|
import { ChangePasswordDto } from "../dtos/change-password.dto";
|
|
33
34
|
import { ConfirmForgotPasswordDto } from '../dtos/confirm-forgot-password.dto';
|
|
@@ -124,33 +125,22 @@ export class AuthenticationService {
|
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
async
|
|
128
|
-
|
|
129
|
-
const user = await this.resolveUser(signInDto.username, signInDto.email);
|
|
130
|
-
|
|
131
|
-
if (!user) {
|
|
132
|
-
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
|
|
133
|
-
}
|
|
128
|
+
private async validateUserForPasswordLogin(user: User, password: string): Promise<void> {
|
|
134
129
|
if (!user.active) {
|
|
135
130
|
throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_ACTIVE);
|
|
136
131
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
user.password,
|
|
140
|
-
user.passwordSchemeVersion
|
|
141
|
-
);
|
|
132
|
+
this.checkAccountBlocked(user);
|
|
133
|
+
const isEqual = await this.hashingService.compare(password, user.password, user.passwordSchemeVersion);
|
|
142
134
|
if (!isEqual) {
|
|
135
|
+
await this.incrementFailedAttempts(user);
|
|
143
136
|
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
|
|
144
137
|
}
|
|
138
|
+
}
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
// Now we check if the password needs to be rehashed based on the current hashing scheme and version.
|
|
140
|
+
private async rehashPasswordIfRequired(user: User, password: string): Promise<void> {
|
|
148
141
|
if (this.hashingService.needsRehash(user.password, user.passwordSchemeVersion)) {
|
|
149
|
-
|
|
150
|
-
return rehashedUser;
|
|
142
|
+
await this.updatePasswordDetails(user, password);
|
|
151
143
|
}
|
|
152
|
-
|
|
153
|
-
return user;
|
|
154
144
|
}
|
|
155
145
|
|
|
156
146
|
async signUp(signUpDto: SignUpDto, activeUser: ActiveUserData = null): Promise<User> {
|
|
@@ -375,60 +365,67 @@ export class AuthenticationService {
|
|
|
375
365
|
}
|
|
376
366
|
|
|
377
367
|
async otpInitiateRegistration(signUpDto: OTPSignUpDto) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
// Validate if either mobile or email is present.
|
|
384
|
-
if (isEmpty(signUpDto.mobile) && isEmpty(signUpDto.email)) {
|
|
385
|
-
throw new BadRequestException(ERROR_MESSAGES.REGISTRATION_REQUIRES_CONTACT);
|
|
386
|
-
}
|
|
387
|
-
if (signUpDto.validationSources.includes(TransactionalRegistrationValidationSource.EMAIL) && isEmpty(signUpDto.email)) {
|
|
388
|
-
throw new BadRequestException(ERROR_MESSAGES.EMAIL_REQUIRED_FOR_VALIDATION);
|
|
389
|
-
}
|
|
390
|
-
if (signUpDto.validationSources.includes(TransactionalRegistrationValidationSource.MOBILE) && isEmpty(signUpDto.mobile)) {
|
|
391
|
-
throw new BadRequestException(ERROR_MESSAGES.MOBILE_REQUIRED_FOR_VALIDATION);
|
|
392
|
-
}
|
|
368
|
+
const isPasswordlessRegistrationEnabled = await this.isPasswordlessRegistrationEnabled();
|
|
369
|
+
if (!isPasswordlessRegistrationEnabled) {
|
|
370
|
+
throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
|
|
371
|
+
}
|
|
393
372
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
where: [
|
|
397
|
-
{ email: signUpDto.email, },
|
|
398
|
-
{ mobile: signUpDto.mobile, },
|
|
399
|
-
{ username: signUpDto.username, }
|
|
400
|
-
]
|
|
401
|
-
});
|
|
402
|
-
if (isNotEmpty(existingUser) && existingUser.active) {
|
|
403
|
-
throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
|
|
404
|
-
}
|
|
405
|
-
let passwordlessRegistrationValidateWhat = this.settingService.getConfigValue<SolidCoreSetting>('passwordlessRegistrationValidateWhat');
|
|
406
|
-
if (!Array.isArray(passwordlessRegistrationValidateWhat)) {
|
|
407
|
-
passwordlessRegistrationValidateWhat = [passwordlessRegistrationValidateWhat];
|
|
408
|
-
}
|
|
409
|
-
const finalRegistrationVerificationSources = this.calculateVerificationSources(passwordlessRegistrationValidateWhat, signUpDto);
|
|
410
|
-
let user = existingUser
|
|
411
|
-
if (isEmpty(user)) {
|
|
412
|
-
user = this.createUser(signUpDto);
|
|
413
|
-
await this.populateVerificationTokens(finalRegistrationVerificationSources, user);
|
|
414
|
-
await this.userRepository.save(user);
|
|
415
|
-
await this.userService.addRoleToUser(user.username, this.settingService.getConfigValue<SolidCoreSetting>('defaultRole'));
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
await this.populateVerificationTokens(finalRegistrationVerificationSources, user);
|
|
419
|
-
await this.userRepository.save(user);
|
|
420
|
-
}
|
|
373
|
+
const validationSource = this.resolvePasswordlessValidationSource();
|
|
374
|
+
this.validateOtpRegistrationInput(signUpDto, validationSource);
|
|
421
375
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
376
|
+
const existingUser = await this.findExistingRegistrationUser(signUpDto);
|
|
377
|
+
if (isNotEmpty(existingUser) && existingUser.active) {
|
|
378
|
+
throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
try {
|
|
382
|
+
const user = await this.upsertUserWithRegistrationVerificationTokens(existingUser, signUpDto, validationSource);
|
|
383
|
+
await this.notifyUserOnOtpInitiateRegistration(user, validationSource);
|
|
425
384
|
} catch (err) {
|
|
426
|
-
|
|
427
|
-
if (err.code === pgUniqueViolationErrorCode) {
|
|
385
|
+
if (err.code === '23505') {
|
|
428
386
|
throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
|
|
429
387
|
}
|
|
430
388
|
throw err;
|
|
431
389
|
}
|
|
390
|
+
|
|
391
|
+
return { message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_REGISTRATION };
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private validateOtpRegistrationInput(signUpDto: OTPSignUpDto, validationSource: string): void {
|
|
395
|
+
if (validationSource === PasswordlessRegistrationValidateWhatSources.EMAIL && isEmpty(signUpDto.email)) {
|
|
396
|
+
throw new BadRequestException(ERROR_MESSAGES.EMAIL_REQUIRED_FOR_VALIDATION);
|
|
397
|
+
}
|
|
398
|
+
if (validationSource === PasswordlessRegistrationValidateWhatSources.MOBILE && isEmpty(signUpDto.mobile)) {
|
|
399
|
+
throw new BadRequestException(ERROR_MESSAGES.MOBILE_REQUIRED_FOR_VALIDATION);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private async findExistingRegistrationUser(signUpDto: OTPSignUpDto): Promise<User> {
|
|
404
|
+
return this.userRepository.findOne({ //TODO Perhaps we should use the user service instead of the repository directly.
|
|
405
|
+
where: [
|
|
406
|
+
{ email: signUpDto.email },
|
|
407
|
+
{ mobile: signUpDto.mobile },
|
|
408
|
+
{ username: signUpDto.username },
|
|
409
|
+
]
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private resolvePasswordlessValidationSource(): string {
|
|
414
|
+
return this.settingService.getConfigValue<SolidCoreSetting>('passwordlessRegistrationValidateWhat');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
private async upsertUserWithRegistrationVerificationTokens(existingUser: User, signUpDto: OTPSignUpDto, validationSource: string): Promise<User> {
|
|
418
|
+
let user = existingUser;
|
|
419
|
+
if (isEmpty(user)) {
|
|
420
|
+
user = this.createUser(signUpDto);
|
|
421
|
+
await this.assignRegistrationOtp(validationSource, user);
|
|
422
|
+
await this.userRepository.save(user);
|
|
423
|
+
await this.userService.addRoleToUser(user.username, this.settingService.getConfigValue<SolidCoreSetting>('defaultRole'));
|
|
424
|
+
} else {
|
|
425
|
+
await this.assignRegistrationOtp(validationSource, user);
|
|
426
|
+
await this.userRepository.save(user);
|
|
427
|
+
}
|
|
428
|
+
return user;
|
|
432
429
|
}
|
|
433
430
|
|
|
434
431
|
// Create a new user entity.
|
|
@@ -442,36 +439,25 @@ export class AuthenticationService {
|
|
|
442
439
|
return user;
|
|
443
440
|
}
|
|
444
441
|
|
|
445
|
-
private calculateVerificationSources(configuredRegistrationValidationSources: string[], signUpDto: OTPSignUpDto): string[] {
|
|
446
|
-
const finalRegistrationValidationSources = configuredRegistrationValidationSources.filter((source) => source !== RegistrationValidationSource.TRANSACTIONAL);
|
|
447
|
-
if (configuredRegistrationValidationSources.includes(RegistrationValidationSource.TRANSACTIONAL)) {
|
|
448
|
-
finalRegistrationValidationSources.push(...signUpDto.validationSources); // Add the validation sources provided by the user.
|
|
449
|
-
}
|
|
450
|
-
return finalRegistrationValidationSources;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
442
|
// Generate the validation tokens for the user i.e (system configured + user provided)
|
|
454
|
-
private async
|
|
455
|
-
if (
|
|
443
|
+
private async assignRegistrationOtp(passwordlessRegistrationValidateWhat: string, user: User) {
|
|
444
|
+
if (!passwordlessRegistrationValidateWhat) {
|
|
456
445
|
throw new BadRequestException(ERROR_MESSAGES.VALIDATION_SOURCE_REQUIRED);
|
|
457
446
|
}
|
|
458
|
-
|
|
447
|
+
const autoLoginUserOnRegistration = this.settingService.getConfigValue<SolidCoreSetting>('autoLoginUserOnRegistration');
|
|
448
|
+
if (passwordlessRegistrationValidateWhat === PasswordlessRegistrationValidateWhatSources.EMAIL) {
|
|
459
449
|
const { token, expiresAt } = await this.otp();
|
|
460
450
|
user.emailVerificationTokenOnRegistration = token;
|
|
461
451
|
user.emailVerificationTokenOnRegistrationExpiresAt = expiresAt;
|
|
462
|
-
const autoLoginUserOnRegistration = this.settingService.getConfigValue<SolidCoreSetting>('autoLoginUserOnRegistration');
|
|
463
|
-
|
|
464
452
|
if (autoLoginUserOnRegistration) {
|
|
465
453
|
user.emailVerificationTokenOnLogin = token;
|
|
466
454
|
user.emailVerificationTokenOnLoginExpiresAt = expiresAt;
|
|
467
455
|
}
|
|
468
456
|
}
|
|
469
|
-
if (
|
|
457
|
+
if (passwordlessRegistrationValidateWhat === PasswordlessRegistrationValidateWhatSources.MOBILE) {
|
|
470
458
|
const { token, expiresAt } = await this.otp();
|
|
471
459
|
user.mobileVerificationTokenOnRegistration = token;
|
|
472
460
|
user.mobileVerificationTokenOnRegistrationExpiresAt = expiresAt;
|
|
473
|
-
|
|
474
|
-
const autoLoginUserOnRegistration = this.settingService.getConfigValue<SolidCoreSetting>('autoLoginUserOnRegistration');
|
|
475
461
|
if (autoLoginUserOnRegistration) {
|
|
476
462
|
user.mobileVerificationTokenOnLogin = token;
|
|
477
463
|
user.mobileVerificationTokenOnLoginExpiresAt = expiresAt;
|
|
@@ -479,13 +465,13 @@ export class AuthenticationService {
|
|
|
479
465
|
}
|
|
480
466
|
}
|
|
481
467
|
|
|
482
|
-
private async notifyUserOnOtpInitiateRegistration(user: User,
|
|
468
|
+
private async notifyUserOnOtpInitiateRegistration(user: User, registrationValidationSource: string) {
|
|
483
469
|
const companyLogo = await this.getCompanyLogo();
|
|
484
470
|
const dummyOtp = this.settingService.getConfigValue<SolidCoreSetting>('dummyOtp');
|
|
485
471
|
|
|
486
472
|
if (dummyOtp)
|
|
487
473
|
return; // Do nothing if dummy otp is configured.
|
|
488
|
-
if (
|
|
474
|
+
if (registrationValidationSource === PasswordlessLoginValidateWhatSources.EMAIL) {
|
|
489
475
|
const mailService = this.mailServiceFactory.getMailService();
|
|
490
476
|
mailService.sendEmailUsingTemplate(
|
|
491
477
|
user.email,
|
|
@@ -505,7 +491,7 @@ export class AuthenticationService {
|
|
|
505
491
|
user.id
|
|
506
492
|
);
|
|
507
493
|
}
|
|
508
|
-
if (
|
|
494
|
+
if (registrationValidationSource === PasswordlessLoginValidateWhatSources.MOBILE) {
|
|
509
495
|
const smsService = this.smsFactory.getSmsService();
|
|
510
496
|
smsService.sendSMSUsingTemplate(
|
|
511
497
|
user.mobile,
|
|
@@ -526,58 +512,68 @@ export class AuthenticationService {
|
|
|
526
512
|
|
|
527
513
|
async otpConfirmRegistration(confirmSignUpDto: OTPConfirmOTPDto) {
|
|
528
514
|
const isPasswordlessRegistrationEnabled = await this.isPasswordlessRegistrationEnabled();
|
|
529
|
-
|
|
530
515
|
if (!isPasswordlessRegistrationEnabled) {
|
|
531
516
|
throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
|
|
532
517
|
}
|
|
533
518
|
|
|
534
|
-
|
|
535
|
-
if (
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
519
|
+
const { type, identifier, otp } = confirmSignUpDto;
|
|
520
|
+
if (type !== PasswordlessRegistrationValidateWhatSources.EMAIL &&
|
|
521
|
+
type !== PasswordlessRegistrationValidateWhatSources.MOBILE) {
|
|
522
|
+
throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const user = await this.findUserByRegistrationIdentifier(type, identifier);
|
|
526
|
+
this.validateRegistrationOtp(user, otp, type);
|
|
527
|
+
this.clearRegistrationOtp(user, type);
|
|
528
|
+
user.active = this.settingService.getConfigValue<SolidCoreSetting>('activateUserOnRegistration') &&
|
|
529
|
+
await this.areAllPasswordlessRegistrationValidationSourcesVerified(user);
|
|
530
|
+
|
|
531
|
+
const savedUser: User = await this.userRepository.save(user);
|
|
532
|
+
this.triggerRegistrationEvent(savedUser);
|
|
533
|
+
return { active: savedUser.active, message: `User registration verified for ${type}` };
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private async findUserByRegistrationIdentifier(
|
|
537
|
+
type: PasswordlessRegistrationValidateWhatSources,
|
|
538
|
+
identifier: string,
|
|
539
|
+
): Promise<User> {
|
|
540
|
+
const where = type === PasswordlessRegistrationValidateWhatSources.EMAIL
|
|
541
|
+
? { email: identifier }
|
|
542
|
+
: { mobile: identifier };
|
|
543
|
+
const user = await this.userRepository.findOne({ where });
|
|
544
|
+
if (!user) {
|
|
545
|
+
throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
|
|
546
|
+
}
|
|
547
|
+
return user;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private validateRegistrationOtp(
|
|
551
|
+
user: User,
|
|
552
|
+
otp: string,
|
|
553
|
+
type: PasswordlessRegistrationValidateWhatSources,
|
|
554
|
+
): void {
|
|
555
|
+
const isEmail = type === PasswordlessRegistrationValidateWhatSources.EMAIL;
|
|
556
|
+
const token = isEmail ? user.emailVerificationTokenOnRegistration : user.mobileVerificationTokenOnRegistration;
|
|
557
|
+
const expiresAt = isEmail ? user.emailVerificationTokenOnRegistrationExpiresAt : user.mobileVerificationTokenOnRegistrationExpiresAt;
|
|
558
|
+
|
|
559
|
+
if (token !== otp) {
|
|
560
|
+
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
|
|
561
|
+
}
|
|
562
|
+
if (expiresAt < new Date()) {
|
|
563
|
+
throw new UnauthorizedException(ERROR_MESSAGES.OTP_EXPIRED);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private clearRegistrationOtp(user: User, type: PasswordlessRegistrationValidateWhatSources): void {
|
|
568
|
+
if (type === PasswordlessRegistrationValidateWhatSources.EMAIL) {
|
|
550
569
|
user.emailVerifiedOnRegistrationAt = new Date();
|
|
551
570
|
user.emailVerificationTokenOnRegistration = null;
|
|
552
571
|
user.emailVerificationTokenOnRegistrationExpiresAt = null;
|
|
553
|
-
|
|
554
|
-
const savedUser: User = await this.userRepository.save(user);
|
|
555
|
-
this.triggerRegistrationEvent(savedUser);
|
|
556
|
-
return { active: savedUser.active, message: `User registration verified for ${confirmSignUpDto.type}` }
|
|
557
|
-
} else if (confirmSignUpDto.type === RegistrationValidationSource.MOBILE) {
|
|
558
|
-
const user = await this.userRepository.findOne({
|
|
559
|
-
where: {
|
|
560
|
-
mobile: confirmSignUpDto.identifier,
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
if (!user) {
|
|
564
|
-
throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
|
|
565
|
-
}
|
|
566
|
-
if (user.mobileVerificationTokenOnRegistration !== confirmSignUpDto.otp) {
|
|
567
|
-
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
|
|
568
|
-
}
|
|
569
|
-
if (user.mobileVerificationTokenOnRegistrationExpiresAt < new Date()) {
|
|
570
|
-
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
|
|
571
|
-
}
|
|
572
|
+
} else {
|
|
572
573
|
user.mobileVerifiedOnRegistrationAt = new Date();
|
|
573
574
|
user.mobileVerificationTokenOnRegistration = null;
|
|
574
575
|
user.mobileVerificationTokenOnRegistrationExpiresAt = null;
|
|
575
|
-
user.active = this.settingService.getConfigValue<SolidCoreSetting>('activateUserOnRegistration') && await this.areRegistrationValidationSourcesVerified(user);
|
|
576
|
-
const savedUser: User = await this.userRepository.save(user);
|
|
577
|
-
this.triggerRegistrationEvent(savedUser);
|
|
578
|
-
return { active: savedUser.active, message: `User registration verified for ${confirmSignUpDto.type}` }
|
|
579
576
|
}
|
|
580
|
-
throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
|
|
581
577
|
}
|
|
582
578
|
|
|
583
579
|
private triggerRegistrationEvent(savedUser: User) {
|
|
@@ -586,16 +582,14 @@ export class AuthenticationService {
|
|
|
586
582
|
this.eventEmitter.emit(EventType.USER_REGISTERED, event);
|
|
587
583
|
}
|
|
588
584
|
|
|
589
|
-
async
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
const registrationValidationSources = passwordlessRegistrationValidateWhat;
|
|
593
|
-
if (registrationValidationSources.includes(RegistrationValidationSource.EMAIL)) {
|
|
585
|
+
private async areAllPasswordlessRegistrationValidationSourcesVerified(user: User): Promise<boolean> {
|
|
586
|
+
const registrationValidationSource = this.resolvePasswordlessValidationSource();
|
|
587
|
+
if (registrationValidationSource === PasswordlessLoginValidateWhatSources.EMAIL) {
|
|
594
588
|
if (!user.emailVerifiedOnRegistrationAt) {
|
|
595
589
|
return false;
|
|
596
590
|
}
|
|
597
591
|
}
|
|
598
|
-
if (
|
|
592
|
+
if (registrationValidationSource === PasswordlessLoginValidateWhatSources.MOBILE) {
|
|
599
593
|
if (!user.mobileVerifiedOnRegistrationAt) {
|
|
600
594
|
return false;
|
|
601
595
|
}
|
|
@@ -615,9 +609,14 @@ export class AuthenticationService {
|
|
|
615
609
|
}
|
|
616
610
|
|
|
617
611
|
async signIn(signInDto: SignInDto) {
|
|
618
|
-
const user = await this.
|
|
612
|
+
const user = await this.resolveUser(signInDto.username, signInDto.email);
|
|
613
|
+
if (!user) {
|
|
614
|
+
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_CREDENTIALS);
|
|
615
|
+
}
|
|
616
|
+
await this.validateUserForPasswordLogin(user, signInDto.password);
|
|
617
|
+
await this.rehashPasswordIfRequired(user, signInDto.password);
|
|
618
|
+
await this.resetFailedAttempts(user);
|
|
619
619
|
|
|
620
|
-
// TODO: Unset the password etc...
|
|
621
620
|
const tokens = await this.generateTokens(user);
|
|
622
621
|
|
|
623
622
|
await this.userActivityHistoryService.logEvent('login', user);
|
|
@@ -665,78 +664,79 @@ export class AuthenticationService {
|
|
|
665
664
|
throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
|
|
666
665
|
}
|
|
667
666
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
// });
|
|
675
|
-
const user = await this.userRepository.findOne({
|
|
676
|
-
where: [
|
|
677
|
-
{ username: signInDto.identifier },
|
|
678
|
-
{ email: signInDto.identifier },
|
|
679
|
-
]
|
|
680
|
-
});
|
|
667
|
+
const type = this.resolveLoginType(signInDto);
|
|
668
|
+
const user = await this.findUserForLogin(type, signInDto.identifier);
|
|
669
|
+
await this.assignLoginOtp(user, type);
|
|
670
|
+
this.notifyUserOnOtpInititateLogin(user, type);
|
|
671
|
+
return this.buildLoginOtpResponse(user, type);
|
|
672
|
+
}
|
|
681
673
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
}
|
|
685
|
-
if (!user.active) {
|
|
686
|
-
throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
|
|
687
|
-
}
|
|
688
|
-
const { token, expiresAt } = await this.otp();
|
|
689
|
-
user.emailVerificationTokenOnLogin = token;
|
|
690
|
-
user.emailVerificationTokenOnLoginExpiresAt = expiresAt;
|
|
691
|
-
await this.userRepository.save(user);
|
|
692
|
-
this.notifyUserOnOtpInititateLogin(user, RegistrationValidationSource.EMAIL);
|
|
693
|
-
return {
|
|
694
|
-
message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_LOGIN,
|
|
695
|
-
user: {
|
|
696
|
-
email: this.maskEmail(user.email)
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
} else if (signInDto.type === RegistrationValidationSource.MOBILE) {
|
|
700
|
-
// const user = await this.userRepository.findOne({
|
|
701
|
-
// where: {
|
|
702
|
-
// mobile: signInDto.identifier,
|
|
703
|
-
// }
|
|
704
|
-
// });
|
|
705
|
-
const user = await this.userRepository.findOne({
|
|
706
|
-
where: [
|
|
707
|
-
{ username: signInDto.identifier },
|
|
708
|
-
{ mobile: signInDto.identifier },
|
|
709
|
-
]
|
|
710
|
-
});
|
|
674
|
+
private resolveLoginType(signInDto: OTPSignInDto): PasswordlessLoginValidateWhatSources {
|
|
675
|
+
const setting = this.settingService.getConfigValue<SolidCoreSetting>('passwordlessLoginValidateWhat') as PasswordlessLoginValidateWhatSources;
|
|
711
676
|
|
|
712
|
-
|
|
713
|
-
|
|
677
|
+
if (setting === PasswordlessLoginValidateWhatSources.SELECTABLE) {
|
|
678
|
+
if (signInDto.type !== PasswordlessLoginValidateWhatSources.EMAIL &&
|
|
679
|
+
signInDto.type !== PasswordlessLoginValidateWhatSources.MOBILE) {
|
|
680
|
+
throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
|
|
714
681
|
}
|
|
682
|
+
return signInDto.type as PasswordlessLoginValidateWhatSources;
|
|
683
|
+
}
|
|
715
684
|
|
|
716
|
-
|
|
685
|
+
if (setting === PasswordlessLoginValidateWhatSources.EMAIL ||
|
|
686
|
+
setting === PasswordlessLoginValidateWhatSources.MOBILE) {
|
|
687
|
+
return setting;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
private async findUserForLogin(
|
|
694
|
+
type: PasswordlessLoginValidateWhatSources,
|
|
695
|
+
identifier: string,
|
|
696
|
+
options: { withRoles?: boolean } = {},
|
|
697
|
+
): Promise<User> {
|
|
698
|
+
const typeWhere = type === PasswordlessLoginValidateWhatSources.EMAIL
|
|
699
|
+
? { email: identifier }
|
|
700
|
+
: { mobile: identifier };
|
|
701
|
+
const user = await this.userRepository.findOne({
|
|
702
|
+
where: [{ username: identifier }, typeWhere],
|
|
703
|
+
...(options.withRoles ? { relations: { roles: true } } : {}),
|
|
704
|
+
});
|
|
705
|
+
if (!user) {
|
|
706
|
+
throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
|
|
707
|
+
}
|
|
708
|
+
if (!user.active) {
|
|
709
|
+
throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
|
|
710
|
+
}
|
|
711
|
+
return user;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
private async assignLoginOtp(user: User, type: PasswordlessLoginValidateWhatSources): Promise<void> {
|
|
715
|
+
const { token, expiresAt } = await this.otp();
|
|
716
|
+
if (type === PasswordlessLoginValidateWhatSources.EMAIL) {
|
|
717
|
+
user.emailVerificationTokenOnLogin = token;
|
|
718
|
+
user.emailVerificationTokenOnLoginExpiresAt = expiresAt;
|
|
719
|
+
} else {
|
|
717
720
|
user.mobileVerificationTokenOnLogin = token;
|
|
718
721
|
user.mobileVerificationTokenOnLoginExpiresAt = expiresAt;
|
|
719
|
-
await this.userRepository.save(user);
|
|
720
|
-
this.notifyUserOnOtpInititateLogin(user, RegistrationValidationSource.MOBILE);
|
|
721
|
-
return {
|
|
722
|
-
message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_LOGIN,
|
|
723
|
-
user: {
|
|
724
|
-
mobile: this.maskMobile(user.mobile)
|
|
725
|
-
}
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
else {
|
|
729
|
-
throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
|
|
730
722
|
}
|
|
723
|
+
await this.userRepository.save(user);
|
|
731
724
|
}
|
|
732
725
|
|
|
733
|
-
private
|
|
726
|
+
private buildLoginOtpResponse(user: User, type: PasswordlessLoginValidateWhatSources) {
|
|
727
|
+
const maskedIdentifier = type === PasswordlessLoginValidateWhatSources.EMAIL
|
|
728
|
+
? { email: this.maskEmail(user.email) }
|
|
729
|
+
: { mobile: this.maskMobile(user.mobile) };
|
|
730
|
+
return { message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_LOGIN, user: maskedIdentifier };
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
private async notifyUserOnOtpInititateLogin(user: User, loginType: PasswordlessLoginValidateWhatSources) {
|
|
734
734
|
const companyLogo = await this.getCompanyLogo();
|
|
735
735
|
const dummyOtp = this.settingService.getConfigValue<SolidCoreSetting>('dummyOtp');
|
|
736
736
|
|
|
737
737
|
if (dummyOtp)
|
|
738
738
|
return; // Do nothing if dummy otp is configured.
|
|
739
|
-
if (loginType ===
|
|
739
|
+
if (loginType === PasswordlessLoginValidateWhatSources.EMAIL) {
|
|
740
740
|
const mailService = this.mailServiceFactory.getMailService();
|
|
741
741
|
mailService.sendEmailUsingTemplate(
|
|
742
742
|
user.email,
|
|
@@ -756,7 +756,7 @@ export class AuthenticationService {
|
|
|
756
756
|
user.id
|
|
757
757
|
);
|
|
758
758
|
}
|
|
759
|
-
if (loginType ===
|
|
759
|
+
if (loginType === PasswordlessLoginValidateWhatSources.MOBILE) {
|
|
760
760
|
const smsService = this.smsFactory.getSmsService();
|
|
761
761
|
smsService.sendSMSUsingTemplate(
|
|
762
762
|
user.mobile,
|
|
@@ -780,81 +780,57 @@ export class AuthenticationService {
|
|
|
780
780
|
if (!isPasswordlessRegistrationEnabled) {
|
|
781
781
|
throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
|
|
782
782
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
783
|
+
|
|
784
|
+
const { type, identifier, otp } = confirmSignInDto;
|
|
785
|
+
if (type !== PasswordlessLoginValidateWhatSources.EMAIL &&
|
|
786
|
+
type !== PasswordlessLoginValidateWhatSources.MOBILE) {
|
|
787
|
+
throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const user = await this.findUserForLogin(type, identifier, { withRoles: true });
|
|
791
|
+
this.checkAccountBlocked(user);
|
|
792
|
+
try {
|
|
793
|
+
this.validateLoginOtp(user, otp, type);
|
|
794
|
+
} catch (e) {
|
|
795
|
+
await this.incrementFailedAttempts(user);
|
|
796
|
+
throw e;
|
|
797
|
+
}
|
|
798
|
+
this.clearLoginOtp(user, type);
|
|
799
|
+
user.failedLoginAttempts = 0;
|
|
800
|
+
await this.userRepository.save(user);
|
|
801
|
+
return this.buildLoginTokenResponse(user);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
private validateLoginOtp(user: User, otp: string, type: PasswordlessLoginValidateWhatSources): void {
|
|
805
|
+
const isEmail = type === PasswordlessLoginValidateWhatSources.EMAIL;
|
|
806
|
+
const token = isEmail ? user.emailVerificationTokenOnLogin : user.mobileVerificationTokenOnLogin;
|
|
807
|
+
const expiresAt = isEmail ? user.emailVerificationTokenOnLoginExpiresAt : user.mobileVerificationTokenOnLoginExpiresAt;
|
|
808
|
+
|
|
809
|
+
if (token !== otp) {
|
|
810
|
+
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
|
|
811
|
+
}
|
|
812
|
+
if (expiresAt < new Date()) {
|
|
813
|
+
throw new UnauthorizedException(ERROR_MESSAGES.OTP_EXPIRED);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
private clearLoginOtp(user: User, type: PasswordlessLoginValidateWhatSources): void {
|
|
818
|
+
if (type === PasswordlessLoginValidateWhatSources.EMAIL) {
|
|
811
819
|
user.emailVerifiedOnLoginAt = new Date();
|
|
812
820
|
user.emailVerificationTokenOnLogin = null;
|
|
813
821
|
user.emailVerificationTokenOnLoginExpiresAt = null;
|
|
814
|
-
|
|
815
|
-
const { accessToken, refreshToken } = await this.generateTokens(user);
|
|
816
|
-
const { id, username, email, mobile, lastLoginProvider } = user;
|
|
817
|
-
const roles = user.roles.map((role) => role.name);
|
|
818
|
-
return { accessToken, refreshToken, user: { id, username, email, mobile, lastLoginProvider, roles } };
|
|
819
|
-
} else if (confirmSignInDto.type === RegistrationValidationSource.MOBILE) {
|
|
820
|
-
// const user = await this.userRepository.findOne({
|
|
821
|
-
// where: {
|
|
822
|
-
// mobile: confirmSignInDto.identifier,
|
|
823
|
-
// },
|
|
824
|
-
// relations: ['roles']
|
|
825
|
-
// });
|
|
826
|
-
const user = await this.userRepository.findOne({
|
|
827
|
-
where: [
|
|
828
|
-
{ username: confirmSignInDto.identifier },
|
|
829
|
-
{ mobile: confirmSignInDto.identifier },
|
|
830
|
-
],
|
|
831
|
-
relations: {
|
|
832
|
-
roles: true
|
|
833
|
-
}
|
|
834
|
-
});
|
|
835
|
-
if (!user) {
|
|
836
|
-
throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_ACTIVE);
|
|
837
|
-
}
|
|
838
|
-
if (!user.active) {
|
|
839
|
-
throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
|
|
840
|
-
}
|
|
841
|
-
if (user.mobileVerificationTokenOnLogin !== confirmSignInDto.otp) {
|
|
842
|
-
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
|
|
843
|
-
}
|
|
844
|
-
if (user.mobileVerificationTokenOnLoginExpiresAt < new Date()) {
|
|
845
|
-
throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
|
|
846
|
-
}
|
|
822
|
+
} else {
|
|
847
823
|
user.mobileVerifiedOnLoginAt = new Date();
|
|
848
824
|
user.mobileVerificationTokenOnLogin = null;
|
|
849
825
|
user.mobileVerificationTokenOnLoginExpiresAt = null;
|
|
850
|
-
await this.userRepository.save(user);
|
|
851
|
-
const { accessToken, refreshToken } = await this.generateTokens(user);
|
|
852
|
-
const { id, username, email, mobile, lastLoginProvider } = user;
|
|
853
|
-
const roles = user.roles.map((role) => role.name);
|
|
854
|
-
return { accessToken, refreshToken, user: { id, username, email, mobile, lastLoginProvider, roles } };
|
|
855
|
-
|
|
856
826
|
}
|
|
857
|
-
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
private async buildLoginTokenResponse(user: User) {
|
|
830
|
+
const { accessToken, refreshToken } = await this.generateTokens(user);
|
|
831
|
+
const { id, username, email, mobile, lastLoginProvider } = user;
|
|
832
|
+
const roles = user.roles.map((role) => role.name);
|
|
833
|
+
return { accessToken, refreshToken, user: { id, username, email, mobile, lastLoginProvider, roles } };
|
|
858
834
|
}
|
|
859
835
|
|
|
860
836
|
async changePassword(changePasswordDto: ChangePasswordDto, activeUser: ActiveUserData) {
|
|
@@ -1251,11 +1227,19 @@ export class AuthenticationService {
|
|
|
1251
1227
|
}
|
|
1252
1228
|
});
|
|
1253
1229
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1230
|
+
if (!user) {
|
|
1231
|
+
throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
|
|
1232
|
+
}
|
|
1233
|
+
this.checkAccountBlocked(user);
|
|
1257
1234
|
|
|
1258
|
-
|
|
1235
|
+
try {
|
|
1236
|
+
await this.validateUserUsingGoogle(user);
|
|
1237
|
+
} catch (e) {
|
|
1238
|
+
await this.incrementFailedAttempts(user);
|
|
1239
|
+
throw e;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
await this.resetFailedAttempts(user);
|
|
1259
1243
|
const tokens = await this.generateTokens(user);
|
|
1260
1244
|
return {
|
|
1261
1245
|
user: {
|
|
@@ -1275,6 +1259,24 @@ export class AuthenticationService {
|
|
|
1275
1259
|
return this.settingService.getConfigValue<SolidCoreSetting>('passwordLessAuth');
|
|
1276
1260
|
}
|
|
1277
1261
|
|
|
1262
|
+
private checkAccountBlocked(user: User): void {
|
|
1263
|
+
const maxFailedAttempts = this.settingService.getConfigValue<SolidCoreSetting>('maxFailedLoginAttempts') as number;
|
|
1264
|
+
if (maxFailedAttempts > 0 && user.failedLoginAttempts >= maxFailedAttempts) {
|
|
1265
|
+
throw new ForbiddenException(ERROR_MESSAGES.ACCOUNT_BLOCKED);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
private async incrementFailedAttempts(user: User): Promise<void> {
|
|
1270
|
+
user.failedLoginAttempts += 1;
|
|
1271
|
+
await this.userRepository.save(user);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
private async resetFailedAttempts(user: User): Promise<void> {
|
|
1275
|
+
if (user.failedLoginAttempts === 0) return;
|
|
1276
|
+
user.failedLoginAttempts = 0;
|
|
1277
|
+
await this.userRepository.save(user);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1278
1280
|
//FIXME - Pending implementation
|
|
1279
1281
|
// async logout() {
|
|
1280
1282
|
// // const user = this.request.user; //TODO: // Access the user from the execution context
|