@sync-in/server 1.9.3 → 1.10.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 (349) hide show
  1. package/CHANGELOG.md +41 -4
  2. package/environment/environment.dist.yaml +15 -5
  3. package/package.json +18 -19
  4. package/server/app.bootstrap.js +1 -1
  5. package/server/app.bootstrap.js.map +1 -1
  6. package/server/app.constants.js +3 -2
  7. package/server/app.constants.js.map +1 -1
  8. package/server/applications/files/constants/cache.js +2 -5
  9. package/server/applications/files/constants/cache.js.map +1 -1
  10. package/server/applications/files/constants/files.js +4 -0
  11. package/server/applications/files/constants/files.js.map +1 -1
  12. package/server/applications/files/constants/operations.js +4 -0
  13. package/server/applications/files/constants/operations.js.map +1 -1
  14. package/server/applications/files/constants/routes.js +1 -26
  15. package/server/applications/files/constants/routes.js.map +1 -1
  16. package/server/applications/files/files.config.js +15 -39
  17. package/server/applications/files/files.config.js.map +1 -1
  18. package/server/applications/files/files.controller.js +4 -4
  19. package/server/applications/files/files.controller.js.map +1 -1
  20. package/server/applications/files/files.module.js +12 -9
  21. package/server/applications/files/files.module.js.map +1 -1
  22. package/server/applications/files/interfaces/file-lock.interface.js.map +1 -1
  23. package/server/applications/files/interfaces/file-props.interface.js.map +1 -1
  24. package/server/applications/files/modules/collabora-online/collabora-online-environment.decorator.js +32 -0
  25. package/server/applications/files/modules/collabora-online/collabora-online-environment.decorator.js.map +1 -0
  26. package/server/applications/files/modules/collabora-online/collabora-online-manager.service.js +280 -0
  27. package/server/applications/files/modules/collabora-online/collabora-online-manager.service.js.map +1 -0
  28. package/server/applications/files/modules/collabora-online/collabora-online-manager.service.spec.js +552 -0
  29. package/server/applications/files/modules/collabora-online/collabora-online-manager.service.spec.js.map +1 -0
  30. package/server/applications/files/modules/collabora-online/collabora-online.config.js +40 -0
  31. package/server/applications/files/modules/collabora-online/collabora-online.config.js.map +1 -0
  32. package/server/applications/files/modules/collabora-online/collabora-online.constants.js +110 -0
  33. package/server/applications/files/modules/collabora-online/collabora-online.constants.js.map +1 -0
  34. package/server/applications/files/modules/collabora-online/collabora-online.controller.js +128 -0
  35. package/server/applications/files/modules/collabora-online/collabora-online.controller.js.map +1 -0
  36. package/server/applications/files/modules/collabora-online/collabora-online.controller.spec.js +47 -0
  37. package/server/applications/files/modules/collabora-online/collabora-online.controller.spec.js.map +1 -0
  38. package/server/applications/files/{interfaces/only-office-config.interface.js → modules/collabora-online/collabora-online.dtos.js} +1 -1
  39. package/server/applications/files/modules/collabora-online/collabora-online.dtos.js.map +1 -0
  40. package/server/applications/files/{guards/files-only-office.guard.js → modules/collabora-online/collabora-online.guard.js} +7 -21
  41. package/server/applications/files/modules/collabora-online/collabora-online.guard.js.map +1 -0
  42. package/server/applications/files/modules/collabora-online/collabora-online.guard.spec.js +86 -0
  43. package/server/applications/files/modules/collabora-online/collabora-online.guard.spec.js.map +1 -0
  44. package/server/applications/files/modules/collabora-online/collabora-online.interface.js +10 -0
  45. package/server/applications/files/modules/collabora-online/collabora-online.interface.js.map +1 -0
  46. package/server/applications/files/modules/collabora-online/collabora-online.module.js +41 -0
  47. package/server/applications/files/modules/collabora-online/collabora-online.module.js.map +1 -0
  48. package/server/applications/files/modules/collabora-online/collabora-online.routes.js +35 -0
  49. package/server/applications/files/modules/collabora-online/collabora-online.routes.js.map +1 -0
  50. package/server/applications/files/modules/collabora-online/collabora-online.strategy.js +59 -0
  51. package/server/applications/files/modules/collabora-online/collabora-online.strategy.js.map +1 -0
  52. package/server/applications/files/modules/collabora-online/collabora-online.utils.js +28 -0
  53. package/server/applications/files/modules/collabora-online/collabora-online.utils.js.map +1 -0
  54. package/server/applications/files/{decorators → modules/only-office}/only-office-environment.decorator.js +5 -5
  55. package/server/applications/files/modules/only-office/only-office-environment.decorator.js.map +1 -0
  56. package/server/applications/files/{services/files-only-office-manager.service.js → modules/only-office/only-office-manager.service.js} +101 -97
  57. package/server/applications/files/modules/only-office/only-office-manager.service.js.map +1 -0
  58. package/server/applications/files/modules/only-office/only-office-manager.service.spec.js +477 -0
  59. package/server/applications/files/modules/only-office/only-office-manager.service.spec.js.map +1 -0
  60. package/server/applications/files/modules/only-office/only-office.config.js +51 -0
  61. package/server/applications/files/modules/only-office/only-office.config.js.map +1 -0
  62. package/server/applications/files/modules/only-office/only-office.constants.js +417 -0
  63. package/server/applications/files/modules/only-office/only-office.constants.js.map +1 -0
  64. package/server/applications/files/{files-only-office.controller.js → modules/only-office/only-office.controller.js} +35 -52
  65. package/server/applications/files/modules/only-office/only-office.controller.js.map +1 -0
  66. package/server/applications/files/{files-only-office.controller.spec.js → modules/only-office/only-office.controller.spec.js} +24 -21
  67. package/server/applications/files/modules/only-office/only-office.controller.spec.js.map +1 -0
  68. package/server/applications/files/modules/only-office/only-office.dtos.js +10 -0
  69. package/server/applications/files/modules/only-office/only-office.dtos.js.map +1 -0
  70. package/server/applications/files/modules/only-office/only-office.guard.js +40 -0
  71. package/server/applications/files/modules/only-office/only-office.guard.js.map +1 -0
  72. package/server/applications/files/{guards/files-only-office.guard.spec.js → modules/only-office/only-office.guard.spec.js} +15 -21
  73. package/server/applications/files/modules/only-office/only-office.guard.spec.js.map +1 -0
  74. package/server/applications/files/modules/only-office/only-office.interface.js +10 -0
  75. package/server/applications/files/modules/only-office/only-office.interface.js.map +1 -0
  76. package/server/applications/files/modules/only-office/only-office.module.js +41 -0
  77. package/server/applications/files/modules/only-office/only-office.module.js.map +1 -0
  78. package/server/applications/files/modules/only-office/only-office.routes.js +45 -0
  79. package/server/applications/files/modules/only-office/only-office.routes.js.map +1 -0
  80. package/server/applications/files/{guards/files-only-office.strategy.js → modules/only-office/only-office.strategy.js} +11 -11
  81. package/server/applications/files/modules/only-office/only-office.strategy.js.map +1 -0
  82. package/server/applications/files/services/files-lock-manager.service.js +25 -33
  83. package/server/applications/files/services/files-lock-manager.service.js.map +1 -1
  84. package/server/applications/files/services/files-manager.service.js +17 -16
  85. package/server/applications/files/services/files-manager.service.js.map +1 -1
  86. package/server/applications/files/services/files-methods.service.js +2 -2
  87. package/server/applications/files/services/files-methods.service.js.map +1 -1
  88. package/server/applications/files/services/files-methods.service.spec.js +5 -5
  89. package/server/applications/files/services/files-methods.service.spec.js.map +1 -1
  90. package/server/applications/files/services/files-recents.service.js +4 -0
  91. package/server/applications/files/services/files-recents.service.js.map +1 -1
  92. package/server/applications/files/services/files-scheduler.service.js +24 -5
  93. package/server/applications/files/services/files-scheduler.service.js.map +1 -1
  94. package/server/applications/files/utils/files.js +10 -2
  95. package/server/applications/files/utils/files.js.map +1 -1
  96. package/server/applications/links/constants/routes.js +5 -0
  97. package/server/applications/links/constants/routes.js.map +1 -1
  98. package/server/applications/links/interfaces/link-space.interface.js.map +1 -1
  99. package/server/applications/links/links.controller.js +25 -5
  100. package/server/applications/links/links.controller.js.map +1 -1
  101. package/server/applications/links/services/links-manager.service.js +43 -21
  102. package/server/applications/links/services/links-manager.service.js.map +1 -1
  103. package/server/applications/links/services/links-manager.service.spec.js +4 -3
  104. package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
  105. package/server/applications/links/services/links-queries.service.js +9 -2
  106. package/server/applications/links/services/links-queries.service.js.map +1 -1
  107. package/server/applications/shares/interfaces/share-link.interface.js.map +1 -1
  108. package/server/applications/shares/services/shares-manager.service.js +3 -0
  109. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  110. package/server/applications/shares/services/shares-manager.service.spec.js +2 -1
  111. package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
  112. package/server/applications/shares/services/shares-queries.service.js +1 -0
  113. package/server/applications/shares/services/shares-queries.service.js.map +1 -1
  114. package/server/applications/spaces/constants/spaces.js +2 -2
  115. package/server/applications/spaces/constants/spaces.js.map +1 -1
  116. package/server/applications/spaces/decorators/space-override-permission.decorator.js +18 -0
  117. package/server/applications/spaces/decorators/space-override-permission.decorator.js.map +1 -0
  118. package/server/applications/spaces/guards/space.guard.js +40 -33
  119. package/server/applications/spaces/guards/space.guard.js.map +1 -1
  120. package/server/applications/spaces/guards/space.guard.spec.js +10 -15
  121. package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
  122. package/server/applications/spaces/services/spaces-scheduler.service.js +9 -1
  123. package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
  124. package/server/applications/webdav/constants/webdav.js +4 -0
  125. package/server/applications/webdav/constants/webdav.js.map +1 -1
  126. package/server/applications/webdav/guards/webdav-protocol.guard.js +9 -8
  127. package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
  128. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +1 -1
  129. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -1
  130. package/server/applications/webdav/interfaces/webdav.interface.js.map +1 -1
  131. package/server/applications/webdav/services/webdav-methods.service.js +40 -17
  132. package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
  133. package/server/applications/webdav/services/webdav-methods.service.spec.js +2157 -1289
  134. package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
  135. package/server/applications/webdav/utils/webdav.js +8 -4
  136. package/server/applications/webdav/utils/webdav.js.map +1 -1
  137. package/server/applications/webdav/webdav.controller.js +4 -4
  138. package/server/applications/webdav/webdav.controller.js.map +1 -1
  139. package/server/authentication/guards/auth-token-access.guard.js +8 -3
  140. package/server/authentication/guards/auth-token-access.guard.js.map +1 -1
  141. package/server/authentication/services/auth-methods/auth-method-two-fa.service.js +1 -1
  142. package/server/authentication/services/auth-methods/auth-method-two-fa.service.js.map +1 -1
  143. package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js +350 -4
  144. package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js.map +1 -1
  145. package/server/configuration/config.environment.js +5 -1
  146. package/server/configuration/config.environment.js.map +1 -1
  147. package/server/configuration/config.interfaces.js.map +1 -1
  148. package/static/3rdpartylicenses.txt +507 -507
  149. package/static/assets/pdfjs/build/pdf.mjs +93 -33
  150. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  151. package/static/assets/pdfjs/build/pdf.sandbox.mjs +3 -3
  152. package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
  153. package/static/assets/pdfjs/build/pdf.worker.mjs +166 -54
  154. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  155. package/static/assets/pdfjs/version +1 -1
  156. package/static/assets/pdfjs/web/images/checkmark.svg +5 -0
  157. package/static/assets/pdfjs/web/images/pages_closeButton.svg +3 -0
  158. package/static/assets/pdfjs/web/images/pages_selected.svg +7 -0
  159. package/static/assets/pdfjs/web/images/pages_viewArrow.svg +3 -0
  160. package/static/assets/pdfjs/web/images/pages_viewButton.svg +3 -0
  161. package/static/assets/pdfjs/web/locale/be/viewer.ftl +0 -2
  162. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -5
  163. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +4 -6
  164. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +0 -2
  165. package/static/assets/pdfjs/web/locale/da/viewer.ftl +0 -2
  166. package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -2
  167. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -2
  168. package/static/assets/pdfjs/web/locale/el/viewer.ftl +0 -2
  169. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +6 -2
  170. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -2
  171. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +82 -17
  172. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +0 -2
  173. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -2
  174. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +0 -2
  175. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +0 -2
  176. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -2
  177. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +0 -2
  178. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -2
  179. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -2
  180. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -5
  181. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +3 -5
  182. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +0 -2
  183. package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -2
  184. package/static/assets/pdfjs/web/locale/hr/viewer.ftl +66 -0
  185. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -2
  186. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -2
  187. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +3 -8
  188. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -2
  189. package/static/assets/pdfjs/web/locale/id/viewer.ftl +0 -5
  190. package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -5
  191. package/static/assets/pdfjs/web/locale/it/viewer.ftl +0 -2
  192. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +0 -14
  193. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +4 -6
  194. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -5
  195. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +0 -2
  196. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -2
  197. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +1 -3
  198. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -2
  199. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +4 -2
  200. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +0 -2
  201. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +0 -2
  202. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +0 -2
  203. package/static/assets/pdfjs/web/locale/pt-PT/viewer.ftl +35 -0
  204. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -5
  205. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +4 -6
  206. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +3 -5
  207. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -2
  208. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +0 -2
  209. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +0 -2
  210. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -2
  211. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +0 -2
  212. package/static/assets/pdfjs/web/locale/th/viewer.ftl +2 -2
  213. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +0 -2
  214. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -2
  215. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +0 -2
  216. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -2
  217. package/static/assets/pdfjs/web/viewer.css +1778 -835
  218. package/static/assets/pdfjs/web/viewer.html +167 -86
  219. package/static/assets/pdfjs/web/viewer.mjs +1106 -801
  220. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  221. package/static/chunk-27V66YJV.js +2 -0
  222. package/static/{chunk-WJYVS27M.js → chunk-27Z3SYRL.js} +1 -1
  223. package/static/{chunk-NFIES7BC.js → chunk-2RWLNKZH.js} +1 -1
  224. package/static/chunk-2YQ4SX3A.js +13 -0
  225. package/static/{chunk-GENTF6JM.js → chunk-3JYMJQYT.js} +1 -1
  226. package/static/chunk-3QTROEHV.js +1 -0
  227. package/static/{chunk-ZPI7RQ2S.js → chunk-3RPUQ22U.js} +1 -1
  228. package/static/{chunk-R6VB3INJ.js → chunk-3WZ6F3LC.js} +1 -1
  229. package/static/chunk-3ZLBVUCX.js +2 -0
  230. package/static/{chunk-5HCVWZMA.js → chunk-45AZ6ZML.js} +1 -1
  231. package/static/chunk-46TJLPJY.js +1 -0
  232. package/static/chunk-4NIYCYRS.js +2 -0
  233. package/static/{chunk-XXYMVRSH.js → chunk-4TPFERL6.js} +1 -1
  234. package/static/{chunk-CAZSNVMS.js → chunk-5O66CLTD.js} +1 -1
  235. package/static/chunk-6OEOADR6.js +1 -0
  236. package/static/chunk-6WMXMIE4.js +1 -0
  237. package/static/{chunk-NK2NMAJI.js → chunk-7VRYTDX4.js} +1 -1
  238. package/static/{chunk-ASBPYTLT.js → chunk-ARS47O5X.js} +1 -1
  239. package/static/chunk-B6HQYQYG.js +1 -0
  240. package/static/chunk-BCN4T5DO.js +2 -0
  241. package/static/{chunk-PKU4IIIR.js → chunk-CCZWPM7Q.js} +1 -1
  242. package/static/{chunk-QUSS6SUC.js → chunk-CMNMPG6Z.js} +1 -1
  243. package/static/{chunk-GDPJRUVU.js → chunk-CSVPAZHK.js} +1 -1
  244. package/static/{chunk-BJARRIS6.js → chunk-D55YR5X7.js} +4 -4
  245. package/static/{chunk-Z6RJZIDG.js → chunk-D5FQ72R4.js} +1 -1
  246. package/static/{chunk-4DF2SQD4.js → chunk-DGCVA6BM.js} +1 -1
  247. package/static/{chunk-TVJQXN73.js → chunk-DVCN3P7Q.js} +1 -1
  248. package/static/chunk-E32J777S.js +5 -0
  249. package/static/{chunk-5NHB7SV3.js → chunk-FIUF2JM4.js} +1 -1
  250. package/static/{chunk-RJOHDAPM.js → chunk-G3PL6YX3.js} +1 -1
  251. package/static/chunk-G7RZN7HN.js +1 -0
  252. package/static/{chunk-DDRGLHOP.js → chunk-GQHXYX6Z.js} +1 -1
  253. package/static/{chunk-5HYSNQR4.js → chunk-GWRAGN3M.js} +1 -1
  254. package/static/{chunk-ZC5ZDCDC.js → chunk-GXWGB7WO.js} +1 -1
  255. package/static/{chunk-25PWAXTJ.js → chunk-HGODIZTV.js} +1 -1
  256. package/static/{chunk-4KXJ6C4N.js → chunk-HZAB6F4Q.js} +1 -1
  257. package/static/chunk-I3FR3A45.js +1 -0
  258. package/static/{chunk-A6J6SOM6.js → chunk-I5SPA4G2.js} +1 -1
  259. package/static/{chunk-TGHBDJZA.js → chunk-IMFO2MI7.js} +1 -1
  260. package/static/{chunk-CURVLK7L.js → chunk-JNTNMIUH.js} +1 -1
  261. package/static/chunk-JRXG43AA.js +2 -0
  262. package/static/{chunk-XAIOGRBO.js → chunk-KAUCN24H.js} +1 -1
  263. package/static/chunk-KDUAB76O.js +1 -0
  264. package/static/chunk-KPOQLDWF.js +1 -0
  265. package/static/{chunk-HE6EDXWI.js → chunk-KWFELZTM.js} +1 -1
  266. package/static/{chunk-2CAAJBRO.js → chunk-L3BIP4AA.js} +1 -1
  267. package/static/{chunk-U75PLYIJ.js → chunk-LGIVVJDD.js} +1 -1
  268. package/static/{chunk-JEVBUJQ4.js → chunk-LNLBIJZD.js} +1 -1
  269. package/static/chunk-LTJNLOX2.js +1 -0
  270. package/static/{chunk-SDR3UG2F.js → chunk-LZUHREOF.js} +1 -1
  271. package/static/{chunk-VO4WVT6K.js → chunk-NIR4YE2E.js} +1 -1
  272. package/static/{chunk-S6YKBWJE.js → chunk-NJJURHX4.js} +1 -1
  273. package/static/chunk-NNZWSNAW.js +1 -0
  274. package/static/chunk-NWKBB7J4.js +1 -0
  275. package/static/chunk-O3YLAEVE.js +3 -0
  276. package/static/chunk-OUHCDDT6.js +1 -0
  277. package/static/{chunk-ZRBLCAOK.js → chunk-PDG7DOEF.js} +1 -1
  278. package/static/chunk-POUWUMC4.js +1 -0
  279. package/static/{chunk-YTBSB2GE.js → chunk-PPJCVBJH.js} +1 -1
  280. package/static/{chunk-K3MOXDU5.js → chunk-PQZLR4P3.js} +1 -1
  281. package/static/chunk-PVYVY3GD.js +1 -0
  282. package/static/chunk-Q5X5TPAG.js +1 -0
  283. package/static/{chunk-LFAQLJZK.js → chunk-QHJT5H4M.js} +1 -1
  284. package/static/{chunk-A7DSX7VP.js → chunk-R4VMWCM5.js} +1 -1
  285. package/static/{chunk-27XEAHMV.js → chunk-R7PLNX75.js} +1 -1
  286. package/static/chunk-RJULB733.js +1 -0
  287. package/static/{chunk-MBFMTBVJ.js → chunk-RNVPQQKT.js} +5 -5
  288. package/static/chunk-RTNEBRKJ.js +1 -0
  289. package/static/{chunk-FXM7XXWA.js → chunk-S3TTWPQA.js} +1 -1
  290. package/static/{chunk-6VJI4X2A.js → chunk-SDJNZULP.js} +1 -1
  291. package/static/chunk-SNOOCDJD.js +1 -0
  292. package/static/chunk-T42BV6TR.js +1 -0
  293. package/static/{chunk-4OV3SAUS.js → chunk-TNCKNU6I.js} +1 -1
  294. package/static/{chunk-2LHHXDD5.js → chunk-ULSPQ3HP.js} +1 -1
  295. package/static/{chunk-4EUHBTWV.js → chunk-UOK3LKSX.js} +1 -1
  296. package/static/{chunk-7NI353LS.js → chunk-VD5JHSDS.js} +1 -1
  297. package/static/{chunk-YXWF2DGF.js → chunk-XBKCQCBI.js} +1 -1
  298. package/static/{chunk-KBWK65KM.js → chunk-XEWLBWFF.js} +1 -1
  299. package/static/{chunk-FLPZB3OX.js → chunk-XTVNHFKX.js} +1 -1
  300. package/static/chunk-ZCSHU3D7.js +1 -0
  301. package/static/{chunk-FRBTL2ER.js → chunk-ZEJLIGAY.js} +1 -1
  302. package/static/{chunk-7H5O4BLV.js → chunk-ZHOE5VEY.js} +1 -1
  303. package/static/chunk-ZOMRIN3G.js +2 -0
  304. package/static/index.html +2 -2
  305. package/static/main-YKDNJ7LK.js +11 -0
  306. package/static/{styles-S5HVK4H5.css → styles-XLLEY5Y3.css} +1 -1
  307. package/server/applications/files/constants/only-office.js +0 -531
  308. package/server/applications/files/constants/only-office.js.map +0 -1
  309. package/server/applications/files/decorators/only-office-environment.decorator.js.map +0 -1
  310. package/server/applications/files/files-only-office.controller.js.map +0 -1
  311. package/server/applications/files/files-only-office.controller.spec.js.map +0 -1
  312. package/server/applications/files/guards/files-only-office.guard.js.map +0 -1
  313. package/server/applications/files/guards/files-only-office.guard.spec.js.map +0 -1
  314. package/server/applications/files/guards/files-only-office.strategy.js.map +0 -1
  315. package/server/applications/files/interfaces/only-office-config.interface.js.map +0 -1
  316. package/server/applications/files/services/files-only-office-manager.service.js.map +0 -1
  317. package/server/applications/files/services/files-only-office-manager.service.spec.js +0 -58
  318. package/server/applications/files/services/files-only-office-manager.service.spec.js.map +0 -1
  319. package/static/chunk-2XY4PMI5.js +0 -1
  320. package/static/chunk-33WFRCUP.js +0 -1
  321. package/static/chunk-3LVFDMTN.js +0 -1
  322. package/static/chunk-42L6C5MT.js +0 -1
  323. package/static/chunk-5WCQBTXW.js +0 -1
  324. package/static/chunk-A7R246NW.js +0 -1
  325. package/static/chunk-BSB4VROD.js +0 -2
  326. package/static/chunk-DHFQIFOF.js +0 -1
  327. package/static/chunk-DRHPEERW.js +0 -2
  328. package/static/chunk-FCGTI42I.js +0 -1
  329. package/static/chunk-H4RLHI3Y.js +0 -1
  330. package/static/chunk-ITVA26X2.js +0 -2
  331. package/static/chunk-IUJ4IK26.js +0 -1
  332. package/static/chunk-L3PDWJZ3.js +0 -3
  333. package/static/chunk-LBXOAKBD.js +0 -1
  334. package/static/chunk-LZKI5P5T.js +0 -1
  335. package/static/chunk-MYM43ENO.js +0 -1
  336. package/static/chunk-MZBO5PAR.js +0 -1
  337. package/static/chunk-NAH4V2R6.js +0 -2
  338. package/static/chunk-O7UXVNR2.js +0 -1
  339. package/static/chunk-PCFH5HCI.js +0 -2
  340. package/static/chunk-SRBOO7AO.js +0 -1
  341. package/static/chunk-UUX3M6DC.js +0 -1
  342. package/static/chunk-VJ2HWQRJ.js +0 -5
  343. package/static/chunk-VZPCXSRG.js +0 -2
  344. package/static/chunk-W72JYHOH.js +0 -1
  345. package/static/chunk-XHQEF2IX.js +0 -1
  346. package/static/chunk-XKEBQNQJ.js +0 -1
  347. package/static/chunk-ZERBTNFW.js +0 -13
  348. package/static/main-FE6GWZXU.js +0 -11
  349. /package/static/assets/pdfjs/web/images/{toolbarButton-sidebarToggle.svg → toolbarButton-viewsManagerToggle.svg} +0 -0
@@ -36,22 +36,11 @@ 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, davLock, ttl) {
40
- let token;
41
- let lockscope;
42
- if (davLock) {
43
- // webdav context
44
- davLock.locktoken = this.genDAVToken();
45
- token = davLock.locktoken;
46
- lockscope = davLock.lockscope;
47
- } else {
48
- // api context
49
- token = null;
50
- lockscope = null;
51
- }
39
+ async create(user, dbFile, app, depth, options, ttl) {
52
40
  try {
53
41
  await this.checkConflicts(dbFile, depth, {
54
- lockScope: lockscope
42
+ app: app,
43
+ lockScope: options?.lockScope
55
44
  });
56
45
  } catch (e) {
57
46
  if (e instanceof _filelockerror.LockConflict) {
@@ -65,16 +54,17 @@ let FilesLockManager = class FilesLockManager {
65
54
  ttl ??= _cache.CACHE_LOCK_DEFAULT_TTL;
66
55
  const key = `${_cache.CACHE_LOCK_PREFIX}|${this.genSuffixKey(dbFile, {
67
56
  depth: depth,
68
- token: token
57
+ token: options?.lockToken
69
58
  })}`;
70
59
  const expiration = Math.floor((0, _shared.currentTimeStamp)() + ttl);
71
60
  const lock = {
72
61
  owner: user.asOwner(),
73
62
  dbFilePath: dbFile.path,
74
63
  key: key,
64
+ app: app,
75
65
  depth: depth,
76
66
  expiration: expiration,
77
- davLock: davLock
67
+ options: options
78
68
  };
79
69
  this.logger.verbose(`${this.create.name} - ${key}`);
80
70
  await this.cache.set(key, lock, ttl);
@@ -83,7 +73,7 @@ let FilesLockManager = class FilesLockManager {
83
73
  lock
84
74
  ];
85
75
  }
86
- async createOrRefresh(user, dbFile, depth, ttl) {
76
+ async createOrRefresh(user, dbFile, app, depth, ttl) {
87
77
  // Returns: [created, lock]
88
78
  ttl ??= _cache.CACHE_LOCK_DEFAULT_TTL;
89
79
  const locks = await this.getLocksByPath(dbFile);
@@ -106,7 +96,7 @@ let FilesLockManager = class FilesLockManager {
106
96
  ];
107
97
  }
108
98
  // Create the lock
109
- const [ok, lock] = await this.create(user, dbFile, depth, null, ttl);
99
+ const [ok, lock] = await this.create(user, dbFile, app, depth, null, ttl);
110
100
  if (!ok) {
111
101
  throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
112
102
  }
@@ -136,7 +126,7 @@ let FilesLockManager = class FilesLockManager {
136
126
  }
137
127
  }
138
128
  async isLockedWithToken(token, dbFilePath) {
139
- // check if url (or any of its parents) is locked by the token
129
+ // check if the url (or any of its parents) is locked by the token
140
130
  const lock = await this.getLockByToken(token);
141
131
  return lock ? dbFilePath.startsWith(lock.dbFilePath) ? lock : null : null;
142
132
  }
@@ -191,16 +181,16 @@ let FilesLockManager = class FilesLockManager {
191
181
  }
192
182
  async checkConflicts(dbFile, depth, options) {
193
183
  /* Checks if a file could be modified, created, moved, or deleted
194
- Throws an `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modification
184
+ Throws a `LockConflict` error when there are parent locks (depth: 0) or child locks (depth: infinite) that prevent modification
195
185
  Returns on the first conflict (compliant with the RFC 4918)
196
186
  */ for await (const l of this.searchParentLocks(dbFile, {
197
187
  includeRoot: true,
198
188
  depth: _webdav.DEPTH.INFINITY
199
189
  })){
200
- if (options?.lockScope && options?.lockScope === _webdav.LOCK_SCOPE.SHARED && l.davLock.lockscope === _webdav.LOCK_SCOPE.SHARED) {
190
+ if (options?.lockScope && options?.lockScope === _webdav.LOCK_SCOPE.SHARED && l.options.lockScope === _webdav.LOCK_SCOPE.SHARED && options?.app === l.app) {
201
191
  continue;
202
192
  }
203
- if (options?.userId === l.owner.id && (!l.davLock || options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1)) {
193
+ if (options?.userId === l.owner.id && (!l.options || options?.lockTokens?.length && options.lockTokens.indexOf(l.options.lockToken) > -1)) {
204
194
  continue;
205
195
  }
206
196
  const conflict = `conflicting parent lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`;
@@ -209,7 +199,7 @@ let FilesLockManager = class FilesLockManager {
209
199
  }
210
200
  if (depth === _webdav.DEPTH.INFINITY) {
211
201
  for await (const l of this.searchChildLocks(dbFile)){
212
- if (options?.userId === l.owner.id && (!l.davLock || options?.lockTokens?.length && options.lockTokens.indexOf(l.davLock.locktoken) > -1)) {
202
+ if (options?.userId === l.owner.id && (!l.options || options?.lockTokens?.length && options.lockTokens.indexOf(l.options.lockToken) > -1)) {
213
203
  continue;
214
204
  }
215
205
  const conflict = `conflicting child lock : ${dbFile.path} -> ${l.dbFilePath} (${l.owner.login})`;
@@ -235,11 +225,15 @@ let FilesLockManager = class FilesLockManager {
235
225
  convertLockToFileLockProps(lock) {
236
226
  if (!lock) return null;
237
227
  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
228
+ owner: lock.owner,
229
+ app: lock?.app,
230
+ info: lock?.options?.lockInfo,
231
+ isExclusive: lock?.options?.lockScope ? lock?.options?.lockScope === _webdav.LOCK_SCOPE.EXCLUSIVE : true
241
232
  };
242
233
  }
234
+ genDAVToken() {
235
+ return `${_webdav.LOCK_PREFIX}${_nodecrypto.default.randomUUID()}`;
236
+ }
243
237
  async *searchParentLocks(dbFile, options = {}) {
244
238
  const props = this.genSuffixKey(dbFile, {
245
239
  ignorePath: true
@@ -275,9 +269,6 @@ let FilesLockManager = class FilesLockManager {
275
269
  searchKeysByPath(path, props = '*', depth) {
276
270
  return this.cache.keys(`${_cache.CACHE_LOCK_PREFIX}*${depth ? `|depth:${depth}` : ''}|path:${path}|${props}`);
277
271
  }
278
- genDAVToken() {
279
- return `${_webdav.LOCK_PREFIX}${_nodecrypto.default.randomUUID()}`;
280
- }
281
272
  genSuffixKey(dbFile, options = {}) {
282
273
  // return -> `depth:infinity|path:code/sync-in|spaceId:1` | `token:xxx|depth:0|path:code/sync-in.ts|ownerId:1`
283
274
  // ignorePath -> `spaceId:1`
@@ -299,16 +290,17 @@ let FilesLockManager = class FilesLockManager {
299
290
  constructor(cache){
300
291
  this.cache = cache;
301
292
  /* Philosophy
302
- Currently this manager only handle conflicting locks between multiple users, not between clients
293
+ Currently this manager only handles conflicting locks between multiple users, not between clients
303
294
  - The locks created from api
304
295
  * They do not contain a token key or a davLock property
305
296
  * They are exclusive only
306
297
  * They must have a depth of 'infinity' (all children) or '0' (root and root members)
307
- - The locks created from WebDAV or OnlyOffice are stored with a token and a davLock property
298
+ - The locks created from WebDAV or OnlyOffice or CollaboraOnline are stored with a token and a davLock property
308
299
  * They must have a depth of 'infinity' (all children) or '0' (root and root members)
309
- * They can be exclusive (WebDAV) or shared (OnlyOffice)
300
+ * They can be exclusive (WebDAV) or shared (OnlyOffice, CollaboraOnline)
310
301
  * If created with WebDAV, they are stored with a token and a davLock property
311
- * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are null
302
+ * If created with OnlyOffice, they are stored with no token and a davLock property whose `locktoken` & `lockroot` properties are `null`
303
+ * If created with CollaboraOnline, they are stored with token and a davLock property whose `lockroot` property is `null`
312
304
  Cache token key format = `flock|token?:${uuid}|path:${path}|ownerId?:${number}|spaceId?:${number}|...props` => FileLock
313
305
  */ this.logger = new _common.Logger(FilesLockManager.name);
314
306
  }
@@ -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_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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"}
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 { CACHE_LOCK_DEFAULT_TTL, CACHE_LOCK_PREFIX } from '../constants/cache'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock, FileLockOptions, LOCK_APP } 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 handles 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 or CollaboraOnline 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, CollaboraOnline)\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 * If created with CollaboraOnline, they are stored with token and a davLock property whose `lockroot` property is `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(\n user: UserModel,\n dbFile: FileDBProps,\n app: LOCK_APP,\n depth: LOCK_DEPTH,\n options?: FileLockOptions,\n ttl?: number\n ): Promise<[boolean, FileLock]> {\n try {\n await this.checkConflicts(dbFile, depth, { app: app, lockScope: options?.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: options?.lockToken })}`\n const expiration = Math.floor(currentTimeStamp() + ttl)\n const lock: FileLock = {\n owner: user.asOwner(),\n dbFilePath: dbFile.path,\n key: key,\n app: app,\n depth: depth,\n expiration: expiration,\n options: options\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, app: LOCK_APP, 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, app, 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 the 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; app?: LOCK_APP; lockScope?: LOCK_SCOPE; lockTokens?: string[] }\n ): Promise<void> {\n /* Checks if a file could be modified, created, moved, or deleted\n Throws a `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.options.lockScope === LOCK_SCOPE.SHARED && options?.app === l.app) {\n // Only compatible with shared locks (with the same owner and the same application)\n continue\n }\n if (options?.userId === l.owner.id && (!l.options || (options?.lockTokens?.length && options.lockTokens.indexOf(l.options.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.options || (options?.lockTokens?.length && options.lockTokens.indexOf(l.options.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.owner,\n app: lock?.app,\n info: lock?.options?.lockInfo,\n isExclusive: lock?.options?.lockScope ? lock?.options?.lockScope === LOCK_SCOPE.EXCLUSIVE : true\n }\n }\n\n genDAVToken(): string {\n return `${LOCK_PREFIX}${crypto.randomUUID()}`\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 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","app","depth","options","ttl","checkConflicts","lockScope","e","LockConflict","lock","Error","CACHE_LOCK_DEFAULT_TTL","key","CACHE_LOCK_PREFIX","genSuffixKey","token","lockToken","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","searchParentLocks","DEPTH","INFINITY","LOCK_SCOPE","SHARED","userId","lockTokens","indexOf","convertLockToFileLockProps","info","lockInfo","isExclusive","EXCLUSIVE","genDAVToken","LOCK_PREFIX","crypto","randomUUID","parentPath","dirName","warn","JSON","stringify","suffixes","k","files","inTrash","sort","unshift","join","Logger"],"mappings":"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"}
@@ -19,6 +19,7 @@ const _nodefs = /*#__PURE__*/ _interop_require_default(require("node:fs"));
19
19
  const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
20
20
  const _tar = require("tar");
21
21
  const _image = require("../../../common/image");
22
+ const _shared = require("../../../common/shared");
22
23
  const _contextmanagerservice = require("../../../infrastructure/context/services/context-manager.service");
23
24
  const _applicationsconstants = require("../../applications.constants");
24
25
  const _notifications = require("../../notifications/constants/notifications");
@@ -61,8 +62,8 @@ let FilesManager = class FilesManager {
61
62
  return new _sendfile.SendFile(space.realPath, downloadName);
62
63
  }
63
64
  async saveStream(user, space, req, options) {
64
- // if tmpPath is used, we lock the final destination during the transfer
65
- // space.realPath is replaced by tmpPath (if allowed), if the move operation failed we remove the tmp file
65
+ // If tmpPath is used, we lock the final destination during the transfer
66
+ // space.realPath is replaced by tmpPath (if allowed). If the move operation failed, we remove the tmp file
66
67
  const fExists = await (0, _files1.isPathExists)(space.realPath);
67
68
  const fTmpExists = options?.tmpPath ? await (0, _files1.isPathExists)(options.tmpPath) : false;
68
69
  if (fExists && req.method === _applicationsconstants.HTTP_METHOD.POST) {
@@ -72,33 +73,33 @@ let FilesManager = class FilesManager {
72
73
  throw new _fileerror.FileError(_common.HttpStatus.METHOD_NOT_ALLOWED, 'The location is a directory');
73
74
  }
74
75
  if (options?.tmpPath) {
75
- // ensure tmpPath parent dir exists
76
+ // Ensure tmpPath parent dir exists
76
77
  await (0, _files1.makeDir)((0, _files1.dirName)(options.tmpPath), true);
77
78
  } else if (!await (0, _files1.isPathExists)((0, _files1.dirName)(space.realPath))) {
78
79
  throw new _fileerror.FileError(_common.HttpStatus.CONFLICT, 'Parent must exists');
79
80
  }
80
81
  /* File Lock */ let fileLock;
81
82
  if (options?.dav) {
82
- // check locks
83
+ // Check locks
83
84
  await this.filesLockManager.checkConflicts(space.dbFile, options?.dav?.depth || _webdav.DEPTH.RESOURCE, {
84
85
  userId: user.id,
85
86
  lockTokens: options.dav?.lockTokens
86
87
  });
87
88
  } else {
88
- // create lock if there is no webdav context
89
- const [ok, lock] = await this.filesLockManager.create(user, space.dbFile, _webdav.DEPTH.RESOURCE);
89
+ // Create lock if there is no webdav context
90
+ const [ok, lock] = await this.filesLockManager.create(user, space.dbFile, _shared.SERVER_NAME, _webdav.DEPTH.RESOURCE);
90
91
  if (!ok) {
91
92
  throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
92
93
  }
93
94
  fileLock = lock;
94
95
  }
95
96
  try {
96
- // check range
97
+ // Check range
97
98
  let startRange = 0;
98
99
  if ((fExists || fTmpExists) && req.headers['content-range']) {
99
- // with PUT method, some webdav clients use the `content-range` header,
100
+ // With PUT method, some webdav clients use the `content-range` header,
100
101
  // which is normally reserved for a response to a request containing the `range` header.
101
- // However, for more compatibility let's accept it
102
+ // However, for more compatibility let's accept it.
102
103
  const match = /\d+/.exec(req.headers['content-range']);
103
104
  if (!match.length) {
104
105
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Content-range : header is malformed');
@@ -202,7 +203,7 @@ let FilesManager = class FilesManager {
202
203
  };
203
204
  // Use a short TTL for the PATCH method (which is also used for refreshing)
204
205
  const ttl = patch ? _cache.CACHE_LOCK_FILE_TTL : undefined;
205
- const [created, fileLock] = await this.filesLockManager.createOrRefresh(user, dbFile, _webdav.DEPTH.RESOURCE, ttl);
206
+ const [created, fileLock] = await this.filesLockManager.createOrRefresh(user, dbFile, _shared.SERVER_NAME, _webdav.DEPTH.RESOURCE, ttl);
206
207
  // Do
207
208
  try {
208
209
  await (0, _files1.writeFromStream)(dstFile, part.file);
@@ -427,7 +428,7 @@ let FilesManager = class FilesManager {
427
428
  const rPath = await (0, _files1.uniqueFilePathFromDir)(space.realPath);
428
429
  const dbFile = space.dbFile;
429
430
  dbFile.path = _nodepath.default.join((0, _files1.dirName)(dbFile.path), (0, _files1.fileName)(space.realPath));
430
- const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, _webdav.DEPTH.RESOURCE);
431
+ const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, _shared.SERVER_NAME, _webdav.DEPTH.RESOURCE);
431
432
  if (!ok) {
432
433
  throw new _filelockerror.LockConflict(fileLock, 'Conflicting lock');
433
434
  }
@@ -498,7 +499,7 @@ let FilesManager = class FilesManager {
498
499
  if (dto.compressInDirectory) {
499
500
  const dbFile = space.dbFile;
500
501
  dbFile.path = _nodepath.default.join((0, _files1.dirName)(dbFile.path), (0, _files1.fileName)(dstPath));
501
- const [ok, lock] = await this.filesLockManager.create(user, dbFile, _webdav.DEPTH.RESOURCE);
502
+ const [ok, lock] = await this.filesLockManager.create(user, dbFile, _shared.SERVER_NAME, _webdav.DEPTH.RESOURCE);
502
503
  if (!ok) {
503
504
  throw new _filelockerror.LockConflict(lock, 'Conflicting lock');
504
505
  }
@@ -548,7 +549,7 @@ let FilesManager = class FilesManager {
548
549
  // create lock
549
550
  const dbFile = space.dbFile;
550
551
  dbFile.path = _nodepath.default.join((0, _files1.dirName)(dbFile.path), (0, _files1.fileName)(dstPath));
551
- const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, _webdav.DEPTH.INFINITY);
552
+ const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, _shared.SERVER_NAME, _webdav.DEPTH.INFINITY);
552
553
  if (!ok) {
553
554
  throw new _filelockerror.LockConflict(fileLock, 'Conflicting lock');
554
555
  }
@@ -590,10 +591,10 @@ let FilesManager = class FilesManager {
590
591
  this.logger.warn('Lock refresh must specify an existing resource');
591
592
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Lock refresh must specify an existing resource');
592
593
  }
593
- const [_created, lock] = await this.filesLockManager.createOrRefresh(user, space.dbFile, _webdav.DEPTH.RESOURCE, _cache.CACHE_LOCK_FILE_TTL);
594
+ const [_created, lock] = await this.filesLockManager.createOrRefresh(user, space.dbFile, _shared.SERVER_NAME, _webdav.DEPTH.RESOURCE, _cache.CACHE_LOCK_FILE_TTL);
594
595
  return this.filesLockManager.convertLockToFileLockProps(lock);
595
596
  }
596
- async unlock(user, space, forceAsOwner = false) {
597
+ async unlock(user, space, forceAsFileOwner = false) {
597
598
  if (!await (0, _files1.isPathExists)(space.realPath)) {
598
599
  this.logger.warn(`Unable to unlock: ${space.url} - resource does not exist`);
599
600
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Unlock must specify an existing resource');
@@ -604,7 +605,7 @@ let FilesManager = class FilesManager {
604
605
  return;
605
606
  }
606
607
  for (const lock of fileLocks){
607
- if (forceAsOwner && space.dbFile?.ownerId === user.id || lock.owner.id === user.id) {
608
+ if (forceAsFileOwner && space.dbFile?.ownerId === user.id || lock.owner.id === user.id) {
608
609
  // Refresh if more than half of the TTL has passed
609
610
  await this.filesLockManager.removeLock(lock.key);
610
611
  } else {