@sync-in/server 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (611) hide show
  1. package/CHANGELOG.md +64 -10
  2. package/environment/environment.dist.yaml +29 -26
  3. package/package.json +18 -17
  4. package/server/app.bootstrap.js +4 -2
  5. package/server/app.bootstrap.js.map +1 -1
  6. package/server/app.constants.js +9 -0
  7. package/server/app.constants.js.map +1 -1
  8. package/server/app.module.js +4 -0
  9. package/server/app.module.js.map +1 -1
  10. package/server/applications/admin/admin.module.js +6 -1
  11. package/server/applications/admin/admin.module.js.map +1 -1
  12. package/server/applications/{notifications/interfaces/user-mail-notification.js → admin/interfaces/check-update.interfaces.js} +1 -1
  13. package/server/applications/admin/interfaces/check-update.interfaces.js.map +1 -0
  14. package/server/applications/admin/services/admin-scheduler.service.js +53 -0
  15. package/server/applications/admin/services/admin-scheduler.service.js.map +1 -0
  16. package/server/applications/admin/services/admin.service.js +102 -0
  17. package/server/applications/admin/services/admin.service.js.map +1 -0
  18. package/server/applications/admin/services/admin.service.spec.js +46 -0
  19. package/server/applications/admin/services/admin.service.spec.js.map +1 -0
  20. package/server/applications/admin/utils/check-update.js +28 -0
  21. package/server/applications/admin/utils/check-update.js.map +1 -0
  22. package/server/applications/comments/services/comments-manager.service.js +1 -1
  23. package/server/applications/comments/services/comments-manager.service.js.map +1 -1
  24. package/server/applications/comments/services/comments-manager.service.spec.js +1 -1
  25. package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
  26. package/server/applications/comments/services/comments-queries.service.js.map +1 -1
  27. package/server/applications/files/constants/cache.js +10 -1
  28. package/server/applications/files/constants/cache.js.map +1 -1
  29. package/server/applications/files/constants/only-office.js +0 -25
  30. package/server/applications/files/constants/only-office.js.map +1 -1
  31. package/server/applications/files/constants/operations.js +20 -3
  32. package/server/applications/files/constants/operations.js.map +1 -1
  33. package/server/applications/files/dto/file-operations.dto.js +7 -0
  34. package/server/applications/files/dto/file-operations.dto.js.map +1 -1
  35. package/server/applications/files/files-only-office.controller.js +3 -2
  36. package/server/applications/files/files-only-office.controller.js.map +1 -1
  37. package/server/applications/files/files-only-office.controller.spec.js +6 -5
  38. package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
  39. package/server/applications/files/files.controller.js +100 -12
  40. package/server/applications/files/files.controller.js.map +1 -1
  41. package/server/applications/files/files.controller.spec.js +29 -8
  42. package/server/applications/files/files.controller.spec.js.map +1 -1
  43. package/server/applications/files/guards/files-only-office.guard.js +6 -0
  44. package/server/applications/files/guards/files-only-office.guard.js.map +1 -1
  45. package/server/applications/files/interfaces/file-db-props.interface.js.map +1 -1
  46. package/server/applications/files/interfaces/file-props.interface.js.map +1 -1
  47. package/server/applications/files/interfaces/only-office-config.interface.js.map +1 -1
  48. package/server/applications/files/services/files-content-manager.service.js +3 -3
  49. package/server/applications/files/services/files-content-manager.service.js.map +1 -1
  50. package/server/applications/files/services/files-lock-manager.service.js +61 -22
  51. package/server/applications/files/services/files-lock-manager.service.js.map +1 -1
  52. package/server/applications/files/services/files-manager.service.js +122 -24
  53. package/server/applications/files/services/files-manager.service.js.map +1 -1
  54. package/server/applications/files/services/files-manager.service.spec.js +15 -0
  55. package/server/applications/files/services/files-manager.service.spec.js.map +1 -1
  56. package/server/applications/files/services/files-methods.service.js +39 -14
  57. package/server/applications/files/services/files-methods.service.js.map +1 -1
  58. package/server/applications/files/services/files-only-office-manager.service.js +12 -12
  59. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  60. package/server/applications/files/services/files-parser.service.js +1 -1
  61. package/server/applications/files/services/files-parser.service.js.map +1 -1
  62. package/server/applications/files/services/files-queries.service.js +10 -0
  63. package/server/applications/files/services/files-queries.service.js.map +1 -1
  64. package/server/applications/files/utils/doc-textify/adapters/pdf.js +5 -16
  65. package/server/applications/files/utils/doc-textify/adapters/pdf.js.map +1 -1
  66. package/server/applications/files/utils/files.js +1 -1
  67. package/server/applications/files/utils/files.js.map +1 -1
  68. package/server/applications/files/utils/send-file.js +3 -2
  69. package/server/applications/files/utils/send-file.js.map +1 -1
  70. package/server/applications/links/services/links-queries.service.js +1 -1
  71. package/server/applications/links/services/links-queries.service.js.map +1 -1
  72. package/server/applications/notifications/constants/notifications.js +5 -1
  73. package/server/applications/notifications/constants/notifications.js.map +1 -1
  74. package/server/applications/notifications/i18n/de.js +8 -2
  75. package/server/applications/notifications/i18n/de.js.map +1 -1
  76. package/server/applications/notifications/i18n/es.js +8 -2
  77. package/server/applications/notifications/i18n/es.js.map +1 -1
  78. package/server/applications/notifications/i18n/fr.js +8 -2
  79. package/server/applications/notifications/i18n/fr.js.map +1 -1
  80. package/server/applications/notifications/i18n/hi.js +8 -2
  81. package/server/applications/notifications/i18n/hi.js.map +1 -1
  82. package/server/applications/notifications/i18n/it.js +8 -2
  83. package/server/applications/notifications/i18n/it.js.map +1 -1
  84. package/server/applications/notifications/i18n/ja.js +8 -2
  85. package/server/applications/notifications/i18n/ja.js.map +1 -1
  86. package/server/applications/notifications/i18n/ko.js +8 -2
  87. package/server/applications/notifications/i18n/ko.js.map +1 -1
  88. package/server/applications/notifications/i18n/pl.js +8 -2
  89. package/server/applications/notifications/i18n/pl.js.map +1 -1
  90. package/server/applications/notifications/i18n/pt.js +8 -2
  91. package/server/applications/notifications/i18n/pt.js.map +1 -1
  92. package/server/applications/notifications/i18n/pt_br.js +8 -2
  93. package/server/applications/notifications/i18n/pt_br.js.map +1 -1
  94. package/server/applications/notifications/i18n/ru.js +8 -2
  95. package/server/applications/notifications/i18n/ru.js.map +1 -1
  96. package/server/applications/notifications/i18n/tr.js +8 -2
  97. package/server/applications/notifications/i18n/tr.js.map +1 -1
  98. package/server/applications/notifications/i18n/zh.js +8 -2
  99. package/server/applications/notifications/i18n/zh.js.map +1 -1
  100. package/server/applications/notifications/interfaces/notification-properties.interface.js.map +1 -1
  101. package/server/applications/notifications/interfaces/user-mail-notification.interface.js +10 -0
  102. package/server/applications/notifications/interfaces/user-mail-notification.interface.js.map +1 -0
  103. package/server/applications/notifications/mails/models.js +38 -3
  104. package/server/applications/notifications/mails/models.js.map +1 -1
  105. package/server/applications/notifications/mails/templates.js +1 -1
  106. package/server/applications/notifications/mails/templates.js.map +1 -1
  107. package/server/applications/notifications/services/notifications-manager.service.js +8 -1
  108. package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
  109. package/server/applications/notifications/services/notifications-queries.service.js.map +1 -1
  110. package/server/applications/shares/services/shares-manager.service.js +17 -10
  111. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  112. package/server/applications/shares/services/shares-manager.service.spec.js +10 -3
  113. package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
  114. package/server/applications/shares/services/shares-queries.service.js +11 -1
  115. package/server/applications/shares/services/shares-queries.service.js.map +1 -1
  116. package/server/applications/spaces/guards/space.guard.spec.js +2 -2
  117. package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
  118. package/server/applications/spaces/services/spaces-browser.service.js +31 -11
  119. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  120. package/server/applications/spaces/services/spaces-manager.service.js +2 -2
  121. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  122. package/server/applications/spaces/services/spaces-queries.service.js +6 -2
  123. package/server/applications/spaces/services/spaces-queries.service.js.map +1 -1
  124. package/server/applications/spaces/utils/permissions.js +2 -2
  125. package/server/applications/spaces/utils/permissions.js.map +1 -1
  126. package/server/applications/sync/services/sync-manager.service.js +1 -0
  127. package/server/applications/sync/services/sync-manager.service.js.map +1 -1
  128. package/server/applications/sync/services/sync-paths-manager.service.js +1 -1
  129. package/server/applications/sync/services/sync-paths-manager.service.js.map +1 -1
  130. package/server/applications/sync/services/sync-paths-manager.service.spec.js +1 -1
  131. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  132. package/server/applications/users/constants/user.js +1 -1
  133. package/server/applications/users/constants/user.js.map +1 -1
  134. package/server/applications/users/services/admin-users-queries.service.js +8 -0
  135. package/server/applications/users/services/admin-users-queries.service.js.map +1 -1
  136. package/server/applications/users/services/users-manager.service.js +1 -2
  137. package/server/applications/users/services/users-manager.service.js.map +1 -1
  138. package/server/applications/users/services/users-queries.service.js +67 -68
  139. package/server/applications/users/services/users-queries.service.js.map +1 -1
  140. package/server/applications/users/users.gateway.js +6 -0
  141. package/server/applications/users/users.gateway.js.map +1 -1
  142. package/server/applications/users/users.module.js +2 -1
  143. package/server/applications/users/users.module.js.map +1 -1
  144. package/server/applications/webdav/guards/webdav-protocol.guard.js +4 -4
  145. package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
  146. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +6 -6
  147. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -1
  148. package/server/applications/webdav/services/webdav-methods.service.js +3 -2
  149. package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
  150. package/server/applications/webdav/services/webdav-methods.service.spec.js +2 -2
  151. package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
  152. package/server/authentication/constants/auth-ldap.js +2 -0
  153. package/server/authentication/constants/auth-ldap.js.map +1 -1
  154. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +34 -21
  155. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  156. package/server/common/functions.js +0 -8
  157. package/server/common/functions.js.map +1 -1
  158. package/server/common/image.js +63 -58
  159. package/server/common/image.js.map +1 -1
  160. package/server/common/shared.js +18 -1
  161. package/server/common/shared.js.map +1 -1
  162. package/server/infrastructure/context/services/context-manager.service.js +3 -0
  163. package/server/infrastructure/context/services/context-manager.service.js.map +1 -1
  164. package/server/infrastructure/websocket/adapters/cluster.adapter.js +4 -4
  165. package/server/infrastructure/websocket/adapters/cluster.adapter.js.map +1 -1
  166. package/static/3rdpartylicenses.txt +1380 -57
  167. package/static/assets/favicon.svg +2 -25
  168. package/static/assets/logo-dark.svg +2 -32
  169. package/static/assets/logo.svg +2 -32
  170. package/static/assets/mimes/application-sql.svg +29 -1
  171. package/static/assets/mimes/application-x-sql.svg +29 -0
  172. package/static/assets/mimes/image-bmp.svg +12 -0
  173. package/static/assets/pdfjs/build/pdf.mjs +4869 -4454
  174. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  175. package/static/assets/pdfjs/build/pdf.sandbox.mjs +3 -3
  176. package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
  177. package/static/assets/pdfjs/build/pdf.worker.mjs +885 -596
  178. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  179. package/static/assets/pdfjs/version +1 -1
  180. package/static/assets/pdfjs/web/locale/be/viewer.ftl +40 -0
  181. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +2 -0
  182. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +41 -0
  183. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +43 -0
  184. package/static/assets/pdfjs/web/locale/da/viewer.ftl +39 -0
  185. package/static/assets/pdfjs/web/locale/de/viewer.ftl +41 -0
  186. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +43 -0
  187. package/static/assets/pdfjs/web/locale/el/viewer.ftl +39 -0
  188. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +35 -0
  189. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +41 -0
  190. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +2 -2
  191. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +39 -0
  192. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +41 -0
  193. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +39 -0
  194. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +72 -0
  195. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +120 -0
  196. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +41 -0
  197. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +41 -0
  198. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +41 -0
  199. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +77 -0
  200. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +41 -0
  201. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +39 -0
  202. package/static/assets/pdfjs/web/locale/he/viewer.ftl +41 -0
  203. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +43 -0
  204. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +41 -0
  205. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +1 -1
  206. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +41 -0
  207. package/static/assets/pdfjs/web/locale/it/viewer.ftl +41 -0
  208. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +32 -0
  209. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +41 -0
  210. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +73 -0
  211. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +21 -0
  212. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -1
  213. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +39 -0
  214. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +41 -0
  215. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +37 -0
  216. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +37 -0
  217. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -0
  218. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +39 -0
  219. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +73 -0
  220. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +41 -0
  221. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +42 -0
  222. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +6 -0
  223. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +43 -0
  224. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +42 -1
  225. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +77 -0
  226. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +41 -0
  227. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +39 -0
  228. package/static/assets/pdfjs/web/locale/th/viewer.ftl +35 -0
  229. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +39 -0
  230. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +42 -5
  231. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +35 -0
  232. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +37 -0
  233. package/static/assets/pdfjs/web/viewer.css +141 -110
  234. package/static/assets/pdfjs/web/viewer.html +7 -7
  235. package/static/assets/pdfjs/web/viewer.mjs +97 -14
  236. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  237. package/static/chunk-22DWHRCL.js +1 -0
  238. package/static/chunk-23UUFZSR.js +1 -0
  239. package/static/{chunk-VM4YX6Q7.js → chunk-24Q7OUU2.js} +1 -1
  240. package/static/chunk-25QTY2GI.js +1 -0
  241. package/static/chunk-2E7IJZLL.js +1 -0
  242. package/static/chunk-2FC5EKS5.js +1 -0
  243. package/static/chunk-2FOWUJQF.js +1 -0
  244. package/static/chunk-2XPHUNYN.js +1 -0
  245. package/static/chunk-32L7RG2G.js +1 -0
  246. package/static/chunk-3IISSX63.js +1 -0
  247. package/static/chunk-3OHSTP3R.js +1 -0
  248. package/static/chunk-42L6C5MT.js +1 -0
  249. package/static/chunk-4AGQL5GV.js +1 -0
  250. package/static/chunk-4BPSQMI2.js +1 -0
  251. package/static/chunk-4FDRWZWT.js +1 -0
  252. package/static/chunk-4FJUCMEG.js +1 -0
  253. package/static/chunk-4GCCF6PF.js +1 -0
  254. package/static/chunk-4ORP3SBY.js +1 -0
  255. package/static/chunk-4QBOHIC3.js +1 -0
  256. package/static/chunk-4YT6K5KY.js +1 -0
  257. package/static/chunk-556I6YIW.js +1 -0
  258. package/static/chunk-5DPIGJU4.js +1 -0
  259. package/static/chunk-5HNQLBSW.js +3 -0
  260. package/static/chunk-5IL7C45D.js +1 -0
  261. package/static/chunk-5KJXGMKR.js +1 -0
  262. package/static/chunk-5SPGSHKL.js +1 -0
  263. package/static/chunk-5WCQBTXW.js +1 -0
  264. package/static/chunk-5XUIPWOH.js +1 -0
  265. package/static/chunk-62WT7PI3.js +1 -0
  266. package/static/chunk-6F6OMQ5H.js +1 -0
  267. package/static/chunk-6I5BGQHT.js +1 -0
  268. package/static/chunk-6NOS45DG.js +1 -0
  269. package/static/chunk-6OKLPRCD.js +1 -0
  270. package/static/chunk-6VEJCG43.js +1 -0
  271. package/static/chunk-77SS36Z2.js +1 -0
  272. package/static/chunk-7AXEPO3G.js +1 -0
  273. package/static/chunk-7CFSJ4BO.js +1 -0
  274. package/static/chunk-7CKHC72R.js +1 -0
  275. package/static/chunk-7DUTYOJG.js +1 -0
  276. package/static/chunk-7HKFYRPF.js +1 -0
  277. package/static/chunk-7NZJZATZ.js +1 -0
  278. package/static/chunk-AADK5D2H.js +1 -0
  279. package/static/chunk-ACUF7IKP.js +1 -0
  280. package/static/chunk-AGREZPV4.js +1 -0
  281. package/static/chunk-ATBJWFA3.js +1 -0
  282. package/static/chunk-ATXLZN2B.js +1 -0
  283. package/static/chunk-AZ5TF5Y3.js +1 -0
  284. package/static/chunk-BBHYIURC.js +1 -0
  285. package/static/chunk-BHZEPHRI.js +13 -0
  286. package/static/chunk-BQZWSZNN.js +1 -0
  287. package/static/chunk-BSB4VROD.js +2 -0
  288. package/static/chunk-BYWSTP3P.js +1 -0
  289. package/static/chunk-C3AAEQKW.js +1 -0
  290. package/static/chunk-CCGGCHGN.js +1 -0
  291. package/static/chunk-CFTKW432.js +1 -0
  292. package/static/chunk-CNOVT6KU.js +1 -0
  293. package/static/chunk-D56H3XE2.js +1 -0
  294. package/static/chunk-DFOOSIIA.js +1 -0
  295. package/static/chunk-DHFQIFOF.js +1 -0
  296. package/static/{chunk-3GMLWAFZ.js → chunk-DIC2MVRI.js} +1 -1
  297. package/static/chunk-DJDRX53V.js +2 -0
  298. package/static/chunk-DKGXUMLT.js +1 -0
  299. package/static/chunk-DRHPEERW.js +2 -0
  300. package/static/chunk-DWYP6ZGG.js +1 -0
  301. package/static/chunk-EDJAISWO.js +13 -0
  302. package/static/chunk-EIYRBM4J.js +1 -0
  303. package/static/chunk-EKEGRXCV.js +7 -0
  304. package/static/chunk-EL6QL4TP.js +1 -0
  305. package/static/chunk-ERDZ7IVF.js +1 -0
  306. package/static/chunk-EVQKKVUZ.js +1 -0
  307. package/static/chunk-F2XG7EWI.js +1 -0
  308. package/static/chunk-F672FY5I.js +1 -0
  309. package/static/chunk-F6V37MKG.js +1 -0
  310. package/static/chunk-F7TXTNZC.js +1 -0
  311. package/static/chunk-FCGTI42I.js +1 -0
  312. package/static/chunk-FQHOSSCO.js +1 -0
  313. package/static/chunk-FTSIPHMG.js +1 -0
  314. package/static/chunk-GAGHHYLF.js +1 -0
  315. package/static/{chunk-JPT5WEAT.js → chunk-GOJYWL2M.js} +1 -1
  316. package/static/chunk-H6WOTGQ5.js +1 -0
  317. package/static/{chunk-CHJ64RJM.js → chunk-H6ZXFINQ.js} +1 -1
  318. package/static/chunk-HC7F57NA.js +1 -0
  319. package/static/chunk-HHWXIK2M.js +7 -0
  320. package/static/chunk-HKRGIRKB.js +3 -0
  321. package/static/chunk-HNMGPG72.js +1 -0
  322. package/static/chunk-HS4S6BV3.js +1 -0
  323. package/static/chunk-IJ7K7ATQ.js +1 -0
  324. package/static/chunk-IOIBQGHN.js +562 -0
  325. package/static/chunk-ITVA26X2.js +2 -0
  326. package/static/chunk-J6YSFHLZ.js +1 -0
  327. package/static/chunk-JAEJ6IMV.js +1 -0
  328. package/static/chunk-JB5R6V33.js +1 -0
  329. package/static/chunk-JF6WIV6M.js +1 -0
  330. package/static/chunk-JGB4LLUT.js +1 -0
  331. package/static/chunk-JGXVTKLG.js +1 -0
  332. package/static/chunk-JMYAD7E2.js +1 -0
  333. package/static/chunk-JSE63Q5X.js +1 -0
  334. package/static/chunk-JVV3ZL6L.js +1 -0
  335. package/static/chunk-JXZCNFW7.js +1 -0
  336. package/static/chunk-KAVP6UXH.js +1 -0
  337. package/static/{chunk-WLMNXRBS.js → chunk-KDEEERWZ.js} +1 -1
  338. package/static/chunk-KHRF67SG.js +1 -0
  339. package/static/chunk-KLOUBIO4.js +1 -0
  340. package/static/chunk-KMF3ZRAO.js +1 -0
  341. package/static/chunk-KNZ3AQPR.js +1 -0
  342. package/static/chunk-KT3TWCST.js +1 -0
  343. package/static/chunk-L6SYG23T.js +1 -0
  344. package/static/chunk-LJSVNPPQ.js +1 -0
  345. package/static/{chunk-LNTUR3GU.js → chunk-LRDKG274.js} +1 -1
  346. package/static/chunk-LRQSPCYZ.js +1 -0
  347. package/static/chunk-LUSVISM6.js +1 -0
  348. package/static/chunk-LXQGVNU2.js +1 -0
  349. package/static/{chunk-BIKLW4YS.js → chunk-LYZGJZNP.js} +1 -1
  350. package/static/chunk-LZKI5P5T.js +1 -0
  351. package/static/chunk-M4XL3JN5.js +6 -0
  352. package/static/{chunk-UNCPXHHT.js → chunk-MGWG7OD7.js} +1 -1
  353. package/static/chunk-MKUUWY6Y.js +1 -0
  354. package/static/{chunk-HAS5ZOTR.js → chunk-MNNCSSHN.js} +1 -1
  355. package/static/chunk-MR3U7TKQ.js +1 -0
  356. package/static/chunk-MRF3CNLZ.js +1 -0
  357. package/static/chunk-MRMSMTWD.js +1 -0
  358. package/static/chunk-MVZJSG5R.js +1 -0
  359. package/static/chunk-MYM43ENO.js +1 -0
  360. package/static/chunk-N3P6P6GW.js +7 -0
  361. package/static/chunk-NAH4V2R6.js +2 -0
  362. package/static/chunk-NBBDVVUF.js +1 -0
  363. package/static/chunk-NMF2ZFBE.js +1 -0
  364. package/static/chunk-NN4ONTOT.js +1 -0
  365. package/static/chunk-NOPACN4F.js +1 -0
  366. package/static/chunk-NYJPOP4L.js +1 -0
  367. package/static/chunk-OJCAIKUK.js +1 -0
  368. package/static/chunk-OQRWXCLY.js +1 -0
  369. package/static/chunk-PCFH5HCI.js +2 -0
  370. package/static/chunk-PG54TWBO.js +4 -0
  371. package/static/chunk-PJF5XUTO.js +1 -0
  372. package/static/{chunk-FJE6BOFL.js → chunk-PSUAQBYM.js} +1 -1
  373. package/static/chunk-PTLYIUFW.js +1 -0
  374. package/static/chunk-PZGLDZZM.js +1 -0
  375. package/static/chunk-Q4VNZGFI.js +1 -0
  376. package/static/chunk-Q556XB3S.js +1 -0
  377. package/static/{chunk-PB4AIT7O.js → chunk-Q7IXRPOO.js} +1 -1
  378. package/static/chunk-Q7U2VPIS.js +1 -0
  379. package/static/chunk-QM6CQMEX.js +1 -0
  380. package/static/chunk-QMHUIHSR.js +1 -0
  381. package/static/chunk-QNFNXDSX.js +1 -0
  382. package/static/chunk-QVFPHTOH.js +1 -0
  383. package/static/chunk-R4MI25E2.js +1 -0
  384. package/static/chunk-R7JRAR3P.js +1 -0
  385. package/static/chunk-R7PNKQU2.js +1 -0
  386. package/static/chunk-RCAORRB7.js +1 -0
  387. package/static/chunk-RK7XRDNB.js +1 -0
  388. package/static/chunk-RO7SAOLK.js +1 -0
  389. package/static/chunk-RQUUINHV.js +1 -0
  390. package/static/chunk-RT3K6DZR.js +1 -0
  391. package/static/chunk-RUN556VW.js +1 -0
  392. package/static/chunk-RX3YQ67K.js +1 -0
  393. package/static/chunk-S6EVLDHA.js +5 -0
  394. package/static/chunk-S7S5M3AZ.js +1 -0
  395. package/static/chunk-SBLNYV74.js +1 -0
  396. package/static/chunk-SIZCHHUA.js +1 -0
  397. package/static/chunk-SRBOO7AO.js +1 -0
  398. package/static/{chunk-PVDHBQRM.js → chunk-STA7NTYL.js} +1 -1
  399. package/static/chunk-T3YI3BSS.js +1 -0
  400. package/static/chunk-T74SMT7I.js +1 -0
  401. package/static/chunk-TAL3RTTQ.js +1 -0
  402. package/static/chunk-TJZKTNNS.js +1 -0
  403. package/static/chunk-UJTFWZEC.js +1 -0
  404. package/static/chunk-UPGVU5LG.js +1 -0
  405. package/static/chunk-UQ6O3I6W.js +1 -0
  406. package/static/{chunk-5NMSIIQB.js → chunk-V43RGNXA.js} +1 -1
  407. package/static/chunk-VWIRXLNE.js +1 -0
  408. package/static/chunk-VZMVGIVW.js +1 -0
  409. package/static/chunk-VZPCXSRG.js +2 -0
  410. package/static/chunk-WR3MA3L3.js +1 -0
  411. package/static/chunk-XCLK7NJL.js +1 -0
  412. package/static/{chunk-DSWEWLXJ.js → chunk-XCPDPB5G.js} +1 -1
  413. package/static/chunk-XEGHEUP5.js +1 -0
  414. package/static/chunk-XKEBQNQJ.js +1 -0
  415. package/static/chunk-XOF4UW3S.js +1 -0
  416. package/static/chunk-XOTKK2NJ.js +1 -0
  417. package/static/chunk-XX7JXKA6.js +1 -0
  418. package/static/chunk-Y2I36A4K.js +1 -0
  419. package/static/chunk-Y44XDRM5.js +1 -0
  420. package/static/{chunk-QO6BTONN.js → chunk-Y4MAPE2C.js} +1 -1
  421. package/static/chunk-Y5RLD72B.js +1 -0
  422. package/static/{chunk-DPUVSXRB.js → chunk-Y5XTRCFK.js} +1 -1
  423. package/static/chunk-Y63UUJGJ.js +1 -0
  424. package/static/chunk-YBNAC7QM.js +1 -0
  425. package/static/chunk-YCTCESL4.js +1 -0
  426. package/static/chunk-YMAN4LIU.js +1 -0
  427. package/static/chunk-YTDE6SXT.js +1 -0
  428. package/static/chunk-YZPIUJB3.js +1 -0
  429. package/static/chunk-ZCOWBVOT.js +1 -0
  430. package/static/chunk-ZHRYYMYE.js +1 -0
  431. package/static/chunk-ZNXTOQFG.js +1 -0
  432. package/static/{chunk-URHTCJ7G.js → chunk-ZQLBPLXI.js} +1 -1
  433. package/static/favicon.ico +0 -0
  434. package/static/index.html +2 -2
  435. package/static/main-3PLRDZTO.js +11 -0
  436. package/static/styles-Q4OZOSSK.css +1 -0
  437. package/server/applications/notifications/interfaces/user-mail-notification.js.map +0 -1
  438. package/static/assets/codemirror/mode/apl/apl.js +0 -174
  439. package/static/assets/codemirror/mode/asciiarmor/asciiarmor.js +0 -74
  440. package/static/assets/codemirror/mode/asn.1/asn.1.js +0 -204
  441. package/static/assets/codemirror/mode/asterisk/asterisk.js +0 -220
  442. package/static/assets/codemirror/mode/brainfuck/brainfuck.js +0 -85
  443. package/static/assets/codemirror/mode/clike/clike.js +0 -942
  444. package/static/assets/codemirror/mode/clojure/clojure.js +0 -293
  445. package/static/assets/codemirror/mode/cmake/cmake.js +0 -97
  446. package/static/assets/codemirror/mode/cobol/cobol.js +0 -255
  447. package/static/assets/codemirror/mode/coffeescript/coffeescript.js +0 -359
  448. package/static/assets/codemirror/mode/commonlisp/commonlisp.js +0 -125
  449. package/static/assets/codemirror/mode/crystal/crystal.js +0 -433
  450. package/static/assets/codemirror/mode/css/css.js +0 -862
  451. package/static/assets/codemirror/mode/cypher/cypher.js +0 -152
  452. package/static/assets/codemirror/mode/d/d.js +0 -223
  453. package/static/assets/codemirror/mode/dart/dart.js +0 -168
  454. package/static/assets/codemirror/mode/diff/diff.js +0 -47
  455. package/static/assets/codemirror/mode/django/django.js +0 -356
  456. package/static/assets/codemirror/mode/dockerfile/dockerfile.js +0 -211
  457. package/static/assets/codemirror/mode/dtd/dtd.js +0 -142
  458. package/static/assets/codemirror/mode/dylan/dylan.js +0 -352
  459. package/static/assets/codemirror/mode/ebnf/ebnf.js +0 -195
  460. package/static/assets/codemirror/mode/ecl/ecl.js +0 -206
  461. package/static/assets/codemirror/mode/eiffel/eiffel.js +0 -160
  462. package/static/assets/codemirror/mode/elm/elm.js +0 -245
  463. package/static/assets/codemirror/mode/erlang/erlang.js +0 -619
  464. package/static/assets/codemirror/mode/factor/factor.js +0 -85
  465. package/static/assets/codemirror/mode/fcl/fcl.js +0 -173
  466. package/static/assets/codemirror/mode/forth/forth.js +0 -180
  467. package/static/assets/codemirror/mode/fortran/fortran.js +0 -188
  468. package/static/assets/codemirror/mode/gas/gas.js +0 -355
  469. package/static/assets/codemirror/mode/gfm/gfm.js +0 -129
  470. package/static/assets/codemirror/mode/gherkin/gherkin.js +0 -194
  471. package/static/assets/codemirror/mode/go/go.js +0 -187
  472. package/static/assets/codemirror/mode/groovy/groovy.js +0 -245
  473. package/static/assets/codemirror/mode/haml/haml.js +0 -161
  474. package/static/assets/codemirror/mode/handlebars/handlebars.js +0 -70
  475. package/static/assets/codemirror/mode/haskell/haskell.js +0 -268
  476. package/static/assets/codemirror/mode/haskell-literate/haskell-literate.js +0 -43
  477. package/static/assets/codemirror/mode/haxe/haxe.js +0 -515
  478. package/static/assets/codemirror/mode/htmlembedded/htmlembedded.js +0 -37
  479. package/static/assets/codemirror/mode/htmlmixed/htmlmixed.js +0 -153
  480. package/static/assets/codemirror/mode/http/http.js +0 -113
  481. package/static/assets/codemirror/mode/idl/idl.js +0 -290
  482. package/static/assets/codemirror/mode/javascript/javascript.js +0 -960
  483. package/static/assets/codemirror/mode/jinja2/jinja2.js +0 -193
  484. package/static/assets/codemirror/mode/jsx/jsx.js +0 -149
  485. package/static/assets/codemirror/mode/julia/julia.js +0 -390
  486. package/static/assets/codemirror/mode/livescript/livescript.js +0 -280
  487. package/static/assets/codemirror/mode/lua/lua.js +0 -160
  488. package/static/assets/codemirror/mode/markdown/markdown.js +0 -886
  489. package/static/assets/codemirror/mode/mathematica/mathematica.js +0 -176
  490. package/static/assets/codemirror/mode/mbox/mbox.js +0 -129
  491. package/static/assets/codemirror/mode/meta.js +0 -221
  492. package/static/assets/codemirror/mode/mirc/mirc.js +0 -193
  493. package/static/assets/codemirror/mode/mllike/mllike.js +0 -359
  494. package/static/assets/codemirror/mode/modelica/modelica.js +0 -245
  495. package/static/assets/codemirror/mode/mscgen/mscgen.js +0 -175
  496. package/static/assets/codemirror/mode/mumps/mumps.js +0 -148
  497. package/static/assets/codemirror/mode/nginx/nginx.js +0 -178
  498. package/static/assets/codemirror/mode/nsis/nsis.js +0 -95
  499. package/static/assets/codemirror/mode/ntriples/ntriples.js +0 -195
  500. package/static/assets/codemirror/mode/octave/octave.js +0 -139
  501. package/static/assets/codemirror/mode/oz/oz.js +0 -252
  502. package/static/assets/codemirror/mode/pascal/pascal.js +0 -136
  503. package/static/assets/codemirror/mode/pegjs/pegjs.js +0 -111
  504. package/static/assets/codemirror/mode/perl/perl.js +0 -836
  505. package/static/assets/codemirror/mode/php/php.js +0 -234
  506. package/static/assets/codemirror/mode/pig/pig.js +0 -178
  507. package/static/assets/codemirror/mode/powershell/powershell.js +0 -398
  508. package/static/assets/codemirror/mode/properties/properties.js +0 -78
  509. package/static/assets/codemirror/mode/protobuf/protobuf.js +0 -72
  510. package/static/assets/codemirror/mode/pug/pug.js +0 -591
  511. package/static/assets/codemirror/mode/puppet/puppet.js +0 -220
  512. package/static/assets/codemirror/mode/python/python.js +0 -402
  513. package/static/assets/codemirror/mode/q/q.js +0 -139
  514. package/static/assets/codemirror/mode/r/r.js +0 -190
  515. package/static/assets/codemirror/mode/rpm/changes/index.html +0 -66
  516. package/static/assets/codemirror/mode/rpm/rpm.js +0 -109
  517. package/static/assets/codemirror/mode/rst/rst.js +0 -557
  518. package/static/assets/codemirror/mode/ruby/ruby.js +0 -303
  519. package/static/assets/codemirror/mode/rust/rust.js +0 -72
  520. package/static/assets/codemirror/mode/sas/sas.js +0 -303
  521. package/static/assets/codemirror/mode/sass/sass.js +0 -459
  522. package/static/assets/codemirror/mode/scheme/scheme.js +0 -284
  523. package/static/assets/codemirror/mode/shell/shell.js +0 -168
  524. package/static/assets/codemirror/mode/sieve/sieve.js +0 -193
  525. package/static/assets/codemirror/mode/slim/slim.js +0 -575
  526. package/static/assets/codemirror/mode/smalltalk/smalltalk.js +0 -168
  527. package/static/assets/codemirror/mode/smarty/smarty.js +0 -225
  528. package/static/assets/codemirror/mode/solr/solr.js +0 -104
  529. package/static/assets/codemirror/mode/soy/soy.js +0 -665
  530. package/static/assets/codemirror/mode/sparql/sparql.js +0 -184
  531. package/static/assets/codemirror/mode/spreadsheet/spreadsheet.js +0 -112
  532. package/static/assets/codemirror/mode/sql/sql.js +0 -529
  533. package/static/assets/codemirror/mode/stex/stex.js +0 -264
  534. package/static/assets/codemirror/mode/stylus/stylus.js +0 -775
  535. package/static/assets/codemirror/mode/swift/swift.js +0 -221
  536. package/static/assets/codemirror/mode/tcl/tcl.js +0 -140
  537. package/static/assets/codemirror/mode/textile/textile.js +0 -469
  538. package/static/assets/codemirror/mode/tiddlywiki/tiddlywiki.css +0 -14
  539. package/static/assets/codemirror/mode/tiddlywiki/tiddlywiki.js +0 -308
  540. package/static/assets/codemirror/mode/tiki/tiki.css +0 -26
  541. package/static/assets/codemirror/mode/tiki/tiki.js +0 -312
  542. package/static/assets/codemirror/mode/toml/toml.js +0 -88
  543. package/static/assets/codemirror/mode/tornado/tornado.js +0 -68
  544. package/static/assets/codemirror/mode/troff/troff.js +0 -84
  545. package/static/assets/codemirror/mode/ttcn/ttcn.js +0 -283
  546. package/static/assets/codemirror/mode/ttcn-cfg/ttcn-cfg.js +0 -214
  547. package/static/assets/codemirror/mode/turtle/turtle.js +0 -162
  548. package/static/assets/codemirror/mode/twig/twig.js +0 -141
  549. package/static/assets/codemirror/mode/vb/vb.js +0 -275
  550. package/static/assets/codemirror/mode/vbscript/vbscript.js +0 -350
  551. package/static/assets/codemirror/mode/velocity/velocity.js +0 -202
  552. package/static/assets/codemirror/mode/verilog/verilog.js +0 -781
  553. package/static/assets/codemirror/mode/vhdl/vhdl.js +0 -189
  554. package/static/assets/codemirror/mode/vue/vue.js +0 -77
  555. package/static/assets/codemirror/mode/wast/wast.js +0 -132
  556. package/static/assets/codemirror/mode/webidl/webidl.js +0 -195
  557. package/static/assets/codemirror/mode/xml/xml.js +0 -417
  558. package/static/assets/codemirror/mode/xquery/xquery.js +0 -448
  559. package/static/assets/codemirror/mode/yacas/yacas.js +0 -204
  560. package/static/assets/codemirror/mode/yaml/yaml.js +0 -120
  561. package/static/assets/codemirror/mode/yaml-frontmatter/yaml-frontmatter.js +0 -72
  562. package/static/assets/codemirror/mode/z80/z80.js +0 -116
  563. package/static/chunk-2KLC4T2Z.js +0 -1
  564. package/static/chunk-373XVRXW.js +0 -1
  565. package/static/chunk-3XVM35O2.js +0 -1
  566. package/static/chunk-3YVRP3VM.js +0 -2
  567. package/static/chunk-AF24EYXU.js +0 -1
  568. package/static/chunk-AKQVEHO6.js +0 -2
  569. package/static/chunk-AY2SZ3G6.js +0 -1
  570. package/static/chunk-BCVX464U.js +0 -2
  571. package/static/chunk-C36MW4ME.js +0 -562
  572. package/static/chunk-DKSEQTMX.js +0 -1
  573. package/static/chunk-FZ3JPGYZ.js +0 -1
  574. package/static/chunk-GUGNR5TF.js +0 -3
  575. package/static/chunk-H6NE33VX.js +0 -1
  576. package/static/chunk-HNQRZALS.js +0 -1
  577. package/static/chunk-JSWCNGXJ.js +0 -1
  578. package/static/chunk-KFJIQIGR.js +0 -1
  579. package/static/chunk-LVM4QB22.js +0 -1
  580. package/static/chunk-M3XVNQZQ.js +0 -1
  581. package/static/chunk-MFLIJH6T.js +0 -1
  582. package/static/chunk-MSUHTBB2.js +0 -1
  583. package/static/chunk-N3U6637P.js +0 -1
  584. package/static/chunk-NNV4OXSB.js +0 -1
  585. package/static/chunk-NO2LTNW3.js +0 -1
  586. package/static/chunk-OOGP4WSH.js +0 -2
  587. package/static/chunk-PCWDQPOM.js +0 -2
  588. package/static/chunk-PGZZP5W3.js +0 -1
  589. package/static/chunk-Q5KM7LTX.js +0 -1
  590. package/static/chunk-QHC6ZPQ4.js +0 -1
  591. package/static/chunk-QZU2S5CV.js +0 -1
  592. package/static/chunk-SBZ572Q4.js +0 -2
  593. package/static/chunk-SHIVUDP3.js +0 -1
  594. package/static/chunk-SLHTEGRU.js +0 -1
  595. package/static/chunk-SSFF27P2.js +0 -24
  596. package/static/chunk-TPYBFZS5.js +0 -1
  597. package/static/chunk-UEQCWMXD.js +0 -1
  598. package/static/chunk-UG5DMXYO.js +0 -1
  599. package/static/chunk-UJPPR4MX.js +0 -1
  600. package/static/chunk-V3AT2BKP.js +0 -1
  601. package/static/chunk-VKK5BSLX.js +0 -1
  602. package/static/chunk-WJW7CT6G.js +0 -27
  603. package/static/chunk-X5XGK6T7.js +0 -4
  604. package/static/chunk-YEKR5OPO.js +0 -1
  605. package/static/chunk-YW57T2PF.js +0 -1
  606. package/static/chunk-Z5J5F5SX.js +0 -1
  607. package/static/chunk-ZPF2DSQV.js +0 -1
  608. package/static/chunk-ZTCRGJ6Y.js +0 -7
  609. package/static/main-VOL6OMJ5.js +0 -9
  610. package/static/scripts-WRDOQIU5.js +0 -24
  611. package/static/styles-2C2UNCNB.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/guards/files-only-office.guard.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 { ExecutionContext, HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { AuthGuard, IAuthGuard } from '@nestjs/passport'\nimport { Observable } from 'rxjs'\nimport { configuration } from '../../../configuration/config.environment'\n\n@Injectable()\nexport class FilesOnlyOfficeGuard extends AuthGuard('filesOnlyOfficeToken') implements IAuthGuard {\n private readonly logger = new Logger(FilesOnlyOfficeGuard.name)\n\n canActivate(ctx: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {\n if (!configuration.applications.files.onlyoffice.enabled) {\n this.logger.warn(`${this.canActivate.name} - feature not enabled`)\n throw new HttpException('Feature not enabled', HttpStatus.BAD_REQUEST)\n }\n return super.canActivate(ctx)\n }\n\n handleRequest<TUser = any>(err: any, user: any, info: Error, ctx: ExecutionContext, status?: any): TUser {\n const req = this.getRequest(ctx)\n req.raw.user = user?.login || 'unauthorized'\n if (info) {\n this.logger.warn(`<${req.raw.user}> <${req.ip}> ${info}`)\n }\n return super.handleRequest(err, user, info, ctx, status)\n }\n}\n"],"names":["FilesOnlyOfficeGuard","AuthGuard","canActivate","ctx","configuration","applications","files","onlyoffice","enabled","logger","warn","name","HttpException","HttpStatus","BAD_REQUEST","handleRequest","err","user","info","status","req","getRequest","raw","login","ip","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAQYA;;;eAAAA;;;wBANmE;0BAC1C;mCAER;;;;;;;AAGvB,IAAA,AAAMA,uBAAN,MAAMA,6BAA6BC,IAAAA,mBAAS,EAAC;IAGlDC,YAAYC,GAAqB,EAAoD;QACnF,IAAI,CAACC,gCAAa,CAACC,YAAY,CAACC,KAAK,CAACC,UAAU,CAACC,OAAO,EAAE;YACxD,IAAI,CAACC,MAAM,CAACC,IAAI,CAAC,GAAG,IAAI,CAACR,WAAW,CAACS,IAAI,CAAC,sBAAsB,CAAC;YACjE,MAAM,IAAIC,qBAAa,CAAC,uBAAuBC,kBAAU,CAACC,WAAW;QACvE;QACA,OAAO,KAAK,CAACZ,YAAYC;IAC3B;IAEAY,cAA2BC,GAAQ,EAAEC,IAAS,EAAEC,IAAW,EAAEf,GAAqB,EAAEgB,MAAY,EAAS;QACvG,MAAMC,MAAM,IAAI,CAACC,UAAU,CAAClB;QAC5BiB,IAAIE,GAAG,CAACL,IAAI,GAAGA,MAAMM,SAAS;QAC9B,IAAIL,MAAM;YACR,IAAI,CAACT,MAAM,CAACC,IAAI,CAAC,CAAC,CAAC,EAAEU,IAAIE,GAAG,CAACL,IAAI,CAAC,GAAG,EAAEG,IAAII,EAAE,CAAC,EAAE,EAAEN,MAAM;QAC1D;QACA,OAAO,KAAK,CAACH,cAAcC,KAAKC,MAAMC,MAAMf,KAAKgB;IACnD;;QAlBK,qBACYV,SAAS,IAAIgB,cAAM,CAACzB,qBAAqBW,IAAI;;AAkBhE"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/guards/files-only-office.guard.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 { ExecutionContext, HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { AuthGuard, IAuthGuard } from '@nestjs/passport'\nimport { FastifyRequest } from 'fastify'\nimport { Observable } from 'rxjs'\nimport { configuration } from '../../../configuration/config.environment'\nimport { API_FILES_ONLY_OFFICE_STATUS } from '../constants/routes'\n\n@Injectable()\nexport class FilesOnlyOfficeGuard extends AuthGuard('filesOnlyOfficeToken') implements IAuthGuard {\n private readonly logger = new Logger(FilesOnlyOfficeGuard.name)\n\n canActivate(ctx: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {\n const req: FastifyRequest = ctx.switchToHttp().getRequest()\n if (req.originalUrl === API_FILES_ONLY_OFFICE_STATUS) {\n // Skip token validation for the status endpoint\n return true\n }\n if (!configuration.applications.files.onlyoffice.enabled) {\n this.logger.warn(`${this.canActivate.name} - feature not enabled`)\n throw new HttpException('Feature not enabled', HttpStatus.BAD_REQUEST)\n }\n return super.canActivate(ctx)\n }\n\n handleRequest<TUser = any>(err: any, user: any, info: Error, ctx: ExecutionContext, status?: any): TUser {\n const req = this.getRequest(ctx)\n req.raw.user = user?.login || 'unauthorized'\n if (info) {\n this.logger.warn(`<${req.raw.user}> <${req.ip}> ${info}`)\n }\n return super.handleRequest(err, user, info, ctx, status)\n }\n}\n"],"names":["FilesOnlyOfficeGuard","AuthGuard","canActivate","ctx","req","switchToHttp","getRequest","originalUrl","API_FILES_ONLY_OFFICE_STATUS","configuration","applications","files","onlyoffice","enabled","logger","warn","name","HttpException","HttpStatus","BAD_REQUEST","handleRequest","err","user","info","status","raw","login","ip","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAUYA;;;eAAAA;;;wBARmE;0BAC1C;mCAGR;wBACe;;;;;;;AAGtC,IAAA,AAAMA,uBAAN,MAAMA,6BAA6BC,IAAAA,mBAAS,EAAC;IAGlDC,YAAYC,GAAqB,EAAoD;QACnF,MAAMC,MAAsBD,IAAIE,YAAY,GAAGC,UAAU;QACzD,IAAIF,IAAIG,WAAW,KAAKC,oCAA4B,EAAE;YACpD,gDAAgD;YAChD,OAAO;QACT;QACA,IAAI,CAACC,gCAAa,CAACC,YAAY,CAACC,KAAK,CAACC,UAAU,CAACC,OAAO,EAAE;YACxD,IAAI,CAACC,MAAM,CAACC,IAAI,CAAC,GAAG,IAAI,CAACb,WAAW,CAACc,IAAI,CAAC,sBAAsB,CAAC;YACjE,MAAM,IAAIC,qBAAa,CAAC,uBAAuBC,kBAAU,CAACC,WAAW;QACvE;QACA,OAAO,KAAK,CAACjB,YAAYC;IAC3B;IAEAiB,cAA2BC,GAAQ,EAAEC,IAAS,EAAEC,IAAW,EAAEpB,GAAqB,EAAEqB,MAAY,EAAS;QACvG,MAAMpB,MAAM,IAAI,CAACE,UAAU,CAACH;QAC5BC,IAAIqB,GAAG,CAACH,IAAI,GAAGA,MAAMI,SAAS;QAC9B,IAAIH,MAAM;YACR,IAAI,CAACT,MAAM,CAACC,IAAI,CAAC,CAAC,CAAC,EAAEX,IAAIqB,GAAG,CAACH,IAAI,CAAC,GAAG,EAAElB,IAAIuB,EAAE,CAAC,EAAE,EAAEJ,MAAM;QAC1D;QACA,OAAO,KAAK,CAACH,cAAcC,KAAKC,MAAMC,MAAMpB,KAAKqB;IACnD;;QAvBK,qBACYV,SAAS,IAAIc,cAAM,CAAC5B,qBAAqBgB,IAAI;;AAuBhE"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/file-db-props.interface.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 type { File } from '../schemas/file.interface'\n\nexport interface FileDBProps extends Partial<Pick<File, 'ownerId' | 'spaceId' | 'spaceExternalRootId' | 'shareExternalId' | 'inTrash' | 'path'>> {\n // warn: used during lock creation, new fields will be used in lock key\n ownerId?: number\n spaceId?: number\n spaceExternalRootId?: number\n shareExternalId?: number\n inTrash: boolean\n // full path with name\n path: string\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/file-db-props.interface.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 type { File } from '../schemas/file.interface'\n\nexport interface FileDBProps extends Partial<Pick<File, 'ownerId' | 'spaceId' | 'spaceExternalRootId' | 'shareExternalId' | 'inTrash' | 'path'>> {\n // warn: used during lock creation, new fields will be used in the lock key\n ownerId?: number\n spaceId?: number\n spaceExternalRootId?: number\n shareExternalId?: number\n inTrash: boolean\n // full path with name\n path: string\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/file-props.interface.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 type { Share } from '../../shares/schemas/share.interface'\nimport type { SpaceRoot } from '../../spaces/schemas/space-root.interface'\nimport type { Space } from '../../spaces/schemas/space.interface'\nimport type { SyncPath } from '../../sync/schemas/sync-path.interface'\nimport type { Owner } from '../../users/interfaces/owner.interface'\nimport type { File } from '../schemas/file.interface'\n\nexport interface FileProps extends Omit<File, 'ownerId' | 'spaceId' | 'spaceExternalRootId' | 'shareExternalId' | 'inTrash'> {\n id: number\n name: string\n path: string\n isDir: boolean\n size: number\n ctime: number\n mtime: number\n mime: string\n inTrash?: boolean\n // used with shares\n origin?: { ownerLogin: string; spaceAlias: string; spaceRootExternalPath?: string }\n // root can be a share or a space root\n // enabled & description are only used for shares\n root?: Pick<SpaceRoot, 'id' | 'alias' | 'permissions'> &\n Partial<Pick<SpaceRoot, 'name' | 'externalPath'>> &\n Partial<Pick<Share, 'enabled' | 'description'>> & {\n owner: Owner\n }\n lock?: { owner: string; ownerLogin: string; isExclusive: boolean }\n // used by the files browser to enrich files\n spaces?: Pick<Space, 'id' | 'alias' | 'name'>[]\n shares?: Pick<Share, 'id' | 'alias' | 'name' | 'type'>[]\n syncs?: Pick<SyncPath, 'clientId' | 'id'> & { clientName: string }[]\n hasComments?: boolean\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/file-props.interface.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 type { Share } from '../../shares/schemas/share.interface'\nimport type { SpaceRoot } from '../../spaces/schemas/space-root.interface'\nimport type { Space } from '../../spaces/schemas/space.interface'\nimport type { SyncPath } from '../../sync/schemas/sync-path.interface'\nimport type { Owner } from '../../users/interfaces/owner.interface'\nimport type { File } from '../schemas/file.interface'\n\nexport interface FileLockProps {\n owner: string\n ownerLogin: string\n isExclusive: boolean\n}\n\nexport interface FileProps extends Omit<File, 'ownerId' | 'spaceId' | 'spaceExternalRootId' | 'shareExternalId' | 'inTrash'> {\n id: number\n name: string\n path: string\n isDir: boolean\n size: number\n ctime: number\n mtime: number\n mime: string\n inTrash?: boolean\n // used with shares\n origin?: {\n ownerId: number\n ownerLogin: string\n spaceId: number\n spaceAlias: string\n spaceExternalRootId: number\n spaceRootExternalPath: string\n shareExternalId: number\n }\n // root can be a share or a space root\n // enabled, and description are only used for shares\n root?: Pick<SpaceRoot, 'id' | 'alias' | 'permissions'> &\n Partial<Pick<SpaceRoot, 'name' | 'externalPath'>> &\n Partial<Pick<Share, 'enabled' | 'description'>> & {\n owner: Owner\n }\n lock?: FileLockProps\n // used by the file browser to enrich files\n spaces?: Pick<Space, 'id' | 'alias' | 'name'>[]\n shares?: Pick<Share, 'id' | 'alias' | 'name' | 'type'>[]\n syncs?: Pick<SyncPath, 'clientId' | 'id'> & { clientName: string }[]\n hasComments?: boolean\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/only-office-config.interface.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\nexport interface OnlyOfficeReqConfig {\n documentServerUrl: string\n config: OnlyOfficeConfig\n}\n\nexport interface OnlyOfficeConvertForm {\n key: string\n url: string\n outputtype: string\n filetype: string\n async: boolean\n token?: string\n}\n\nexport interface OnlyOfficeConfig {\n documentType?: string\n token?: string\n type?: 'mobile' | 'desktop'\n height?: string\n width?: string\n document?: {\n fileType: string\n key: string\n referenceData?: {\n fileKey: string\n instanceId: string\n }\n title: string\n url: string\n info?: {\n owner?: string\n uploaded?: string\n favorite?: boolean\n folder?: string\n sharingSettings?: any[]\n }\n permissions?: {\n /**\n * @deprecated Deprecated since version 5.5, please add the onRequestRestore field instead.\n */\n changeHistory?: boolean\n chat?: boolean\n comment?: boolean\n commentGroups?: any\n copy?: boolean\n deleteCommentAuthorOnly?: boolean\n download?: boolean\n edit?: boolean\n editCommentAuthorOnly?: boolean\n fillForms?: boolean\n modifyContentControl?: boolean\n modifyFilter?: boolean\n print?: boolean\n protect?: boolean\n review?: boolean\n reviewGroups?: string[]\n userInfoGroups?: string[]\n }\n }\n editorConfig?: {\n actionLink?: any\n callbackUrl?: string\n coEditing?: {\n mode: string\n change: boolean\n }\n createUrl?: string\n lang?: string\n mode?: 'view' | 'edit'\n recent?: any[]\n region?: string\n templates?: any[]\n user?: {\n group?: string\n id?: string\n image?: string\n name?: string\n }\n customization?: {\n anonymous?: {\n request?: boolean\n label?: string\n }\n autosave?: boolean\n forcesave?: boolean\n close?: {\n visible: boolean\n text: string\n }\n comments?: boolean\n compactHeader?: boolean\n compactToolbar?: boolean\n compatibleFeatures?: boolean\n customer?: {\n address?: string\n info?: string\n logo?: string\n logoDark?: string\n mail?: string\n name?: string\n phone?: string\n www?: string\n }\n features?: any\n feedback?: any\n goback?: any\n help?: boolean\n hideNotes?: boolean\n hideRightMenu?: boolean\n hideRulers?: boolean\n integrationMode?: string\n logo?: {\n image?: string\n imageDark?: string\n imageLight?: string\n imageEmbedded?: string\n url?: string\n visible?: boolean\n }\n macros?: boolean\n macrosMode?: string\n mentionShare?: boolean\n mobileForceView?: boolean\n plugins?: boolean\n review?: {\n hideReviewDisplay?: boolean\n hoverMode?: boolean\n reviewDisplay?: string\n showReviewChanges?: boolean\n trackChanges?: boolean\n }\n submitForm?: boolean\n toolbarHideFileName?: boolean\n toolbarNoTabs?: boolean\n uiTheme?: string\n unit?: string\n zoom?: number\n about?: boolean\n }\n embedded?: {\n embedUrl?: string\n fullscreenUrl?: string\n saveUrl?: string\n shareUrl?: string\n toolbarDocked?: string\n }\n plugins?: {\n autostart?: string[]\n options?: {\n all?: any\n pluginGuid: any\n }\n pluginsData?: string[]\n }\n }\n events?: {\n onAppReady?: (event: object) => void\n onCollaborativeChanges?: (event: object) => void\n onDocumentReady?: (event: object) => void\n onDocumentStateChange?: (event: object) => void\n onDownloadAs?: (event: object) => void\n onError?: (event: object) => void\n onInfo?: (event: object) => void\n onMetaChange?: (event: object) => void\n onMakeActionLink?: (event: object) => void\n onRequestRefreshFile?: (event: object) => void\n onPluginsReady?: (event: object) => void\n onReady?: (event: object) => void\n onRequestClose?: (event: object) => void\n onRequestCreateNew?: (event: object) => void\n onRequestEditRights?: (event: object) => void\n onRequestHistory?: (event: object) => void\n onRequestHistoryClose?: (event: object) => void\n onRequestHistoryData?: (event: object) => void\n onRequestInsertImage?: (event: object) => void\n onRequestOpen?: (event: object) => void\n onRequestReferenceData?: (event: object) => void\n onRequestReferenceSource?: (event: object) => void\n onRequestRename?: (event: object) => void\n onRequestRestore?: (event: object) => void\n onRequestSaveAs?: (event: object) => void\n onRequestSelectDocument?: (event: object) => void\n onRequestSelectSpreadsheet?: (event: object) => void\n onRequestSendNotify?: (event: object) => void\n onRequestSharingSettings?: (event: object) => void\n onRequestStartFilling: (event: object) => void\n onRequestUsers?: (event: object) => void\n onSubmit?: (event: object) => void\n onWarning?: (event: object) => void\n }\n}\n\nexport interface OnlyOfficeCallBack {\n /* documentation : https://api.onlyoffice.com/docs/docs-api/usage-api/callback-handler/ */\n key: string // document key\n /*\n status:\n 1 - document is being edited\n 2 - document is ready for saving\n 3 - document saving error has occurred\n 4 - document is closed with no changes\n 6 - document is being edited, but the current document state is saved\n 7 - error has occurred while force saving the document\n */\n status: 1 | 2 | 3 | 4 | 6 | 7\n url?: string // link to download the modified version (for status: 2, 3, 6 or 7)\n notmodified?: boolean // only with status 2\n /*\n actions:\n 0 - the user disconnects from the document co-editing\n 1 - the new user connects to the document co-editing\n 2 - the user clicks the forcesave button.\n */\n actions?: { type: 0 | 1 | 2; userid: string }[]\n forcesavetype?: 0 | 1 | 2 | 3 // The type is present when the status value is equal to 6 or 7 only\n /*\n forcesavetype:\n 0 - to the command service\n 1 - each time the saving is done (e.g. the Save button is clicked), which is only available when the forcesave option is set to true\n 2 - by timer with the settings from the server config\n 3 - each time the form is submitted (e.g. the Complete & Submit button is clicked)\n */\n users?: string[] // when multiple users are editing the document\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/interfaces/only-office-config.interface.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 { FILE_MODE } from '../constants/operations'\n\nexport interface OnlyOfficeReqConfig {\n documentServerUrl: string\n config: OnlyOfficeConfig\n}\n\nexport interface OnlyOfficeConvertForm {\n key: string\n url: string\n outputtype: string\n filetype: string\n async: boolean\n token?: string\n}\n\nexport interface OnlyOfficeConfig {\n documentType?: string\n token?: string\n type?: 'mobile' | 'desktop'\n height?: string\n width?: string\n document?: {\n fileType: string\n key: string\n referenceData?: {\n fileKey: string\n instanceId: string\n }\n title: string\n url: string\n info?: {\n owner?: string\n uploaded?: string\n favorite?: boolean\n folder?: string\n sharingSettings?: any[]\n }\n permissions?: {\n /**\n * @deprecated Deprecated since version 5.5, please add the onRequestRestore field instead.\n */\n changeHistory?: boolean\n chat?: boolean\n comment?: boolean\n commentGroups?: any\n copy?: boolean\n deleteCommentAuthorOnly?: boolean\n download?: boolean\n edit?: boolean\n editCommentAuthorOnly?: boolean\n fillForms?: boolean\n modifyContentControl?: boolean\n modifyFilter?: boolean\n print?: boolean\n protect?: boolean\n review?: boolean\n reviewGroups?: string[]\n userInfoGroups?: string[]\n }\n }\n editorConfig?: {\n actionLink?: any\n callbackUrl?: string\n coEditing?: {\n mode: string\n change: boolean\n }\n createUrl?: string\n lang?: string\n mode?: FILE_MODE\n recent?: any[]\n region?: string\n templates?: any[]\n user?: {\n group?: string\n id?: string\n image?: string\n name?: string\n }\n customization?: {\n anonymous?: {\n request?: boolean\n label?: string\n }\n autosave?: boolean\n forcesave?: boolean\n close?: {\n visible: boolean\n text: string\n }\n comments?: boolean\n compactHeader?: boolean\n compactToolbar?: boolean\n compatibleFeatures?: boolean\n customer?: {\n address?: string\n info?: string\n logo?: string\n logoDark?: string\n mail?: string\n name?: string\n phone?: string\n www?: string\n }\n features?: any\n feedback?: any\n goback?: any\n help?: boolean\n hideNotes?: boolean\n hideRightMenu?: boolean\n hideRulers?: boolean\n integrationMode?: string\n logo?: {\n image?: string\n imageDark?: string\n imageLight?: string\n imageEmbedded?: string\n url?: string\n visible?: boolean\n }\n macros?: boolean\n macrosMode?: string\n mentionShare?: boolean\n mobileForceView?: boolean\n plugins?: boolean\n review?: {\n hideReviewDisplay?: boolean\n hoverMode?: boolean\n reviewDisplay?: string\n showReviewChanges?: boolean\n trackChanges?: boolean\n }\n submitForm?: boolean\n toolbarHideFileName?: boolean\n toolbarNoTabs?: boolean\n uiTheme?: string\n unit?: string\n zoom?: number\n about?: boolean\n }\n embedded?: {\n embedUrl?: string\n fullscreenUrl?: string\n saveUrl?: string\n shareUrl?: string\n toolbarDocked?: string\n }\n plugins?: {\n autostart?: string[]\n options?: {\n all?: any\n pluginGuid: any\n }\n pluginsData?: string[]\n }\n }\n events?: {\n onAppReady?: (event: object) => void\n onCollaborativeChanges?: (event: object) => void\n onDocumentReady?: (event: object) => void\n onDocumentStateChange?: (event: object) => void\n onDownloadAs?: (event: object) => void\n onError?: (event: object) => void\n onInfo?: (event: object) => void\n onMetaChange?: (event: object) => void\n onMakeActionLink?: (event: object) => void\n onRequestRefreshFile?: (event: object) => void\n onPluginsReady?: (event: object) => void\n onReady?: (event: object) => void\n onRequestClose?: (event: object) => void\n onRequestCreateNew?: (event: object) => void\n onRequestEditRights?: (event: object) => void\n onRequestHistory?: (event: object) => void\n onRequestHistoryClose?: (event: object) => void\n onRequestHistoryData?: (event: object) => void\n onRequestInsertImage?: (event: object) => void\n onRequestOpen?: (event: object) => void\n onRequestReferenceData?: (event: object) => void\n onRequestReferenceSource?: (event: object) => void\n onRequestRename?: (event: object) => void\n onRequestRestore?: (event: object) => void\n onRequestSaveAs?: (event: object) => void\n onRequestSelectDocument?: (event: object) => void\n onRequestSelectSpreadsheet?: (event: object) => void\n onRequestSendNotify?: (event: object) => void\n onRequestSharingSettings?: (event: object) => void\n onRequestStartFilling: (event: object) => void\n onRequestUsers?: (event: object) => void\n onSubmit?: (event: object) => void\n onWarning?: (event: object) => void\n }\n}\n\nexport interface OnlyOfficeCallBack {\n /* documentation : https://api.onlyoffice.com/docs/docs-api/usage-api/callback-handler/ */\n key: string // document key\n /*\n status:\n 1 - document is being edited\n 2 - document is ready for saving\n 3 - document saving error has occurred\n 4 - document is closed with no changes\n 6 - document is being edited, but the current document state is saved\n 7 - error has occurred while force saving the document\n */\n status: 1 | 2 | 3 | 4 | 6 | 7\n url?: string // link to download the modified version (for status: 2, 3, 6 or 7)\n notmodified?: boolean // only with status 2\n /*\n actions:\n 0 - the user disconnects from the document co-editing\n 1 - the new user connects to the document co-editing\n 2 - the user clicks the forcesave button.\n */\n actions?: { type: 0 | 1 | 2; userid: string }[]\n forcesavetype?: 0 | 1 | 2 | 3 // The type is present when the status value is equal to 6 or 7 only\n /*\n forcesavetype:\n 0 - to the command service\n 1 - each time the saving is done (e.g. the Save button is clicked), which is only available when the forcesave option is set to true\n 2 - by timer with the settings from the server config\n 3 - each time the form is submitted (e.g. the Complete & Submit button is clicked)\n */\n users?: string[] // when multiple users are editing the document\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
@@ -131,7 +131,7 @@ let FilesContentManager = class FilesContentManager {
131
131
  }
132
132
  }
133
133
  } catch (e) {
134
- this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`);
134
+ this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse: ${dir} - ${e}`);
135
135
  }
136
136
  }
137
137
  async analyzeFile(realPath, context, isRootFile = false) {
@@ -144,7 +144,7 @@ let FilesContentManager = class FilesContentManager {
144
144
  try {
145
145
  stats = await _promises.default.stat(realPath);
146
146
  } catch (e) {
147
- this.logger.warn(`${this.analyzeFile.name} - unable to stats ${realPath} : ${e}`);
147
+ this.logger.warn(`${this.analyzeFile.name} - unable to stats: ${realPath} - ${e}`);
148
148
  return null;
149
149
  }
150
150
  if (stats.size === 0 || stats.size > this.maxDocumentSize) {
@@ -181,7 +181,7 @@ let FilesContentManager = class FilesContentManager {
181
181
  });
182
182
  return content.length ? content : null;
183
183
  } catch (e) {
184
- this.logger.warn(`${this.parseContent.name} - unable to index : ${rPath} : ${e}`);
184
+ this.logger.warn(`${this.parseContent.name} - unable to index: ${rPath} - ${e}`);
185
185
  }
186
186
  return null;
187
187
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-content-manager.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 { Injectable, Logger } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { indexableExtensions, shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { FileIndexContext, FileParseContext } from '../interfaces/file-parse-index'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { docTextify } from '../utils/doc-textify/doc-textify'\nimport { getMimeType } from '../utils/files'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesContentManager {\n private readonly maxDocumentSize = 150 * 1_000_000\n private readonly logger = new Logger(FilesContentManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser\n ) {}\n\n async parseAndIndexAllFiles(): Promise<void> {\n const indexSuffixes: string[] = []\n for await (const [id, type, paths] of this.filesParser.allPaths()) {\n let indexSuffix: string\n switch (type) {\n case 'user':\n indexSuffix = `${userIndexPrefix}${id}`\n break\n case 'space':\n indexSuffix = `${spaceIndexPrefix}${id}`\n break\n case 'share':\n indexSuffix = `${shareIndexPrefix}${id}`\n }\n try {\n await this.indexFiles(indexSuffix, paths)\n } catch (e) {\n this.logger.error(`${this.parseAndIndexAllFiles.name} : ${e}`)\n }\n indexSuffixes.push(indexSuffix)\n }\n // clean up old tables\n await this.filesIndexer.cleanIndexes(indexSuffixes)\n }\n\n private async indexFiles(indexSuffix: string, paths: FileParseContext[]): Promise<void> {\n const indexName = this.filesIndexer.getIndexName(indexSuffix)\n if (!(await this.filesIndexer.createIndex(indexName))) {\n return\n }\n const context: FileIndexContext = {\n indexSuffix: indexSuffix,\n pathPrefix: '',\n regexBasePath: undefined,\n db: await this.filesIndexer.getRecordStats(indexName),\n fs: new Set()\n }\n let indexedRecords = 0\n let errorRecords = 0\n\n for (const p of paths) {\n context.regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n context.pathPrefix = p.pathPrefix || ''\n if (!p.isDir) {\n // Handles the space root file or shared file case\n const rootFileContent = await this.analyzeFile(p.realPath, context, true)\n if (rootFileContent !== null) {\n this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${rootFileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n continue\n }\n for await (const fileContent of this.parseFiles(p.realPath, context)) {\n this.filesIndexer.insertRecord(indexName, fileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${fileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n }\n\n if (context.db.size === 0 && indexedRecords === 0) {\n // case when no data\n this.filesIndexer\n .dropIndex(indexName)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to drop index : ${e}`))\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no data, index not stored`)\n } else {\n // clean up old records\n const recordsToDelete: number[] = [...context.db.keys()].filter((key) => !context.fs.has(key))\n if (recordsToDelete.length > 0) {\n this.filesIndexer\n .deleteRecords(indexName, recordsToDelete)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to delete records : ${e}`))\n }\n if (indexedRecords === 0 && errorRecords === 0 && recordsToDelete.length === 0) {\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no new data`)\n } else {\n this.logger.log(\n `${this.indexFiles.name} - ${indexSuffix} - indexed: ${indexedRecords - errorRecords}, errors: ${errorRecords}, deleted: ${recordsToDelete.length}`\n )\n }\n }\n }\n\n private async *parseFiles(dir: string, context: FileIndexContext): AsyncGenerator<FileContent> {\n try {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const realPath = path.join(entry.parentPath, entry.name)\n if (entry.isDirectory()) {\n yield* this.parseFiles(realPath, context)\n continue\n }\n const fileContent = await this.analyzeFile(realPath, context)\n if (fileContent !== null) {\n yield fileContent\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse : ${dir} : ${e}`)\n }\n }\n\n private async analyzeFile(realPath: string, context: FileIndexContext, isRootFile = false): Promise<FileContent> {\n const extension = path.extname(realPath).slice(1).toLowerCase()\n if (!indexableExtensions.has(extension)) return null\n\n const fileName = isRootFile ? path.basename(context.pathPrefix) : path.basename(realPath)\n\n // ignore temporary documents\n if (fileName.startsWith('~$')) return null\n\n let stats: Stats\n try {\n stats = await fs.stat(realPath)\n } catch (e) {\n this.logger.warn(`${this.analyzeFile.name} - unable to stats ${realPath} : ${e}`)\n return null\n }\n if (stats.size === 0 || stats.size > this.maxDocumentSize) {\n return null\n }\n\n const filePath = isRootFile\n ? path.dirname(context.pathPrefix) || '.'\n : path.join(context.pathPrefix, path.dirname(realPath).replace(context.regexBasePath, '') || '.')\n\n const f = context.db.get(stats.ino)\n if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {\n // no changes, store inode id & skip it\n context.fs.add(stats.ino)\n return null\n }\n\n // store inode id\n context.fs.add(stats.ino)\n\n // store the content with null value to not parse it later\n return {\n id: stats.ino,\n path: filePath,\n name: fileName,\n mime: getMimeType(realPath, false),\n size: stats.size,\n mtime: stats.mtime.getTime(),\n content: await this.parseContent(realPath, extension)\n }\n }\n\n private async parseContent(rPath: string, extension: string): Promise<string> {\n try {\n const content = await docTextify(\n rPath,\n { newlineDelimiter: ' ', minCharsToExtract: 10 },\n {\n extension: extension,\n verified: true\n }\n )\n return content.length ? content : null\n } catch (e) {\n this.logger.warn(`${this.parseContent.name} - unable to index : ${rPath} : ${e}`)\n }\n return null\n }\n}\n"],"names":["FilesContentManager","parseAndIndexAllFiles","indexSuffixes","id","type","paths","filesParser","allPaths","indexSuffix","userIndexPrefix","spaceIndexPrefix","shareIndexPrefix","indexFiles","e","logger","error","name","push","filesIndexer","cleanIndexes","indexName","getIndexName","createIndex","context","pathPrefix","regexBasePath","undefined","db","getRecordStats","fs","Set","indexedRecords","errorRecords","p","RegExp","realPath","isDir","rootFileContent","analyzeFile","insertRecord","catch","fileContent","parseFiles","size","dropIndex","log","recordsToDelete","keys","filter","key","has","length","deleteRecords","dir","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","isRootFile","extension","extname","slice","toLowerCase","indexableExtensions","fileName","basename","startsWith","stats","stat","maxDocumentSize","filePath","dirname","replace","f","get","ino","add","mime","getMimeType","mtime","getTime","content","parseContent","rPath","docTextify","newlineDelimiter","minCharsToExtract","verified","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAeYA;;;eAAAA;;;wBAbsB;iEACpB;iEAEE;0BACwE;8BAE5D;4BAEF;uBACC;oCACA;;;;;;;;;;;;;;;AAGrB,IAAA,AAAMA,sBAAN,MAAMA;IASX,MAAMC,wBAAuC;QAC3C,MAAMC,gBAA0B,EAAE;QAClC,WAAW,MAAM,CAACC,IAAIC,MAAMC,MAAM,IAAI,IAAI,CAACC,WAAW,CAACC,QAAQ,GAAI;YACjE,IAAIC;YACJ,OAAQJ;gBACN,KAAK;oBACHI,cAAc,GAAGC,yBAAe,GAAGN,IAAI;oBACvC;gBACF,KAAK;oBACHK,cAAc,GAAGE,0BAAgB,GAAGP,IAAI;oBACxC;gBACF,KAAK;oBACHK,cAAc,GAAGG,0BAAgB,GAAGR,IAAI;YAC5C;YACA,IAAI;gBACF,MAAM,IAAI,CAACS,UAAU,CAACJ,aAAaH;YACrC,EAAE,OAAOQ,GAAG;gBACV,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACd,qBAAqB,CAACe,IAAI,CAAC,GAAG,EAAEH,GAAG;YAC/D;YACAX,cAAce,IAAI,CAACT;QACrB;QACA,sBAAsB;QACtB,MAAM,IAAI,CAACU,YAAY,CAACC,YAAY,CAACjB;IACvC;IAEA,MAAcU,WAAWJ,WAAmB,EAAEH,KAAyB,EAAiB;QACtF,MAAMe,YAAY,IAAI,CAACF,YAAY,CAACG,YAAY,CAACb;QACjD,IAAI,CAAE,MAAM,IAAI,CAACU,YAAY,CAACI,WAAW,CAACF,YAAa;YACrD;QACF;QACA,MAAMG,UAA4B;YAChCf,aAAaA;YACbgB,YAAY;YACZC,eAAeC;YACfC,IAAI,MAAM,IAAI,CAACT,YAAY,CAACU,cAAc,CAACR;YAC3CS,IAAI,IAAIC;QACV;QACA,IAAIC,iBAAiB;QACrB,IAAIC,eAAe;QAEnB,KAAK,MAAMC,KAAK5B,MAAO;YACrBkB,QAAQE,aAAa,GAAG,IAAIS,OAAO,CAAC,GAAG,EAAED,EAAEE,QAAQ,CAAC,EAAE,CAAC;YACvDZ,QAAQC,UAAU,GAAGS,EAAET,UAAU,IAAI;YACrC,IAAI,CAACS,EAAEG,KAAK,EAAE;gBACZ,kDAAkD;gBAClD,MAAMC,kBAAkB,MAAM,IAAI,CAACC,WAAW,CAACL,EAAEE,QAAQ,EAAEZ,SAAS;gBACpE,IAAIc,oBAAoB,MAAM;oBAC5B,IAAI,CAACnB,YAAY,CAACqB,YAAY,CAACnB,WAAWiB,iBAAiBG,KAAK,CAAC,CAAC3B;wBAChEmB;wBACA,IAAI,CAAClB,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,GAAG,EAAE6B,gBAAgBrB,IAAI,CAAC,GAAG,EAAEH,GAAG;oBAC/F;oBACAkB;gBACF;gBACA;YACF;YACA,WAAW,MAAMU,eAAe,IAAI,CAACC,UAAU,CAACT,EAAEE,QAAQ,EAAEZ,SAAU;gBACpE,IAAI,CAACL,YAAY,CAACqB,YAAY,CAACnB,WAAWqB,aAAaD,KAAK,CAAC,CAAC3B;oBAC5DmB;oBACA,IAAI,CAAClB,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,GAAG,EAAEiC,YAAYzB,IAAI,CAAC,GAAG,EAAEH,GAAG;gBAC3F;gBACAkB;YACF;QACF;QAEA,IAAIR,QAAQI,EAAE,CAACgB,IAAI,KAAK,KAAKZ,mBAAmB,GAAG;YACjD,oBAAoB;YACpB,IAAI,CAACb,YAAY,CACd0B,SAAS,CAACxB,WACVoB,KAAK,CAAC,CAAC3B,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,0BAA0B,EAAEK,GAAG;YACjH,IAAI,CAACC,MAAM,CAAC+B,GAAG,CAAC,GAAG,IAAI,CAACjC,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,4BAA4B,CAAC;QACxF,OAAO;YACL,uBAAuB;YACvB,MAAMsC,kBAA4B;mBAAIvB,QAAQI,EAAE,CAACoB,IAAI;aAAG,CAACC,MAAM,CAAC,CAACC,MAAQ,CAAC1B,QAAQM,EAAE,CAACqB,GAAG,CAACD;YACzF,IAAIH,gBAAgBK,MAAM,GAAG,GAAG;gBAC9B,IAAI,CAACjC,YAAY,CACdkC,aAAa,CAAChC,WAAW0B,iBACzBN,KAAK,CAAC,CAAC3B,IAAa,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACH,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,8BAA8B,EAAEK,GAAG;YACvH;YACA,IAAIkB,mBAAmB,KAAKC,iBAAiB,KAAKc,gBAAgBK,MAAM,KAAK,GAAG;gBAC9E,IAAI,CAACrC,MAAM,CAAC+B,GAAG,CAAC,GAAG,IAAI,CAACjC,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,cAAc,CAAC;YAC1E,OAAO;gBACL,IAAI,CAACM,MAAM,CAAC+B,GAAG,CACb,GAAG,IAAI,CAACjC,UAAU,CAACI,IAAI,CAAC,GAAG,EAAER,YAAY,YAAY,EAAEuB,iBAAiBC,aAAa,UAAU,EAAEA,aAAa,WAAW,EAAEc,gBAAgBK,MAAM,EAAE;YAEvJ;QACF;IACF;IAEA,OAAeT,WAAWW,GAAW,EAAE9B,OAAyB,EAA+B;QAC7F,IAAI;YACF,KAAK,MAAM+B,SAAS,CAAA,MAAMzB,iBAAE,CAAC0B,OAAO,CAACF,KAAK;gBAAEG,eAAe;YAAK,EAAC,EAAG;gBAClE,MAAMrB,WAAWsB,iBAAI,CAACC,IAAI,CAACJ,MAAMK,UAAU,EAAEL,MAAMtC,IAAI;gBACvD,IAAIsC,MAAMM,WAAW,IAAI;oBACvB,OAAO,IAAI,CAAClB,UAAU,CAACP,UAAUZ;oBACjC;gBACF;gBACA,MAAMkB,cAAc,MAAM,IAAI,CAACH,WAAW,CAACH,UAAUZ;gBACrD,IAAIkB,gBAAgB,MAAM;oBACxB,MAAMA;gBACR;YACF;QACF,EAAE,OAAO5B,GAAG;YACV,IAAI,CAACC,MAAM,CAAC+C,IAAI,CAAC,GAAG,IAAI,CAACnB,UAAU,CAAC1B,IAAI,CAAC,GAAG,EAAEO,QAAQf,WAAW,CAAC,qBAAqB,EAAE6C,IAAI,GAAG,EAAExC,GAAG;QACvG;IACF;IAEA,MAAcyB,YAAYH,QAAgB,EAAEZ,OAAyB,EAAEuC,aAAa,KAAK,EAAwB;QAC/G,MAAMC,YAAYN,iBAAI,CAACO,OAAO,CAAC7B,UAAU8B,KAAK,CAAC,GAAGC,WAAW;QAC7D,IAAI,CAACC,6BAAmB,CAACjB,GAAG,CAACa,YAAY,OAAO;QAEhD,MAAMK,WAAWN,aAAaL,iBAAI,CAACY,QAAQ,CAAC9C,QAAQC,UAAU,IAAIiC,iBAAI,CAACY,QAAQ,CAAClC;QAEhF,6BAA6B;QAC7B,IAAIiC,SAASE,UAAU,CAAC,OAAO,OAAO;QAEtC,IAAIC;QACJ,IAAI;YACFA,QAAQ,MAAM1C,iBAAE,CAAC2C,IAAI,CAACrC;QACxB,EAAE,OAAOtB,GAAG;YACV,IAAI,CAACC,MAAM,CAAC+C,IAAI,CAAC,GAAG,IAAI,CAACvB,WAAW,CAACtB,IAAI,CAAC,mBAAmB,EAAEmB,SAAS,GAAG,EAAEtB,GAAG;YAChF,OAAO;QACT;QACA,IAAI0D,MAAM5B,IAAI,KAAK,KAAK4B,MAAM5B,IAAI,GAAG,IAAI,CAAC8B,eAAe,EAAE;YACzD,OAAO;QACT;QAEA,MAAMC,WAAWZ,aACbL,iBAAI,CAACkB,OAAO,CAACpD,QAAQC,UAAU,KAAK,MACpCiC,iBAAI,CAACC,IAAI,CAACnC,QAAQC,UAAU,EAAEiC,iBAAI,CAACkB,OAAO,CAACxC,UAAUyC,OAAO,CAACrD,QAAQE,aAAa,EAAE,OAAO;QAE/F,MAAMoD,IAAItD,QAAQI,EAAE,CAACmD,GAAG,CAACP,MAAMQ,GAAG;QAClC,IAAIF,KAAKA,EAAElC,IAAI,KAAK4B,MAAM5B,IAAI,IAAIkC,EAAEpB,IAAI,KAAKiB,YAAYG,EAAE7D,IAAI,KAAKoD,UAAU;YAC5E,uCAAuC;YACvC7C,QAAQM,EAAE,CAACmD,GAAG,CAACT,MAAMQ,GAAG;YACxB,OAAO;QACT;QAEA,iBAAiB;QACjBxD,QAAQM,EAAE,CAACmD,GAAG,CAACT,MAAMQ,GAAG;QAExB,0DAA0D;QAC1D,OAAO;YACL5E,IAAIoE,MAAMQ,GAAG;YACbtB,MAAMiB;YACN1D,MAAMoD;YACNa,MAAMC,IAAAA,kBAAW,EAAC/C,UAAU;YAC5BQ,MAAM4B,MAAM5B,IAAI;YAChBwC,OAAOZ,MAAMY,KAAK,CAACC,OAAO;YAC1BC,SAAS,MAAM,IAAI,CAACC,YAAY,CAACnD,UAAU4B;QAC7C;IACF;IAEA,MAAcuB,aAAaC,KAAa,EAAExB,SAAiB,EAAmB;QAC5E,IAAI;YACF,MAAMsB,UAAU,MAAMG,IAAAA,sBAAU,EAC9BD,OACA;gBAAEE,kBAAkB;gBAAKC,mBAAmB;YAAG,GAC/C;gBACE3B,WAAWA;gBACX4B,UAAU;YACZ;YAEF,OAAON,QAAQlC,MAAM,GAAGkC,UAAU;QACpC,EAAE,OAAOxE,GAAG;YACV,IAAI,CAACC,MAAM,CAAC+C,IAAI,CAAC,GAAG,IAAI,CAACyB,YAAY,CAACtE,IAAI,CAAC,qBAAqB,EAAEuE,MAAM,GAAG,EAAE1E,GAAG;QAClF;QACA,OAAO;IACT;IA5KA,YACE,AAAiBK,YAA0B,EAC3C,AAAiBZ,WAAwB,CACzC;aAFiBY,eAAAA;aACAZ,cAAAA;aALFmE,kBAAkB,MAAM;aACxB3D,SAAS,IAAI8E,cAAM,CAAC5F,oBAAoBgB,IAAI;IAK1D;AA0KL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-content-manager.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 { Injectable, Logger } from '@nestjs/common'\nimport fs from 'fs/promises'\nimport { Stats } from 'node:fs'\nimport path from 'node:path'\nimport { indexableExtensions, shareIndexPrefix, spaceIndexPrefix, userIndexPrefix } from '../constants/indexing'\nimport { FileIndexContext, FileParseContext } from '../interfaces/file-parse-index'\nimport { FilesIndexer } from '../models/files-indexer'\nimport { FileContent } from '../schemas/file-content.interface'\nimport { docTextify } from '../utils/doc-textify/doc-textify'\nimport { getMimeType } from '../utils/files'\nimport { FilesParser } from './files-parser.service'\n\n@Injectable()\nexport class FilesContentManager {\n private readonly maxDocumentSize = 150 * 1_000_000\n private readonly logger = new Logger(FilesContentManager.name)\n\n constructor(\n private readonly filesIndexer: FilesIndexer,\n private readonly filesParser: FilesParser\n ) {}\n\n async parseAndIndexAllFiles(): Promise<void> {\n const indexSuffixes: string[] = []\n for await (const [id, type, paths] of this.filesParser.allPaths()) {\n let indexSuffix: string\n switch (type) {\n case 'user':\n indexSuffix = `${userIndexPrefix}${id}`\n break\n case 'space':\n indexSuffix = `${spaceIndexPrefix}${id}`\n break\n case 'share':\n indexSuffix = `${shareIndexPrefix}${id}`\n }\n try {\n await this.indexFiles(indexSuffix, paths)\n } catch (e) {\n this.logger.error(`${this.parseAndIndexAllFiles.name} : ${e}`)\n }\n indexSuffixes.push(indexSuffix)\n }\n // clean up old tables\n await this.filesIndexer.cleanIndexes(indexSuffixes)\n }\n\n private async indexFiles(indexSuffix: string, paths: FileParseContext[]): Promise<void> {\n const indexName = this.filesIndexer.getIndexName(indexSuffix)\n if (!(await this.filesIndexer.createIndex(indexName))) {\n return\n }\n const context: FileIndexContext = {\n indexSuffix: indexSuffix,\n pathPrefix: '',\n regexBasePath: undefined,\n db: await this.filesIndexer.getRecordStats(indexName),\n fs: new Set()\n }\n let indexedRecords = 0\n let errorRecords = 0\n\n for (const p of paths) {\n context.regexBasePath = new RegExp(`^/?${p.realPath}/?`)\n context.pathPrefix = p.pathPrefix || ''\n if (!p.isDir) {\n // Handles the space root file or shared file case\n const rootFileContent = await this.analyzeFile(p.realPath, context, true)\n if (rootFileContent !== null) {\n this.filesIndexer.insertRecord(indexName, rootFileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${rootFileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n continue\n }\n for await (const fileContent of this.parseFiles(p.realPath, context)) {\n this.filesIndexer.insertRecord(indexName, fileContent).catch((e: Error) => {\n errorRecords++\n this.logger.error(`${this.indexFiles.name} - ${indexSuffix} | ${fileContent.name} : ${e}`)\n })\n indexedRecords++\n }\n }\n\n if (context.db.size === 0 && indexedRecords === 0) {\n // case when no data\n this.filesIndexer\n .dropIndex(indexName)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to drop index : ${e}`))\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no data, index not stored`)\n } else {\n // clean up old records\n const recordsToDelete: number[] = [...context.db.keys()].filter((key) => !context.fs.has(key))\n if (recordsToDelete.length > 0) {\n this.filesIndexer\n .deleteRecords(indexName, recordsToDelete)\n .catch((e: Error) => this.logger.error(`${this.indexFiles.name} - ${indexSuffix} - unable to delete records : ${e}`))\n }\n if (indexedRecords === 0 && errorRecords === 0 && recordsToDelete.length === 0) {\n this.logger.log(`${this.indexFiles.name} - ${indexSuffix} - no new data`)\n } else {\n this.logger.log(\n `${this.indexFiles.name} - ${indexSuffix} - indexed: ${indexedRecords - errorRecords}, errors: ${errorRecords}, deleted: ${recordsToDelete.length}`\n )\n }\n }\n }\n\n private async *parseFiles(dir: string, context: FileIndexContext): AsyncGenerator<FileContent> {\n try {\n for (const entry of await fs.readdir(dir, { withFileTypes: true })) {\n const realPath = path.join(entry.parentPath, entry.name)\n if (entry.isDirectory()) {\n yield* this.parseFiles(realPath, context)\n continue\n }\n const fileContent = await this.analyzeFile(realPath, context)\n if (fileContent !== null) {\n yield fileContent\n }\n }\n } catch (e) {\n this.logger.warn(`${this.parseFiles.name} - ${context.indexSuffix} - unable to parse: ${dir} - ${e}`)\n }\n }\n\n private async analyzeFile(realPath: string, context: FileIndexContext, isRootFile = false): Promise<FileContent> {\n const extension = path.extname(realPath).slice(1).toLowerCase()\n if (!indexableExtensions.has(extension)) return null\n\n const fileName = isRootFile ? path.basename(context.pathPrefix) : path.basename(realPath)\n\n // ignore temporary documents\n if (fileName.startsWith('~$')) return null\n\n let stats: Stats\n try {\n stats = await fs.stat(realPath)\n } catch (e) {\n this.logger.warn(`${this.analyzeFile.name} - unable to stats: ${realPath} - ${e}`)\n return null\n }\n if (stats.size === 0 || stats.size > this.maxDocumentSize) {\n return null\n }\n\n const filePath = isRootFile\n ? path.dirname(context.pathPrefix) || '.'\n : path.join(context.pathPrefix, path.dirname(realPath).replace(context.regexBasePath, '') || '.')\n\n const f = context.db.get(stats.ino)\n if (f && f.size === stats.size && f.path === filePath && f.name === fileName) {\n // no changes, store inode id & skip it\n context.fs.add(stats.ino)\n return null\n }\n\n // store inode id\n context.fs.add(stats.ino)\n\n // store the content with null value to not parse it later\n return {\n id: stats.ino,\n path: filePath,\n name: fileName,\n mime: getMimeType(realPath, false),\n size: stats.size,\n mtime: stats.mtime.getTime(),\n content: await this.parseContent(realPath, extension)\n }\n }\n\n private async parseContent(rPath: string, extension: string): Promise<string> {\n try {\n const content = await docTextify(\n rPath,\n { newlineDelimiter: ' ', minCharsToExtract: 10 },\n {\n extension: extension,\n verified: true\n }\n )\n return content.length ? content : null\n } catch (e) {\n this.logger.warn(`${this.parseContent.name} - unable to index: ${rPath} - ${e}`)\n }\n return null\n }\n}\n"],"names":["FilesContentManager","parseAndIndexAllFiles","indexSuffixes","id","type","paths","filesParser","allPaths","indexSuffix","userIndexPrefix","spaceIndexPrefix","shareIndexPrefix","indexFiles","e","logger","error","name","push","filesIndexer","cleanIndexes","indexName","getIndexName","createIndex","context","pathPrefix","regexBasePath","undefined","db","getRecordStats","fs","Set","indexedRecords","errorRecords","p","RegExp","realPath","isDir","rootFileContent","analyzeFile","insertRecord","catch","fileContent","parseFiles","size","dropIndex","log","recordsToDelete","keys","filter","key","has","length","deleteRecords","dir","entry","readdir","withFileTypes","path","join","parentPath","isDirectory","warn","isRootFile","extension","extname","slice","toLowerCase","indexableExtensions","fileName","basename","startsWith","stats","stat","maxDocumentSize","filePath","dirname","replace","f","get","ino","add","mime","getMimeType","mtime","getTime","content","parseContent","rPath","docTextify","newlineDelimiter","minCharsToExtract","verified","Logger"],"mappings":"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"}
@@ -36,7 +36,7 @@ function _ts_metadata(k, v) {
36
36
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
37
37
  }
38
38
  let FilesLockManager = class FilesLockManager {
39
- async create(user, dbFile, depth, ttl, davLock) {
39
+ async create(user, dbFile, depth, davLock, ttl) {
40
40
  let token;
41
41
  let lockscope;
42
42
  if (davLock) {
@@ -62,7 +62,7 @@ let FilesLockManager = class FilesLockManager {
62
62
  }
63
63
  throw new Error(e);
64
64
  }
65
- ttl ??= FilesLockManager.defaultLockTimeoutSeconds;
65
+ ttl ??= _cache.CACHE_LOCK_DEFAULT_TTL;
66
66
  const key = `${_cache.CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, {
67
67
  depth: depth,
68
68
  token: token
@@ -83,6 +83,38 @@ let FilesLockManager = class FilesLockManager {
83
83
  lock
84
84
  ];
85
85
  }
86
+ async createOrRefresh(user, dbFile, depth, ttl) {
87
+ // Returns: [created, lock]
88
+ ttl ??= _cache.CACHE_LOCK_DEFAULT_TTL;
89
+ const locks = await this.getLocksByPath(dbFile);
90
+ // Check the existing lock and refresh it if needed
91
+ if (locks.length > 0) {
92
+ for (const lock of locks){
93
+ if (lock.owner.id === user.id) {
94
+ // Refresh if more than half of the TTL has passed
95
+ const mustRefresh = lock.expiration - (0, _shared.currentTimeStamp)() < ttl / 2;
96
+ if (mustRefresh) {
97
+ this.refreshLockTimeout(lock, ttl).catch((e)=>this.logger.error(`${this.createOrRefresh.name} - ${e}`));
98
+ }
99
+ } else {
100
+ throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
101
+ }
102
+ }
103
+ return [
104
+ false,
105
+ locks[0]
106
+ ];
107
+ }
108
+ // Create the lock
109
+ const [ok, lock] = await this.create(user, dbFile, depth, null, ttl);
110
+ if (!ok) {
111
+ throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
112
+ }
113
+ return [
114
+ true,
115
+ lock
116
+ ];
117
+ }
86
118
  removeLock(key) {
87
119
  this.logger.verbose(`${this.removeLock.name} - ${key}`);
88
120
  return this.cache.del(key);
@@ -159,7 +191,7 @@ let FilesLockManager = class FilesLockManager {
159
191
  }
160
192
  async checkConflicts(dbFile, depth, options) {
161
193
  /* Checks if a file could be modified, created, moved, or deleted
162
- Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modifications
194
+ Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modification
163
195
  Returns on the first conflict (compliant with the RFC 4918)
164
196
  */ for await (const l of this.searchParentLocks(dbFile, {
165
197
  includeRoot: true,
@@ -186,6 +218,28 @@ let FilesLockManager = class FilesLockManager {
186
218
  }
187
219
  }
188
220
  }
221
+ async *searchChildLocks(dbFile) {
222
+ const props = this.genSuffixKey(dbFile, {
223
+ ignorePath: true
224
+ });
225
+ const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`;
226
+ this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`);
227
+ const keys = await this.searchKeysByPath(path, props);
228
+ if (keys.length) {
229
+ for (const l of (await this.cache.mget(keys)).filter(Boolean)){
230
+ this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`);
231
+ yield l;
232
+ }
233
+ }
234
+ }
235
+ convertLockToFileLockProps(lock) {
236
+ if (!lock) return null;
237
+ return {
238
+ owner: lock?.davLock?.owner || `${lock.owner.fullName} (${lock.owner.email})`,
239
+ ownerLogin: lock.owner.login,
240
+ isExclusive: lock?.davLock?.lockscope ? lock?.davLock?.lockscope === _webdav.LOCK_SCOPE.EXCLUSIVE : true
241
+ };
242
+ }
189
243
  async *searchParentLocks(dbFile, options = {}) {
190
244
  const props = this.genSuffixKey(dbFile, {
191
245
  ignorePath: true
@@ -209,20 +263,6 @@ let FilesLockManager = class FilesLockManager {
209
263
  path = (0, _files.dirName)(path);
210
264
  }
211
265
  }
212
- async *searchChildLocks(dbFile) {
213
- const props = this.genSuffixKey(dbFile, {
214
- ignorePath: true
215
- });
216
- const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`;
217
- this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`);
218
- const keys = await this.searchKeysByPath(path, props);
219
- if (keys.length) {
220
- for (const l of (await this.cache.mget(keys)).filter(Boolean)){
221
- this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`);
222
- yield l;
223
- }
224
- }
225
- }
226
266
  async searchKeyByToken(token) {
227
267
  const keys = await this.cache.keys(`${_cache.CACHE_LOCK_PREFIX}|token:${token}|*`);
228
268
  if (!keys.length) {
@@ -258,10 +298,7 @@ let FilesLockManager = class FilesLockManager {
258
298
  }
259
299
  constructor(cache){
260
300
  this.cache = cache;
261
- this.logger = new _common.Logger(FilesLockManager.name);
262
- }
263
- };
264
- /* Philosophy
301
+ /* Philosophy
265
302
  Currently this manager only handle conflicting locks between multiple users, not between clients
266
303
  - The locks created from api
267
304
  * They do not contain a token key or a davLock property
@@ -273,7 +310,9 @@ let FilesLockManager = class FilesLockManager {
273
310
  * If created with WebDAV, they are stored with a token and a davLock property
274
311
  * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null
275
312
  Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock
276
- */ FilesLockManager.defaultLockTimeoutSeconds = 86400; // 1 day
313
+ */ this.logger = new _common.Logger(FilesLockManager.name);
314
+ }
315
+ };
277
316
  FilesLockManager = _ts_decorate([
278
317
  (0, _common.Injectable)(),
279
318
  _ts_metadata("design:type", Function),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-lock-manager.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 { Injectable, Logger } from '@nestjs/common'\nimport crypto from 'node:crypto'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { DEPTH, LOCK_DEPTH, LOCK_PREFIX, LOCK_SCOPE } from '../../webdav/constants/webdav'\nimport { WebDAVLock } from '../../webdav/interfaces/webdav.interface'\nimport { CACHE_LOCK_PREFIX } from '../constants/cache'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock } from '../interfaces/file-lock.interface'\nimport { LockConflict } from '../models/file-lock-error'\nimport { files } from '../schemas/files.schema'\nimport { dirName, fileName } from '../utils/files'\n\n@Injectable()\nexport class FilesLockManager {\n /* Philosophy\n Currently this manager only handle conflicting locks between multiple users, not between clients\n - The locks created from api\n * They do not contain a token key or a davLock property\n * They are exclusive only\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n - The locks created from WebDAV or OnlyOffice are stored with a token and a davLock property\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n * They can be exclusive (WebDAV) or shared (OnlyOffice)\n * If created with WebDAV, they are stored with a token and a davLock property\n * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null\n Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock\n */\n public static readonly defaultLockTimeoutSeconds = 86400 // 1 day\n private readonly logger = new Logger(FilesLockManager.name)\n\n constructor(private readonly cache: Cache) {}\n\n async create(user: UserModel, dbFile: FileDBProps, depth: LOCK_DEPTH, ttl?: number, davLock?: WebDAVLock): Promise<[boolean, FileLock]> {\n let token: string\n let lockscope: LOCK_SCOPE\n if (davLock) {\n // webdav context\n davLock.locktoken = this.genDAVToken()\n token = davLock.locktoken\n lockscope = davLock.lockscope\n } else {\n // api context\n token = null\n lockscope = null\n }\n try {\n await this.checkConflicts(dbFile, depth, { lockScope: lockscope })\n } catch (e) {\n if (e instanceof LockConflict) {\n return [false, e.lock]\n }\n throw new Error(e)\n }\n ttl ??= FilesLockManager.defaultLockTimeoutSeconds\n const key = `${CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, { depth: depth, token: token })}`\n const expiration = Math.floor(currentTimeStamp() + ttl)\n const lock: FileLock = {\n owner: user.asOwner(),\n dbFilePath: dbFile.path,\n key: key,\n depth: depth,\n expiration: expiration,\n davLock: davLock\n }\n this.logger.verbose(`${this.create.name} - ${key}`)\n await this.cache.set(key, lock, ttl)\n return [true, lock]\n }\n\n removeLock(key: string): Promise<boolean> {\n this.logger.verbose(`${this.removeLock.name} - ${key}`)\n return this.cache.del(key)\n }\n\n async removeChildLocks(user: UserModel, dbFile: FileDBProps) {\n const ownedLockKeys: string[] = []\n for await (const lock of this.searchChildLocks(dbFile)) {\n if (user.id === lock.owner.id) {\n ownedLockKeys.push(lock.key)\n continue\n }\n const conflict = `cannot remove conflicting child lock : ${dbFile.path} (${user.login}) -> ${lock.dbFilePath} (${lock.owner.login})`\n this.logger.debug(`${this.removeChildLocks.name} - ${conflict}`)\n throw new LockConflict(lock, conflict)\n }\n for (const key of ownedLockKeys) {\n this.logger.verbose(`${this.removeChildLocks.name} - child locks: ${key}`)\n await this.removeLock(key)\n }\n }\n\n async isLockedWithToken(token: string, dbFilePath: string): Promise<FileLock> {\n // check if url (or any of its parents) is locked by the token\n const lock = await this.getLockByToken(token)\n return lock ? (dbFilePath.startsWith(lock.dbFilePath) ? lock : null) : null\n }\n\n async browseParentChildLocks(dbFile: FileDBProps, includeRoot = true): Promise<Record<string, FileLock>> {\n // find child locks inside the path\n const childLocks: Record<string, FileLock> = includeRoot ? await this.browseLocks(dbFile) : {}\n const lengthFilter = dbFile.path === '.' ? 1 : dbFile.path.split('/').length + 1\n for await (const lock of this.searchChildLocks(dbFile)) {\n // filter child locks on length\n if (lengthFilter === lock.dbFilePath.split('/').length) {\n // !!! locks with shared scope can have the same file name, in this case we only keep the first entry\n const dbFileName = fileName(lock.dbFilePath)\n if (!(dbFileName in childLocks)) {\n childLocks[fileName(lock.dbFilePath)] = lock\n }\n }\n }\n return childLocks\n }\n\n async browseLocks(dbFile: FileDBProps): Promise<Record<string, FileLock>> {\n return Object.fromEntries((await this.getLocksByPath(dbFile)).map((l) => [fileName(l.dbFilePath), l]))\n }\n\n async refreshLockTimeout(lock: FileLock, ttl: number) {\n lock.expiration = currentTimeStamp() + ttl\n this.cache.set(lock.key, lock, ttl).catch((e: Error) => this.logger.error(`${this.refreshLockTimeout.name} - ${e}`))\n }\n\n async getLockByToken(token: string): Promise<FileLock> {\n const key = await this.searchKeyByToken(token)\n return key ? (await this.cache.get(key)) || null : null\n }\n\n async getLocksByPath(dbFile: FileDBProps): Promise<FileLock[]> {\n if (dbFile.path !== '.') {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const keys = await this.searchKeysByPath(dbFile.path, props)\n if (keys.length) {\n return (await this.cache.mget(keys)).filter(Boolean)\n }\n }\n return []\n }\n\n async isPathLocked(dbFile: FileDBProps): Promise<boolean> {\n if (dbFile.path !== '.') return false\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n return !!(await this.searchKeysByPath(dbFile.path, props)).length\n }\n\n async checkConflicts(\n dbFile: FileDBProps,\n depth: LOCK_DEPTH,\n options?: { userId?: number; lockScope?: LOCK_SCOPE; lockTokens?: string[] }\n ): Promise<void> {\n /* Checks if a file could be modified, created, moved, or deleted\n Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modifications\n Returns on the first conflict (compliant with the RFC 4918)\n */\n for await (const l of this.searchParentLocks(dbFile, { includeRoot: true, depth: DEPTH.INFINITY })) {\n if (options?.lockScope && options?.lockScope === LOCK_SCOPE.SHARED && l.davLock.lockscope === LOCK_SCOPE.SHARED) {\n // Only compatible with shared locks (even by same owner)\n continue\n }\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting parent lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n if (depth === DEPTH.INFINITY) {\n for await (const l of this.searchChildLocks(dbFile)) {\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting child lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n }\n }\n\n private async *searchParentLocks(dbFile: FileDBProps, options: { includeRoot?: boolean; depth?: LOCK_DEPTH } = {}): AsyncGenerator<FileLock> {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n let path = dbFile.path\n const parentPath = dirName(path)\n this.logger.verbose(`${this.searchParentLocks.name} - (including root : ${options.includeRoot}) : ${path} (${props})`)\n if (!options.includeRoot) {\n path = dirName(path)\n }\n while (path !== '.') {\n // Even if the depth is \"infinite\", the path and the parent path could be locked with depth \"0\"\n const depth = options.depth && (dbFile.path === path || parentPath === path) ? null : options.depth\n const keys = await this.searchKeysByPath(path, props, depth)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath}`)\n yield l\n }\n }\n path = dirName(path)\n }\n }\n\n async *searchChildLocks(dbFile: FileDBProps) {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`\n this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`)\n const keys = await this.searchKeysByPath(path, props)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`)\n yield l\n }\n }\n }\n\n private async searchKeyByToken(token: string): Promise<string> {\n const keys = await this.cache.keys(`${CACHE_LOCK_PREFIX}|token:${token}|*`)\n if (!keys.length) {\n return null\n } else if (keys.length > 1) {\n this.logger.warn(`Several keys found for token : ${token} => ${JSON.stringify(keys)}`)\n }\n return keys[0]\n }\n\n private searchKeysByPath(path: string, props = '*', depth?: LOCK_DEPTH): Promise<string[]> {\n return this.cache.keys(`${CACHE_LOCK_PREFIX}*${depth ? `|depth:${depth}` : ''}|path:${path}|${props}`)\n }\n\n private genDAVToken(): string {\n return `${LOCK_PREFIX}${crypto.randomUUID()}`\n }\n\n private genSuffixKey(dbFile: FileDBProps, options: { ignorePath?: boolean; depth?: LOCK_DEPTH; token?: string } = {}): string {\n // return -> `depth:infinity|path:code/sync-in|spaceId:1` | `token:xxx|depth:0|path:code/sync-in.ts|ownerId:1`\n // ignorePath -> `spaceId:1`\n const suffixes = []\n for (const k of Object.keys(dbFile)\n .filter((k) => k !== files.inTrash.name && dbFile[k] !== null)\n .sort()) {\n if (k === files.path.name) {\n if (options.ignorePath) {\n continue\n }\n suffixes.unshift(`${k}:${dbFile[k]}`)\n } else {\n suffixes.push(`${k}:${dbFile[k]}`)\n }\n }\n if (options.depth) suffixes.unshift(`depth:${options.depth}`)\n if (options.token) suffixes.unshift(`token:${options.token}`)\n return suffixes.join('|')\n }\n}\n"],"names":["FilesLockManager","create","user","dbFile","depth","ttl","davLock","token","lockscope","locktoken","genDAVToken","checkConflicts","lockScope","e","LockConflict","lock","Error","defaultLockTimeoutSeconds","key","CACHE_LOCK_PREFIX","genSuffixKey","expiration","Math","floor","currentTimeStamp","owner","asOwner","dbFilePath","path","logger","verbose","name","cache","set","removeLock","del","removeChildLocks","ownedLockKeys","searchChildLocks","id","push","conflict","login","debug","isLockedWithToken","getLockByToken","startsWith","browseParentChildLocks","includeRoot","childLocks","browseLocks","lengthFilter","split","length","dbFileName","fileName","Object","fromEntries","getLocksByPath","map","l","refreshLockTimeout","catch","error","searchKeyByToken","get","props","ignorePath","keys","searchKeysByPath","mget","filter","Boolean","isPathLocked","options","searchParentLocks","DEPTH","INFINITY","LOCK_SCOPE","SHARED","userId","lockTokens","indexOf","parentPath","dirName","warn","JSON","stringify","LOCK_PREFIX","crypto","randomUUID","suffixes","k","files","inTrash","sort","unshift","join","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-lock-manager.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 { Injectable, Logger } from '@nestjs/common'\nimport crypto from 'node:crypto'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { DEPTH, LOCK_DEPTH, LOCK_PREFIX, LOCK_SCOPE } from '../../webdav/constants/webdav'\nimport { WebDAVLock } from '../../webdav/interfaces/webdav.interface'\nimport { CACHE_LOCK_DEFAULT_TTL, CACHE_LOCK_PREFIX } from '../constants/cache'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock } from '../interfaces/file-lock.interface'\nimport { FileLockProps } from '../interfaces/file-props.interface'\nimport { LockConflict } from '../models/file-lock-error'\nimport { files } from '../schemas/files.schema'\nimport { dirName, fileName } from '../utils/files'\n\n@Injectable()\nexport class FilesLockManager {\n /* Philosophy\n Currently this manager only handle conflicting locks between multiple users, not between clients\n - The locks created from api\n * They do not contain a token key or a davLock property\n * They are exclusive only\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n - The locks created from WebDAV or OnlyOffice are stored with a token and a davLock property\n * They must have a depth of 'infinity' (all children) or '0' (root and root members)\n * They can be exclusive (WebDAV) or shared (OnlyOffice)\n * If created with WebDAV, they are stored with a token and a davLock property\n * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null\n Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock\n */\n private readonly logger = new Logger(FilesLockManager.name)\n\n constructor(private readonly cache: Cache) {}\n\n async create(user: UserModel, dbFile: FileDBProps, depth: LOCK_DEPTH, davLock?: WebDAVLock, ttl?: number): Promise<[boolean, FileLock]> {\n let token: string\n let lockscope: LOCK_SCOPE\n if (davLock) {\n // webdav context\n davLock.locktoken = this.genDAVToken()\n token = davLock.locktoken\n lockscope = davLock.lockscope\n } else {\n // api context\n token = null\n lockscope = null\n }\n try {\n await this.checkConflicts(dbFile, depth, { lockScope: lockscope })\n } catch (e) {\n if (e instanceof LockConflict) {\n return [false, e.lock]\n }\n throw new Error(e)\n }\n ttl ??= CACHE_LOCK_DEFAULT_TTL\n const key = `${CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, { depth: depth, token: token })}`\n const expiration = Math.floor(currentTimeStamp() + ttl)\n const lock: FileLock = {\n owner: user.asOwner(),\n dbFilePath: dbFile.path,\n key: key,\n depth: depth,\n expiration: expiration,\n davLock: davLock\n }\n this.logger.verbose(`${this.create.name} - ${key}`)\n await this.cache.set(key, lock, ttl)\n return [true, lock]\n }\n\n async createOrRefresh(user: UserModel, dbFile: FileDBProps, depth: LOCK_DEPTH, ttl?: number): Promise<[boolean, FileLock]> {\n // Returns: [created, lock]\n ttl ??= CACHE_LOCK_DEFAULT_TTL\n const locks = await this.getLocksByPath(dbFile)\n // Check the existing lock and refresh it if needed\n if (locks.length > 0) {\n for (const lock of locks) {\n if (lock.owner.id === user.id) {\n // Refresh if more than half of the TTL has passed\n const mustRefresh = lock.expiration - currentTimeStamp() < ttl / 2\n if (mustRefresh) {\n this.refreshLockTimeout(lock, ttl).catch((e: Error) => this.logger.error(`${this.createOrRefresh.name} - ${e}`))\n }\n } else {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n }\n return [false, locks[0]]\n }\n // Create the lock\n const [ok, lock] = await this.create(user, dbFile, depth, null, ttl)\n if (!ok) {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n return [true, lock]\n }\n\n removeLock(key: string): Promise<boolean> {\n this.logger.verbose(`${this.removeLock.name} - ${key}`)\n return this.cache.del(key)\n }\n\n async removeChildLocks(user: UserModel, dbFile: FileDBProps) {\n const ownedLockKeys: string[] = []\n for await (const lock of this.searchChildLocks(dbFile)) {\n if (user.id === lock.owner.id) {\n ownedLockKeys.push(lock.key)\n continue\n }\n const conflict = `cannot remove conflicting child lock : ${dbFile.path} (${user.login}) -> ${lock.dbFilePath} (${lock.owner.login})`\n this.logger.debug(`${this.removeChildLocks.name} - ${conflict}`)\n throw new LockConflict(lock, conflict)\n }\n for (const key of ownedLockKeys) {\n this.logger.verbose(`${this.removeChildLocks.name} - child locks: ${key}`)\n await this.removeLock(key)\n }\n }\n\n async isLockedWithToken(token: string, dbFilePath: string): Promise<FileLock> {\n // check if url (or any of its parents) is locked by the token\n const lock = await this.getLockByToken(token)\n return lock ? (dbFilePath.startsWith(lock.dbFilePath) ? lock : null) : null\n }\n\n async browseParentChildLocks(dbFile: FileDBProps, includeRoot = true): Promise<Record<string, FileLock>> {\n // find child locks inside the path\n const childLocks: Record<string, FileLock> = includeRoot ? await this.browseLocks(dbFile) : {}\n const lengthFilter = dbFile.path === '.' ? 1 : dbFile.path.split('/').length + 1\n for await (const lock of this.searchChildLocks(dbFile)) {\n // filter child locks on length\n if (lengthFilter === lock.dbFilePath.split('/').length) {\n // !!! locks with shared scope can have the same file name, in this case we only keep the first entry\n const dbFileName = fileName(lock.dbFilePath)\n if (!(dbFileName in childLocks)) {\n childLocks[fileName(lock.dbFilePath)] = lock\n }\n }\n }\n return childLocks\n }\n\n async browseLocks(dbFile: FileDBProps): Promise<Record<string, FileLock>> {\n return Object.fromEntries((await this.getLocksByPath(dbFile)).map((l) => [fileName(l.dbFilePath), l]))\n }\n\n async refreshLockTimeout(lock: FileLock, ttl: number) {\n lock.expiration = currentTimeStamp() + ttl\n this.cache.set(lock.key, lock, ttl).catch((e: Error) => this.logger.error(`${this.refreshLockTimeout.name} - ${e}`))\n }\n\n async getLockByToken(token: string): Promise<FileLock> {\n const key = await this.searchKeyByToken(token)\n return key ? (await this.cache.get(key)) || null : null\n }\n\n async getLocksByPath(dbFile: FileDBProps): Promise<FileLock[]> {\n if (dbFile.path !== '.') {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const keys = await this.searchKeysByPath(dbFile.path, props)\n if (keys.length) {\n return (await this.cache.mget(keys)).filter(Boolean)\n }\n }\n return []\n }\n\n async isPathLocked(dbFile: FileDBProps): Promise<boolean> {\n if (dbFile.path !== '.') return false\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n return !!(await this.searchKeysByPath(dbFile.path, props)).length\n }\n\n async checkConflicts(\n dbFile: FileDBProps,\n depth: LOCK_DEPTH,\n options?: { userId?: number; lockScope?: LOCK_SCOPE; lockTokens?: string[] }\n ): Promise<void> {\n /* Checks if a file could be modified, created, moved, or deleted\n Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modification\n Returns on the first conflict (compliant with the RFC 4918)\n */\n for await (const l of this.searchParentLocks(dbFile, { includeRoot: true, depth: DEPTH.INFINITY })) {\n if (options?.lockScope && options?.lockScope === LOCK_SCOPE.SHARED && l.davLock.lockscope === LOCK_SCOPE.SHARED) {\n // Only compatible with shared locks (even by same owner)\n continue\n }\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting parent lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n if (depth === DEPTH.INFINITY) {\n for await (const l of this.searchChildLocks(dbFile)) {\n if (options?.userId === l.owner.id && (!l.davLock || (options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1))) {\n // Owner owns this lock (no davLock if the lock was created from api)\n continue\n }\n const conflict = `conflicting child lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`\n this.logger.debug(`${this.checkConflicts.name} - ${conflict}`)\n throw new LockConflict(l, conflict)\n }\n }\n }\n\n async *searchChildLocks(dbFile: FileDBProps) {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n const path = dbFile.path === '.' ? '*' : `${dbFile.path}/*`\n this.logger.verbose(`${this.searchChildLocks.name} - ${path} (${props})`)\n const keys = await this.searchKeysByPath(path, props)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath} (owner: ${l.owner.login})`)\n yield l\n }\n }\n }\n\n convertLockToFileLockProps(lock: FileLock): FileLockProps {\n if (!lock) return null\n return {\n owner: lock?.davLock?.owner || `${lock.owner.fullName} (${lock.owner.email})`,\n ownerLogin: lock.owner.login,\n isExclusive: lock?.davLock?.lockscope ? lock?.davLock?.lockscope === LOCK_SCOPE.EXCLUSIVE : true\n }\n }\n\n private async *searchParentLocks(dbFile: FileDBProps, options: { includeRoot?: boolean; depth?: LOCK_DEPTH } = {}): AsyncGenerator<FileLock> {\n const props = this.genSuffixKey(dbFile, { ignorePath: true })\n let path = dbFile.path\n const parentPath = dirName(path)\n this.logger.verbose(`${this.searchParentLocks.name} - (including root : ${options.includeRoot}) : ${path} (${props})`)\n if (!options.includeRoot) {\n path = dirName(path)\n }\n while (path !== '.') {\n // Even if the depth is \"infinite\", the path and the parent path could be locked with depth \"0\"\n const depth = options.depth && (dbFile.path === path || parentPath === path) ? null : options.depth\n const keys = await this.searchKeysByPath(path, props, depth)\n if (keys.length) {\n for (const l of (await this.cache.mget(keys)).filter(Boolean) as FileLock[]) {\n this.logger.verbose(`-> ${l.dbFilePath}`)\n yield l\n }\n }\n path = dirName(path)\n }\n }\n\n private async searchKeyByToken(token: string): Promise<string> {\n const keys = await this.cache.keys(`${CACHE_LOCK_PREFIX}|token:${token}|*`)\n if (!keys.length) {\n return null\n } else if (keys.length > 1) {\n this.logger.warn(`Several keys found for token : ${token} => ${JSON.stringify(keys)}`)\n }\n return keys[0]\n }\n\n private searchKeysByPath(path: string, props = '*', depth?: LOCK_DEPTH): Promise<string[]> {\n return this.cache.keys(`${CACHE_LOCK_PREFIX}*${depth ? `|depth:${depth}` : ''}|path:${path}|${props}`)\n }\n\n private genDAVToken(): string {\n return `${LOCK_PREFIX}${crypto.randomUUID()}`\n }\n\n private genSuffixKey(dbFile: FileDBProps, options: { ignorePath?: boolean; depth?: LOCK_DEPTH; token?: string } = {}): string {\n // return -> `depth:infinity|path:code/sync-in|spaceId:1` | `token:xxx|depth:0|path:code/sync-in.ts|ownerId:1`\n // ignorePath -> `spaceId:1`\n const suffixes = []\n for (const k of Object.keys(dbFile)\n .filter((k) => k !== files.inTrash.name && dbFile[k] !== null)\n .sort()) {\n if (k === files.path.name) {\n if (options.ignorePath) {\n continue\n }\n suffixes.unshift(`${k}:${dbFile[k]}`)\n } else {\n suffixes.push(`${k}:${dbFile[k]}`)\n }\n }\n if (options.depth) suffixes.unshift(`depth:${options.depth}`)\n if (options.token) suffixes.unshift(`token:${options.token}`)\n return suffixes.join('|')\n }\n}\n"],"names":["FilesLockManager","create","user","dbFile","depth","davLock","ttl","token","lockscope","locktoken","genDAVToken","checkConflicts","lockScope","e","LockConflict","lock","Error","CACHE_LOCK_DEFAULT_TTL","key","CACHE_LOCK_PREFIX","genSuffixKey","expiration","Math","floor","currentTimeStamp","owner","asOwner","dbFilePath","path","logger","verbose","name","cache","set","createOrRefresh","locks","getLocksByPath","length","id","mustRefresh","refreshLockTimeout","catch","error","ok","removeLock","del","removeChildLocks","ownedLockKeys","searchChildLocks","push","conflict","login","debug","isLockedWithToken","getLockByToken","startsWith","browseParentChildLocks","includeRoot","childLocks","browseLocks","lengthFilter","split","dbFileName","fileName","Object","fromEntries","map","l","searchKeyByToken","get","props","ignorePath","keys","searchKeysByPath","mget","filter","Boolean","isPathLocked","options","searchParentLocks","DEPTH","INFINITY","LOCK_SCOPE","SHARED","userId","lockTokens","indexOf","convertLockToFileLockProps","fullName","email","ownerLogin","isExclusive","EXCLUSIVE","parentPath","dirName","warn","JSON","stringify","LOCK_PREFIX","crypto","randomUUID","suffixes","k","files","inTrash","sort","unshift","join","Logger"],"mappings":"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"}