@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.
Files changed (469) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/dist/commands/run-tests.command.d.ts +37 -0
  3. package/dist/commands/run-tests.command.d.ts.map +1 -0
  4. package/dist/commands/run-tests.command.js +345 -0
  5. package/dist/commands/run-tests.command.js.map +1 -0
  6. package/dist/commands/test-data.command.d.ts +6 -6
  7. package/dist/commands/test-data.command.d.ts.map +1 -1
  8. package/dist/commands/test-data.command.js +25 -25
  9. package/dist/commands/test-data.command.js.map +1 -1
  10. package/dist/commands/test.command.d.ts +5 -0
  11. package/dist/commands/test.command.d.ts.map +1 -0
  12. package/dist/commands/test.command.js +26 -0
  13. package/dist/commands/test.command.js.map +1 -0
  14. package/dist/constants/error-messages.d.ts +1 -0
  15. package/dist/constants/error-messages.d.ts.map +1 -1
  16. package/dist/constants/error-messages.js +1 -0
  17. package/dist/constants/error-messages.js.map +1 -1
  18. package/dist/constants.d.ts +3 -3
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +12 -12
  21. package/dist/constants.js.map +1 -1
  22. package/dist/controllers/otp-authentication.controller.d.ts +1 -4
  23. package/dist/controllers/otp-authentication.controller.d.ts.map +1 -1
  24. package/dist/controllers/otp-authentication.controller.js +1 -1
  25. package/dist/controllers/role-metadata.controller.d.ts +1 -0
  26. package/dist/controllers/role-metadata.controller.d.ts.map +1 -1
  27. package/dist/controllers/role-metadata.controller.js +15 -0
  28. package/dist/controllers/role-metadata.controller.js.map +1 -1
  29. package/dist/controllers/service.controller.d.ts +0 -9
  30. package/dist/controllers/service.controller.d.ts.map +1 -1
  31. package/dist/controllers/service.controller.js +0 -45
  32. package/dist/controllers/service.controller.js.map +1 -1
  33. package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
  34. package/dist/dtos/basic-filters.dto.js.map +1 -1
  35. package/dist/dtos/create-email-template.dto.d.ts.map +1 -1
  36. package/dist/dtos/create-email-template.dto.js.map +1 -1
  37. package/dist/dtos/create-list-of-values.dto.d.ts.map +1 -1
  38. package/dist/dtos/create-list-of-values.dto.js.map +1 -1
  39. package/dist/dtos/create-menu-item-metadata.dto.d.ts.map +1 -1
  40. package/dist/dtos/create-menu-item-metadata.dto.js.map +1 -1
  41. package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
  42. package/dist/dtos/create-role-metadata.dto.js.map +1 -1
  43. package/dist/dtos/create-scheduled-job.dto.d.ts.map +1 -1
  44. package/dist/dtos/create-scheduled-job.dto.js.map +1 -1
  45. package/dist/dtos/create-security-rule.dto.d.ts.map +1 -1
  46. package/dist/dtos/create-security-rule.dto.js.map +1 -1
  47. package/dist/dtos/create-sms-template.dto.d.ts.map +1 -1
  48. package/dist/dtos/create-sms-template.dto.js.map +1 -1
  49. package/dist/dtos/create-user.dto.d.ts +1 -0
  50. package/dist/dtos/create-user.dto.d.ts.map +1 -1
  51. package/dist/dtos/create-user.dto.js +2 -1
  52. package/dist/dtos/create-user.dto.js.map +1 -1
  53. package/dist/dtos/create-view-metadata.dto.d.ts.map +1 -1
  54. package/dist/dtos/create-view-metadata.dto.js.map +1 -1
  55. package/dist/dtos/otp-sign-in.dto.d.ts +1 -1
  56. package/dist/dtos/otp-sign-in.dto.d.ts.map +1 -1
  57. package/dist/dtos/otp-sign-in.dto.js +2 -2
  58. package/dist/dtos/otp-sign-in.dto.js.map +1 -1
  59. package/dist/dtos/otp-sign-up.dto.d.ts +2 -2
  60. package/dist/dtos/otp-sign-up.dto.d.ts.map +1 -1
  61. package/dist/dtos/otp-sign-up.dto.js +2 -2
  62. package/dist/dtos/otp-sign-up.dto.js.map +1 -1
  63. package/dist/dtos/resolve-s3-url.dto.d.ts +2 -5
  64. package/dist/dtos/resolve-s3-url.dto.d.ts.map +1 -1
  65. package/dist/dtos/resolve-s3-url.dto.js +1 -13
  66. package/dist/dtos/resolve-s3-url.dto.js.map +1 -1
  67. package/dist/dtos/sign-up.dto.d.ts.map +1 -1
  68. package/dist/dtos/sign-up.dto.js.map +1 -1
  69. package/dist/dtos/update-email-template.dto.d.ts.map +1 -1
  70. package/dist/dtos/update-email-template.dto.js.map +1 -1
  71. package/dist/dtos/update-list-of-values.dto.d.ts.map +1 -1
  72. package/dist/dtos/update-list-of-values.dto.js.map +1 -1
  73. package/dist/dtos/update-menu-item-metadata.dto.d.ts.map +1 -1
  74. package/dist/dtos/update-menu-item-metadata.dto.js.map +1 -1
  75. package/dist/dtos/update-scheduled-job.dto.d.ts.map +1 -1
  76. package/dist/dtos/update-scheduled-job.dto.js.map +1 -1
  77. package/dist/dtos/update-security-rule.dto.d.ts.map +1 -1
  78. package/dist/dtos/update-security-rule.dto.js.map +1 -1
  79. package/dist/dtos/update-sms-template.dto.d.ts.map +1 -1
  80. package/dist/dtos/update-sms-template.dto.js.map +1 -1
  81. package/dist/dtos/update-view-metadata.dto.d.ts.map +1 -1
  82. package/dist/dtos/update-view-metadata.dto.js.map +1 -1
  83. package/dist/entities/user.entity.d.ts +1 -0
  84. package/dist/entities/user.entity.d.ts.map +1 -1
  85. package/dist/entities/user.entity.js +6 -1
  86. package/dist/entities/user.entity.js.map +1 -1
  87. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts +2 -0
  88. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts.map +1 -1
  89. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js +33 -23
  90. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js.map +1 -1
  91. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts +3 -0
  92. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts.map +1 -1
  93. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js +36 -23
  94. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js.map +1 -1
  95. package/dist/helpers/security.helper.js +1 -0
  96. package/dist/helpers/security.helper.js.map +1 -1
  97. package/dist/index.d.ts +3 -4
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +3 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/repository/solid-base.repository.d.ts +10 -1
  102. package/dist/repository/solid-base.repository.d.ts.map +1 -1
  103. package/dist/repository/solid-base.repository.js +109 -0
  104. package/dist/repository/solid-base.repository.js.map +1 -1
  105. package/dist/seeders/module-metadata-seeder.service.d.ts +2 -0
  106. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  107. package/dist/seeders/module-metadata-seeder.service.js +142 -91
  108. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  109. package/dist/seeders/module-test-data.service.d.ts.map +1 -1
  110. package/dist/seeders/module-test-data.service.js +3 -3
  111. package/dist/seeders/module-test-data.service.js.map +1 -1
  112. package/dist/seeders/permission-metadata-seeder.service.d.ts +1 -1
  113. package/dist/seeders/permission-metadata-seeder.service.d.ts.map +1 -1
  114. package/dist/seeders/permission-metadata-seeder.service.js +1 -1
  115. package/dist/seeders/permission-metadata-seeder.service.js.map +1 -1
  116. package/dist/seeders/seed-data/solid-core-metadata.json +12 -25
  117. package/dist/services/authentication.service.d.ts +22 -8
  118. package/dist/services/authentication.service.d.ts.map +1 -1
  119. package/dist/services/authentication.service.js +228 -214
  120. package/dist/services/authentication.service.js.map +1 -1
  121. package/dist/services/chatter-message.service.d.ts +2 -0
  122. package/dist/services/chatter-message.service.d.ts.map +1 -1
  123. package/dist/services/chatter-message.service.js +18 -2
  124. package/dist/services/chatter-message.service.js.map +1 -1
  125. package/dist/services/crud-helper.service.d.ts +4 -0
  126. package/dist/services/crud-helper.service.d.ts.map +1 -1
  127. package/dist/services/crud-helper.service.js +66 -32
  128. package/dist/services/crud-helper.service.js.map +1 -1
  129. package/dist/services/crud.service.d.ts.map +1 -1
  130. package/dist/services/crud.service.js +7 -4
  131. package/dist/services/crud.service.js.map +1 -1
  132. package/dist/services/field-metadata.service.d.ts.map +1 -1
  133. package/dist/services/field-metadata.service.js.map +1 -1
  134. package/dist/services/file/disk-file.service.d.ts +0 -2
  135. package/dist/services/file/disk-file.service.d.ts.map +1 -1
  136. package/dist/services/file/disk-file.service.js +7 -16
  137. package/dist/services/file/disk-file.service.js.map +1 -1
  138. package/dist/services/file/index.d.ts +1 -0
  139. package/dist/services/file/index.d.ts.map +1 -1
  140. package/dist/services/file/index.js +1 -0
  141. package/dist/services/file/index.js.map +1 -1
  142. package/dist/services/file/storage-path-builder.d.ts +17 -0
  143. package/dist/services/file/storage-path-builder.d.ts.map +1 -0
  144. package/dist/{seeders/sms-template-seeder.service.js → services/file/storage-path-builder.js} +45 -35
  145. package/dist/services/file/storage-path-builder.js.map +1 -0
  146. package/dist/services/media.service.d.ts +1 -1
  147. package/dist/services/media.service.d.ts.map +1 -1
  148. package/dist/services/media.service.js +45 -6
  149. package/dist/services/media.service.js.map +1 -1
  150. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  151. package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
  152. package/dist/services/mediaStorageProviders/file-storage-provider.js +46 -7
  153. package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
  154. package/dist/services/module-metadata.service.d.ts +4 -6
  155. package/dist/services/module-metadata.service.d.ts.map +1 -1
  156. package/dist/services/module-metadata.service.js +16 -14
  157. package/dist/services/module-metadata.service.js.map +1 -1
  158. package/dist/services/queues/common.d.ts +3 -0
  159. package/dist/services/queues/common.d.ts.map +1 -0
  160. package/dist/services/queues/common.js +39 -0
  161. package/dist/services/queues/common.js.map +1 -0
  162. package/dist/services/queues/database-publisher.service.d.ts.map +1 -1
  163. package/dist/services/queues/database-publisher.service.js +3 -1
  164. package/dist/services/queues/database-publisher.service.js.map +1 -1
  165. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  166. package/dist/services/queues/database-subscriber.service.js +5 -2
  167. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  168. package/dist/services/queues/rabbitmq-publisher.service.d.ts.map +1 -1
  169. package/dist/services/queues/rabbitmq-publisher.service.js +13 -6
  170. package/dist/services/queues/rabbitmq-publisher.service.js.map +1 -1
  171. package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
  172. package/dist/services/queues/rabbitmq-subscriber.service.js +9 -5
  173. package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
  174. package/dist/services/setting.service.d.ts +3 -2
  175. package/dist/services/setting.service.d.ts.map +1 -1
  176. package/dist/services/setting.service.js +7 -4
  177. package/dist/services/setting.service.js.map +1 -1
  178. package/dist/services/settings/default-settings-provider.service.d.ts +24 -2
  179. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  180. package/dist/services/settings/default-settings-provider.service.js +8 -6
  181. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  182. package/dist/solid-core.module.d.ts +3 -1
  183. package/dist/solid-core.module.d.ts.map +1 -1
  184. package/dist/solid-core.module.js +49 -9
  185. package/dist/solid-core.module.js.map +1 -1
  186. package/dist/testing/__examples__/register-example-specs.d.ts +3 -0
  187. package/dist/testing/__examples__/register-example-specs.d.ts.map +1 -0
  188. package/dist/testing/__examples__/register-example-specs.js +8 -0
  189. package/dist/testing/__examples__/register-example-specs.js.map +1 -0
  190. package/dist/testing/__examples__/specs/custom-health.spec.d.ts +17 -0
  191. package/dist/testing/__examples__/specs/custom-health.spec.d.ts.map +1 -0
  192. package/dist/testing/__examples__/specs/custom-health.spec.js +30 -0
  193. package/dist/testing/__examples__/specs/custom-health.spec.js.map +1 -0
  194. package/dist/testing/adapters/api/api-adapter.d.ts +9 -0
  195. package/dist/testing/adapters/api/api-adapter.d.ts.map +1 -0
  196. package/dist/testing/adapters/api/api-adapter.js +76 -0
  197. package/dist/testing/adapters/api/api-adapter.js.map +1 -0
  198. package/dist/testing/adapters/api/api.types.d.ts +14 -0
  199. package/dist/testing/adapters/api/api.types.d.ts.map +1 -0
  200. package/dist/testing/adapters/api/api.types.js +3 -0
  201. package/dist/testing/adapters/api/api.types.js.map +1 -0
  202. package/dist/testing/adapters/ui/playwright-adapter.d.ts +14 -0
  203. package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -0
  204. package/dist/testing/adapters/ui/playwright-adapter.js +80 -0
  205. package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -0
  206. package/dist/testing/adapters/ui/ui.types.d.ts +5 -0
  207. package/dist/testing/adapters/ui/ui.types.d.ts.map +1 -0
  208. package/dist/testing/adapters/ui/ui.types.js +3 -0
  209. package/dist/testing/adapters/ui/ui.types.js.map +1 -0
  210. package/dist/testing/contracts/runtime-context.types.d.ts +35 -0
  211. package/dist/testing/contracts/runtime-context.types.d.ts.map +1 -0
  212. package/dist/testing/contracts/runtime-context.types.js +3 -0
  213. package/dist/testing/contracts/runtime-context.types.js.map +1 -0
  214. package/dist/testing/contracts/test-spec.types.d.ts +21 -0
  215. package/dist/testing/contracts/test-spec.types.d.ts.map +1 -0
  216. package/dist/testing/contracts/test-spec.types.js +3 -0
  217. package/dist/testing/contracts/test-spec.types.js.map +1 -0
  218. package/dist/testing/contracts/testing-metadata.types.d.ts +41 -0
  219. package/dist/testing/contracts/testing-metadata.types.d.ts.map +1 -0
  220. package/dist/testing/contracts/testing-metadata.types.js +3 -0
  221. package/dist/testing/contracts/testing-metadata.types.js.map +1 -0
  222. package/dist/testing/core/interpolation.d.ts +4 -0
  223. package/dist/testing/core/interpolation.d.ts.map +1 -0
  224. package/dist/testing/core/interpolation.js +180 -0
  225. package/dist/testing/core/interpolation.js.map +1 -0
  226. package/dist/testing/core/normalize-steps.d.ts +7 -0
  227. package/dist/testing/core/normalize-steps.d.ts.map +1 -0
  228. package/dist/testing/core/normalize-steps.js +20 -0
  229. package/dist/testing/core/normalize-steps.js.map +1 -0
  230. package/dist/testing/core/resource-store.d.ts +8 -0
  231. package/dist/testing/core/resource-store.d.ts.map +1 -0
  232. package/dist/testing/core/resource-store.js +41 -0
  233. package/dist/testing/core/resource-store.js.map +1 -0
  234. package/dist/testing/core/spec-registry.d.ts +10 -0
  235. package/dist/testing/core/spec-registry.d.ts.map +1 -0
  236. package/dist/testing/core/spec-registry.js +32 -0
  237. package/dist/testing/core/spec-registry.js.map +1 -0
  238. package/dist/testing/core/step-registry.d.ts +10 -0
  239. package/dist/testing/core/step-registry.d.ts.map +1 -0
  240. package/dist/testing/core/step-registry.js +26 -0
  241. package/dist/testing/core/step-registry.js.map +1 -0
  242. package/dist/testing/core/testing-engine.d.ts +14 -0
  243. package/dist/testing/core/testing-engine.d.ts.map +1 -0
  244. package/dist/testing/core/testing-engine.js +97 -0
  245. package/dist/testing/core/testing-engine.js.map +1 -0
  246. package/dist/testing/core/timeout.d.ts +2 -0
  247. package/dist/testing/core/timeout.d.ts.map +1 -0
  248. package/dist/testing/core/timeout.js +18 -0
  249. package/dist/testing/core/timeout.js.map +1 -0
  250. package/dist/testing/reporter/attachments.d.ts +4 -0
  251. package/dist/testing/reporter/attachments.d.ts.map +1 -0
  252. package/dist/testing/reporter/attachments.js +25 -0
  253. package/dist/testing/reporter/attachments.js.map +1 -0
  254. package/dist/testing/reporter/console-reporter.d.ts +45 -0
  255. package/dist/testing/reporter/console-reporter.d.ts.map +1 -0
  256. package/dist/testing/reporter/console-reporter.js +189 -0
  257. package/dist/testing/reporter/console-reporter.js.map +1 -0
  258. package/dist/testing/reporter/reporter.types.d.ts +37 -0
  259. package/dist/testing/reporter/reporter.types.d.ts.map +1 -0
  260. package/dist/testing/reporter/reporter.types.js +3 -0
  261. package/dist/testing/reporter/reporter.types.js.map +1 -0
  262. package/dist/testing/runner/lifecycle.d.ts +9 -0
  263. package/dist/testing/runner/lifecycle.d.ts.map +1 -0
  264. package/dist/testing/runner/lifecycle.js +33 -0
  265. package/dist/testing/runner/lifecycle.js.map +1 -0
  266. package/dist/testing/runner/run-from-metadata.d.ts +24 -0
  267. package/dist/testing/runner/run-from-metadata.d.ts.map +1 -0
  268. package/dist/testing/runner/run-from-metadata.js +70 -0
  269. package/dist/testing/runner/run-from-metadata.js.map +1 -0
  270. package/dist/testing/runner/scenario-filter.d.ts +9 -0
  271. package/dist/testing/runner/scenario-filter.d.ts.map +1 -0
  272. package/dist/testing/runner/scenario-filter.js +22 -0
  273. package/dist/testing/runner/scenario-filter.js.map +1 -0
  274. package/dist/testing/steps/api/auth.step.d.ts +3 -0
  275. package/dist/testing/steps/api/auth.step.d.ts.map +1 -0
  276. package/dist/testing/steps/api/auth.step.js +38 -0
  277. package/dist/testing/steps/api/auth.step.js.map +1 -0
  278. package/dist/testing/steps/api/index.d.ts +3 -0
  279. package/dist/testing/steps/api/index.d.ts.map +1 -0
  280. package/dist/testing/steps/api/index.js +10 -0
  281. package/dist/testing/steps/api/index.js.map +1 -0
  282. package/dist/testing/steps/api/request.step.d.ts +3 -0
  283. package/dist/testing/steps/api/request.step.d.ts.map +1 -0
  284. package/dist/testing/steps/api/request.step.js +281 -0
  285. package/dist/testing/steps/api/request.step.js.map +1 -0
  286. package/dist/testing/steps/assert/http.step.d.ts +3 -0
  287. package/dist/testing/steps/assert/http.step.d.ts.map +1 -0
  288. package/dist/testing/steps/assert/http.step.js +27 -0
  289. package/dist/testing/steps/assert/http.step.js.map +1 -0
  290. package/dist/testing/steps/assert/index.d.ts +3 -0
  291. package/dist/testing/steps/assert/index.d.ts.map +1 -0
  292. package/dist/testing/steps/assert/index.js +12 -0
  293. package/dist/testing/steps/assert/index.js.map +1 -0
  294. package/dist/testing/steps/assert/jsonpath.step.d.ts +3 -0
  295. package/dist/testing/steps/assert/jsonpath.step.d.ts.map +1 -0
  296. package/dist/testing/steps/assert/jsonpath.step.js +40 -0
  297. package/dist/testing/steps/assert/jsonpath.step.js.map +1 -0
  298. package/dist/testing/steps/assert/primitives.step.d.ts +3 -0
  299. package/dist/testing/steps/assert/primitives.step.d.ts.map +1 -0
  300. package/dist/testing/steps/assert/primitives.step.js +43 -0
  301. package/dist/testing/steps/assert/primitives.step.js.map +1 -0
  302. package/dist/testing/steps/test/index.d.ts +3 -0
  303. package/dist/testing/steps/test/index.d.ts.map +1 -0
  304. package/dist/testing/steps/test/index.js +8 -0
  305. package/dist/testing/steps/test/index.js.map +1 -0
  306. package/dist/testing/steps/test/test-spec.step.d.ts +3 -0
  307. package/dist/testing/steps/test/test-spec.step.d.ts.map +1 -0
  308. package/dist/testing/steps/test/test-spec.step.js +41 -0
  309. package/dist/testing/steps/test/test-spec.step.js.map +1 -0
  310. package/dist/testing/steps/ui/actions.step.d.ts +3 -0
  311. package/dist/testing/steps/ui/actions.step.d.ts.map +1 -0
  312. package/dist/testing/steps/ui/actions.step.js +31 -0
  313. package/dist/testing/steps/ui/actions.step.js.map +1 -0
  314. package/dist/testing/steps/ui/assertions.step.d.ts +3 -0
  315. package/dist/testing/steps/ui/assertions.step.d.ts.map +1 -0
  316. package/dist/testing/steps/ui/assertions.step.js +41 -0
  317. package/dist/testing/steps/ui/assertions.step.js.map +1 -0
  318. package/dist/testing/steps/ui/form.step.d.ts +3 -0
  319. package/dist/testing/steps/ui/form.step.d.ts.map +1 -0
  320. package/dist/testing/steps/ui/form.step.js +34 -0
  321. package/dist/testing/steps/ui/form.step.js.map +1 -0
  322. package/dist/testing/steps/ui/index.d.ts +3 -0
  323. package/dist/testing/steps/ui/index.d.ts.map +1 -0
  324. package/dist/testing/steps/ui/index.js +14 -0
  325. package/dist/testing/steps/ui/index.js.map +1 -0
  326. package/dist/testing/steps/ui/navigation.step.d.ts +3 -0
  327. package/dist/testing/steps/ui/navigation.step.d.ts.map +1 -0
  328. package/dist/testing/steps/ui/navigation.step.js +39 -0
  329. package/dist/testing/steps/ui/navigation.step.js.map +1 -0
  330. package/dist/testing/steps/util/index.d.ts +3 -0
  331. package/dist/testing/steps/util/index.d.ts.map +1 -0
  332. package/dist/testing/steps/util/index.js +12 -0
  333. package/dist/testing/steps/util/index.js.map +1 -0
  334. package/dist/testing/steps/util/log.step.d.ts +3 -0
  335. package/dist/testing/steps/util/log.step.d.ts.map +1 -0
  336. package/dist/testing/steps/util/log.step.js +18 -0
  337. package/dist/testing/steps/util/log.step.js.map +1 -0
  338. package/dist/testing/steps/util/require.step.d.ts +3 -0
  339. package/dist/testing/steps/util/require.step.d.ts.map +1 -0
  340. package/dist/testing/steps/util/require.step.js +16 -0
  341. package/dist/testing/steps/util/require.step.js.map +1 -0
  342. package/dist/testing/steps/util/sleep.step.d.ts +3 -0
  343. package/dist/testing/steps/util/sleep.step.d.ts.map +1 -0
  344. package/dist/testing/steps/util/sleep.step.js +13 -0
  345. package/dist/testing/steps/util/sleep.step.js.map +1 -0
  346. package/docs/test-data-workflow.md +51 -11
  347. package/package.json +10 -2
  348. package/src/commands/run-tests.command.ts +278 -0
  349. package/src/commands/test-data.command.ts +26 -26
  350. package/src/commands/test.command.ts +14 -0
  351. package/src/constants/error-messages.ts +1 -0
  352. package/src/constants.ts +3 -3
  353. package/src/controllers/role-metadata.controller.ts +26 -18
  354. package/src/controllers/service.controller.ts +58 -59
  355. package/src/dtos/basic-filters.dto.ts +0 -2
  356. package/src/dtos/create-email-template.dto.ts +7 -0
  357. package/src/dtos/create-list-of-values.dto.ts +7 -0
  358. package/src/dtos/create-menu-item-metadata.dto.ts +12 -1
  359. package/src/dtos/create-role-metadata.dto.ts +9 -0
  360. package/src/dtos/create-scheduled-job.dto.ts +14 -0
  361. package/src/dtos/create-security-rule.dto.ts +6 -0
  362. package/src/dtos/create-sms-template.dto.ts +6 -0
  363. package/src/dtos/create-user.dto.ts +1 -0
  364. package/src/dtos/create-view-metadata.dto.ts +11 -0
  365. package/src/dtos/otp-sign-in.dto.ts +3 -3
  366. package/src/dtos/otp-sign-up.dto.ts +3 -3
  367. package/src/dtos/resolve-s3-url.dto.ts +2 -12
  368. package/src/dtos/sign-up.dto.ts +0 -2
  369. package/src/dtos/update-email-template.dto.ts +6 -0
  370. package/src/dtos/update-list-of-values.dto.ts +8 -0
  371. package/src/dtos/update-menu-item-metadata.dto.ts +12 -0
  372. package/src/dtos/update-scheduled-job.dto.ts +15 -0
  373. package/src/dtos/update-security-rule.dto.ts +7 -0
  374. package/src/dtos/update-sms-template.dto.ts +32 -32
  375. package/src/dtos/update-view-metadata.dto.ts +12 -0
  376. package/src/entities/user.entity.ts +3 -0
  377. package/src/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.ts +43 -32
  378. package/src/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.ts +45 -33
  379. package/src/helpers/security.helper.ts +1 -1
  380. package/src/index.ts +3 -4
  381. package/src/repository/solid-base.repository.ts +172 -1
  382. package/src/seeders/module-metadata-seeder.service.ts +191 -150
  383. package/src/seeders/module-test-data.service.ts +5 -3
  384. package/src/seeders/permission-metadata-seeder.service.ts +1 -4
  385. package/src/seeders/seed-data/solid-core-metadata.json +12 -25
  386. package/src/services/authentication.service.ts +268 -266
  387. package/src/services/chatter-message.service.ts +18 -1
  388. package/src/services/crud-helper.service.ts +79 -36
  389. package/src/services/crud.service.ts +10 -4
  390. package/src/services/field-metadata.service.ts +0 -71
  391. package/src/services/file/disk-file.service.ts +8 -18
  392. package/src/services/file/index.ts +1 -0
  393. package/src/services/file/storage-path-builder.ts +56 -0
  394. package/src/services/media.service.ts +13 -7
  395. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +1 -1
  396. package/src/services/mediaStorageProviders/file-storage-provider.ts +13 -8
  397. package/src/services/module-metadata.service.ts +18 -15
  398. package/src/services/queues/common.ts +75 -0
  399. package/src/services/queues/database-publisher.service.ts +4 -1
  400. package/src/services/queues/database-subscriber.service.ts +5 -3
  401. package/src/services/queues/rabbitmq-publisher.service.ts +17 -7
  402. package/src/services/queues/rabbitmq-subscriber.service.ts +9 -5
  403. package/src/services/setting.service.ts +5 -3
  404. package/src/services/settings/default-settings-provider.service.ts +5 -3
  405. package/src/solid-core.module.ts +20 -12
  406. package/src/testing/README.md +364 -0
  407. package/src/testing/__examples__/register-example-specs.ts +6 -0
  408. package/src/testing/__examples__/specs/custom-health.spec.ts +29 -0
  409. package/src/testing/__examples__/testing.sample.json +82 -0
  410. package/src/testing/adapters/api/api-adapter.ts +85 -0
  411. package/src/testing/adapters/api/api.types.ts +15 -0
  412. package/src/testing/adapters/ui/playwright-adapter.ts +54 -0
  413. package/src/testing/adapters/ui/ui.types.ts +4 -0
  414. package/src/testing/contracts/runtime-context.types.ts +36 -0
  415. package/src/testing/contracts/test-spec.types.ts +24 -0
  416. package/src/testing/contracts/testing-metadata.types.ts +46 -0
  417. package/src/testing/core/interpolation.ts +189 -0
  418. package/src/testing/core/normalize-steps.ts +21 -0
  419. package/src/testing/core/resource-store.ts +38 -0
  420. package/src/testing/core/spec-registry.ts +33 -0
  421. package/src/testing/core/step-registry.ts +27 -0
  422. package/src/testing/core/testing-engine.ts +127 -0
  423. package/src/testing/core/timeout.ts +19 -0
  424. package/src/testing/reporter/attachments.ts +25 -0
  425. package/src/testing/reporter/console-reporter.ts +229 -0
  426. package/src/testing/reporter/reporter.types.ts +36 -0
  427. package/src/testing/runner/lifecycle.ts +31 -0
  428. package/src/testing/runner/run-from-metadata.ts +87 -0
  429. package/src/testing/runner/scenario-filter.ts +33 -0
  430. package/src/testing/steps/api/auth.step.ts +66 -0
  431. package/src/testing/steps/api/index.ts +10 -0
  432. package/src/testing/steps/api/request.step.ts +358 -0
  433. package/src/testing/steps/assert/http.step.ts +33 -0
  434. package/src/testing/steps/assert/index.ts +12 -0
  435. package/src/testing/steps/assert/jsonpath.step.ts +50 -0
  436. package/src/testing/steps/assert/primitives.step.ts +69 -0
  437. package/src/testing/steps/test/index.ts +8 -0
  438. package/src/testing/steps/test/test-spec.step.ts +52 -0
  439. package/src/testing/steps/ui/actions.step.ts +36 -0
  440. package/src/testing/steps/ui/assertions.step.ts +54 -0
  441. package/src/testing/steps/ui/form.step.ts +39 -0
  442. package/src/testing/steps/ui/index.ts +12 -0
  443. package/src/testing/steps/ui/navigation.step.ts +53 -0
  444. package/src/testing/steps/util/index.ts +10 -0
  445. package/src/testing/steps/util/log.step.ts +19 -0
  446. package/src/testing/steps/util/require.step.ts +16 -0
  447. package/src/testing/steps/util/sleep.step.ts +15 -0
  448. package/tsconfig.json +35 -25
  449. package/tsconfig.tests.json +14 -0
  450. package/dist/passport-strategies/local.strategy.d.ts +0 -15
  451. package/dist/passport-strategies/local.strategy.d.ts.map +0 -1
  452. package/dist/passport-strategies/local.strategy.js +0 -44
  453. package/dist/passport-strategies/local.strategy.js.map +0 -1
  454. package/dist/seeders/email-template-seeder.service.d.ts +0 -10
  455. package/dist/seeders/email-template-seeder.service.d.ts.map +0 -1
  456. package/dist/seeders/email-template-seeder.service.js +0 -84
  457. package/dist/seeders/email-template-seeder.service.js.map +0 -1
  458. package/dist/seeders/sms-template-seeder.service.d.ts +0 -10
  459. package/dist/seeders/sms-template-seeder.service.d.ts.map +0 -1
  460. package/dist/seeders/sms-template-seeder.service.js.map +0 -1
  461. package/dist/seeders/user-seeder.service.d.ts +0 -10
  462. package/dist/seeders/user-seeder.service.d.ts.map +0 -1
  463. package/dist/seeders/user-seeder.service.js +0 -44
  464. package/dist/seeders/user-seeder.service.js.map +0 -1
  465. package/dist/tsconfig.tsbuildinfo +0 -1
  466. package/src/passport-strategies/local.strategy.ts +0 -28
  467. package/src/seeders/email-template-seeder.service.ts +0 -49
  468. package/src/seeders/sms-template-seeder.service.ts +0 -50
  469. 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
- RegistrationValidationSource,
30
- TransactionalRegistrationValidationSource
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 validateUserAndRehashPasswordIfRequired(signInDto: SignInDto) {
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
- const isEqual = await this.hashingService.compare(
138
- signInDto.password,
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
- // If we reach here means that the user has been validated successfully.
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
- const rehashedUser = await this.updatePasswordDetails(user, signInDto.password);
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
- try {
379
- const isPasswordlessRegistrationEnabled = await this.isPasswordlessRegistrationEnabled();
380
- if (!isPasswordlessRegistrationEnabled) {
381
- throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
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
- // Validate if user already exists.
395
- const existingUser = await this.userRepository.findOne({ //TODO Perhaps we should use the user service instead of the repository directly.
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
- // Send OTP to the user through email or SMS, depending on the configuration.
423
- await this.notifyUserOnOtpInitiateRegistration(user, finalRegistrationVerificationSources);
424
- return { message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_REGISTRATION }
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
- const pgUniqueViolationErrorCode = '23505';
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 populateVerificationTokens(finalRegistrationValidationSources: string[], user: User) {
455
- if (finalRegistrationValidationSources.length === 0) {
443
+ private async assignRegistrationOtp(passwordlessRegistrationValidateWhat: string, user: User) {
444
+ if (!passwordlessRegistrationValidateWhat) {
456
445
  throw new BadRequestException(ERROR_MESSAGES.VALIDATION_SOURCE_REQUIRED);
457
446
  }
458
- if (finalRegistrationValidationSources.includes(TransactionalRegistrationValidationSource.EMAIL)) {
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 (finalRegistrationValidationSources.includes(TransactionalRegistrationValidationSource.MOBILE)) {
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, registrationValidationSources: string[]) {
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 (registrationValidationSources.includes(RegistrationValidationSource.EMAIL)) {
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 (registrationValidationSources.includes(RegistrationValidationSource.MOBILE)) {
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
- // Based on the identifier, validate by query the user table.
535
- if (confirmSignUpDto.type === RegistrationValidationSource.EMAIL) {
536
- const user = await this.userRepository.findOne({
537
- where: {
538
- email: confirmSignUpDto.identifier,
539
- }
540
- });
541
- if (!user) {
542
- throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
543
- }
544
- if (user.emailVerificationTokenOnRegistration !== confirmSignUpDto.otp) {
545
- throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
546
- }
547
- if (user.emailVerificationTokenOnRegistrationExpiresAt < new Date()) {
548
- throw new UnauthorizedException(ERROR_MESSAGES.OTP_EXPIRED);
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
- user.active = this.settingService.getConfigValue<SolidCoreSetting>('activateUserOnRegistration') && await this.areRegistrationValidationSourcesVerified(user);
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 areRegistrationValidationSourcesVerified(user: User): Promise<boolean> {
590
- const passwordlessRegistrationValidateWhat = this.settingService.getConfigValue<SolidCoreSetting>('passwordlessRegistrationValidateWhat');
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 (registrationValidationSources.includes(RegistrationValidationSource.MOBILE)) {
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.validateUserAndRehashPasswordIfRequired(signInDto);
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
- // Validate & generate otp token for the user based on the identifier type.
669
- if (signInDto.type === RegistrationValidationSource.EMAIL) {
670
- // const user = await this.userRepository.findOne({
671
- // where: {
672
- // email: signInDto.identifier,
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
- if (!user) {
683
- throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
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
- if (!user) {
713
- throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
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
- const { token, expiresAt } = await this.otp();
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 async notifyUserOnOtpInititateLogin(user: User, loginType: RegistrationValidationSource) {
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 === RegistrationValidationSource.EMAIL) {
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 === RegistrationValidationSource.MOBILE) {
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
- if (confirmSignInDto.type === RegistrationValidationSource.EMAIL) {
784
- // const user = await this.userRepository.findOne({
785
- // where: {
786
- // email: confirmSignInDto.identifier,
787
- // },
788
- // relations: ['roles']
789
- // });
790
- const user = await this.userRepository.findOne({
791
- where: [
792
- { username: confirmSignInDto.identifier },
793
- { email: confirmSignInDto.identifier },
794
- ],
795
- relations: {
796
- roles: true
797
- }
798
- });
799
- if (!user) {
800
- throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
801
- }
802
- if (!user.active) {
803
- throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
804
- }
805
- if (user.emailVerificationTokenOnLogin !== confirmSignInDto.otp) {
806
- throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
807
- }
808
- if (user.emailVerificationTokenOnLoginExpiresAt < new Date()) {
809
- throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
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
- await this.userRepository.save(user);
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
- throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
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
- // Validate the user against the Google oauth provider.
1255
- // If the below call finishes without raising an exception then we have validated the user properly.
1256
- await this.validateUserUsingGoogle(user);
1230
+ if (!user) {
1231
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
1232
+ }
1233
+ this.checkAccountBlocked(user);
1257
1234
 
1258
- // finally we simply generate the tokens.
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