@sync-in/server 1.5.2 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +2 -1
  3. package/environment/environment.dist.min.yaml +1 -0
  4. package/environment/environment.dist.yaml +88 -30
  5. package/migrations/0002_sleepy_korath.sql +1 -0
  6. package/migrations/meta/0002_snapshot.json +2424 -0
  7. package/migrations/meta/_journal.json +7 -0
  8. package/package.json +14 -12
  9. package/server/app.bootstrap.js +1 -1
  10. package/server/app.bootstrap.js.map +1 -1
  11. package/server/applications/files/services/files-manager.service.js +1 -2
  12. package/server/applications/files/services/files-manager.service.js.map +1 -1
  13. package/server/applications/files/services/files-only-office-manager.service.js +5 -6
  14. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  15. package/server/applications/files/utils/files.js +6 -4
  16. package/server/applications/files/utils/files.js.map +1 -1
  17. package/server/applications/links/links.controller.js +2 -2
  18. package/server/applications/links/links.controller.js.map +1 -1
  19. package/server/applications/links/services/links-manager.service.js +2 -1
  20. package/server/applications/links/services/links-manager.service.js.map +1 -1
  21. package/server/applications/links/services/links-manager.service.spec.js +6 -3
  22. package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
  23. package/server/applications/notifications/constants/notifications.js +9 -0
  24. package/server/applications/notifications/constants/notifications.js.map +1 -1
  25. package/server/applications/notifications/i18n/fr.js +10 -1
  26. package/server/applications/notifications/i18n/fr.js.map +1 -1
  27. package/server/applications/notifications/interfaces/notification-properties.interface.js.map +1 -1
  28. package/server/applications/notifications/mails/models.js +41 -3
  29. package/server/applications/notifications/mails/models.js.map +1 -1
  30. package/server/applications/notifications/mails/templates.js +1 -1
  31. package/server/applications/notifications/mails/templates.js.map +1 -1
  32. package/server/applications/notifications/schemas/notifications.schema.js +2 -1
  33. package/server/applications/notifications/schemas/notifications.schema.js.map +1 -1
  34. package/server/applications/notifications/services/notifications-manager.service.js +16 -13
  35. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  36. package/server/applications/notifications/services/notifications-manager.service.spec.js +9 -8
  37. package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
  38. package/server/applications/notifications/services/notifications-queries.service.js +1 -1
  39. package/server/applications/notifications/services/notifications-queries.service.js.map +1 -1
  40. package/server/applications/shares/services/shares-manager.service.js +3 -2
  41. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  42. package/server/applications/sync/constants/auth.js +2 -2
  43. package/server/applications/sync/constants/auth.js.map +1 -1
  44. package/server/applications/sync/dtos/sync-client-registration.dto.js +5 -0
  45. package/server/applications/sync/dtos/sync-client-registration.dto.js.map +1 -1
  46. package/server/applications/sync/dtos/sync-operations.dto.js +1 -2
  47. package/server/applications/sync/dtos/sync-operations.dto.js.map +1 -1
  48. package/server/applications/sync/schemas/sync-clients.schema.js +2 -1
  49. package/server/applications/sync/schemas/sync-clients.schema.js.map +1 -1
  50. package/server/applications/sync/schemas/sync-paths.schema.js +2 -1
  51. package/server/applications/sync/schemas/sync-paths.schema.js.map +1 -1
  52. package/server/applications/sync/services/sync-clients-manager.service.js +28 -20
  53. package/server/applications/sync/services/sync-clients-manager.service.js.map +1 -1
  54. package/server/applications/sync/services/sync-clients-manager.service.spec.js +24 -18
  55. package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
  56. package/server/applications/sync/services/sync-queries.service.js +5 -5
  57. package/server/applications/sync/services/sync-queries.service.js.map +1 -1
  58. package/server/applications/users/admin-users.controller.js +48 -37
  59. package/server/applications/users/admin-users.controller.js.map +1 -1
  60. package/server/applications/users/admin-users.controller.spec.js +15 -0
  61. package/server/applications/users/admin-users.controller.spec.js.map +1 -1
  62. package/server/applications/users/constants/routes.js +5 -0
  63. package/server/applications/users/constants/routes.js.map +1 -1
  64. package/server/applications/users/constants/user.js +8 -0
  65. package/server/applications/users/constants/user.js.map +1 -1
  66. package/server/applications/users/dto/delete-user.dto.js +5 -23
  67. package/server/applications/users/dto/delete-user.dto.js.map +1 -1
  68. package/server/applications/users/dto/user-properties.dto.js +38 -3
  69. package/server/applications/users/dto/user-properties.dto.js.map +1 -1
  70. package/server/applications/users/interfaces/admin-user.interface.js.map +1 -1
  71. package/server/applications/users/interfaces/user-secrets.interface.js +10 -0
  72. package/server/applications/users/interfaces/user-secrets.interface.js.map +1 -0
  73. package/server/applications/users/models/user.model.js +84 -50
  74. package/server/applications/users/models/user.model.js.map +1 -1
  75. package/server/applications/users/schemas/user.interface.js.map +1 -1
  76. package/server/applications/users/schemas/users.schema.js +2 -0
  77. package/server/applications/users/schemas/users.schema.js.map +1 -1
  78. package/server/applications/users/services/admin-users-manager.service.js +7 -19
  79. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  80. package/server/applications/users/services/admin-users-manager.service.spec.js +7 -26
  81. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  82. package/server/applications/users/services/admin-users-queries.service.js +1 -0
  83. package/server/applications/users/services/admin-users-queries.service.js.map +1 -1
  84. package/server/applications/users/services/users-manager.service.js +138 -28
  85. package/server/applications/users/services/users-manager.service.js.map +1 -1
  86. package/server/applications/users/services/users-manager.service.spec.js +11 -9
  87. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  88. package/server/applications/users/services/users-queries.service.js +63 -57
  89. package/server/applications/users/services/users-queries.service.js.map +1 -1
  90. package/server/applications/users/users.controller.js +48 -1
  91. package/server/applications/users/users.controller.js.map +1 -1
  92. package/server/applications/users/users.controller.spec.js +8 -1
  93. package/server/applications/users/users.controller.spec.js.map +1 -1
  94. package/server/applications/users/users.e2e-spec.js +2 -1
  95. package/server/applications/users/users.e2e-spec.js.map +1 -1
  96. package/server/applications/users/utils/avatar.js +48 -0
  97. package/server/applications/users/utils/avatar.js.map +1 -0
  98. package/server/authentication/auth.config.js +89 -26
  99. package/server/authentication/auth.config.js.map +1 -1
  100. package/server/authentication/auth.controller.js +117 -9
  101. package/server/authentication/auth.controller.js.map +1 -1
  102. package/server/authentication/auth.controller.spec.js +16 -1
  103. package/server/authentication/auth.controller.spec.js.map +1 -1
  104. package/server/authentication/auth.e2e-spec.js +4 -3
  105. package/server/authentication/auth.e2e-spec.js.map +1 -1
  106. package/server/authentication/auth.module.js +4 -1
  107. package/server/authentication/auth.module.js.map +1 -1
  108. package/server/authentication/constants/auth-ldap.js +44 -0
  109. package/server/authentication/constants/auth-ldap.js.map +1 -0
  110. package/server/authentication/constants/auth.js +37 -4
  111. package/server/authentication/constants/auth.js.map +1 -1
  112. package/server/authentication/constants/routes.js +21 -0
  113. package/server/authentication/constants/routes.js.map +1 -1
  114. package/server/authentication/constants/scope.js +20 -0
  115. package/server/authentication/constants/scope.js.map +1 -0
  116. package/server/authentication/dto/login-response.dto.js +27 -4
  117. package/server/authentication/dto/login-response.dto.js.map +1 -1
  118. package/server/authentication/dto/token-response.dto.js +5 -0
  119. package/server/authentication/dto/token-response.dto.js.map +1 -1
  120. package/server/{applications/users/dto/user-password.dto.js → authentication/dto/two-fa-verify.dto.js} +27 -9
  121. package/server/authentication/dto/two-fa-verify.dto.js.map +1 -0
  122. package/server/authentication/guards/auth-basic.strategy.js +6 -5
  123. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  124. package/server/authentication/guards/auth-token-access.strategy.js +3 -2
  125. package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
  126. package/server/authentication/guards/auth-token-refresh.strategy.js +3 -2
  127. package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
  128. package/server/authentication/guards/auth-two-fa-guard.js +81 -0
  129. package/server/authentication/guards/auth-two-fa-guard.js.map +1 -0
  130. package/server/authentication/interfaces/jwt-payload.interface.js +5 -0
  131. package/server/authentication/interfaces/jwt-payload.interface.js.map +1 -1
  132. package/server/authentication/interfaces/token.interface.js +2 -0
  133. package/server/authentication/interfaces/token.interface.js.map +1 -1
  134. package/server/authentication/interfaces/two-fa-setup.interface.js +10 -0
  135. package/server/authentication/interfaces/two-fa-setup.interface.js.map +1 -0
  136. package/server/authentication/models/auth-method.js.map +1 -1
  137. package/server/authentication/services/auth-manager.service.js +72 -49
  138. package/server/authentication/services/auth-manager.service.js.map +1 -1
  139. package/server/authentication/services/auth-methods/auth-method-database.service.js +3 -3
  140. package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
  141. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +5 -0
  142. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
  143. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +151 -66
  144. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  145. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +52 -50
  146. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
  147. package/server/authentication/services/auth-methods/auth-method-two-fa.service.js +251 -0
  148. package/server/authentication/services/auth-methods/auth-method-two-fa.service.js.map +1 -0
  149. package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js +41 -0
  150. package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js.map +1 -0
  151. package/server/authentication/utils/crypt-secret.js +68 -0
  152. package/server/authentication/utils/crypt-secret.js.map +1 -0
  153. package/server/common/functions.js +18 -2
  154. package/server/common/functions.js.map +1 -1
  155. package/server/common/qrcode.js +34 -0
  156. package/server/common/qrcode.js.map +1 -0
  157. package/server/common/shared.js +18 -0
  158. package/server/common/shared.js.map +1 -1
  159. package/server/configuration/config.environment.js +23 -6
  160. package/server/configuration/config.environment.js.map +1 -1
  161. package/server/configuration/config.interfaces.js +10 -0
  162. package/server/configuration/config.interfaces.js.map +1 -0
  163. package/server/configuration/config.loader.js.map +1 -1
  164. package/server/configuration/config.validation.js +13 -13
  165. package/server/configuration/config.validation.js.map +1 -1
  166. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +6 -6
  167. package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
  168. package/server/infrastructure/cache/schemas/mysql-cache.schema.js +2 -1
  169. package/server/infrastructure/cache/schemas/mysql-cache.schema.js.map +1 -1
  170. package/server/infrastructure/cache/services/cache.service.js.map +1 -1
  171. package/server/infrastructure/database/columns.js +39 -0
  172. package/server/infrastructure/database/columns.js.map +1 -0
  173. package/server/infrastructure/database/database.config.js +0 -1
  174. package/server/infrastructure/database/database.config.js.map +1 -1
  175. package/server/infrastructure/mailer/interfaces/mail.interface.js.map +1 -1
  176. package/server/infrastructure/mailer/mailer.config.js +12 -0
  177. package/server/infrastructure/mailer/mailer.config.js.map +1 -1
  178. package/server/infrastructure/mailer/mailer.service.js +2 -1
  179. package/server/infrastructure/mailer/mailer.service.js.map +1 -1
  180. package/static/assets/mimes/text-x-c.svg +1 -0
  181. package/static/assets/pdfjs/build/pdf.mjs +2522 -914
  182. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  183. package/static/assets/pdfjs/build/pdf.sandbox.mjs +2 -2
  184. package/static/assets/pdfjs/build/pdf.worker.mjs +1024 -566
  185. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  186. package/static/assets/pdfjs/version +1 -1
  187. package/static/assets/pdfjs/web/debugger.mjs +116 -37
  188. package/static/assets/pdfjs/web/images/comment-popup-editButton.svg +5 -0
  189. package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -12
  190. package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -12
  191. package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -16
  192. package/static/assets/pdfjs/web/locale/ar/viewer.ftl +0 -32
  193. package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -19
  194. package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -16
  195. package/static/assets/pdfjs/web/locale/be/viewer.ftl +0 -32
  196. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -32
  197. package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -16
  198. package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -12
  199. package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -22
  200. package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -16
  201. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -32
  202. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +12 -23
  203. package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -23
  204. package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -16
  205. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +0 -32
  206. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +0 -32
  207. package/static/assets/pdfjs/web/locale/da/viewer.ftl +3 -35
  208. package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -32
  209. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -32
  210. package/static/assets/pdfjs/web/locale/el/viewer.ftl +0 -32
  211. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +0 -32
  212. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -32
  213. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -13
  214. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +0 -32
  215. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -32
  216. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +0 -32
  217. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +5 -32
  218. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -32
  219. package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -16
  220. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +38 -32
  221. package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -19
  222. package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -12
  223. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -32
  224. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -32
  225. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -32
  226. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +0 -32
  227. package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -12
  228. package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -23
  229. package/static/assets/pdfjs/web/locale/gl/viewer.ftl +0 -32
  230. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +0 -32
  231. package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -12
  232. package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -32
  233. package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -16
  234. package/static/assets/pdfjs/web/locale/hr/viewer.ftl +0 -32
  235. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -32
  236. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -32
  237. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +372 -16
  238. package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -16
  239. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -32
  240. package/static/assets/pdfjs/web/locale/id/viewer.ftl +38 -32
  241. package/static/assets/pdfjs/web/locale/is/viewer.ftl +27 -32
  242. package/static/assets/pdfjs/web/locale/it/viewer.ftl +0 -33
  243. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +31 -33
  244. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +0 -32
  245. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -32
  246. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +31 -32
  247. package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -12
  248. package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -12
  249. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -32
  250. package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -12
  251. package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -23
  252. package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -16
  253. package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -12
  254. package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -12
  255. package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -14
  256. package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -19
  257. package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -31
  258. package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -16
  259. package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -12
  260. package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -12
  261. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +0 -32
  262. package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -12
  263. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -32
  264. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +0 -32
  265. package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -24
  266. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +0 -32
  267. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +0 -32
  268. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +0 -32
  269. package/static/assets/pdfjs/web/locale/pt-PT/viewer.ftl +0 -32
  270. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -32
  271. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +5 -37
  272. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +0 -32
  273. package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -23
  274. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +8 -27
  275. package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -16
  276. package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -22
  277. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -32
  278. package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -32
  279. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +30 -32
  280. package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -12
  281. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +0 -32
  282. package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -32
  283. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -32
  284. package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -16
  285. package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -12
  286. package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -16
  287. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +0 -32
  288. package/static/assets/pdfjs/web/locale/th/viewer.ftl +38 -32
  289. package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -16
  290. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +0 -32
  291. package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -12
  292. package/static/assets/pdfjs/web/locale/uk/viewer.ftl +0 -32
  293. package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -16
  294. package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -12
  295. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -32
  296. package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -12
  297. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +0 -32
  298. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -32
  299. package/static/assets/pdfjs/web/viewer.css +586 -437
  300. package/static/assets/pdfjs/web/viewer.html +12 -23
  301. package/static/assets/pdfjs/web/viewer.mjs +955 -514
  302. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  303. package/static/assets/pdfjs/web/wasm/openjpeg.wasm +0 -0
  304. package/static/assets/pdfjs/web/wasm/openjpeg_nowasm_fallback.js +10 -22
  305. package/static/{chunk-SPTF6FSM.js → chunk-27YQB3TE.js} +1 -1
  306. package/static/chunk-2I4CUFUA.js +1 -0
  307. package/static/chunk-2MTM6SWN.js +4 -0
  308. package/static/{chunk-7VRUZRJG.js → chunk-34MKICK5.js} +2 -2
  309. package/static/chunk-5O3DIUU3.js +1 -0
  310. package/static/{chunk-VJRTMDEJ.js → chunk-6NMVZIIT.js} +1 -1
  311. package/static/{chunk-L6MU6S2V.js → chunk-7DN7ZAPU.js} +1 -1
  312. package/static/{chunk-MVO4WZLK.js → chunk-7FUM3JGM.js} +1 -1
  313. package/static/{chunk-RSS6GYNE.js → chunk-7ITZXYYJ.js} +1 -1
  314. package/static/chunk-7P27WBGC.js +4 -0
  315. package/static/chunk-ATP3BFHV.js +562 -0
  316. package/static/chunk-AWQ2YTVC.js +1 -0
  317. package/static/chunk-DSOE3FEP.js +1 -0
  318. package/static/{chunk-2R6HHGUR.js → chunk-EFKMBLRE.js} +1 -1
  319. package/static/chunk-FUFKVHPU.js +1 -0
  320. package/static/{chunk-MRSWNAVB.js → chunk-HCDLWTMW.js} +1 -1
  321. package/static/chunk-IPAC4VAF.js +1 -0
  322. package/static/{chunk-ZC5NIT55.js → chunk-IQOALFYU.js} +1 -1
  323. package/static/chunk-JASU3CIH.js +1 -0
  324. package/static/{chunk-6OJZWYRZ.js → chunk-JQ5FTO2M.js} +1 -1
  325. package/static/chunk-JUNZFADM.js +1 -0
  326. package/static/{chunk-LLWSLOSX.js → chunk-LJUKI4SQ.js} +1 -1
  327. package/static/{chunk-WI7FOANP.js → chunk-LUWQFIWR.js} +1 -1
  328. package/static/{chunk-BIUNUYZ5.js → chunk-ORMRCEGT.js} +1 -1
  329. package/static/{chunk-IZL7JPTS.js → chunk-Q7D6RN4N.js} +1 -1
  330. package/static/{chunk-JYXLQRHG.js → chunk-QJX6ITLW.js} +1 -1
  331. package/static/{chunk-YJMN3B4N.js → chunk-QQ6UQQBR.js} +1 -1
  332. package/static/chunk-S2HDY3OL.js +1 -0
  333. package/static/{chunk-NE4NDO45.js → chunk-S75P2FFI.js} +1 -1
  334. package/static/{chunk-CRQNEHTX.js → chunk-T3EYFSVZ.js} +1 -1
  335. package/static/{chunk-MCLQFZ3S.js → chunk-U34OZUZ7.js} +1 -1
  336. package/static/chunk-Y7EH7G5K.js +1 -0
  337. package/static/{chunk-MGGT6MIJ.js → chunk-ZQQPUYLU.js} +1 -1
  338. package/static/index.html +2 -2
  339. package/static/main-7SQDDVMD.js +9 -0
  340. package/static/{styles-FYUSO6OJ.css → styles-A5VYX3CE.css} +1 -1
  341. package/server/applications/users/dto/user-password.dto.js.map +0 -1
  342. package/static/chunk-4U5A2DEP.js +0 -4
  343. package/static/chunk-54EAZ2UD.js +0 -1
  344. package/static/chunk-7ZRXJONB.js +0 -1
  345. package/static/chunk-F2J2IIJE.js +0 -1
  346. package/static/chunk-FNFGUIQH.js +0 -4
  347. package/static/chunk-GGLK52CG.js +0 -1
  348. package/static/chunk-HW2H3ISM.js +0 -559
  349. package/static/chunk-HX6BBYVD.js +0 -1
  350. package/static/chunk-JF7S3UYQ.js +0 -1
  351. package/static/chunk-KSHPKI4G.js +0 -1
  352. package/static/chunk-VPJ2V27B.js +0 -1
  353. package/static/chunk-VUI3KV7V.js +0 -1
  354. package/static/chunk-ZXS4V7J2.js +0 -1
  355. package/static/main-FFIWFD2F.js +0 -7
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/authentication/services/auth-methods/auth-method-database.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { CONNECT_ERROR_CODE } from '../../../app.constants'\nimport { UserModel } from '../../../applications/users/models/user.model'\nimport { AdminUsersManager } from '../../../applications/users/services/admin-users-manager.service'\nimport { AdminUsersQueries } from '../../../applications/users/services/admin-users-queries.service'\nimport { UsersManager } from '../../../applications/users/services/users-manager.service'\nimport { UsersQueries } from '../../../applications/users/services/users-queries.service'\nimport { generateUserTest } from '../../../applications/users/utils/test'\nimport { hashPassword } from '../../../common/functions'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { AuthManager } from '../auth-manager.service'\nimport { AuthMethodDatabase } from './auth-method-database.service'\n\ndescribe(AuthMethodDatabase.name, () => {\n let authMethodDatabase: AuthMethodDatabase\n let usersManager: UsersManager\n let userTest: UserModel\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthMethodDatabase,\n UsersManager,\n UsersQueries,\n AdminUsersManager,\n AdminUsersQueries,\n { provide: AuthManager, useValue: {} },\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n {\n provide: Cache,\n useValue: {}\n }\n ]\n }).compile()\n\n authMethodDatabase = module.get<AuthMethodDatabase>(AuthMethodDatabase)\n usersManager = module.get<UsersManager>(UsersManager)\n module.useLogger(['fatal'])\n // mocks\n userTest = new UserModel(generateUserTest(), false)\n usersManager.updateAccesses = jest.fn(() => Promise.resolve())\n })\n\n it('should be defined', () => {\n expect(authMethodDatabase).toBeDefined()\n expect(usersManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should validate the user', async () => {\n userTest.makePaths = jest.fn()\n usersManager.findUser = jest.fn().mockReturnValue({ ...userTest, password: await hashPassword(userTest.password) })\n expect(await authMethodDatabase.validateUser(userTest.login, userTest.password)).toBeDefined()\n expect(userTest.makePaths).toHaveBeenCalled()\n })\n\n it('should not validate the user', async () => {\n usersManager.findUser = jest\n .fn()\n .mockReturnValueOnce(null)\n .mockReturnValueOnce({ ...userTest, password: await hashPassword('bar') })\n .mockRejectedValueOnce({ message: 'db error', code: 'OTHER' })\n .mockRejectedValueOnce(\n new Error('Authentication service error', {\n cause: { code: Array.from(CONNECT_ERROR_CODE)[0] }\n })\n )\n expect(await authMethodDatabase.validateUser(userTest.login, userTest.password)).toBeNull()\n expect(await authMethodDatabase.validateUser(userTest.login, userTest.password)).toBeNull()\n await expect(authMethodDatabase.validateUser(userTest.login, userTest.password)).rejects.toThrow(/db error/i)\n await expect(authMethodDatabase.validateUser(userTest.login, userTest.password)).rejects.toThrow(/authentication service/i)\n })\n})\n"],"names":["describe","AuthMethodDatabase","name","authMethodDatabase","usersManager","userTest","beforeAll","module","Test","createTestingModule","providers","UsersManager","UsersQueries","AdminUsersManager","AdminUsersQueries","provide","AuthManager","useValue","DB_TOKEN_PROVIDER","Cache","compile","get","useLogger","UserModel","generateUserTest","updateAccesses","jest","fn","Promise","resolve","it","expect","toBeDefined","makePaths","findUser","mockReturnValue","password","hashPassword","validateUser","login","toHaveBeenCalled","mockReturnValueOnce","mockRejectedValueOnce","message","code","Error","cause","Array","from","CONNECT_ERROR_CODE","toBeNull","rejects","toThrow"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;8BACD;2BACT;0CACQ;0CACA;qCACL;qCACA;sBACI;2BACJ;8BACP;2BACY;oCACN;2CACO;AAEnCA,SAASC,6CAAkB,CAACC,IAAI,EAAE;IAChC,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTT,6CAAkB;gBAClBU,iCAAY;gBACZC,iCAAY;gBACZC,2CAAiB;gBACjBC,2CAAiB;gBACjB;oBAAEC,SAASC,+BAAW;oBAAEC,UAAU,CAAC;gBAAE;gBACrC;oBAAEF,SAASG,4BAAiB;oBAAED,UAAU,CAAC;gBAAE;gBAC3C;oBACEF,SAASI,mBAAK;oBACdF,UAAU,CAAC;gBACb;aACD;QACH,GAAGG,OAAO;QAEVjB,qBAAqBI,OAAOc,GAAG,CAAqBpB,6CAAkB;QACtEG,eAAeG,OAAOc,GAAG,CAAeV,iCAAY;QACpDJ,OAAOe,SAAS,CAAC;YAAC;SAAQ;QAC1B,QAAQ;QACRjB,WAAW,IAAIkB,oBAAS,CAACC,IAAAA,sBAAgB,KAAI;QAC7CpB,aAAaqB,cAAc,GAAGC,KAAKC,EAAE,CAAC,IAAMC,QAAQC,OAAO;IAC7D;IAEAC,GAAG,qBAAqB;QACtBC,OAAO5B,oBAAoB6B,WAAW;QACtCD,OAAO3B,cAAc4B,WAAW;QAChCD,OAAO1B,UAAU2B,WAAW;IAC9B;IAEAF,GAAG,4BAA4B;QAC7BzB,SAAS4B,SAAS,GAAGP,KAAKC,EAAE;QAC5BvB,aAAa8B,QAAQ,GAAGR,KAAKC,EAAE,GAAGQ,eAAe,CAAC;YAAE,GAAG9B,QAAQ;YAAE+B,UAAU,MAAMC,IAAAA,uBAAY,EAAChC,SAAS+B,QAAQ;QAAE;QACjHL,OAAO,MAAM5B,mBAAmBmC,YAAY,CAACjC,SAASkC,KAAK,EAAElC,SAAS+B,QAAQ,GAAGJ,WAAW;QAC5FD,OAAO1B,SAAS4B,SAAS,EAAEO,gBAAgB;IAC7C;IAEAV,GAAG,gCAAgC;QACjC1B,aAAa8B,QAAQ,GAAGR,KACrBC,EAAE,GACFc,mBAAmB,CAAC,MACpBA,mBAAmB,CAAC;YAAE,GAAGpC,QAAQ;YAAE+B,UAAU,MAAMC,IAAAA,uBAAY,EAAC;QAAO,GACvEK,qBAAqB,CAAC;YAAEC,SAAS;YAAYC,MAAM;QAAQ,GAC3DF,qBAAqB,CACpB,IAAIG,MAAM,gCAAgC;YACxCC,OAAO;gBAAEF,MAAMG,MAAMC,IAAI,CAACC,gCAAkB,CAAC,CAAC,EAAE;YAAC;QACnD;QAEJlB,OAAO,MAAM5B,mBAAmBmC,YAAY,CAACjC,SAASkC,KAAK,EAAElC,SAAS+B,QAAQ,GAAGc,QAAQ;QACzFnB,OAAO,MAAM5B,mBAAmBmC,YAAY,CAACjC,SAASkC,KAAK,EAAElC,SAAS+B,QAAQ,GAAGc,QAAQ;QACzF,MAAMnB,OAAO5B,mBAAmBmC,YAAY,CAACjC,SAASkC,KAAK,EAAElC,SAAS+B,QAAQ,GAAGe,OAAO,CAACC,OAAO,CAAC;QACjG,MAAMrB,OAAO5B,mBAAmBmC,YAAY,CAACjC,SAASkC,KAAK,EAAElC,SAAS+B,QAAQ,GAAGe,OAAO,CAACC,OAAO,CAAC;IACnG;AACF"}
1
+ {"version":3,"sources":["../../../../../backend/src/authentication/services/auth-methods/auth-method-database.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { CONNECT_ERROR_CODE } from '../../../app.constants'\nimport { NotificationsManager } from '../../../applications/notifications/services/notifications-manager.service'\nimport { UserModel } from '../../../applications/users/models/user.model'\nimport { AdminUsersManager } from '../../../applications/users/services/admin-users-manager.service'\nimport { AdminUsersQueries } from '../../../applications/users/services/admin-users-queries.service'\nimport { UsersManager } from '../../../applications/users/services/users-manager.service'\nimport { UsersQueries } from '../../../applications/users/services/users-queries.service'\nimport { generateUserTest } from '../../../applications/users/utils/test'\nimport { hashPassword } from '../../../common/functions'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { AuthManager } from '../auth-manager.service'\nimport { AuthMethodDatabase } from './auth-method-database.service'\n\ndescribe(AuthMethodDatabase.name, () => {\n let authMethodDatabase: AuthMethodDatabase\n let usersManager: UsersManager\n let userTest: UserModel\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthMethodDatabase,\n UsersManager,\n UsersQueries,\n AdminUsersManager,\n AdminUsersQueries,\n { provide: AuthManager, useValue: {} },\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n { provide: Cache, useValue: {} },\n { provide: NotificationsManager, useValue: {} }\n ]\n }).compile()\n\n authMethodDatabase = module.get<AuthMethodDatabase>(AuthMethodDatabase)\n usersManager = module.get<UsersManager>(UsersManager)\n module.useLogger(['fatal'])\n // mocks\n userTest = new UserModel(generateUserTest(), false)\n usersManager.updateAccesses = jest.fn(() => Promise.resolve())\n })\n\n it('should be defined', () => {\n expect(authMethodDatabase).toBeDefined()\n expect(usersManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should validate the user', async () => {\n userTest.makePaths = jest.fn()\n usersManager.findUser = jest.fn().mockReturnValue({ ...userTest, password: await hashPassword(userTest.password) })\n expect(await authMethodDatabase.validateUser(userTest.login, userTest.password)).toBeDefined()\n expect(userTest.makePaths).toHaveBeenCalled()\n })\n\n it('should not validate the user', async () => {\n usersManager.findUser = jest\n .fn()\n .mockReturnValueOnce(null)\n .mockReturnValueOnce({ ...userTest, password: await hashPassword('bar') })\n .mockRejectedValueOnce({ message: 'db error', code: 'OTHER' })\n .mockRejectedValueOnce(\n new Error('Authentication service error', {\n cause: { code: Array.from(CONNECT_ERROR_CODE)[0] }\n })\n )\n expect(await authMethodDatabase.validateUser(userTest.login, userTest.password)).toBeNull()\n expect(await authMethodDatabase.validateUser(userTest.login, userTest.password)).toBeNull()\n await expect(authMethodDatabase.validateUser(userTest.login, userTest.password)).rejects.toThrow(/db error/i)\n await expect(authMethodDatabase.validateUser(userTest.login, userTest.password)).rejects.toThrow(/authentication service/i)\n })\n})\n"],"names":["describe","AuthMethodDatabase","name","authMethodDatabase","usersManager","userTest","beforeAll","module","Test","createTestingModule","providers","UsersManager","UsersQueries","AdminUsersManager","AdminUsersQueries","provide","AuthManager","useValue","DB_TOKEN_PROVIDER","Cache","NotificationsManager","compile","get","useLogger","UserModel","generateUserTest","updateAccesses","jest","fn","Promise","resolve","it","expect","toBeDefined","makePaths","findUser","mockReturnValue","password","hashPassword","validateUser","login","toHaveBeenCalled","mockReturnValueOnce","mockRejectedValueOnce","message","code","Error","cause","Array","from","CONNECT_ERROR_CODE","toBeNull","rejects","toThrow"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;8BACD;6CACE;2BACX;0CACQ;0CACA;qCACL;qCACA;sBACI;2BACJ;8BACP;2BACY;oCACN;2CACO;AAEnCA,SAASC,6CAAkB,CAACC,IAAI,EAAE;IAChC,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTT,6CAAkB;gBAClBU,iCAAY;gBACZC,iCAAY;gBACZC,2CAAiB;gBACjBC,2CAAiB;gBACjB;oBAAEC,SAASC,+BAAW;oBAAEC,UAAU,CAAC;gBAAE;gBACrC;oBAAEF,SAASG,4BAAiB;oBAAED,UAAU,CAAC;gBAAE;gBAC3C;oBAAEF,SAASI,mBAAK;oBAAEF,UAAU,CAAC;gBAAE;gBAC/B;oBAAEF,SAASK,iDAAoB;oBAAEH,UAAU,CAAC;gBAAE;aAC/C;QACH,GAAGI,OAAO;QAEVlB,qBAAqBI,OAAOe,GAAG,CAAqBrB,6CAAkB;QACtEG,eAAeG,OAAOe,GAAG,CAAeX,iCAAY;QACpDJ,OAAOgB,SAAS,CAAC;YAAC;SAAQ;QAC1B,QAAQ;QACRlB,WAAW,IAAImB,oBAAS,CAACC,IAAAA,sBAAgB,KAAI;QAC7CrB,aAAasB,cAAc,GAAGC,KAAKC,EAAE,CAAC,IAAMC,QAAQC,OAAO;IAC7D;IAEAC,GAAG,qBAAqB;QACtBC,OAAO7B,oBAAoB8B,WAAW;QACtCD,OAAO5B,cAAc6B,WAAW;QAChCD,OAAO3B,UAAU4B,WAAW;IAC9B;IAEAF,GAAG,4BAA4B;QAC7B1B,SAAS6B,SAAS,GAAGP,KAAKC,EAAE;QAC5BxB,aAAa+B,QAAQ,GAAGR,KAAKC,EAAE,GAAGQ,eAAe,CAAC;YAAE,GAAG/B,QAAQ;YAAEgC,UAAU,MAAMC,IAAAA,uBAAY,EAACjC,SAASgC,QAAQ;QAAE;QACjHL,OAAO,MAAM7B,mBAAmBoC,YAAY,CAAClC,SAASmC,KAAK,EAAEnC,SAASgC,QAAQ,GAAGJ,WAAW;QAC5FD,OAAO3B,SAAS6B,SAAS,EAAEO,gBAAgB;IAC7C;IAEAV,GAAG,gCAAgC;QACjC3B,aAAa+B,QAAQ,GAAGR,KACrBC,EAAE,GACFc,mBAAmB,CAAC,MACpBA,mBAAmB,CAAC;YAAE,GAAGrC,QAAQ;YAAEgC,UAAU,MAAMC,IAAAA,uBAAY,EAAC;QAAO,GACvEK,qBAAqB,CAAC;YAAEC,SAAS;YAAYC,MAAM;QAAQ,GAC3DF,qBAAqB,CACpB,IAAIG,MAAM,gCAAgC;YACxCC,OAAO;gBAAEF,MAAMG,MAAMC,IAAI,CAACC,gCAAkB,CAAC,CAAC,EAAE;YAAC;QACnD;QAEJlB,OAAO,MAAM7B,mBAAmBoC,YAAY,CAAClC,SAASmC,KAAK,EAAEnC,SAASgC,QAAQ,GAAGc,QAAQ;QACzFnB,OAAO,MAAM7B,mBAAmBoC,YAAY,CAAClC,SAASmC,KAAK,EAAEnC,SAASgC,QAAQ,GAAGc,QAAQ;QACzF,MAAMnB,OAAO7B,mBAAmBoC,YAAY,CAAClC,SAASmC,KAAK,EAAEnC,SAASgC,QAAQ,GAAGe,OAAO,CAACC,OAAO,CAAC;QACjG,MAAMrB,OAAO7B,mBAAmBoC,YAAY,CAAClC,SAASmC,KAAK,EAAEnC,SAASgC,QAAQ,GAAGe,OAAO,CAACC,OAAO,CAAC;IACnG;AACF"}
@@ -20,6 +20,7 @@ const _adminusersmanagerservice = require("../../../applications/users/services/
20
20
  const _usersmanagerservice = require("../../../applications/users/services/users-manager.service");
21
21
  const _functions = require("../../../common/functions");
22
22
  const _configenvironment = require("../../../configuration/config.environment");
23
+ const _authldap = require("../../constants/auth-ldap");
23
24
  function _ts_decorate(decorators, target, key, desc) {
24
25
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
25
26
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -30,8 +31,8 @@ function _ts_metadata(k, v) {
30
31
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
31
32
  }
32
33
  let AuthMethodLdapService = class AuthMethodLdapService {
33
- async validateUser(loginOrEmail, password, ip) {
34
- let user = await this.usersManager.findUser(loginOrEmail, false);
34
+ async validateUser(login, password, ip, scope) {
35
+ let user = await this.usersManager.findUser(this.normalizeLogin(login), false);
35
36
  if (user) {
36
37
  if (user.isGuest) {
37
38
  // allow guests to be authenticated from db and check if the current user is defined as active
@@ -42,48 +43,58 @@ let AuthMethodLdapService = class AuthMethodLdapService {
42
43
  throw new _common.HttpException('Account locked', _common.HttpStatus.FORBIDDEN);
43
44
  }
44
45
  }
45
- const entry = await this.checkAuth(loginOrEmail, password);
46
+ const entry = await this.checkAuth(login, password);
46
47
  if (entry === false) {
48
+ // LDAP auth failed
47
49
  if (user) {
48
- this.usersManager.updateAccesses(user, ip, false).catch((e)=>this.logger.error(`${this.validateUser.name} : ${e}`));
50
+ let authSuccess = false;
51
+ if (scope) {
52
+ // try user app password
53
+ authSuccess = await this.usersManager.validateAppPassword(user, password, ip, scope);
54
+ }
55
+ this.usersManager.updateAccesses(user, ip, authSuccess).catch((e)=>this.logger.error(`${this.validateUser.name} : ${e}`));
56
+ if (authSuccess) {
57
+ // logged with app password
58
+ return user;
59
+ }
49
60
  }
50
61
  return null;
51
- } else if (!entry.mail || !entry.uid) {
52
- this.logger.error(`${this.validateUser.name} - ${loginOrEmail} : some ldap fields are missing => (${JSON.stringify(entry)})`);
62
+ } else if (!entry[this.loginAttribute] || !entry[this.emailAttribute]) {
63
+ this.logger.error(`${this.validateUser.name} - required ldap fields are missing :
64
+ [${this.loginAttribute}, ${this.emailAttribute}] =>
65
+ (${JSON.stringify(entry)})`);
53
66
  return null;
54
67
  }
55
- const identity = {
56
- login: entry.uid,
57
- email: entry.mail,
58
- password: password,
59
- ...(0, _functions.splitFullName)(entry.cn)
60
- };
68
+ const identity = this.createIdentity(entry, password);
61
69
  user = await this.updateOrCreateUser(identity, user);
62
70
  this.usersManager.updateAccesses(user, ip, true).catch((e)=>this.logger.error(`${this.validateUser.name} : ${e}`));
63
71
  return user;
64
72
  }
65
- async checkAuth(uid, password) {
66
- const servers = _configenvironment.configuration.auth.ldap.servers;
67
- const bindUserDN = `${_configenvironment.configuration.auth.ldap.loginAttribute}=${uid},${_configenvironment.configuration.auth.ldap.baseDN}`;
73
+ async checkAuth(login, password) {
74
+ const loginAttr = this.loginAttribute;
75
+ const isAD = loginAttr === _authldap.LDAP_LOGIN_ATTR.SAM || loginAttr === _authldap.LDAP_LOGIN_ATTR.UPN;
76
+ // AD: bind directly with the user input (UPN or DOMAIN\user)
77
+ // Generic LDAP: build DN from login attribute + baseDN
78
+ const bindUserDN = isAD ? login : `${loginAttr}=${login},${this.baseDN}`;
68
79
  let client;
69
80
  let error;
70
- for (const s of servers){
81
+ for (const s of this.servers){
71
82
  client = new _ldapts.Client({
72
83
  ...this.clientOptions,
73
84
  url: s
74
85
  });
75
86
  try {
76
87
  await client.bind(bindUserDN, password);
77
- return await this.checkAccess(client, uid);
88
+ return await this.checkAccess(client, login);
78
89
  } catch (e) {
79
90
  if (e.errors?.length) {
80
91
  for (const err of e.errors){
81
- this.logger.warn(`${this.checkAuth.name} - ${uid} : ${err}`);
92
+ this.logger.warn(`${this.checkAuth.name} - ${login} : ${err}`);
82
93
  error = err;
83
94
  }
84
95
  } else {
85
96
  error = e;
86
- this.logger.warn(`${this.checkAuth.name} - ${uid} : ${e}`);
97
+ this.logger.warn(`${this.checkAuth.name} - ${login} : ${e}`);
87
98
  }
88
99
  if (error instanceof _ldapts.InvalidCredentialsError) {
89
100
  return false;
@@ -97,75 +108,149 @@ let AuthMethodLdapService = class AuthMethodLdapService {
97
108
  }
98
109
  return false;
99
110
  }
100
- async checkAccess(client, uid) {
101
- const searchFilter = `(&(${_configenvironment.configuration.auth.ldap.loginAttribute}=${uid})${_configenvironment.configuration.auth.ldap.filter || ''})`;
111
+ async checkAccess(client, login) {
112
+ const searchFilter = this.buildUserFilter(login, this.filter);
102
113
  try {
103
- const { searchEntries } = await client.search(_configenvironment.configuration.auth.ldap.baseDN, {
114
+ const { searchEntries } = await client.search(this.baseDN, {
104
115
  scope: 'sub',
105
116
  filter: searchFilter,
106
- attributes: this.entryAttributes
117
+ attributes: _authldap.ALL_LDAP_ATTRIBUTES
107
118
  });
108
- for (const entry of searchEntries){
109
- if (entry[_configenvironment.configuration.auth.ldap.loginAttribute] === uid) {
110
- if (Array.isArray(entry.mail)) {
111
- // handles the case of multiple emails, keep the first
112
- entry.mail = entry.mail[0];
113
- }
114
- return entry;
115
- }
119
+ if (searchEntries.length === 0) {
120
+ this.logger.debug(`${this.checkAccess.name} - search filter : ${searchFilter}`);
121
+ this.logger.warn(`${this.checkAccess.name} - no LDAP entry found for : ${login}`);
122
+ return false;
116
123
  }
117
- return false;
124
+ if (searchEntries.length > 1) {
125
+ this.logger.warn(`${this.checkAccess.name} - multiple LDAP entries found for : ${login}, using first one`);
126
+ }
127
+ // Always return the first valid entry
128
+ return this.convertToLdapUserEntry(searchEntries[0]);
118
129
  } catch (e) {
119
- this.logger.warn(`${this.checkAccess.name} - ${uid} : ${e}`);
130
+ this.logger.debug(`${this.checkAccess.name} - search filter : ${searchFilter}`);
131
+ this.logger.error(`${this.checkAccess.name} - ${login} : ${e}`);
120
132
  return false;
121
133
  }
122
134
  }
123
135
  async updateOrCreateUser(identity, user) {
124
136
  if (user === null) {
125
- return this.adminUsersManager.createUserOrGuest(identity, _user.USER_ROLE.USER);
126
- } else {
127
- if (identity.login !== user.login) {
128
- this.logger.error(`${this.updateOrCreateUser.name} - user id mismatch : ${identity.login} !== ${user.login}`);
129
- throw new _common.HttpException('Account matching error', _common.HttpStatus.FORBIDDEN);
137
+ const createdUser = await this.adminUsersManager.createUserOrGuest(identity, _user.USER_ROLE.USER);
138
+ const freshUser = await this.usersManager.fromUserId(createdUser.id);
139
+ if (!freshUser) {
140
+ this.logger.error(`${this.updateOrCreateUser.name} - user was not found : ${createdUser.login} (${createdUser.id})`);
141
+ throw new _common.HttpException('User not found', _common.HttpStatus.NOT_FOUND);
130
142
  }
131
- // check if user information has changed
132
- const identityHasChanged = Object.fromEntries((await Promise.all(Object.keys(identity).map(async (key)=>{
133
- if (key === 'password') {
134
- const isSame = await (0, _functions.comparePassword)(identity[key], user.password);
135
- return isSame ? null : [
136
- key,
137
- identity[key]
138
- ];
139
- }
140
- return identity[key] !== user[key] ? [
143
+ return freshUser;
144
+ }
145
+ if (identity.login !== user.login) {
146
+ this.logger.error(`${this.updateOrCreateUser.name} - user login mismatch : ${identity.login} !== ${user.login}`);
147
+ throw new _common.HttpException('Account matching error', _common.HttpStatus.FORBIDDEN);
148
+ }
149
+ // check if user information has changed
150
+ const identityHasChanged = Object.fromEntries((await Promise.all(Object.keys(identity).map(async (key)=>{
151
+ if (key === 'password') {
152
+ const isSame = await (0, _functions.comparePassword)(identity[key], user.password);
153
+ return isSame ? null : [
141
154
  key,
142
155
  identity[key]
143
- ] : null;
144
- }))).filter(Boolean));
145
- if (Object.keys(identityHasChanged).length > 0) {
146
- try {
147
- await this.adminUsersManager.updateUserOrGuest(user.id, identityHasChanged);
148
- if (identityHasChanged?.password) {
149
- delete identityHasChanged.password;
150
- }
151
- Object.assign(user, identityHasChanged);
152
- } catch (e) {
153
- this.logger.warn(`${this.updateOrCreateUser.name} - unable to update user *${user.login}* : ${e}`);
156
+ ];
157
+ }
158
+ return identity[key] !== user[key] ? [
159
+ key,
160
+ identity[key]
161
+ ] : null;
162
+ }))).filter(Boolean));
163
+ if (Object.keys(identityHasChanged).length > 0) {
164
+ try {
165
+ await this.adminUsersManager.updateUserOrGuest(user.id, identityHasChanged);
166
+ if (identityHasChanged?.password) {
167
+ delete identityHasChanged.password;
154
168
  }
169
+ Object.assign(user, identityHasChanged);
170
+ if ('lastName' in identityHasChanged || 'firstName' in identityHasChanged) {
171
+ // force fullName update in current user model
172
+ user.setFullName(true);
173
+ }
174
+ } catch (e) {
175
+ this.logger.warn(`${this.updateOrCreateUser.name} - unable to update user *${user.login}* : ${e}`);
155
176
  }
156
- await user.makePaths();
157
- return user;
158
177
  }
178
+ return user;
179
+ }
180
+ convertToLdapUserEntry(entry) {
181
+ for (const attr of _authldap.ALL_LDAP_ATTRIBUTES){
182
+ if (Array.isArray(entry[attr])) {
183
+ entry[attr] = entry[attr].length > 0 ? entry[attr][0] : null;
184
+ }
185
+ }
186
+ return entry;
187
+ }
188
+ createIdentity(entry, password) {
189
+ return {
190
+ login: this.normalizeLogin(entry[this.loginAttribute]),
191
+ email: entry[this.emailAttribute],
192
+ password: password,
193
+ ...this.getFirstNameAndLastName(entry)
194
+ };
195
+ }
196
+ getFirstNameAndLastName(entry) {
197
+ // 1) Prefer structured attributes
198
+ if (entry.sn && entry.givenName) {
199
+ return {
200
+ firstName: entry.givenName,
201
+ lastName: entry.sn
202
+ };
203
+ }
204
+ // 2) Fallback to displayName if available
205
+ if (entry.displayName && entry.displayName.trim()) {
206
+ return (0, _functions.splitFullName)(entry.displayName);
207
+ }
208
+ // 3) Fallback to cn
209
+ if (entry.cn && entry.cn.trim()) {
210
+ return (0, _functions.splitFullName)(entry.cn);
211
+ }
212
+ // 4) Nothing usable
213
+ return {
214
+ firstName: '',
215
+ lastName: ''
216
+ };
217
+ }
218
+ normalizeLogin(login, toLowerCase = true) {
219
+ const normalized = (login.includes('\\') ? login.split('\\').slice(-1)[0] : login).trim();
220
+ return toLowerCase ? normalized.toLowerCase() : normalized;
221
+ }
222
+ buildUserFilter(login, extraFilter) {
223
+ // Build a safe LDAP filter to search for a user.
224
+ // Important: - Values passed to EqualityFilter are auto-escaped by ldapts
225
+ // - extraFilter is appended as-is (assumed trusted configuration)
226
+ // Output: (&(|(userPrincipalName=john.doe)(sAMAccountName=john.doe)(uid=john.doe))(*extraFilter*))
227
+ // OR clause: accept UPN, sAMAccountName, or uid
228
+ const normalizedLogin = this.normalizeLogin(login, false);
229
+ const eq = new _ldapts.EqualityFilter({
230
+ attribute: this.loginAttribute,
231
+ value: normalizedLogin
232
+ });
233
+ // Convert to LDAP filter string
234
+ let filterString = new _ldapts.AndFilter({
235
+ filters: [
236
+ eq
237
+ ]
238
+ }).toString();
239
+ // Optionally append an extra filter from config (trusted source)
240
+ if (extraFilter && extraFilter.trim()) {
241
+ filterString = `(&${filterString}${extraFilter})`;
242
+ }
243
+ return filterString;
159
244
  }
160
245
  constructor(usersManager, adminUsersManager){
161
246
  this.usersManager = usersManager;
162
247
  this.adminUsersManager = adminUsersManager;
163
248
  this.logger = new _common.Logger(AuthMethodLdapService.name);
164
- this.entryAttributes = [
165
- 'uid',
166
- 'mail',
167
- 'cn'
168
- ];
249
+ this.loginAttribute = _configenvironment.configuration.auth.ldap.attributes.login;
250
+ this.emailAttribute = _configenvironment.configuration.auth.ldap.attributes.email;
251
+ this.servers = _configenvironment.configuration.auth.ldap.servers;
252
+ this.baseDN = _configenvironment.configuration.auth.ldap.baseDN;
253
+ this.filter = _configenvironment.configuration.auth.ldap.filter;
169
254
  this.clientOptions = {
170
255
  timeout: 6000,
171
256
  connectTimeout: 6000,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/authentication/services/auth-methods/auth-method-ldap.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { Client, ClientOptions, Entry, InvalidCredentialsError } from 'ldapts'\nimport { CONNECT_ERROR_CODE } from '../../../app.constants'\nimport { USER_ROLE } from '../../../applications/users/constants/user'\nimport { CreateUserDto, UpdateUserDto } from '../../../applications/users/dto/create-or-update-user.dto'\nimport { UserModel } from '../../../applications/users/models/user.model'\nimport { AdminUsersManager } from '../../../applications/users/services/admin-users-manager.service'\nimport { UsersManager } from '../../../applications/users/services/users-manager.service'\nimport { comparePassword, splitFullName } from '../../../common/functions'\nimport { configuration } from '../../../configuration/config.environment'\nimport { AuthMethod } from '../../models/auth-method'\n\ntype LdapUserEntry = Entry & { uid: string; mail: string; cn: string }\n\n@Injectable()\nexport class AuthMethodLdapService implements AuthMethod {\n private readonly logger = new Logger(AuthMethodLdapService.name)\n private readonly entryAttributes = ['uid', 'mail', 'cn']\n private clientOptions: ClientOptions = { timeout: 6000, connectTimeout: 6000, url: '' }\n\n constructor(\n private readonly usersManager: UsersManager,\n private readonly adminUsersManager: AdminUsersManager\n ) {}\n\n async validateUser(loginOrEmail: string, password: string, ip?: string): Promise<UserModel> {\n let user = await this.usersManager.findUser(loginOrEmail, false)\n if (user) {\n if (user.isGuest) {\n // allow guests to be authenticated from db and check if the current user is defined as active\n return this.usersManager.logUser(user, password, ip)\n }\n if (!user.isActive) {\n this.logger.error(`${this.validateUser.name} - user *${user.login}* is locked`)\n throw new HttpException('Account locked', HttpStatus.FORBIDDEN)\n }\n }\n const entry: false | LdapUserEntry = await this.checkAuth(loginOrEmail, password)\n if (entry === false) {\n if (user) {\n this.usersManager.updateAccesses(user, ip, false).catch((e: Error) => this.logger.error(`${this.validateUser.name} : ${e}`))\n }\n return null\n } else if (!entry.mail || !entry.uid) {\n this.logger.error(`${this.validateUser.name} - ${loginOrEmail} : some ldap fields are missing => (${JSON.stringify(entry)})`)\n return null\n }\n const identity = { login: entry.uid, email: entry.mail, password: password, ...splitFullName(entry.cn) } satisfies CreateUserDto\n user = await this.updateOrCreateUser(identity, user)\n this.usersManager.updateAccesses(user, ip, true).catch((e: Error) => this.logger.error(`${this.validateUser.name} : ${e}`))\n return user\n }\n\n private async checkAuth(uid: string, password: string): Promise<LdapUserEntry | false> {\n const servers = configuration.auth.ldap.servers\n const bindUserDN = `${configuration.auth.ldap.loginAttribute}=${uid},${configuration.auth.ldap.baseDN}`\n let client: Client\n let error: any\n for (const s of servers) {\n client = new Client({ ...this.clientOptions, url: s })\n try {\n await client.bind(bindUserDN, password)\n return await this.checkAccess(client, uid)\n } catch (e) {\n if (e.errors?.length) {\n for (const err of e.errors) {\n this.logger.warn(`${this.checkAuth.name} - ${uid} : ${err}`)\n error = err\n }\n } else {\n error = e\n this.logger.warn(`${this.checkAuth.name} - ${uid} : ${e}`)\n }\n if (error instanceof InvalidCredentialsError) {\n return false\n }\n } finally {\n await client.unbind()\n }\n }\n if (error && CONNECT_ERROR_CODE.has(error.code)) {\n throw new HttpException('Authentication service error', HttpStatus.INTERNAL_SERVER_ERROR)\n }\n return false\n }\n\n private async checkAccess(client: Client, uid: string): Promise<LdapUserEntry | false> {\n const searchFilter = `(&(${configuration.auth.ldap.loginAttribute}=${uid})${configuration.auth.ldap.filter || ''})`\n try {\n const { searchEntries } = await client.search(configuration.auth.ldap.baseDN, {\n scope: 'sub',\n filter: searchFilter,\n attributes: this.entryAttributes\n })\n for (const entry of searchEntries) {\n if (entry[configuration.auth.ldap.loginAttribute] === uid) {\n if (Array.isArray(entry.mail)) {\n // handles the case of multiple emails, keep the first\n entry.mail = entry.mail[0]\n }\n return entry as LdapUserEntry\n }\n }\n return false\n } catch (e) {\n this.logger.warn(`${this.checkAccess.name} - ${uid} : ${e}`)\n return false\n }\n }\n\n private async updateOrCreateUser(identity: CreateUserDto, user: UserModel): Promise<UserModel> {\n if (user === null) {\n return this.adminUsersManager.createUserOrGuest(identity, USER_ROLE.USER)\n } else {\n if (identity.login !== user.login) {\n this.logger.error(`${this.updateOrCreateUser.name} - user id mismatch : ${identity.login} !== ${user.login}`)\n throw new HttpException('Account matching error', HttpStatus.FORBIDDEN)\n }\n // check if user information has changed\n const identityHasChanged: UpdateUserDto = Object.fromEntries(\n (\n await Promise.all(\n Object.keys(identity).map(async (key: string) => {\n if (key === 'password') {\n const isSame = await comparePassword(identity[key], user.password)\n return isSame ? null : [key, identity[key]]\n }\n return identity[key] !== user[key] ? [key, identity[key]] : null\n })\n )\n ).filter(Boolean)\n )\n if (Object.keys(identityHasChanged).length > 0) {\n try {\n await this.adminUsersManager.updateUserOrGuest(user.id, identityHasChanged)\n if (identityHasChanged?.password) {\n delete identityHasChanged.password\n }\n Object.assign(user, identityHasChanged)\n } catch (e) {\n this.logger.warn(`${this.updateOrCreateUser.name} - unable to update user *${user.login}* : ${e}`)\n }\n }\n await user.makePaths()\n return user\n }\n }\n}\n"],"names":["AuthMethodLdapService","validateUser","loginOrEmail","password","ip","user","usersManager","findUser","isGuest","logUser","isActive","logger","error","name","login","HttpException","HttpStatus","FORBIDDEN","entry","checkAuth","updateAccesses","catch","e","mail","uid","JSON","stringify","identity","email","splitFullName","cn","updateOrCreateUser","servers","configuration","auth","ldap","bindUserDN","loginAttribute","baseDN","client","s","Client","clientOptions","url","bind","checkAccess","errors","length","err","warn","InvalidCredentialsError","unbind","CONNECT_ERROR_CODE","has","code","INTERNAL_SERVER_ERROR","searchFilter","filter","searchEntries","search","scope","attributes","entryAttributes","Array","isArray","adminUsersManager","createUserOrGuest","USER_ROLE","USER","identityHasChanged","Object","fromEntries","Promise","all","keys","map","key","isSame","comparePassword","Boolean","updateUserOrGuest","id","assign","makePaths","Logger","timeout","connectTimeout"],"mappings":"AAAA;;;;CAIC;;;;+BAiBYA;;;eAAAA;;;wBAfiD;wBACQ;8BACnC;sBACT;0CAGQ;qCACL;2BACkB;mCACjB;;;;;;;;;;AAMvB,IAAA,AAAMA,wBAAN,MAAMA;IAUX,MAAMC,aAAaC,YAAoB,EAAEC,QAAgB,EAAEC,EAAW,EAAsB;QAC1F,IAAIC,OAAO,MAAM,IAAI,CAACC,YAAY,CAACC,QAAQ,CAACL,cAAc;QAC1D,IAAIG,MAAM;YACR,IAAIA,KAAKG,OAAO,EAAE;gBAChB,8FAA8F;gBAC9F,OAAO,IAAI,CAACF,YAAY,CAACG,OAAO,CAACJ,MAAMF,UAAUC;YACnD;YACA,IAAI,CAACC,KAAKK,QAAQ,EAAE;gBAClB,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACX,YAAY,CAACY,IAAI,CAAC,SAAS,EAAER,KAAKS,KAAK,CAAC,WAAW,CAAC;gBAC9E,MAAM,IAAIC,qBAAa,CAAC,kBAAkBC,kBAAU,CAACC,SAAS;YAChE;QACF;QACA,MAAMC,QAA+B,MAAM,IAAI,CAACC,SAAS,CAACjB,cAAcC;QACxE,IAAIe,UAAU,OAAO;YACnB,IAAIb,MAAM;gBACR,IAAI,CAACC,YAAY,CAACc,cAAc,CAACf,MAAMD,IAAI,OAAOiB,KAAK,CAAC,CAACC,IAAa,IAAI,CAACX,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACX,YAAY,CAACY,IAAI,CAAC,GAAG,EAAES,GAAG;YAC5H;YACA,OAAO;QACT,OAAO,IAAI,CAACJ,MAAMK,IAAI,IAAI,CAACL,MAAMM,GAAG,EAAE;YACpC,IAAI,CAACb,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACX,YAAY,CAACY,IAAI,CAAC,GAAG,EAAEX,aAAa,oCAAoC,EAAEuB,KAAKC,SAAS,CAACR,OAAO,CAAC,CAAC;YAC5H,OAAO;QACT;QACA,MAAMS,WAAW;YAAEb,OAAOI,MAAMM,GAAG;YAAEI,OAAOV,MAAMK,IAAI;YAAEpB,UAAUA;YAAU,GAAG0B,IAAAA,wBAAa,EAACX,MAAMY,EAAE,CAAC;QAAC;QACvGzB,OAAO,MAAM,IAAI,CAAC0B,kBAAkB,CAACJ,UAAUtB;QAC/C,IAAI,CAACC,YAAY,CAACc,cAAc,CAACf,MAAMD,IAAI,MAAMiB,KAAK,CAAC,CAACC,IAAa,IAAI,CAACX,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACX,YAAY,CAACY,IAAI,CAAC,GAAG,EAAES,GAAG;QACzH,OAAOjB;IACT;IAEA,MAAcc,UAAUK,GAAW,EAAErB,QAAgB,EAAkC;QACrF,MAAM6B,UAAUC,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACH,OAAO;QAC/C,MAAMI,aAAa,GAAGH,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACE,cAAc,CAAC,CAAC,EAAEb,IAAI,CAAC,EAAES,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACG,MAAM,EAAE;QACvG,IAAIC;QACJ,IAAI3B;QACJ,KAAK,MAAM4B,KAAKR,QAAS;YACvBO,SAAS,IAAIE,cAAM,CAAC;gBAAE,GAAG,IAAI,CAACC,aAAa;gBAAEC,KAAKH;YAAE;YACpD,IAAI;gBACF,MAAMD,OAAOK,IAAI,CAACR,YAAYjC;gBAC9B,OAAO,MAAM,IAAI,CAAC0C,WAAW,CAACN,QAAQf;YACxC,EAAE,OAAOF,GAAG;gBACV,IAAIA,EAAEwB,MAAM,EAAEC,QAAQ;oBACpB,KAAK,MAAMC,OAAO1B,EAAEwB,MAAM,CAAE;wBAC1B,IAAI,CAACnC,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAAC9B,SAAS,CAACN,IAAI,CAAC,GAAG,EAAEW,IAAI,GAAG,EAAEwB,KAAK;wBAC3DpC,QAAQoC;oBACV;gBACF,OAAO;oBACLpC,QAAQU;oBACR,IAAI,CAACX,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAAC9B,SAAS,CAACN,IAAI,CAAC,GAAG,EAAEW,IAAI,GAAG,EAAEF,GAAG;gBAC3D;gBACA,IAAIV,iBAAiBsC,+BAAuB,EAAE;oBAC5C,OAAO;gBACT;YACF,SAAU;gBACR,MAAMX,OAAOY,MAAM;YACrB;QACF;QACA,IAAIvC,SAASwC,gCAAkB,CAACC,GAAG,CAACzC,MAAM0C,IAAI,GAAG;YAC/C,MAAM,IAAIvC,qBAAa,CAAC,gCAAgCC,kBAAU,CAACuC,qBAAqB;QAC1F;QACA,OAAO;IACT;IAEA,MAAcV,YAAYN,MAAc,EAAEf,GAAW,EAAkC;QACrF,MAAMgC,eAAe,CAAC,GAAG,EAAEvB,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACE,cAAc,CAAC,CAAC,EAAEb,IAAI,CAAC,EAAES,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACsB,MAAM,IAAI,GAAG,CAAC,CAAC;QACnH,IAAI;YACF,MAAM,EAAEC,aAAa,EAAE,GAAG,MAAMnB,OAAOoB,MAAM,CAAC1B,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACG,MAAM,EAAE;gBAC5EsB,OAAO;gBACPH,QAAQD;gBACRK,YAAY,IAAI,CAACC,eAAe;YAClC;YACA,KAAK,MAAM5C,SAASwC,cAAe;gBACjC,IAAIxC,KAAK,CAACe,gCAAa,CAACC,IAAI,CAACC,IAAI,CAACE,cAAc,CAAC,KAAKb,KAAK;oBACzD,IAAIuC,MAAMC,OAAO,CAAC9C,MAAMK,IAAI,GAAG;wBAC7B,sDAAsD;wBACtDL,MAAMK,IAAI,GAAGL,MAAMK,IAAI,CAAC,EAAE;oBAC5B;oBACA,OAAOL;gBACT;YACF;YACA,OAAO;QACT,EAAE,OAAOI,GAAG;YACV,IAAI,CAACX,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAACJ,WAAW,CAAChC,IAAI,CAAC,GAAG,EAAEW,IAAI,GAAG,EAAEF,GAAG;YAC3D,OAAO;QACT;IACF;IAEA,MAAcS,mBAAmBJ,QAAuB,EAAEtB,IAAe,EAAsB;QAC7F,IAAIA,SAAS,MAAM;YACjB,OAAO,IAAI,CAAC4D,iBAAiB,CAACC,iBAAiB,CAACvC,UAAUwC,eAAS,CAACC,IAAI;QAC1E,OAAO;YACL,IAAIzC,SAASb,KAAK,KAAKT,KAAKS,KAAK,EAAE;gBACjC,IAAI,CAACH,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACmB,kBAAkB,CAAClB,IAAI,CAAC,sBAAsB,EAAEc,SAASb,KAAK,CAAC,KAAK,EAAET,KAAKS,KAAK,EAAE;gBAC5G,MAAM,IAAIC,qBAAa,CAAC,0BAA0BC,kBAAU,CAACC,SAAS;YACxE;YACA,wCAAwC;YACxC,MAAMoD,qBAAoCC,OAAOC,WAAW,CAC1D,AACE,CAAA,MAAMC,QAAQC,GAAG,CACfH,OAAOI,IAAI,CAAC/C,UAAUgD,GAAG,CAAC,OAAOC;gBAC/B,IAAIA,QAAQ,YAAY;oBACtB,MAAMC,SAAS,MAAMC,IAAAA,0BAAe,EAACnD,QAAQ,CAACiD,IAAI,EAAEvE,KAAKF,QAAQ;oBACjE,OAAO0E,SAAS,OAAO;wBAACD;wBAAKjD,QAAQ,CAACiD,IAAI;qBAAC;gBAC7C;gBACA,OAAOjD,QAAQ,CAACiD,IAAI,KAAKvE,IAAI,CAACuE,IAAI,GAAG;oBAACA;oBAAKjD,QAAQ,CAACiD,IAAI;iBAAC,GAAG;YAC9D,GACF,EACAnB,MAAM,CAACsB;YAEX,IAAIT,OAAOI,IAAI,CAACL,oBAAoBtB,MAAM,GAAG,GAAG;gBAC9C,IAAI;oBACF,MAAM,IAAI,CAACkB,iBAAiB,CAACe,iBAAiB,CAAC3E,KAAK4E,EAAE,EAAEZ;oBACxD,IAAIA,oBAAoBlE,UAAU;wBAChC,OAAOkE,mBAAmBlE,QAAQ;oBACpC;oBACAmE,OAAOY,MAAM,CAAC7E,MAAMgE;gBACtB,EAAE,OAAO/C,GAAG;oBACV,IAAI,CAACX,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAAClB,kBAAkB,CAAClB,IAAI,CAAC,0BAA0B,EAAER,KAAKS,KAAK,CAAC,IAAI,EAAEQ,GAAG;gBACnG;YACF;YACA,MAAMjB,KAAK8E,SAAS;YACpB,OAAO9E;QACT;IACF;IA9HA,YACE,AAAiBC,YAA0B,EAC3C,AAAiB2D,iBAAoC,CACrD;aAFiB3D,eAAAA;aACA2D,oBAAAA;aANFtD,SAAS,IAAIyE,cAAM,CAACpF,sBAAsBa,IAAI;aAC9CiD,kBAAkB;YAAC;YAAO;YAAQ;SAAK;aAChDpB,gBAA+B;YAAE2C,SAAS;YAAMC,gBAAgB;YAAM3C,KAAK;QAAG;IAKnF;AA4HL"}
1
+ {"version":3,"sources":["../../../../../backend/src/authentication/services/auth-methods/auth-method-ldap.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { AndFilter, Client, ClientOptions, Entry, EqualityFilter, InvalidCredentialsError } from 'ldapts'\nimport { CONNECT_ERROR_CODE } from '../../../app.constants'\nimport { USER_ROLE } from '../../../applications/users/constants/user'\nimport type { CreateUserDto, UpdateUserDto } from '../../../applications/users/dto/create-or-update-user.dto'\nimport { UserModel } from '../../../applications/users/models/user.model'\nimport { AdminUsersManager } from '../../../applications/users/services/admin-users-manager.service'\nimport { UsersManager } from '../../../applications/users/services/users-manager.service'\nimport { comparePassword, splitFullName } from '../../../common/functions'\nimport { configuration } from '../../../configuration/config.environment'\nimport { ALL_LDAP_ATTRIBUTES, LDAP_COMMON_ATTR, LDAP_LOGIN_ATTR } from '../../constants/auth-ldap'\nimport type { AUTH_SCOPE } from '../../constants/scope'\nimport { AuthMethod } from '../../models/auth-method'\n\ntype LdapUserEntry = Entry & Record<LDAP_LOGIN_ATTR | (typeof LDAP_COMMON_ATTR)[keyof typeof LDAP_COMMON_ATTR], string>\n\n@Injectable()\nexport class AuthMethodLdapService implements AuthMethod {\n private readonly logger = new Logger(AuthMethodLdapService.name)\n private readonly loginAttribute: LDAP_LOGIN_ATTR = configuration.auth.ldap.attributes.login\n private readonly emailAttribute: string = configuration.auth.ldap.attributes.email\n private readonly servers: string[] = configuration.auth.ldap.servers\n private readonly baseDN: string = configuration.auth.ldap.baseDN\n private readonly filter: string = configuration.auth.ldap.filter\n private clientOptions: ClientOptions = { timeout: 6000, connectTimeout: 6000, url: '' }\n\n constructor(\n private readonly usersManager: UsersManager,\n private readonly adminUsersManager: AdminUsersManager\n ) {}\n\n async validateUser(login: string, password: string, ip?: string, scope?: AUTH_SCOPE): Promise<UserModel> {\n let user: UserModel = await this.usersManager.findUser(this.normalizeLogin(login), false)\n if (user) {\n if (user.isGuest) {\n // allow guests to be authenticated from db and check if the current user is defined as active\n return this.usersManager.logUser(user, password, ip)\n }\n if (!user.isActive) {\n this.logger.error(`${this.validateUser.name} - user *${user.login}* is locked`)\n throw new HttpException('Account locked', HttpStatus.FORBIDDEN)\n }\n }\n const entry: false | LdapUserEntry = await this.checkAuth(login, password)\n if (entry === false) {\n // LDAP auth failed\n if (user) {\n let authSuccess = false\n if (scope) {\n // try user app password\n authSuccess = await this.usersManager.validateAppPassword(user, password, ip, scope)\n }\n this.usersManager.updateAccesses(user, ip, authSuccess).catch((e: Error) => this.logger.error(`${this.validateUser.name} : ${e}`))\n if (authSuccess) {\n // logged with app password\n return user\n }\n }\n return null\n } else if (!entry[this.loginAttribute] || !entry[this.emailAttribute]) {\n this.logger.error(`${this.validateUser.name} - required ldap fields are missing : \n [${this.loginAttribute}, ${this.emailAttribute}] => \n (${JSON.stringify(entry)})`)\n return null\n }\n const identity = this.createIdentity(entry, password)\n user = await this.updateOrCreateUser(identity, user)\n this.usersManager.updateAccesses(user, ip, true).catch((e: Error) => this.logger.error(`${this.validateUser.name} : ${e}`))\n return user\n }\n\n private async checkAuth(login: string, password: string): Promise<LdapUserEntry | false> {\n const loginAttr = this.loginAttribute\n const isAD = loginAttr === LDAP_LOGIN_ATTR.SAM || loginAttr === LDAP_LOGIN_ATTR.UPN\n // AD: bind directly with the user input (UPN or DOMAIN\\user)\n // Generic LDAP: build DN from login attribute + baseDN\n const bindUserDN = isAD ? login : `${loginAttr}=${login},${this.baseDN}`\n let client: Client\n let error: any\n for (const s of this.servers) {\n client = new Client({ ...this.clientOptions, url: s })\n try {\n await client.bind(bindUserDN, password)\n return await this.checkAccess(client, login)\n } catch (e) {\n if (e.errors?.length) {\n for (const err of e.errors) {\n this.logger.warn(`${this.checkAuth.name} - ${login} : ${err}`)\n error = err\n }\n } else {\n error = e\n this.logger.warn(`${this.checkAuth.name} - ${login} : ${e}`)\n }\n if (error instanceof InvalidCredentialsError) {\n return false\n }\n } finally {\n await client.unbind()\n }\n }\n if (error && CONNECT_ERROR_CODE.has(error.code)) {\n throw new HttpException('Authentication service error', HttpStatus.INTERNAL_SERVER_ERROR)\n }\n return false\n }\n\n private async checkAccess(client: Client, login: string): Promise<LdapUserEntry | false> {\n const searchFilter = this.buildUserFilter(login, this.filter)\n try {\n const { searchEntries } = await client.search(this.baseDN, {\n scope: 'sub',\n filter: searchFilter,\n attributes: ALL_LDAP_ATTRIBUTES\n })\n\n if (searchEntries.length === 0) {\n this.logger.debug(`${this.checkAccess.name} - search filter : ${searchFilter}`)\n this.logger.warn(`${this.checkAccess.name} - no LDAP entry found for : ${login}`)\n return false\n }\n\n if (searchEntries.length > 1) {\n this.logger.warn(`${this.checkAccess.name} - multiple LDAP entries found for : ${login}, using first one`)\n }\n\n // Always return the first valid entry\n return this.convertToLdapUserEntry(searchEntries[0])\n } catch (e) {\n this.logger.debug(`${this.checkAccess.name} - search filter : ${searchFilter}`)\n this.logger.error(`${this.checkAccess.name} - ${login} : ${e}`)\n return false\n }\n }\n\n private async updateOrCreateUser(identity: CreateUserDto, user: UserModel): Promise<UserModel> {\n if (user === null) {\n const createdUser = await this.adminUsersManager.createUserOrGuest(identity, USER_ROLE.USER)\n const freshUser = await this.usersManager.fromUserId(createdUser.id)\n if (!freshUser) {\n this.logger.error(`${this.updateOrCreateUser.name} - user was not found : ${createdUser.login} (${createdUser.id})`)\n throw new HttpException('User not found', HttpStatus.NOT_FOUND)\n }\n return freshUser\n }\n if (identity.login !== user.login) {\n this.logger.error(`${this.updateOrCreateUser.name} - user login mismatch : ${identity.login} !== ${user.login}`)\n throw new HttpException('Account matching error', HttpStatus.FORBIDDEN)\n }\n // check if user information has changed\n const identityHasChanged: UpdateUserDto = Object.fromEntries(\n (\n await Promise.all(\n Object.keys(identity).map(async (key: string) => {\n if (key === 'password') {\n const isSame = await comparePassword(identity[key], user.password)\n return isSame ? null : [key, identity[key]]\n }\n return identity[key] !== user[key] ? [key, identity[key]] : null\n })\n )\n ).filter(Boolean)\n )\n if (Object.keys(identityHasChanged).length > 0) {\n try {\n await this.adminUsersManager.updateUserOrGuest(user.id, identityHasChanged)\n if (identityHasChanged?.password) {\n delete identityHasChanged.password\n }\n Object.assign(user, identityHasChanged)\n if ('lastName' in identityHasChanged || 'firstName' in identityHasChanged) {\n // force fullName update in current user model\n user.setFullName(true)\n }\n } catch (e) {\n this.logger.warn(`${this.updateOrCreateUser.name} - unable to update user *${user.login}* : ${e}`)\n }\n }\n return user\n }\n\n private convertToLdapUserEntry(entry: Entry): LdapUserEntry {\n for (const attr of ALL_LDAP_ATTRIBUTES) {\n if (Array.isArray(entry[attr])) {\n entry[attr] = entry[attr].length > 0 ? entry[attr][0] : null\n }\n }\n return entry as LdapUserEntry\n }\n\n private createIdentity(entry: LdapUserEntry, password: string): CreateUserDto {\n return {\n login: this.normalizeLogin(entry[this.loginAttribute]),\n email: entry[this.emailAttribute] as string,\n password: password,\n ...this.getFirstNameAndLastName(entry)\n } satisfies CreateUserDto\n }\n\n private getFirstNameAndLastName(entry: LdapUserEntry): { firstName: string; lastName: string } {\n // 1) Prefer structured attributes\n if (entry.sn && entry.givenName) {\n return { firstName: entry.givenName, lastName: entry.sn }\n }\n // 2) Fallback to displayName if available\n if (entry.displayName && entry.displayName.trim()) {\n return splitFullName(entry.displayName)\n }\n // 3) Fallback to cn\n if (entry.cn && entry.cn.trim()) {\n return splitFullName(entry.cn)\n }\n // 4) Nothing usable\n return { firstName: '', lastName: '' }\n }\n\n private normalizeLogin(login: string, toLowerCase = true): string {\n const normalized = (login.includes('\\\\') ? login.split('\\\\').slice(-1)[0] : login).trim()\n return toLowerCase ? normalized.toLowerCase() : normalized\n }\n\n private buildUserFilter(login: string, extraFilter?: string): string {\n // Build a safe LDAP filter to search for a user.\n // Important: - Values passed to EqualityFilter are auto-escaped by ldapts\n // - extraFilter is appended as-is (assumed trusted configuration)\n // Output: (&(|(userPrincipalName=john.doe)(sAMAccountName=john.doe)(uid=john.doe))(*extraFilter*))\n\n // OR clause: accept UPN, sAMAccountName, or uid\n const normalizedLogin = this.normalizeLogin(login, false)\n\n const eq = new EqualityFilter({ attribute: this.loginAttribute, value: normalizedLogin })\n // Convert to LDAP filter string\n let filterString = new AndFilter({ filters: [eq] }).toString()\n\n // Optionally append an extra filter from config (trusted source)\n if (extraFilter && extraFilter.trim()) {\n filterString = `(&${filterString}${extraFilter})`\n }\n return filterString\n }\n}\n"],"names":["AuthMethodLdapService","validateUser","login","password","ip","scope","user","usersManager","findUser","normalizeLogin","isGuest","logUser","isActive","logger","error","name","HttpException","HttpStatus","FORBIDDEN","entry","checkAuth","authSuccess","validateAppPassword","updateAccesses","catch","e","loginAttribute","emailAttribute","JSON","stringify","identity","createIdentity","updateOrCreateUser","loginAttr","isAD","LDAP_LOGIN_ATTR","SAM","UPN","bindUserDN","baseDN","client","s","servers","Client","clientOptions","url","bind","checkAccess","errors","length","err","warn","InvalidCredentialsError","unbind","CONNECT_ERROR_CODE","has","code","INTERNAL_SERVER_ERROR","searchFilter","buildUserFilter","filter","searchEntries","search","attributes","ALL_LDAP_ATTRIBUTES","debug","convertToLdapUserEntry","createdUser","adminUsersManager","createUserOrGuest","USER_ROLE","USER","freshUser","fromUserId","id","NOT_FOUND","identityHasChanged","Object","fromEntries","Promise","all","keys","map","key","isSame","comparePassword","Boolean","updateUserOrGuest","assign","setFullName","attr","Array","isArray","email","getFirstNameAndLastName","sn","givenName","firstName","lastName","displayName","trim","splitFullName","cn","toLowerCase","normalized","includes","split","slice","extraFilter","normalizedLogin","eq","EqualityFilter","attribute","value","filterString","AndFilter","filters","toString","Logger","configuration","auth","ldap","timeout","connectTimeout"],"mappings":"AAAA;;;;CAIC;;;;+BAmBYA;;;eAAAA;;;wBAjBiD;wBACmC;8BAC9D;sBACT;0CAGQ;qCACL;2BACkB;mCACjB;0BACyC;;;;;;;;;;AAOhE,IAAA,AAAMA,wBAAN,MAAMA;IAcX,MAAMC,aAAaC,KAAa,EAAEC,QAAgB,EAAEC,EAAW,EAAEC,KAAkB,EAAsB;QACvG,IAAIC,OAAkB,MAAM,IAAI,CAACC,YAAY,CAACC,QAAQ,CAAC,IAAI,CAACC,cAAc,CAACP,QAAQ;QACnF,IAAII,MAAM;YACR,IAAIA,KAAKI,OAAO,EAAE;gBAChB,8FAA8F;gBAC9F,OAAO,IAAI,CAACH,YAAY,CAACI,OAAO,CAACL,MAAMH,UAAUC;YACnD;YACA,IAAI,CAACE,KAAKM,QAAQ,EAAE;gBAClB,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACb,YAAY,CAACc,IAAI,CAAC,SAAS,EAAET,KAAKJ,KAAK,CAAC,WAAW,CAAC;gBAC9E,MAAM,IAAIc,qBAAa,CAAC,kBAAkBC,kBAAU,CAACC,SAAS;YAChE;QACF;QACA,MAAMC,QAA+B,MAAM,IAAI,CAACC,SAAS,CAAClB,OAAOC;QACjE,IAAIgB,UAAU,OAAO;YACnB,mBAAmB;YACnB,IAAIb,MAAM;gBACR,IAAIe,cAAc;gBAClB,IAAIhB,OAAO;oBACT,wBAAwB;oBACxBgB,cAAc,MAAM,IAAI,CAACd,YAAY,CAACe,mBAAmB,CAAChB,MAAMH,UAAUC,IAAIC;gBAChF;gBACA,IAAI,CAACE,YAAY,CAACgB,cAAc,CAACjB,MAAMF,IAAIiB,aAAaG,KAAK,CAAC,CAACC,IAAa,IAAI,CAACZ,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACb,YAAY,CAACc,IAAI,CAAC,GAAG,EAAEU,GAAG;gBAChI,IAAIJ,aAAa;oBACf,2BAA2B;oBAC3B,OAAOf;gBACT;YACF;YACA,OAAO;QACT,OAAO,IAAI,CAACa,KAAK,CAAC,IAAI,CAACO,cAAc,CAAC,IAAI,CAACP,KAAK,CAAC,IAAI,CAACQ,cAAc,CAAC,EAAE;YACrE,IAAI,CAACd,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACb,YAAY,CAACc,IAAI,CAAC;OAC3C,EAAE,IAAI,CAACW,cAAc,CAAC,EAAE,EAAE,IAAI,CAACC,cAAc,CAAC;OAC9C,EAAEC,KAAKC,SAAS,CAACV,OAAO,CAAC,CAAC;YAC3B,OAAO;QACT;QACA,MAAMW,WAAW,IAAI,CAACC,cAAc,CAACZ,OAAOhB;QAC5CG,OAAO,MAAM,IAAI,CAAC0B,kBAAkB,CAACF,UAAUxB;QAC/C,IAAI,CAACC,YAAY,CAACgB,cAAc,CAACjB,MAAMF,IAAI,MAAMoB,KAAK,CAAC,CAACC,IAAa,IAAI,CAACZ,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACb,YAAY,CAACc,IAAI,CAAC,GAAG,EAAEU,GAAG;QACzH,OAAOnB;IACT;IAEA,MAAcc,UAAUlB,KAAa,EAAEC,QAAgB,EAAkC;QACvF,MAAM8B,YAAY,IAAI,CAACP,cAAc;QACrC,MAAMQ,OAAOD,cAAcE,yBAAe,CAACC,GAAG,IAAIH,cAAcE,yBAAe,CAACE,GAAG;QACnF,6DAA6D;QAC7D,uDAAuD;QACvD,MAAMC,aAAaJ,OAAOhC,QAAQ,GAAG+B,UAAU,CAAC,EAAE/B,MAAM,CAAC,EAAE,IAAI,CAACqC,MAAM,EAAE;QACxE,IAAIC;QACJ,IAAI1B;QACJ,KAAK,MAAM2B,KAAK,IAAI,CAACC,OAAO,CAAE;YAC5BF,SAAS,IAAIG,cAAM,CAAC;gBAAE,GAAG,IAAI,CAACC,aAAa;gBAAEC,KAAKJ;YAAE;YACpD,IAAI;gBACF,MAAMD,OAAOM,IAAI,CAACR,YAAYnC;gBAC9B,OAAO,MAAM,IAAI,CAAC4C,WAAW,CAACP,QAAQtC;YACxC,EAAE,OAAOuB,GAAG;gBACV,IAAIA,EAAEuB,MAAM,EAAEC,QAAQ;oBACpB,KAAK,MAAMC,OAAOzB,EAAEuB,MAAM,CAAE;wBAC1B,IAAI,CAACnC,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAAC/B,SAAS,CAACL,IAAI,CAAC,GAAG,EAAEb,MAAM,GAAG,EAAEgD,KAAK;wBAC7DpC,QAAQoC;oBACV;gBACF,OAAO;oBACLpC,QAAQW;oBACR,IAAI,CAACZ,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAAC/B,SAAS,CAACL,IAAI,CAAC,GAAG,EAAEb,MAAM,GAAG,EAAEuB,GAAG;gBAC7D;gBACA,IAAIX,iBAAiBsC,+BAAuB,EAAE;oBAC5C,OAAO;gBACT;YACF,SAAU;gBACR,MAAMZ,OAAOa,MAAM;YACrB;QACF;QACA,IAAIvC,SAASwC,gCAAkB,CAACC,GAAG,CAACzC,MAAM0C,IAAI,GAAG;YAC/C,MAAM,IAAIxC,qBAAa,CAAC,gCAAgCC,kBAAU,CAACwC,qBAAqB;QAC1F;QACA,OAAO;IACT;IAEA,MAAcV,YAAYP,MAAc,EAAEtC,KAAa,EAAkC;QACvF,MAAMwD,eAAe,IAAI,CAACC,eAAe,CAACzD,OAAO,IAAI,CAAC0D,MAAM;QAC5D,IAAI;YACF,MAAM,EAAEC,aAAa,EAAE,GAAG,MAAMrB,OAAOsB,MAAM,CAAC,IAAI,CAACvB,MAAM,EAAE;gBACzDlC,OAAO;gBACPuD,QAAQF;gBACRK,YAAYC,6BAAmB;YACjC;YAEA,IAAIH,cAAcZ,MAAM,KAAK,GAAG;gBAC9B,IAAI,CAACpC,MAAM,CAACoD,KAAK,CAAC,GAAG,IAAI,CAAClB,WAAW,CAAChC,IAAI,CAAC,mBAAmB,EAAE2C,cAAc;gBAC9E,IAAI,CAAC7C,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAACJ,WAAW,CAAChC,IAAI,CAAC,6BAA6B,EAAEb,OAAO;gBAChF,OAAO;YACT;YAEA,IAAI2D,cAAcZ,MAAM,GAAG,GAAG;gBAC5B,IAAI,CAACpC,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAACJ,WAAW,CAAChC,IAAI,CAAC,qCAAqC,EAAEb,MAAM,iBAAiB,CAAC;YAC3G;YAEA,sCAAsC;YACtC,OAAO,IAAI,CAACgE,sBAAsB,CAACL,aAAa,CAAC,EAAE;QACrD,EAAE,OAAOpC,GAAG;YACV,IAAI,CAACZ,MAAM,CAACoD,KAAK,CAAC,GAAG,IAAI,CAAClB,WAAW,CAAChC,IAAI,CAAC,mBAAmB,EAAE2C,cAAc;YAC9E,IAAI,CAAC7C,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACiC,WAAW,CAAChC,IAAI,CAAC,GAAG,EAAEb,MAAM,GAAG,EAAEuB,GAAG;YAC9D,OAAO;QACT;IACF;IAEA,MAAcO,mBAAmBF,QAAuB,EAAExB,IAAe,EAAsB;QAC7F,IAAIA,SAAS,MAAM;YACjB,MAAM6D,cAAc,MAAM,IAAI,CAACC,iBAAiB,CAACC,iBAAiB,CAACvC,UAAUwC,eAAS,CAACC,IAAI;YAC3F,MAAMC,YAAY,MAAM,IAAI,CAACjE,YAAY,CAACkE,UAAU,CAACN,YAAYO,EAAE;YACnE,IAAI,CAACF,WAAW;gBACd,IAAI,CAAC3D,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACkB,kBAAkB,CAACjB,IAAI,CAAC,wBAAwB,EAAEoD,YAAYjE,KAAK,CAAC,EAAE,EAAEiE,YAAYO,EAAE,CAAC,CAAC,CAAC;gBACnH,MAAM,IAAI1D,qBAAa,CAAC,kBAAkBC,kBAAU,CAAC0D,SAAS;YAChE;YACA,OAAOH;QACT;QACA,IAAI1C,SAAS5B,KAAK,KAAKI,KAAKJ,KAAK,EAAE;YACjC,IAAI,CAACW,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACkB,kBAAkB,CAACjB,IAAI,CAAC,yBAAyB,EAAEe,SAAS5B,KAAK,CAAC,KAAK,EAAEI,KAAKJ,KAAK,EAAE;YAC/G,MAAM,IAAIc,qBAAa,CAAC,0BAA0BC,kBAAU,CAACC,SAAS;QACxE;QACA,wCAAwC;QACxC,MAAM0D,qBAAoCC,OAAOC,WAAW,CAC1D,AACE,CAAA,MAAMC,QAAQC,GAAG,CACfH,OAAOI,IAAI,CAACnD,UAAUoD,GAAG,CAAC,OAAOC;YAC/B,IAAIA,QAAQ,YAAY;gBACtB,MAAMC,SAAS,MAAMC,IAAAA,0BAAe,EAACvD,QAAQ,CAACqD,IAAI,EAAE7E,KAAKH,QAAQ;gBACjE,OAAOiF,SAAS,OAAO;oBAACD;oBAAKrD,QAAQ,CAACqD,IAAI;iBAAC;YAC7C;YACA,OAAOrD,QAAQ,CAACqD,IAAI,KAAK7E,IAAI,CAAC6E,IAAI,GAAG;gBAACA;gBAAKrD,QAAQ,CAACqD,IAAI;aAAC,GAAG;QAC9D,GACF,EACAvB,MAAM,CAAC0B;QAEX,IAAIT,OAAOI,IAAI,CAACL,oBAAoB3B,MAAM,GAAG,GAAG;YAC9C,IAAI;gBACF,MAAM,IAAI,CAACmB,iBAAiB,CAACmB,iBAAiB,CAACjF,KAAKoE,EAAE,EAAEE;gBACxD,IAAIA,oBAAoBzE,UAAU;oBAChC,OAAOyE,mBAAmBzE,QAAQ;gBACpC;gBACA0E,OAAOW,MAAM,CAAClF,MAAMsE;gBACpB,IAAI,cAAcA,sBAAsB,eAAeA,oBAAoB;oBACzE,8CAA8C;oBAC9CtE,KAAKmF,WAAW,CAAC;gBACnB;YACF,EAAE,OAAOhE,GAAG;gBACV,IAAI,CAACZ,MAAM,CAACsC,IAAI,CAAC,GAAG,IAAI,CAACnB,kBAAkB,CAACjB,IAAI,CAAC,0BAA0B,EAAET,KAAKJ,KAAK,CAAC,IAAI,EAAEuB,GAAG;YACnG;QACF;QACA,OAAOnB;IACT;IAEQ4D,uBAAuB/C,KAAY,EAAiB;QAC1D,KAAK,MAAMuE,QAAQ1B,6BAAmB,CAAE;YACtC,IAAI2B,MAAMC,OAAO,CAACzE,KAAK,CAACuE,KAAK,GAAG;gBAC9BvE,KAAK,CAACuE,KAAK,GAAGvE,KAAK,CAACuE,KAAK,CAACzC,MAAM,GAAG,IAAI9B,KAAK,CAACuE,KAAK,CAAC,EAAE,GAAG;YAC1D;QACF;QACA,OAAOvE;IACT;IAEQY,eAAeZ,KAAoB,EAAEhB,QAAgB,EAAiB;QAC5E,OAAO;YACLD,OAAO,IAAI,CAACO,cAAc,CAACU,KAAK,CAAC,IAAI,CAACO,cAAc,CAAC;YACrDmE,OAAO1E,KAAK,CAAC,IAAI,CAACQ,cAAc,CAAC;YACjCxB,UAAUA;YACV,GAAG,IAAI,CAAC2F,uBAAuB,CAAC3E,MAAM;QACxC;IACF;IAEQ2E,wBAAwB3E,KAAoB,EAA2C;QAC7F,kCAAkC;QAClC,IAAIA,MAAM4E,EAAE,IAAI5E,MAAM6E,SAAS,EAAE;YAC/B,OAAO;gBAAEC,WAAW9E,MAAM6E,SAAS;gBAAEE,UAAU/E,MAAM4E,EAAE;YAAC;QAC1D;QACA,0CAA0C;QAC1C,IAAI5E,MAAMgF,WAAW,IAAIhF,MAAMgF,WAAW,CAACC,IAAI,IAAI;YACjD,OAAOC,IAAAA,wBAAa,EAAClF,MAAMgF,WAAW;QACxC;QACA,oBAAoB;QACpB,IAAIhF,MAAMmF,EAAE,IAAInF,MAAMmF,EAAE,CAACF,IAAI,IAAI;YAC/B,OAAOC,IAAAA,wBAAa,EAAClF,MAAMmF,EAAE;QAC/B;QACA,oBAAoB;QACpB,OAAO;YAAEL,WAAW;YAAIC,UAAU;QAAG;IACvC;IAEQzF,eAAeP,KAAa,EAAEqG,cAAc,IAAI,EAAU;QAChE,MAAMC,aAAa,AAACtG,CAAAA,MAAMuG,QAAQ,CAAC,QAAQvG,MAAMwG,KAAK,CAAC,MAAMC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,GAAGzG,KAAI,EAAGkG,IAAI;QACvF,OAAOG,cAAcC,WAAWD,WAAW,KAAKC;IAClD;IAEQ7C,gBAAgBzD,KAAa,EAAE0G,WAAoB,EAAU;QACnE,iDAAiD;QACjD,0EAA0E;QAC1E,6EAA6E;QAC7E,mGAAmG;QAEnG,gDAAgD;QAChD,MAAMC,kBAAkB,IAAI,CAACpG,cAAc,CAACP,OAAO;QAEnD,MAAM4G,KAAK,IAAIC,sBAAc,CAAC;YAAEC,WAAW,IAAI,CAACtF,cAAc;YAAEuF,OAAOJ;QAAgB;QACvF,gCAAgC;QAChC,IAAIK,eAAe,IAAIC,iBAAS,CAAC;YAAEC,SAAS;gBAACN;aAAG;QAAC,GAAGO,QAAQ;QAE5D,iEAAiE;QACjE,IAAIT,eAAeA,YAAYR,IAAI,IAAI;YACrCc,eAAe,CAAC,EAAE,EAAEA,eAAeN,YAAY,CAAC,CAAC;QACnD;QACA,OAAOM;IACT;IArNA,YACE,AAAiB3G,YAA0B,EAC3C,AAAiB6D,iBAAoC,CACrD;aAFiB7D,eAAAA;aACA6D,oBAAAA;aAVFvD,SAAS,IAAIyG,cAAM,CAACtH,sBAAsBe,IAAI;aAC9CW,iBAAkC6F,gCAAa,CAACC,IAAI,CAACC,IAAI,CAAC1D,UAAU,CAAC7D,KAAK;aAC1EyB,iBAAyB4F,gCAAa,CAACC,IAAI,CAACC,IAAI,CAAC1D,UAAU,CAAC8B,KAAK;aACjEnD,UAAoB6E,gCAAa,CAACC,IAAI,CAACC,IAAI,CAAC/E,OAAO;aACnDH,SAAiBgF,gCAAa,CAACC,IAAI,CAACC,IAAI,CAAClF,MAAM;aAC/CqB,SAAiB2D,gCAAa,CAACC,IAAI,CAACC,IAAI,CAAC7D,MAAM;aACxDhB,gBAA+B;YAAE8E,SAAS;YAAMC,gBAAgB;YAAM9E,KAAK;QAAG;IAKnF;AAmNL"}