@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
@@ -0,0 +1,251 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "AuthMethod2FA", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return AuthMethod2FA;
13
+ }
14
+ });
15
+ const _common = require("@nestjs/common");
16
+ const _time2fa = require("time2fa");
17
+ const _notifications = require("../../../applications/notifications/constants/notifications");
18
+ const _notificationsmanagerservice = require("../../../applications/notifications/services/notifications-manager.service");
19
+ const _usersmanagerservice = require("../../../applications/users/services/users-manager.service");
20
+ const _constants = require("../../../common/constants");
21
+ const _functions = require("../../../common/functions");
22
+ const _qrcode = require("../../../common/qrcode");
23
+ const _configenvironment = require("../../../configuration/config.environment");
24
+ const _cacheservice = require("../../../infrastructure/cache/services/cache.service");
25
+ const _auth = require("../../constants/auth");
26
+ const _cryptsecret = require("../../utils/crypt-secret");
27
+ function _ts_decorate(decorators, target, key, desc) {
28
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
30
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
31
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
32
+ }
33
+ function _ts_metadata(k, v) {
34
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
35
+ }
36
+ let AuthMethod2FA = class AuthMethod2FA {
37
+ async initTwoFactor(user) {
38
+ const { secret, qrDataUrl } = this.generateSecretAndQr(user.email);
39
+ // store encrypted secret in cache for 5 minutes
40
+ await this.cache.set(this.getCacheKey(user.id), this.encryptSecret(secret), 300);
41
+ return {
42
+ secret,
43
+ qrDataUrl
44
+ };
45
+ }
46
+ async enableTwoFactor(body, req) {
47
+ // retrieve encrypted secret from cache
48
+ const secret = await this.cache.get(this.getCacheKey(req.user.id));
49
+ if (!secret) {
50
+ throw new _common.HttpException('The secret has expired', _common.HttpStatus.BAD_REQUEST);
51
+ }
52
+ // load user
53
+ const [auth, user] = await this.verify(body, req, true, secret);
54
+ if (!auth.success) {
55
+ throw new _common.HttpException(auth.message, _common.HttpStatus.FORBIDDEN);
56
+ }
57
+ // verify user password
58
+ await this.verifyUserPassword(user, body.password, req.ip);
59
+ // generate recovery codes
60
+ const recoveryCodes = this.generateRecoveryCodes();
61
+ // store and enable TwoFA & recovery codes
62
+ await this.usersManager.updateSecrets(user.id, {
63
+ twoFaSecret: secret,
64
+ recoveryCodes: recoveryCodes.map((code)=>this.encryptSecret(code))
65
+ });
66
+ this.sendEmailNotification(req, _constants.ACTION.ADD);
67
+ return {
68
+ ...auth,
69
+ recoveryCodes: recoveryCodes
70
+ };
71
+ }
72
+ async disableTwoFactor(body, req) {
73
+ // load user
74
+ const [auth, user] = await this.verify(body, req, true);
75
+ if (!auth.success) {
76
+ throw new _common.HttpException(auth.message, _common.HttpStatus.FORBIDDEN);
77
+ }
78
+ // verify user password
79
+ await this.verifyUserPassword(user, body.password, req.ip);
80
+ // store and disable TwoFA & recovery codes
81
+ await this.usersManager.updateSecrets(user.id, {
82
+ twoFaSecret: undefined,
83
+ recoveryCodes: undefined
84
+ });
85
+ this.sendEmailNotification(req, _constants.ACTION.DELETE);
86
+ return auth;
87
+ }
88
+ async verify(verifyDto, req, fromLogin = false, secret) {
89
+ const user = await this.loadUser(req.user.id, req.ip);
90
+ secret = secret || user.secrets.twoFaSecret;
91
+ const auth = verifyDto.isRecoveryCode ? await this.validateRecoveryCode(req.user.id, verifyDto.code, user.secrets.recoveryCodes) : this.validateTwoFactorCode(verifyDto.code, secret);
92
+ this.usersManager.updateAccesses(user, req.ip, auth.success, true).catch((e)=>this.logger.error(`${this.verify.name} - ${e}`));
93
+ return fromLogin ? [
94
+ auth,
95
+ user
96
+ ] : auth;
97
+ }
98
+ async adminResetUserTwoFa(userId) {
99
+ const auth = {
100
+ success: false,
101
+ message: ''
102
+ };
103
+ try {
104
+ await this.usersManager.updateSecrets(userId, {
105
+ twoFaSecret: undefined,
106
+ recoveryCodes: undefined
107
+ });
108
+ auth.success = true;
109
+ } catch (e) {
110
+ auth.success = false;
111
+ auth.message = e.message;
112
+ this.logger.error(`${this.adminResetUserTwoFa.name} - ${e}`);
113
+ }
114
+ return auth;
115
+ }
116
+ async loadUser(userId, ip) {
117
+ const user = await this.usersManager.fromUserId(userId);
118
+ if (!user) {
119
+ this.logger.warn(`User *${user.login}* (${user.id}) not found`);
120
+ throw new _common.HttpException(`User not found`, _common.HttpStatus.NOT_FOUND);
121
+ }
122
+ this.usersManager.validateUserAccess(user, ip);
123
+ return user;
124
+ }
125
+ async verifyUserPassword(user, password, ip) {
126
+ // This function works with any authentication method, provided that
127
+ // the authentication service implements proper user password updates in the database.
128
+ if (!await this.usersManager.compareUserPassword(user.id, password)) {
129
+ this.usersManager.updateAccesses(user, ip, false, true).catch((e)=>this.logger.error(`${this.enableTwoFactor.name} - ${e}`));
130
+ throw new _common.HttpException('Incorrect code or password', _common.HttpStatus.BAD_REQUEST);
131
+ }
132
+ }
133
+ validateTwoFactorCode(code, encryptedSecret) {
134
+ const auth = {
135
+ success: false,
136
+ message: ''
137
+ };
138
+ if (!encryptedSecret) {
139
+ auth.message = 'Incorrect code or password';
140
+ return auth;
141
+ }
142
+ try {
143
+ auth.success = _time2fa.Totp.validate({
144
+ passcode: code,
145
+ secret: this.decryptSecret(encryptedSecret),
146
+ drift: 1
147
+ });
148
+ if (!auth.success) auth.message = 'Incorrect code or password';
149
+ } catch (e) {
150
+ this.logger.error(`${this.validateTwoFactorCode.name} - ${e}`);
151
+ auth.message = e.message;
152
+ }
153
+ return auth;
154
+ }
155
+ async validateRecoveryCode(userId, code, encryptedCodes) {
156
+ const auth = {
157
+ success: false,
158
+ message: ''
159
+ };
160
+ if (!encryptedCodes || encryptedCodes.length === 0) {
161
+ auth.message = 'Invalid code';
162
+ } else {
163
+ try {
164
+ for (const encCode of encryptedCodes){
165
+ if (code === this.decryptSecret(encCode)) {
166
+ auth.success = true;
167
+ // removed used code
168
+ encryptedCodes.splice(encryptedCodes.indexOf(encCode), 1);
169
+ break;
170
+ }
171
+ }
172
+ if (auth.success) {
173
+ // update recovery codes
174
+ await this.usersManager.updateSecrets(userId, {
175
+ recoveryCodes: encryptedCodes
176
+ });
177
+ } else {
178
+ auth.message = 'Invalid code';
179
+ }
180
+ } catch (e) {
181
+ this.logger.error(`${this.validateRecoveryCode.name} - ${e}`);
182
+ auth.message = e.message;
183
+ }
184
+ }
185
+ return auth;
186
+ }
187
+ generateSecretAndQr(userEmail) {
188
+ // Generate secret + otpauth URL + QR (DataURL)
189
+ // Totp.generateKey returns { issuer, user, config, secret, url }
190
+ const key = _time2fa.Totp.generateKey({
191
+ issuer: _configenvironment.configuration.auth.mfa.totp.issuer,
192
+ user: userEmail
193
+ }, {
194
+ digits: _auth.TWO_FA_CODE_LENGTH
195
+ });
196
+ const qrDataUrl = (0, _qrcode.qrcodeToDataURL)(key.url);
197
+ return {
198
+ secret: key.secret,
199
+ qrDataUrl: qrDataUrl
200
+ };
201
+ }
202
+ getCacheKey(userId) {
203
+ return `${this.cacheKeyPrefix}${userId}`;
204
+ }
205
+ encryptSecret(secret) {
206
+ if (_configenvironment.configuration.auth.encryptionKey) {
207
+ return (0, _cryptsecret.encryptSecret)(secret, _configenvironment.configuration.auth.encryptionKey);
208
+ }
209
+ return secret;
210
+ }
211
+ decryptSecret(secret) {
212
+ if (_configenvironment.configuration.auth.encryptionKey) {
213
+ return (0, _cryptsecret.decryptSecret)(secret, _configenvironment.configuration.auth.encryptionKey);
214
+ }
215
+ return secret;
216
+ }
217
+ generateRecoveryCodes(count = 5) {
218
+ return Array.from({
219
+ length: count
220
+ }, ()=>(0, _functions.generateShortUUID)());
221
+ }
222
+ sendEmailNotification(req, action) {
223
+ const notification = {
224
+ app: _notifications.NOTIFICATION_APP.AUTH_2FA,
225
+ event: _notifications.NOTIFICATION_APP_EVENT.AUTH_2FA[action],
226
+ element: req.headers['user-agent'],
227
+ url: req.ip
228
+ };
229
+ this.notificationsManager.sendEmailNotification([
230
+ req.user
231
+ ], notification).catch((e)=>this.logger.error(`${this.sendEmailNotification.name} - ${e}`));
232
+ }
233
+ constructor(cache, usersManager, notificationsManager){
234
+ this.cache = cache;
235
+ this.usersManager = usersManager;
236
+ this.notificationsManager = notificationsManager;
237
+ this.logger = new _common.Logger(AuthMethod2FA.name);
238
+ this.cacheKeyPrefix = 'auth-2fa-pending-user-';
239
+ }
240
+ };
241
+ AuthMethod2FA = _ts_decorate([
242
+ (0, _common.Injectable)(),
243
+ _ts_metadata("design:type", Function),
244
+ _ts_metadata("design:paramtypes", [
245
+ typeof _cacheservice.Cache === "undefined" ? Object : _cacheservice.Cache,
246
+ typeof _usersmanagerservice.UsersManager === "undefined" ? Object : _usersmanagerservice.UsersManager,
247
+ typeof _notificationsmanagerservice.NotificationsManager === "undefined" ? Object : _notificationsmanagerservice.NotificationsManager
248
+ ])
249
+ ], AuthMethod2FA);
250
+
251
+ //# sourceMappingURL=auth-method-two-fa.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/authentication/services/auth-methods/auth-method-two-fa.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 { Totp } from 'time2fa'\nimport { NOTIFICATION_APP, NOTIFICATION_APP_EVENT } from '../../../applications/notifications/constants/notifications'\nimport { NotificationContent } from '../../../applications/notifications/interfaces/notification-properties.interface'\nimport { NotificationsManager } from '../../../applications/notifications/services/notifications-manager.service'\nimport { UserModel } from '../../../applications/users/models/user.model'\nimport { UsersManager } from '../../../applications/users/services/users-manager.service'\nimport { ACTION } from '../../../common/constants'\nimport { generateShortUUID } from '../../../common/functions'\nimport { qrcodeToDataURL } from '../../../common/qrcode'\nimport { configuration } from '../../../configuration/config.environment'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { TWO_FA_CODE_LENGTH } from '../../constants/auth'\nimport { TwoFaVerifyDto, TwoFaVerifyWithPasswordDto } from '../../dto/two-fa-verify.dto'\nimport { FastifyAuthenticatedRequest } from '../../interfaces/auth-request.interface'\nimport { TwoFaEnableResult, TwoFaSetup, TwoFaVerifyResult } from '../../interfaces/two-fa-setup.interface'\nimport { decryptSecret, encryptSecret } from '../../utils/crypt-secret'\n\n@Injectable()\nexport class AuthMethod2FA {\n private readonly logger = new Logger(AuthMethod2FA.name)\n private readonly cacheKeyPrefix = 'auth-2fa-pending-user-'\n\n constructor(\n private readonly cache: Cache,\n private readonly usersManager: UsersManager,\n private readonly notificationsManager: NotificationsManager\n ) {}\n\n async initTwoFactor(user: UserModel): Promise<TwoFaSetup> {\n const { secret, qrDataUrl } = this.generateSecretAndQr(user.email)\n // store encrypted secret in cache for 5 minutes\n await this.cache.set(this.getCacheKey(user.id), this.encryptSecret(secret), 300)\n return { secret, qrDataUrl }\n }\n\n async enableTwoFactor(body: TwoFaVerifyWithPasswordDto, req: FastifyAuthenticatedRequest): Promise<TwoFaEnableResult> {\n // retrieve encrypted secret from cache\n const secret: string = await this.cache.get(this.getCacheKey(req.user.id))\n if (!secret) {\n throw new HttpException('The secret has expired', HttpStatus.BAD_REQUEST)\n }\n // load user\n const [auth, user] = await this.verify(body, req, true, secret)\n if (!auth.success) {\n throw new HttpException(auth.message, HttpStatus.FORBIDDEN)\n }\n // verify user password\n await this.verifyUserPassword(user, body.password, req.ip)\n // generate recovery codes\n const recoveryCodes = this.generateRecoveryCodes()\n // store and enable TwoFA & recovery codes\n await this.usersManager.updateSecrets(user.id, {\n twoFaSecret: secret,\n recoveryCodes: recoveryCodes.map((code) => this.encryptSecret(code))\n })\n this.sendEmailNotification(req, ACTION.ADD)\n return { ...auth, recoveryCodes: recoveryCodes }\n }\n\n async disableTwoFactor(body: TwoFaVerifyWithPasswordDto, req: FastifyAuthenticatedRequest): Promise<TwoFaVerifyResult> {\n // load user\n const [auth, user] = await this.verify(body, req, true)\n if (!auth.success) {\n throw new HttpException(auth.message, HttpStatus.FORBIDDEN)\n }\n // verify user password\n await this.verifyUserPassword(user, body.password, req.ip)\n // store and disable TwoFA & recovery codes\n await this.usersManager.updateSecrets(user.id, { twoFaSecret: undefined, recoveryCodes: undefined })\n this.sendEmailNotification(req, ACTION.DELETE)\n return auth\n }\n\n async verify(verifyDto: TwoFaVerifyDto, req: FastifyAuthenticatedRequest, fromLogin?: false, secret?: string): Promise<TwoFaVerifyResult>\n async verify(verifyDto: TwoFaVerifyDto, req: FastifyAuthenticatedRequest, fromLogin: true, secret?: string): Promise<[TwoFaVerifyResult, UserModel]>\n async verify(\n verifyDto: TwoFaVerifyDto,\n req: FastifyAuthenticatedRequest,\n fromLogin = false,\n secret?: string\n ): Promise<TwoFaVerifyResult | [TwoFaVerifyResult, UserModel]> {\n const user = await this.loadUser(req.user.id, req.ip)\n secret = secret || user.secrets.twoFaSecret\n const auth = verifyDto.isRecoveryCode\n ? await this.validateRecoveryCode(req.user.id, verifyDto.code, user.secrets.recoveryCodes)\n : this.validateTwoFactorCode(verifyDto.code, secret)\n this.usersManager.updateAccesses(user, req.ip, auth.success, true).catch((e: Error) => this.logger.error(`${this.verify.name} - ${e}`))\n return fromLogin ? [auth, user] : auth\n }\n\n async adminResetUserTwoFa(userId: number) {\n const auth: TwoFaVerifyResult = { success: false, message: '' }\n try {\n await this.usersManager.updateSecrets(userId, { twoFaSecret: undefined, recoveryCodes: undefined })\n auth.success = true\n } catch (e) {\n auth.success = false\n auth.message = e.message\n this.logger.error(`${this.adminResetUserTwoFa.name} - ${e}`)\n }\n return auth\n }\n\n async loadUser(userId: number, ip: string) {\n const user: UserModel = await this.usersManager.fromUserId(userId)\n if (!user) {\n this.logger.warn(`User *${user.login}* (${user.id}) not found`)\n throw new HttpException(`User not found`, HttpStatus.NOT_FOUND)\n }\n this.usersManager.validateUserAccess(user, ip)\n return user\n }\n\n async verifyUserPassword(user: UserModel, password: string, ip: string) {\n // This function works with any authentication method, provided that\n // the authentication service implements proper user password updates in the database.\n if (!(await this.usersManager.compareUserPassword(user.id, password))) {\n this.usersManager.updateAccesses(user, ip, false, true).catch((e: Error) => this.logger.error(`${this.enableTwoFactor.name} - ${e}`))\n throw new HttpException('Incorrect code or password', HttpStatus.BAD_REQUEST)\n }\n }\n\n validateTwoFactorCode(code: string, encryptedSecret: string): TwoFaVerifyResult {\n const auth: TwoFaVerifyResult = { success: false, message: '' }\n if (!encryptedSecret) {\n auth.message = 'Incorrect code or password'\n return auth\n }\n try {\n auth.success = Totp.validate({ passcode: code, secret: this.decryptSecret(encryptedSecret), drift: 1 })\n if (!auth.success) auth.message = 'Incorrect code or password'\n } catch (e) {\n this.logger.error(`${this.validateTwoFactorCode.name} - ${e}`)\n auth.message = e.message\n }\n return auth\n }\n\n private async validateRecoveryCode(userId: number, code: string, encryptedCodes: string[]): Promise<TwoFaVerifyResult> {\n const auth: TwoFaVerifyResult = { success: false, message: '' }\n if (!encryptedCodes || encryptedCodes.length === 0) {\n auth.message = 'Invalid code'\n } else {\n try {\n for (const encCode of encryptedCodes) {\n if (code === this.decryptSecret(encCode)) {\n auth.success = true\n // removed used code\n encryptedCodes.splice(encryptedCodes.indexOf(encCode), 1)\n break\n }\n }\n if (auth.success) {\n // update recovery codes\n await this.usersManager.updateSecrets(userId, { recoveryCodes: encryptedCodes })\n } else {\n auth.message = 'Invalid code'\n }\n } catch (e) {\n this.logger.error(`${this.validateRecoveryCode.name} - ${e}`)\n auth.message = e.message\n }\n }\n return auth\n }\n\n private generateSecretAndQr(userEmail: string): TwoFaSetup {\n // Generate secret + otpauth URL + QR (DataURL)\n // Totp.generateKey returns { issuer, user, config, secret, url }\n const key = Totp.generateKey({ issuer: configuration.auth.mfa.totp.issuer, user: userEmail }, { digits: TWO_FA_CODE_LENGTH })\n const qrDataUrl = qrcodeToDataURL(key.url)\n return { secret: key.secret, qrDataUrl: qrDataUrl }\n }\n\n private getCacheKey(userId: number): string {\n return `${this.cacheKeyPrefix}${userId}`\n }\n\n private encryptSecret(secret: string): string {\n if (configuration.auth.encryptionKey) {\n return encryptSecret(secret, configuration.auth.encryptionKey)\n }\n return secret\n }\n\n private decryptSecret(secret: string): string {\n if (configuration.auth.encryptionKey) {\n return decryptSecret(secret, configuration.auth.encryptionKey)\n }\n return secret\n }\n\n private generateRecoveryCodes(count = 5): string[] {\n return Array.from({ length: count }, () => generateShortUUID())\n }\n\n private sendEmailNotification(req: FastifyAuthenticatedRequest, action: ACTION) {\n const notification: NotificationContent = {\n app: NOTIFICATION_APP.AUTH_2FA,\n event: NOTIFICATION_APP_EVENT.AUTH_2FA[action],\n element: req.headers['user-agent'],\n url: req.ip\n }\n this.notificationsManager\n .sendEmailNotification([req.user], notification)\n .catch((e: Error) => this.logger.error(`${this.sendEmailNotification.name} - ${e}`))\n }\n}\n"],"names":["AuthMethod2FA","initTwoFactor","user","secret","qrDataUrl","generateSecretAndQr","email","cache","set","getCacheKey","id","encryptSecret","enableTwoFactor","body","req","get","HttpException","HttpStatus","BAD_REQUEST","auth","verify","success","message","FORBIDDEN","verifyUserPassword","password","ip","recoveryCodes","generateRecoveryCodes","usersManager","updateSecrets","twoFaSecret","map","code","sendEmailNotification","ACTION","ADD","disableTwoFactor","undefined","DELETE","verifyDto","fromLogin","loadUser","secrets","isRecoveryCode","validateRecoveryCode","validateTwoFactorCode","updateAccesses","catch","e","logger","error","name","adminResetUserTwoFa","userId","fromUserId","warn","login","NOT_FOUND","validateUserAccess","compareUserPassword","encryptedSecret","Totp","validate","passcode","decryptSecret","drift","encryptedCodes","length","encCode","splice","indexOf","userEmail","key","generateKey","issuer","configuration","mfa","totp","digits","TWO_FA_CODE_LENGTH","qrcodeToDataURL","url","cacheKeyPrefix","encryptionKey","count","Array","from","generateShortUUID","action","notification","app","NOTIFICATION_APP","AUTH_2FA","event","NOTIFICATION_APP_EVENT","element","headers","notificationsManager","Logger"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ const _testing = require("@nestjs/testing");
10
+ const _notificationsmanagerservice = require("../../../applications/notifications/services/notifications-manager.service");
11
+ const _usersmanagerservice = require("../../../applications/users/services/users-manager.service");
12
+ const _cacheservice = require("../../../infrastructure/cache/services/cache.service");
13
+ const _authmethodtwofaservice = require("./auth-method-two-fa.service");
14
+ describe(_authmethodtwofaservice.AuthMethod2FA.name, ()=>{
15
+ let service;
16
+ beforeAll(async ()=>{
17
+ const module = await _testing.Test.createTestingModule({
18
+ providers: [
19
+ _authmethodtwofaservice.AuthMethod2FA,
20
+ {
21
+ provide: _cacheservice.Cache,
22
+ useValue: {}
23
+ },
24
+ {
25
+ provide: _usersmanagerservice.UsersManager,
26
+ useValue: {}
27
+ },
28
+ {
29
+ provide: _notificationsmanagerservice.NotificationsManager,
30
+ useValue: {}
31
+ }
32
+ ]
33
+ }).compile();
34
+ service = module.get(_authmethodtwofaservice.AuthMethod2FA);
35
+ });
36
+ it('should be defined', ()=>{
37
+ expect(service).toBeDefined();
38
+ });
39
+ });
40
+
41
+ //# sourceMappingURL=auth-method-two-fa.service.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/authentication/services/auth-methods/auth-method-two-fa.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 { NotificationsManager } from '../../../applications/notifications/services/notifications-manager.service'\nimport { UsersManager } from '../../../applications/users/services/users-manager.service'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { AuthMethod2FA } from './auth-method-two-fa.service'\n\ndescribe(AuthMethod2FA.name, () => {\n let service: AuthMethod2FA\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthMethod2FA,\n { provide: Cache, useValue: {} },\n { provide: UsersManager, useValue: {} },\n { provide: NotificationsManager, useValue: {} }\n ]\n }).compile()\n\n service = module.get<AuthMethod2FA>(AuthMethod2FA)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n})\n"],"names":["describe","AuthMethod2FA","name","service","beforeAll","module","Test","createTestingModule","providers","provide","Cache","useValue","UsersManager","NotificationsManager","compile","get","it","expect","toBeDefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;6CACC;qCACR;8BACP;wCACQ;AAE9BA,SAASC,qCAAa,CAACC,IAAI,EAAE;IAC3B,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTP,qCAAa;gBACb;oBAAEQ,SAASC,mBAAK;oBAAEC,UAAU,CAAC;gBAAE;gBAC/B;oBAAEF,SAASG,iCAAY;oBAAED,UAAU,CAAC;gBAAE;gBACtC;oBAAEF,SAASI,iDAAoB;oBAAEF,UAAU,CAAC;gBAAE;aAC/C;QACH,GAAGG,OAAO;QAEVX,UAAUE,OAAOU,GAAG,CAAgBd,qCAAa;IACnD;IAEAe,GAAG,qBAAqB;QACtBC,OAAOd,SAASe,WAAW;IAC7B;AACF"}
@@ -0,0 +1,68 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ function _export(target, all) {
10
+ for(var name in all)Object.defineProperty(target, name, {
11
+ enumerable: true,
12
+ get: Object.getOwnPropertyDescriptor(all, name).get
13
+ });
14
+ }
15
+ _export(exports, {
16
+ get decryptSecret () {
17
+ return decryptSecret;
18
+ },
19
+ get encryptSecret () {
20
+ return encryptSecret;
21
+ }
22
+ });
23
+ const _crypto = /*#__PURE__*/ _interop_require_default(require("crypto"));
24
+ function _interop_require_default(obj) {
25
+ return obj && obj.__esModule ? obj : {
26
+ default: obj
27
+ };
28
+ }
29
+ function encryptSecret(plaintext, passphrase) {
30
+ const salt = _crypto.default.randomBytes(16) // for key derivation (scrypt)
31
+ ;
32
+ const iv = _crypto.default.randomBytes(12) // recommended IV length for GCM
33
+ ;
34
+ const key = _crypto.default.scryptSync(passphrase, salt, 32);
35
+ const cipher = _crypto.default.createCipheriv('aes-256-gcm', key, iv);
36
+ const ciphertext = Buffer.concat([
37
+ cipher.update(plaintext, 'utf8'),
38
+ cipher.final()
39
+ ]);
40
+ const tag = cipher.getAuthTag();
41
+ // Encode everything in base64 and concatenate: salt.iv.tag.cipher
42
+ return [
43
+ salt.toString('base64'),
44
+ iv.toString('base64'),
45
+ tag.toString('base64'),
46
+ ciphertext.toString('base64')
47
+ ].join('.');
48
+ }
49
+ function decryptSecret(payload, passphrase) {
50
+ const [saltB64, ivB64, tagB64, ctB64] = payload.split('.');
51
+ if (!saltB64 || !ivB64 || !tagB64 || !ctB64) {
52
+ throw new Error('Invalid payload format');
53
+ }
54
+ const salt = Buffer.from(saltB64, 'base64');
55
+ const iv = Buffer.from(ivB64, 'base64');
56
+ const tag = Buffer.from(tagB64, 'base64');
57
+ const ct = Buffer.from(ctB64, 'base64');
58
+ const key = _crypto.default.scryptSync(passphrase, salt, 32);
59
+ const decipher = _crypto.default.createDecipheriv('aes-256-gcm', key, iv);
60
+ decipher.setAuthTag(tag);
61
+ const plaintext = Buffer.concat([
62
+ decipher.update(ct),
63
+ decipher.final()
64
+ ]);
65
+ return plaintext.toString('utf8');
66
+ }
67
+
68
+ //# sourceMappingURL=crypt-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../backend/src/authentication/utils/crypt-secret.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 crypto from 'crypto'\n\n// Encrypt a plaintext string with a passphrase. Returns a compact string.\nexport function encryptSecret(plaintext: string, passphrase: string) {\n const salt = crypto.randomBytes(16) // for key derivation (scrypt)\n const iv = crypto.randomBytes(12) // recommended IV length for GCM\n const key = crypto.scryptSync(passphrase, salt, 32)\n\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])\n const tag = cipher.getAuthTag()\n\n // Encode everything in base64 and concatenate: salt.iv.tag.cipher\n return [salt.toString('base64'), iv.toString('base64'), tag.toString('base64'), ciphertext.toString('base64')].join('.')\n}\n\n// Decrypt the string generated by encryptSecret with the same passphrase.\nexport function decryptSecret(payload: string, passphrase: string) {\n const [saltB64, ivB64, tagB64, ctB64] = payload.split('.')\n if (!saltB64 || !ivB64 || !tagB64 || !ctB64) {\n throw new Error('Invalid payload format')\n }\n\n const salt = Buffer.from(saltB64, 'base64')\n const iv = Buffer.from(ivB64, 'base64')\n const tag = Buffer.from(tagB64, 'base64')\n const ct = Buffer.from(ctB64, 'base64')\n\n const key = crypto.scryptSync(passphrase, salt, 32)\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)\n decipher.setAuthTag(tag)\n\n const plaintext = Buffer.concat([decipher.update(ct), decipher.final()])\n return plaintext.toString('utf8')\n}\n"],"names":["decryptSecret","encryptSecret","plaintext","passphrase","salt","crypto","randomBytes","iv","key","scryptSync","cipher","createCipheriv","ciphertext","Buffer","concat","update","final","tag","getAuthTag","toString","join","payload","saltB64","ivB64","tagB64","ctB64","split","Error","from","ct","decipher","createDecipheriv","setAuthTag"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAmBeA;eAAAA;;QAdAC;eAAAA;;;+DAHG;;;;;;AAGZ,SAASA,cAAcC,SAAiB,EAAEC,UAAkB;IACjE,MAAMC,OAAOC,eAAM,CAACC,WAAW,CAAC,IAAI,8BAA8B;;IAClE,MAAMC,KAAKF,eAAM,CAACC,WAAW,CAAC,IAAI,gCAAgC;;IAClE,MAAME,MAAMH,eAAM,CAACI,UAAU,CAACN,YAAYC,MAAM;IAEhD,MAAMM,SAASL,eAAM,CAACM,cAAc,CAAC,eAAeH,KAAKD;IACzD,MAAMK,aAAaC,OAAOC,MAAM,CAAC;QAACJ,OAAOK,MAAM,CAACb,WAAW;QAASQ,OAAOM,KAAK;KAAG;IACnF,MAAMC,MAAMP,OAAOQ,UAAU;IAE7B,kEAAkE;IAClE,OAAO;QAACd,KAAKe,QAAQ,CAAC;QAAWZ,GAAGY,QAAQ,CAAC;QAAWF,IAAIE,QAAQ,CAAC;QAAWP,WAAWO,QAAQ,CAAC;KAAU,CAACC,IAAI,CAAC;AACtH;AAGO,SAASpB,cAAcqB,OAAe,EAAElB,UAAkB;IAC/D,MAAM,CAACmB,SAASC,OAAOC,QAAQC,MAAM,GAAGJ,QAAQK,KAAK,CAAC;IACtD,IAAI,CAACJ,WAAW,CAACC,SAAS,CAACC,UAAU,CAACC,OAAO;QAC3C,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAMvB,OAAOS,OAAOe,IAAI,CAACN,SAAS;IAClC,MAAMf,KAAKM,OAAOe,IAAI,CAACL,OAAO;IAC9B,MAAMN,MAAMJ,OAAOe,IAAI,CAACJ,QAAQ;IAChC,MAAMK,KAAKhB,OAAOe,IAAI,CAACH,OAAO;IAE9B,MAAMjB,MAAMH,eAAM,CAACI,UAAU,CAACN,YAAYC,MAAM;IAChD,MAAM0B,WAAWzB,eAAM,CAAC0B,gBAAgB,CAAC,eAAevB,KAAKD;IAC7DuB,SAASE,UAAU,CAACf;IAEpB,MAAMf,YAAYW,OAAOC,MAAM,CAAC;QAACgB,SAASf,MAAM,CAACc;QAAKC,SAASd,KAAK;KAAG;IACvE,OAAOd,UAAUiB,QAAQ,CAAC;AAC5B"}
@@ -188,19 +188,34 @@ async function hashPassword(password) {
188
188
  async function comparePassword(password, hash) {
189
189
  return await _bcryptjs.default.compare(password, hash);
190
190
  }
191
- function generateShortUUID(length = 16) {
192
- return _nodecrypto.default.randomBytes(length).toString('base64url');
191
+ function generateShortUUID(length = 32, encoding = 'base64url') {
192
+ const bytes = Math.ceil(length * 3 / 4) // adapt to real length
193
+ ;
194
+ return _nodecrypto.default.randomBytes(bytes).toString(encoding);
193
195
  }
194
196
  function anonymizePassword(obj) {
195
197
  return {
196
198
  ...obj,
197
199
  ...obj?.password && {
198
200
  password: '********'
201
+ },
202
+ ...obj?.secrets && {
203
+ secrets: '********'
199
204
  }
200
205
  };
201
206
  }
202
207
  function splitFullName(fullName) {
208
+ if (!fullName || !fullName.trim()) return {
209
+ firstName: '',
210
+ lastName: ''
211
+ };
203
212
  const parts = fullName.trim().split(/\s+/);
213
+ if (parts.length === 1) {
214
+ return {
215
+ firstName: '',
216
+ lastName: parts[0]
217
+ };
218
+ }
204
219
  const lastName = parts.pop();
205
220
  const firstName = parts.join(' ');
206
221
  return {
@@ -209,6 +224,7 @@ function splitFullName(fullName) {
209
224
  };
210
225
  }
211
226
  function transformAndValidate(schema, object, transformOptions = {}, validatorOptions = {}) {
227
+ // warning: plainToInstance do not use constructor to instantiate class
212
228
  const instance = (0, _classtransformer.plainToInstance)(schema, object, transformOptions);
213
229
  const errors = (0, _classvalidator.validateSync)(instance, validatorOptions);
214
230
  if (errors.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/common/functions.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 { parse as parseMs } from '@lukeed/ms'\nimport bcrypt from 'bcryptjs'\nimport { ClassTransformOptions, plainToInstance } from 'class-transformer'\nimport { validateSync } from 'class-validator'\nimport { ValidationError } from 'class-validator/types/validation/ValidationError'\nimport { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions'\nimport crypto from 'node:crypto'\nimport { setTimeout } from 'node:timers/promises'\nimport { SPACE_PERMS_SEP } from '../applications/spaces/constants/spaces'\n\nexport const regexpEscape = /[.*+?^${}()|[\\]\\\\]/g\nexport const regexSpecialChars = /[-[\\]{}()*+!<=:?./\\\\^$|#,]/g\nexport const regexSpecialCharsWithSpace = /[-[\\]{}()*+!<=:?./\\\\^$|#\\s,]/g\n\nexport async function loadOptionalModule(moduleName: string): Promise<any> {\n return await import(moduleName)\n}\n\nexport async function sleep(ms: number): Promise<void> {\n await setTimeout(ms)\n}\n\nexport function escapeSQLRegexp(input: string): string {\n return input.replace(regexSpecialCharsWithSpace, '\\\\\\\\$&').replaceAll(\"'\", \"''\")\n}\n\nexport function escapeString(input: string): string {\n return input.replace(regexSpecialChars, '\\\\$&')\n}\n\nexport function escapePath(path: string): string {\n return path.replace(regexpEscape, '\\\\$&')\n}\n\nexport function regExpPathPattern(path: string): RegExp {\n return new RegExp(`^${escapePath(path)}[/\\\\\\\\]`)\n}\n\nexport function convertHumanTimeToSeconds(value: string): number {\n return parseMs(value) / 1000\n}\n\nexport function convertHumanTimeToMs(value: string): number {\n return parseMs(value)\n}\n\nexport function formatDateISOString(date: Date): string {\n return date.toISOString().replaceAll('-', '.').replaceAll(':', '-').replace('T', ' ').replace('Z', '')\n}\n\nexport function urlToPath(url: string): string {\n // transform https://sync-in.com/webdav/ to /webdav/\n try {\n // transform https://sync-in.com/webdav/ to /webdav/\n return new URL(url).pathname\n } catch {\n // or allows uri like : /webdav/\n return url\n }\n}\n\nexport async function hashPassword(password: string): Promise<string> {\n return await bcrypt.hash(password, 10)\n}\n\nexport async function comparePassword(password: string, hash: string): Promise<boolean> {\n return await bcrypt.compare(password, hash)\n}\n\nexport function generateShortUUID(length: number = 16): string {\n return crypto.randomBytes(length).toString('base64url')\n}\n\nexport function anonymizePassword(obj: { password?: string }) {\n return { ...obj, ...(obj?.password && { password: '********' }) }\n}\n\nexport function splitFullName(fullName: string): { firstName: string; lastName: string } {\n const parts = fullName.trim().split(/\\s+/)\n const lastName = parts.pop()\n const firstName = parts.join(' ')\n return { firstName, lastName }\n}\n\nexport function transformAndValidate<T extends object>(\n schema: new () => T,\n object: any,\n transformOptions: ClassTransformOptions = {},\n validatorOptions: ValidatorOptions = {}\n): T {\n const instance: T = plainToInstance(schema, object, transformOptions)\n const errors: ValidationError[] = validateSync(instance, validatorOptions)\n if (errors.length > 0) {\n throw new Error(errors.toString())\n }\n return instance\n}\n\nexport function uniquePermissions(permissions: string, permissionsSeparator: string = SPACE_PERMS_SEP) {\n /*\n Returns unique permissions : 'c:r:w:c:r' -> 'c:r:w'\n */\n if (permissions.length === 0) return permissions\n return [\n ...new Set(\n permissions\n .split(permissionsSeparator)\n .filter((p: string) => p && p !== 'null')\n .sort()\n )\n ].join(permissionsSeparator)\n}\n\nexport function intersectPermissions(aPermissions: string, bPermissions: string, permissionsSeparator: string = SPACE_PERMS_SEP): string {\n const aPerms = aPermissions.split(permissionsSeparator)\n const bPerms = bPermissions.split(permissionsSeparator)\n return aPerms\n .filter((p: string) => p !== '' && p !== 'null' && bPerms.indexOf(p) > -1)\n .sort()\n .join(permissionsSeparator)\n}\n\nexport function differencePermissions(aPermissions: string, bPermissions: string, permissionsSeparator: string = SPACE_PERMS_SEP): string[] {\n const aPerms = aPermissions.split(permissionsSeparator)\n const bPerms = bPermissions.split(permissionsSeparator)\n return aPerms.filter((p: string) => p !== '' && bPerms.indexOf(p) === -1).sort()\n}\n\nexport function sortObjByName(a: { name: string }, b: { name: string }, asc = false): 0 | 1 | -1 {\n const aN = a.name.toLowerCase()\n const bN = b.name.toLowerCase()\n if (asc) {\n return aN < bN ? 1 : aN > bN ? -1 : 0\n } else {\n return aN < bN ? -1 : aN > bN ? 1 : 0\n }\n}\n\nfunction diffProperties(a: any, b: any, props: string[]): boolean {\n for (const p of props) {\n if (a[p] !== b[p]) {\n return false\n }\n }\n return true\n}\n\nexport function diffCollection<T>(\n curCollection: T[],\n newCollection: T[],\n updateProps: string[],\n compareProps: string[] = ['id']\n): [T[], Record<string | 'object', { old: any; new: any } | T>[], T[]] {\n const toAdd: T[] = []\n const toUpdate: Record<string | 'object', { old: any; new: any } | T>[] = []\n const toRemove: T[] = curCollection.filter((c: T) => !newCollection.find((n: T) => diffProperties(c, n, compareProps)))\n for (const n of newCollection) {\n const o = curCollection.find((c: T) => diffProperties(c, n, compareProps))\n if (o) {\n const diff: Record<string | 'object', { old: any; new: any } | T> = {}\n for (const p of updateProps.filter((p: string) => n[p] !== o[p])) {\n diff[p] = { old: o[p], new: n[p] }\n }\n if (Object.keys(diff).length) {\n diff['object'] = n\n toUpdate.push(diff)\n }\n } else {\n toAdd.push(n)\n }\n }\n return [toAdd, toUpdate, toRemove]\n}\n\nexport function convertDiffUpdate(update: Record<string | 'object', { old: any; new: any } | any>[]): Record<string | 'object', any>[] {\n // only keep the new values\n return update.map((o) => Object.fromEntries(Object.entries(o).map(([p, v]) => [p, p === 'object' ? v : v.new])))\n}\n"],"names":["anonymizePassword","comparePassword","convertDiffUpdate","convertHumanTimeToMs","convertHumanTimeToSeconds","diffCollection","differencePermissions","escapePath","escapeSQLRegexp","escapeString","formatDateISOString","generateShortUUID","hashPassword","intersectPermissions","loadOptionalModule","regExpPathPattern","regexSpecialChars","regexSpecialCharsWithSpace","regexpEscape","sleep","sortObjByName","splitFullName","transformAndValidate","uniquePermissions","urlToPath","moduleName","ms","setTimeout","input","replace","replaceAll","path","RegExp","value","parseMs","date","toISOString","url","URL","pathname","password","bcrypt","hash","compare","length","crypto","randomBytes","toString","obj","fullName","parts","trim","split","lastName","pop","firstName","join","schema","object","transformOptions","validatorOptions","instance","plainToInstance","errors","validateSync","Error","permissions","permissionsSeparator","SPACE_PERMS_SEP","Set","filter","p","sort","aPermissions","bPermissions","aPerms","bPerms","indexOf","a","b","asc","aN","name","toLowerCase","bN","diffProperties","props","curCollection","newCollection","updateProps","compareProps","toAdd","toUpdate","toRemove","c","find","n","o","diff","old","new","Object","keys","push","update","map","fromEntries","entries","v"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../backend/src/common/functions.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 { parse as parseMs } from '@lukeed/ms'\nimport bcrypt from 'bcryptjs'\nimport { ClassTransformOptions, plainToInstance } from 'class-transformer'\nimport { validateSync } from 'class-validator'\nimport { ValidationError } from 'class-validator/types/validation/ValidationError'\nimport { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions'\nimport crypto from 'node:crypto'\nimport { setTimeout } from 'node:timers/promises'\nimport { SPACE_PERMS_SEP } from '../applications/spaces/constants/spaces'\n\nexport const regexpEscape = /[.*+?^${}()|[\\]\\\\]/g\nexport const regexSpecialChars = /[-[\\]{}()*+!<=:?./\\\\^$|#,]/g\nexport const regexSpecialCharsWithSpace = /[-[\\]{}()*+!<=:?./\\\\^$|#\\s,]/g\n\nexport async function loadOptionalModule(moduleName: string): Promise<any> {\n return await import(moduleName)\n}\n\nexport async function sleep(ms: number): Promise<void> {\n await setTimeout(ms)\n}\n\nexport function escapeSQLRegexp(input: string): string {\n return input.replace(regexSpecialCharsWithSpace, '\\\\\\\\$&').replaceAll(\"'\", \"''\")\n}\n\nexport function escapeString(input: string): string {\n return input.replace(regexSpecialChars, '\\\\$&')\n}\n\nexport function escapePath(path: string): string {\n return path.replace(regexpEscape, '\\\\$&')\n}\n\nexport function regExpPathPattern(path: string): RegExp {\n return new RegExp(`^${escapePath(path)}[/\\\\\\\\]`)\n}\n\nexport function convertHumanTimeToSeconds(value: string): number {\n return parseMs(value) / 1000\n}\n\nexport function convertHumanTimeToMs(value: string): number {\n return parseMs(value)\n}\n\nexport function formatDateISOString(date: Date): string {\n return date.toISOString().replaceAll('-', '.').replaceAll(':', '-').replace('T', ' ').replace('Z', '')\n}\n\nexport function urlToPath(url: string): string {\n // transform https://sync-in.com/webdav/ to /webdav/\n try {\n // transform https://sync-in.com/webdav/ to /webdav/\n return new URL(url).pathname\n } catch {\n // or allows uri like : /webdav/\n return url\n }\n}\n\nexport async function hashPassword(password: string): Promise<string> {\n return await bcrypt.hash(password, 10)\n}\n\nexport async function comparePassword(password: string, hash: string): Promise<boolean> {\n return await bcrypt.compare(password, hash)\n}\n\nexport function generateShortUUID(length: number = 32, encoding: BufferEncoding = 'base64url'): string {\n const bytes = Math.ceil((length * 3) / 4) // adapt to real length\n return crypto.randomBytes(bytes).toString(encoding)\n}\n\nexport function anonymizePassword(obj: { password?: string; secrets?: string }) {\n return { ...obj, ...(obj?.password && { password: '********' }), ...(obj?.secrets && { secrets: '********' }) }\n}\n\nexport function splitFullName(fullName?: string): { firstName: string; lastName: string } {\n if (!fullName || !fullName.trim()) return { firstName: '', lastName: '' }\n const parts = fullName.trim().split(/\\s+/)\n if (parts.length === 1) {\n return { firstName: '', lastName: parts[0] }\n }\n const lastName = parts.pop()!\n const firstName = parts.join(' ')\n return { firstName, lastName }\n}\n\nexport function transformAndValidate<T extends object>(\n schema: new () => T,\n object: any,\n transformOptions: ClassTransformOptions = {},\n validatorOptions: ValidatorOptions = {}\n): T {\n // warning: plainToInstance do not use constructor to instantiate class\n const instance: T = plainToInstance(schema, object, transformOptions)\n const errors: ValidationError[] = validateSync(instance, validatorOptions)\n if (errors.length > 0) {\n throw new Error(errors.toString())\n }\n return instance\n}\n\nexport function uniquePermissions(permissions: string, permissionsSeparator: string = SPACE_PERMS_SEP) {\n /*\n Returns unique permissions : 'c:r:w:c:r' -> 'c:r:w'\n */\n if (permissions.length === 0) return permissions\n return [\n ...new Set(\n permissions\n .split(permissionsSeparator)\n .filter((p: string) => p && p !== 'null')\n .sort()\n )\n ].join(permissionsSeparator)\n}\n\nexport function intersectPermissions(aPermissions: string, bPermissions: string, permissionsSeparator: string = SPACE_PERMS_SEP): string {\n const aPerms = aPermissions.split(permissionsSeparator)\n const bPerms = bPermissions.split(permissionsSeparator)\n return aPerms\n .filter((p: string) => p !== '' && p !== 'null' && bPerms.indexOf(p) > -1)\n .sort()\n .join(permissionsSeparator)\n}\n\nexport function differencePermissions(aPermissions: string, bPermissions: string, permissionsSeparator: string = SPACE_PERMS_SEP): string[] {\n const aPerms = aPermissions.split(permissionsSeparator)\n const bPerms = bPermissions.split(permissionsSeparator)\n return aPerms.filter((p: string) => p !== '' && bPerms.indexOf(p) === -1).sort()\n}\n\nexport function sortObjByName(a: { name: string }, b: { name: string }, asc = false): 0 | 1 | -1 {\n const aN = a.name.toLowerCase()\n const bN = b.name.toLowerCase()\n if (asc) {\n return aN < bN ? 1 : aN > bN ? -1 : 0\n } else {\n return aN < bN ? -1 : aN > bN ? 1 : 0\n }\n}\n\nfunction diffProperties(a: any, b: any, props: string[]): boolean {\n for (const p of props) {\n if (a[p] !== b[p]) {\n return false\n }\n }\n return true\n}\n\nexport function diffCollection<T>(\n curCollection: T[],\n newCollection: T[],\n updateProps: string[],\n compareProps: string[] = ['id']\n): [T[], Record<string | 'object', { old: any; new: any } | T>[], T[]] {\n const toAdd: T[] = []\n const toUpdate: Record<string | 'object', { old: any; new: any } | T>[] = []\n const toRemove: T[] = curCollection.filter((c: T) => !newCollection.find((n: T) => diffProperties(c, n, compareProps)))\n for (const n of newCollection) {\n const o = curCollection.find((c: T) => diffProperties(c, n, compareProps))\n if (o) {\n const diff: Record<string | 'object', { old: any; new: any } | T> = {}\n for (const p of updateProps.filter((p: string) => n[p] !== o[p])) {\n diff[p] = { old: o[p], new: n[p] }\n }\n if (Object.keys(diff).length) {\n diff['object'] = n\n toUpdate.push(diff)\n }\n } else {\n toAdd.push(n)\n }\n }\n return [toAdd, toUpdate, toRemove]\n}\n\nexport function convertDiffUpdate(update: Record<string | 'object', { old: any; new: any } | any>[]): Record<string | 'object', any>[] {\n // only keep the new values\n return update.map((o) => Object.fromEntries(Object.entries(o).map(([p, v]) => [p, p === 'object' ? v : v.new])))\n}\n"],"names":["anonymizePassword","comparePassword","convertDiffUpdate","convertHumanTimeToMs","convertHumanTimeToSeconds","diffCollection","differencePermissions","escapePath","escapeSQLRegexp","escapeString","formatDateISOString","generateShortUUID","hashPassword","intersectPermissions","loadOptionalModule","regExpPathPattern","regexSpecialChars","regexSpecialCharsWithSpace","regexpEscape","sleep","sortObjByName","splitFullName","transformAndValidate","uniquePermissions","urlToPath","moduleName","ms","setTimeout","input","replace","replaceAll","path","RegExp","value","parseMs","date","toISOString","url","URL","pathname","password","bcrypt","hash","compare","length","encoding","bytes","Math","ceil","crypto","randomBytes","toString","obj","secrets","fullName","trim","firstName","lastName","parts","split","pop","join","schema","object","transformOptions","validatorOptions","instance","plainToInstance","errors","validateSync","Error","permissions","permissionsSeparator","SPACE_PERMS_SEP","Set","filter","p","sort","aPermissions","bPermissions","aPerms","bPerms","indexOf","a","b","asc","aN","name","toLowerCase","bN","diffProperties","props","curCollection","newCollection","updateProps","compareProps","toAdd","toUpdate","toRemove","c","find","n","o","diff","old","new","Object","keys","push","update","map","fromEntries","entries","v"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "qrcodeToDataURL", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return qrcodeToDataURL;
13
+ }
14
+ });
15
+ const _qrcodegenerator = /*#__PURE__*/ _interop_require_default(require("qrcode-generator"));
16
+ function _interop_require_default(obj) {
17
+ return obj && obj.__esModule ? obj : {
18
+ default: obj
19
+ };
20
+ }
21
+ function qrcodeToDataURL(text) {
22
+ const qr = (0, _qrcodegenerator.default)(0, 'M') // version auto, correction M
23
+ ;
24
+ qr.addData(text);
25
+ qr.make();
26
+ const svg = qr.createSvgTag({
27
+ margin: 2,
28
+ scalable: true
29
+ });
30
+ const base64 = Buffer.from(svg).toString('base64');
31
+ return `data:image/svg+xml;base64,${base64}`;
32
+ }
33
+
34
+ //# sourceMappingURL=qrcode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../backend/src/common/qrcode.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 qrcode from 'qrcode-generator'\n\nexport function qrcodeToDataURL(text: string) {\n const qr = qrcode(0, 'M') // version auto, correction M\n qr.addData(text)\n qr.make()\n\n const svg = qr.createSvgTag({ margin: 2, scalable: true })\n\n const base64 = Buffer.from(svg).toString('base64')\n return `data:image/svg+xml;base64,${base64}`\n}\n"],"names":["qrcodeToDataURL","text","qr","qrcode","addData","make","svg","createSvgTag","margin","scalable","base64","Buffer","from","toString"],"mappings":"AAAA;;;;CAIC;;;;+BAIeA;;;eAAAA;;;wEAFG;;;;;;AAEZ,SAASA,gBAAgBC,IAAY;IAC1C,MAAMC,KAAKC,IAAAA,wBAAM,EAAC,GAAG,KAAK,6BAA6B;;IACvDD,GAAGE,OAAO,CAACH;IACXC,GAAGG,IAAI;IAEP,MAAMC,MAAMJ,GAAGK,YAAY,CAAC;QAAEC,QAAQ;QAAGC,UAAU;IAAK;IAExD,MAAMC,SAASC,OAAOC,IAAI,CAACN,KAAKO,QAAQ,CAAC;IACzC,OAAO,CAAC,0BAA0B,EAAEH,QAAQ;AAC9C"}
@@ -17,6 +17,9 @@ _export(exports, {
17
17
  get capitalizeString () {
18
18
  return capitalizeString;
19
19
  },
20
+ get createLightSlug () {
21
+ return createLightSlug;
22
+ },
20
23
  get createSlug () {
21
24
  return createSlug;
22
25
  },
@@ -35,6 +38,9 @@ _export(exports, {
35
38
  get forbiddenChars () {
36
39
  return forbiddenChars;
37
40
  },
41
+ get genPassword () {
42
+ return genPassword;
43
+ },
38
44
  get isValidFileName () {
39
45
  return isValidFileName;
40
46
  },
@@ -74,6 +80,18 @@ function createSlug(input, replaceCount = false) {
74
80
  if (replaceCount) return r.replace(regExpNumberSuffix, '');
75
81
  return r;
76
82
  }
83
+ function createLightSlug(input) {
84
+ return input.toLowerCase().trim().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
85
+ }
86
+ function genPassword(length = 12) {
87
+ const chars = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ';
88
+ let password = '';
89
+ for(let i = 0; i <= length; i++){
90
+ const randomNumber = Math.floor(Math.random() * chars.length);
91
+ password += chars.substring(randomNumber, randomNumber + 1);
92
+ }
93
+ return password;
94
+ }
77
95
  function popFromObject(key, object) {
78
96
  const item = object[key];
79
97
  delete object[key];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../backend/src/common/shared.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\n// eslint-disable-next-line no-control-regex\nexport const regExpInvalidFileName = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:\"/\\\\|?*\\x00-\\x1f\\x80-\\x9f]/\nexport const regExpPreventPathTraversal = /^(\\.\\.(\\/|\\\\|$))+/\nexport const regExpNumberSuffix = /-\\d+$/\nexport const forbiddenChars = '\\\\ / : * ? \" < > |'\n\nexport function isValidFileName(fileName: string) {\n if (regExpInvalidFileName.test(fileName)) {\n throw new Error('Forbidden characters')\n }\n}\n\nexport function currentTimeStamp(date?: Date, ms = false): number {\n return Math.floor((date ? date : new Date()).getTime() / (ms ? 1 : 1000))\n}\n\nexport function currentDate(value?: string): Date {\n return new Date((value ? value : new Date().toISOString()).split('T')[0])\n}\n\nexport function createSlug(input: string, replaceCount = false): string {\n const r = input\n .toLowerCase()\n .trim()\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n if (replaceCount) return r.replace(regExpNumberSuffix, '')\n return r\n}\n\nexport function popFromObject(key: string, object: any): any {\n const item = object[key]\n delete object[key]\n return item\n}\n\nexport function encodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => encodeURIComponent(e))\n .join('/')\n}\n\nexport function decodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => decodeURIComponent(e))\n .join('/')\n}\n\nexport function objectPropertyFromString(obj: any, property: string): any {\n const a = property.split('.')\n let o = obj\n for (let i = 0, n = a.length; i < n; i++) {\n const k = a[i]\n if (k in o) {\n o = o[k]\n } else {\n return null\n }\n }\n return o\n}\n\nexport function capitalizeString(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n"],"names":["capitalizeString","createSlug","currentDate","currentTimeStamp","decodeUrl","encodeUrl","forbiddenChars","isValidFileName","objectPropertyFromString","popFromObject","regExpInvalidFileName","regExpNumberSuffix","regExpPreventPathTraversal","fileName","test","Error","date","ms","Math","floor","Date","getTime","value","toISOString","split","input","replaceCount","r","toLowerCase","trim","replace","normalize","key","object","item","url","map","e","encodeURIComponent","join","decodeURIComponent","obj","property","a","o","i","n","length","k","charAt","toUpperCase","slice"],"mappings":"AAAA;;;;CAIC,GAED,4CAA4C;;;;;;;;;;;;QAkE5BA;eAAAA;;QA9CAC;eAAAA;;QAJAC;eAAAA;;QAJAC;eAAAA;;QAiCAC;eAAAA;;QAPAC;eAAAA;;QAlCHC;eAAAA;;QAEGC;eAAAA;;QA8CAC;eAAAA;;QApBAC;eAAAA;;QA/BHC;eAAAA;;QAEAC;eAAAA;;QADAC;eAAAA;;;AADN,MAAMF,wBAAwB;AAC9B,MAAME,6BAA6B;AACnC,MAAMD,qBAAqB;AAC3B,MAAML,iBAAiB;AAEvB,SAASC,gBAAgBM,QAAgB;IAC9C,IAAIH,sBAAsBI,IAAI,CAACD,WAAW;QACxC,MAAM,IAAIE,MAAM;IAClB;AACF;AAEO,SAASZ,iBAAiBa,IAAW,EAAEC,KAAK,KAAK;IACtD,OAAOC,KAAKC,KAAK,CAAC,AAACH,CAAAA,OAAOA,OAAO,IAAII,MAAK,EAAGC,OAAO,KAAMJ,CAAAA,KAAK,IAAI,IAAG;AACxE;AAEO,SAASf,YAAYoB,KAAc;IACxC,OAAO,IAAIF,KAAK,AAACE,CAAAA,QAAQA,QAAQ,IAAIF,OAAOG,WAAW,EAAC,EAAGC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC1E;AAEO,SAASvB,WAAWwB,KAAa,EAAEC,eAAe,KAAK;IAC5D,MAAMC,IAAIF,MACPG,WAAW,GACXC,IAAI,GACJC,OAAO,CAAC,YAAY,KACpBA,OAAO,CAAC,YAAY,IACpBC,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;IAC/B,IAAIJ,cAAc,OAAOC,EAAEG,OAAO,CAACnB,oBAAoB;IACvD,OAAOgB;AACT;AAEO,SAASlB,cAAcuB,GAAW,EAAEC,MAAW;IACpD,MAAMC,OAAOD,MAAM,CAACD,IAAI;IACxB,OAAOC,MAAM,CAACD,IAAI;IAClB,OAAOE;AACT;AAEO,SAAS7B,UAAU8B,GAAW;IACnC,OAAOA,IACJX,KAAK,CAAC,KACNY,GAAG,CAAC,CAACC,IAAMC,mBAAmBD,IAC9BE,IAAI,CAAC;AACV;AAEO,SAASnC,UAAU+B,GAAW;IACnC,OAAOA,IACJX,KAAK,CAAC,KACNY,GAAG,CAAC,CAACC,IAAMG,mBAAmBH,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAS/B,yBAAyBiC,GAAQ,EAAEC,QAAgB;IACjE,MAAMC,IAAID,SAASlB,KAAK,CAAC;IACzB,IAAIoB,IAAIH;IACR,IAAK,IAAII,IAAI,GAAGC,IAAIH,EAAEI,MAAM,EAAEF,IAAIC,GAAGD,IAAK;QACxC,MAAMG,IAAIL,CAAC,CAACE,EAAE;QACd,IAAIG,KAAKJ,GAAG;YACVA,IAAIA,CAAC,CAACI,EAAE;QACV,OAAO;YACL,OAAO;QACT;IACF;IACA,OAAOJ;AACT;AAEO,SAAS5C,iBAAiBsB,KAAa;IAC5C,OAAOA,MAAM2B,MAAM,CAAC,GAAGC,WAAW,KAAK5B,MAAM6B,KAAK,CAAC;AACrD"}
1
+ {"version":3,"sources":["../../../backend/src/common/shared.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\n// eslint-disable-next-line no-control-regex\nexport const regExpInvalidFileName = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$|[<>:\"/\\\\|?*\\x00-\\x1f\\x80-\\x9f]/\nexport const regExpPreventPathTraversal = /^(\\.\\.(\\/|\\\\|$))+/\nexport const regExpNumberSuffix = /-\\d+$/\nexport const forbiddenChars = '\\\\ / : * ? \" < > |'\n\nexport function isValidFileName(fileName: string) {\n if (regExpInvalidFileName.test(fileName)) {\n throw new Error('Forbidden characters')\n }\n}\n\nexport function currentTimeStamp(date?: Date, ms = false): number {\n return Math.floor((date ? date : new Date()).getTime() / (ms ? 1 : 1000))\n}\n\nexport function currentDate(value?: string): Date {\n return new Date((value ? value : new Date().toISOString()).split('T')[0])\n}\n\nexport function createSlug(input: string, replaceCount = false): string {\n const r = input\n .toLowerCase()\n .trim()\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n if (replaceCount) return r.replace(regExpNumberSuffix, '')\n return r\n}\n\nexport function createLightSlug(input: string) {\n return input\n .toLowerCase()\n .trim()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n}\n\nexport function genPassword(length = 12) {\n const chars = '0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n let password = ''\n for (let i = 0; i <= length; i++) {\n const randomNumber = Math.floor(Math.random() * chars.length)\n password += chars.substring(randomNumber, randomNumber + 1)\n }\n return password\n}\n\nexport function popFromObject(key: string, object: any): any {\n const item = object[key]\n delete object[key]\n return item\n}\n\nexport function encodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => encodeURIComponent(e))\n .join('/')\n}\n\nexport function decodeUrl(url: string): string {\n return url\n .split('/')\n .map((e) => decodeURIComponent(e))\n .join('/')\n}\n\nexport function objectPropertyFromString(obj: any, property: string): any {\n const a = property.split('.')\n let o = obj\n for (let i = 0, n = a.length; i < n; i++) {\n const k = a[i]\n if (k in o) {\n o = o[k]\n } else {\n return null\n }\n }\n return o\n}\n\nexport function capitalizeString(value: string): string {\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n"],"names":["capitalizeString","createLightSlug","createSlug","currentDate","currentTimeStamp","decodeUrl","encodeUrl","forbiddenChars","genPassword","isValidFileName","objectPropertyFromString","popFromObject","regExpInvalidFileName","regExpNumberSuffix","regExpPreventPathTraversal","fileName","test","Error","date","ms","Math","floor","Date","getTime","value","toISOString","split","input","replaceCount","r","toLowerCase","trim","replace","normalize","length","chars","password","i","randomNumber","random","substring","key","object","item","url","map","e","encodeURIComponent","join","decodeURIComponent","obj","property","a","o","n","k","charAt","toUpperCase","slice"],"mappings":"AAAA;;;;CAIC,GAED,4CAA4C;;;;;;;;;;;;QAoF5BA;eAAAA;;QApDAC;eAAAA;;QAZAC;eAAAA;;QAJAC;eAAAA;;QAJAC;eAAAA;;QAmDAC;eAAAA;;QAPAC;eAAAA;;QApDHC;eAAAA;;QAoCGC;eAAAA;;QAlCAC;eAAAA;;QAgEAC;eAAAA;;QApBAC;eAAAA;;QAjDHC;eAAAA;;QAEAC;eAAAA;;QADAC;eAAAA;;;AADN,MAAMF,wBAAwB;AAC9B,MAAME,6BAA6B;AACnC,MAAMD,qBAAqB;AAC3B,MAAMN,iBAAiB;AAEvB,SAASE,gBAAgBM,QAAgB;IAC9C,IAAIH,sBAAsBI,IAAI,CAACD,WAAW;QACxC,MAAM,IAAIE,MAAM;IAClB;AACF;AAEO,SAASb,iBAAiBc,IAAW,EAAEC,KAAK,KAAK;IACtD,OAAOC,KAAKC,KAAK,CAAC,AAACH,CAAAA,OAAOA,OAAO,IAAII,MAAK,EAAGC,OAAO,KAAMJ,CAAAA,KAAK,IAAI,IAAG;AACxE;AAEO,SAAShB,YAAYqB,KAAc;IACxC,OAAO,IAAIF,KAAK,AAACE,CAAAA,QAAQA,QAAQ,IAAIF,OAAOG,WAAW,EAAC,EAAGC,KAAK,CAAC,IAAI,CAAC,EAAE;AAC1E;AAEO,SAASxB,WAAWyB,KAAa,EAAEC,eAAe,KAAK;IAC5D,MAAMC,IAAIF,MACPG,WAAW,GACXC,IAAI,GACJC,OAAO,CAAC,YAAY,KACpBA,OAAO,CAAC,YAAY,IACpBC,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;IAC/B,IAAIJ,cAAc,OAAOC,EAAEG,OAAO,CAACnB,oBAAoB;IACvD,OAAOgB;AACT;AAEO,SAAS5B,gBAAgB0B,KAAa;IAC3C,OAAOA,MACJG,WAAW,GACXC,IAAI,GACJE,SAAS,CAAC,OACVD,OAAO,CAAC,oBAAoB;AACjC;AAEO,SAASxB,YAAY0B,SAAS,EAAE;IACrC,MAAMC,QAAQ;IACd,IAAIC,WAAW;IACf,IAAK,IAAIC,IAAI,GAAGA,KAAKH,QAAQG,IAAK;QAChC,MAAMC,eAAelB,KAAKC,KAAK,CAACD,KAAKmB,MAAM,KAAKJ,MAAMD,MAAM;QAC5DE,YAAYD,MAAMK,SAAS,CAACF,cAAcA,eAAe;IAC3D;IACA,OAAOF;AACT;AAEO,SAASzB,cAAc8B,GAAW,EAAEC,MAAW;IACpD,MAAMC,OAAOD,MAAM,CAACD,IAAI;IACxB,OAAOC,MAAM,CAACD,IAAI;IAClB,OAAOE;AACT;AAEO,SAASrC,UAAUsC,GAAW;IACnC,OAAOA,IACJlB,KAAK,CAAC,KACNmB,GAAG,CAAC,CAACC,IAAMC,mBAAmBD,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAS3C,UAAUuC,GAAW;IACnC,OAAOA,IACJlB,KAAK,CAAC,KACNmB,GAAG,CAAC,CAACC,IAAMG,mBAAmBH,IAC9BE,IAAI,CAAC;AACV;AAEO,SAAStC,yBAAyBwC,GAAQ,EAAEC,QAAgB;IACjE,MAAMC,IAAID,SAASzB,KAAK,CAAC;IACzB,IAAI2B,IAAIH;IACR,IAAK,IAAIb,IAAI,GAAGiB,IAAIF,EAAElB,MAAM,EAAEG,IAAIiB,GAAGjB,IAAK;QACxC,MAAMkB,IAAIH,CAAC,CAACf,EAAE;QACd,IAAIkB,KAAKF,GAAG;YACVA,IAAIA,CAAC,CAACE,EAAE;QACV,OAAO;YACL,OAAO;QACT;IACF;IACA,OAAOF;AACT;AAEO,SAASrD,iBAAiBwB,KAAa;IAC5C,OAAOA,MAAMgC,MAAM,CAAC,GAAGC,WAAW,KAAKjC,MAAMkC,KAAK,CAAC;AACrD"}