@sync-in/server 1.3.9 → 1.5.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 (294) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +5 -3
  3. package/environment/environment.dist.yaml +2 -0
  4. package/package.json +6 -6
  5. package/server/app.bootstrap.js +9 -0
  6. package/server/app.bootstrap.js.map +1 -1
  7. package/server/app.service.spec.js +44 -19
  8. package/server/app.service.spec.js.map +1 -1
  9. package/server/applications/comments/comments.controller.spec.js +103 -4
  10. package/server/applications/comments/comments.controller.spec.js.map +1 -1
  11. package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
  12. package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
  13. package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
  14. package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
  15. package/server/applications/files/constants/files.js +0 -23
  16. package/server/applications/files/constants/files.js.map +1 -1
  17. package/server/applications/files/constants/only-office.js +8 -0
  18. package/server/applications/files/constants/only-office.js.map +1 -1
  19. package/server/applications/files/constants/routes.js +6 -1
  20. package/server/applications/files/constants/routes.js.map +1 -1
  21. package/server/applications/files/files-only-office.controller.js +11 -0
  22. package/server/applications/files/files-only-office.controller.js.map +1 -1
  23. package/server/applications/files/files-only-office.controller.spec.js +97 -3
  24. package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
  25. package/server/applications/files/files-tasks.controller.spec.js +91 -1
  26. package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
  27. package/server/applications/files/files.config.js +5 -0
  28. package/server/applications/files/files.config.js.map +1 -1
  29. package/server/applications/files/files.controller.spec.js +268 -46
  30. package/server/applications/files/files.controller.spec.js.map +1 -1
  31. package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
  32. package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
  33. package/server/applications/files/guards/files-only-office.strategy.js +0 -1
  34. package/server/applications/files/guards/files-only-office.strategy.js.map +1 -1
  35. package/server/applications/files/services/files-only-office-manager.service.js +5 -0
  36. package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
  37. package/server/applications/links/links.controller.spec.js +91 -58
  38. package/server/applications/links/links.controller.spec.js.map +1 -1
  39. package/server/applications/links/services/links-manager.service.js +4 -6
  40. package/server/applications/links/services/links-manager.service.js.map +1 -1
  41. package/server/applications/links/services/links-manager.service.spec.js +378 -14
  42. package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
  43. package/server/applications/links/services/links-queries.service.js +1 -1
  44. package/server/applications/links/services/links-queries.service.js.map +1 -1
  45. package/server/applications/notifications/notifications.controller.spec.js +56 -1
  46. package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
  47. package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
  48. package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
  49. package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
  50. package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
  51. package/server/applications/spaces/guards/space.guard.spec.js +153 -18
  52. package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
  53. package/server/applications/spaces/services/spaces-browser.service.js +7 -7
  54. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  55. package/server/applications/spaces/services/spaces-manager.service.js +17 -17
  56. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  57. package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
  58. package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
  59. package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
  60. package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
  61. package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
  62. package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
  63. package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
  64. package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
  65. package/server/applications/sync/utils/routes.js +1 -1
  66. package/server/applications/sync/utils/routes.js.map +1 -1
  67. package/server/applications/users/guards/permissions.guard.js +4 -4
  68. package/server/applications/users/guards/permissions.guard.js.map +1 -1
  69. package/server/applications/users/guards/permissions.guard.spec.js +6 -6
  70. package/server/applications/users/guards/permissions.guard.spec.js.map +1 -1
  71. package/server/applications/users/guards/roles.guard.js +1 -1
  72. package/server/applications/users/guards/roles.guard.js.map +1 -1
  73. package/server/applications/users/models/user.model.js +1 -1
  74. package/server/applications/users/models/user.model.js.map +1 -1
  75. package/server/applications/users/services/admin-users-manager.service.js +22 -24
  76. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  77. package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
  78. package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
  79. package/server/applications/users/services/users-manager.service.js +1 -1
  80. package/server/applications/users/services/users-manager.service.js.map +1 -1
  81. package/server/applications/users/services/users-manager.service.spec.js +938 -49
  82. package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
  83. package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
  84. package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
  85. package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
  86. package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
  87. package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
  88. package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
  89. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
  90. package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
  91. package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
  92. package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
  93. package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
  94. package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
  95. package/server/applications/webdav/webdav.controller.js +2 -2
  96. package/server/applications/webdav/webdav.controller.js.map +1 -1
  97. package/server/authentication/guards/auth-basic.guard.js.map +1 -1
  98. package/server/authentication/guards/auth-basic.guard.spec.js +38 -2
  99. package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
  100. package/server/authentication/guards/auth-basic.strategy.js +0 -1
  101. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  102. package/server/authentication/guards/auth-digest.guard.js +1 -2
  103. package/server/authentication/guards/auth-digest.guard.js.map +1 -1
  104. package/server/authentication/guards/auth-local.guard.js.map +1 -1
  105. package/server/authentication/guards/auth-local.guard.spec.js +7 -5
  106. package/server/authentication/guards/auth-local.guard.spec.js.map +1 -1
  107. package/server/authentication/guards/auth-local.strategy.js +0 -1
  108. package/server/authentication/guards/auth-local.strategy.js.map +1 -1
  109. package/server/authentication/guards/auth-token-access.guard.spec.js +30 -0
  110. package/server/authentication/guards/auth-token-access.guard.spec.js.map +1 -1
  111. package/server/authentication/guards/auth-token-access.strategy.js +0 -1
  112. package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
  113. package/server/authentication/guards/auth-token-refresh.strategy.js +0 -1
  114. package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
  115. package/server/authentication/services/auth-methods/auth-method-database.service.js +1 -1
  116. package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
  117. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +8 -6
  118. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
  119. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +2 -2
  120. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  121. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +500 -5
  122. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
  123. package/server/configuration/config.loader.js +0 -3
  124. package/server/configuration/config.loader.js.map +1 -1
  125. package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
  126. package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
  127. package/server/infrastructure/context/services/context-manager.service.spec.js +98 -0
  128. package/server/infrastructure/context/services/context-manager.service.spec.js.map +1 -0
  129. package/server/infrastructure/database/constants.js +0 -1
  130. package/server/infrastructure/database/constants.js.map +1 -1
  131. package/server/infrastructure/database/scripts/seed/usersgroups.js +3 -3
  132. package/server/infrastructure/database/scripts/seed/usersgroups.js.map +1 -1
  133. package/server/infrastructure/mailer/mailer.service.js +20 -19
  134. package/server/infrastructure/mailer/mailer.service.js.map +1 -1
  135. package/server/infrastructure/mailer/mailer.service.spec.js +176 -0
  136. package/server/infrastructure/mailer/mailer.service.spec.js.map +1 -0
  137. package/static/3rdpartylicenses.txt +26 -26
  138. package/static/assets/pdfjs/build/pdf.mjs +1177 -255
  139. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  140. package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
  141. package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
  142. package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
  143. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  144. package/static/assets/pdfjs/version +1 -1
  145. package/static/assets/pdfjs/web/debugger.css +31 -0
  146. package/static/assets/pdfjs/web/debugger.mjs +144 -2
  147. package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
  148. package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
  149. package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
  150. package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
  151. package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
  152. package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
  153. package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
  154. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
  155. package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
  156. package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
  157. package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
  158. package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
  159. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
  160. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
  161. package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
  162. package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
  163. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
  164. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
  165. package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
  166. package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
  167. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
  168. package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
  169. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
  170. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
  171. package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
  172. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
  173. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
  174. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
  175. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
  176. package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
  177. package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
  178. package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
  179. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
  180. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
  181. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
  182. package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
  183. package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
  184. package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
  185. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
  186. package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
  187. package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
  188. package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
  189. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
  190. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
  191. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
  192. package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
  193. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
  194. package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
  195. package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
  196. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
  197. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
  198. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
  199. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
  200. package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
  201. package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
  202. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
  203. package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
  204. package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
  205. package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
  206. package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
  207. package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
  208. package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
  209. package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
  210. package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
  211. package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
  212. package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
  213. package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
  214. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
  215. package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
  216. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
  217. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
  218. package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
  219. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
  220. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
  221. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
  222. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
  223. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
  224. package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
  225. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
  226. package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
  227. package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
  228. package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
  229. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
  230. package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
  231. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
  232. package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
  233. package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
  234. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
  235. package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
  236. package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
  237. package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
  238. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
  239. package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
  240. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
  241. package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
  242. package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
  243. package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
  244. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
  245. package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
  246. package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
  247. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
  248. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
  249. package/static/assets/pdfjs/web/viewer.css +649 -120
  250. package/static/assets/pdfjs/web/viewer.html +19 -0
  251. package/static/assets/pdfjs/web/viewer.mjs +489 -38
  252. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  253. package/static/chunk-22EANI6R.js +1 -0
  254. package/static/{chunk-KFM544CA.js → chunk-2UWN7IQF.js} +1 -1
  255. package/static/{chunk-N3T57OCA.js → chunk-2VSPDSJS.js} +1 -1
  256. package/static/{chunk-HUWQHCUX.js → chunk-34UZ7SYI.js} +1 -1
  257. package/static/{chunk-MWFRZBJD.js → chunk-45UQJGGY.js} +1 -1
  258. package/static/{chunk-LYTD6AJE.js → chunk-5TEXH3LJ.js} +1 -1
  259. package/static/{chunk-4KESSWTF.js → chunk-66FMKVJX.js} +1 -1
  260. package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
  261. package/static/chunk-CK4BY2NX.js +27 -0
  262. package/static/{chunk-QTW62OKJ.js → chunk-CSBDAY77.js} +1 -1
  263. package/static/{chunk-XUZSYWRF.js → chunk-CXXPLBDZ.js} +1 -1
  264. package/static/{chunk-ZTXJC5IC.js → chunk-EILQG525.js} +1 -1
  265. package/static/{chunk-FJFNDK67.js → chunk-ENWABUR4.js} +1 -1
  266. package/static/{chunk-WL65GYD5.js → chunk-FR4AOLYL.js} +4 -4
  267. package/static/chunk-HW2H3ISM.js +559 -0
  268. package/static/{chunk-BW5PQAKK.js → chunk-HYMDGBZL.js} +1 -1
  269. package/static/{chunk-WLPYIJFI.js → chunk-IML5UYQG.js} +1 -1
  270. package/static/{chunk-Z5X7LVMZ.js → chunk-IPSMJHMQ.js} +1 -1
  271. package/static/{chunk-3S4WNZ2T.js → chunk-JVCWYSNP.js} +1 -1
  272. package/static/{chunk-CLSVDV7J.js → chunk-KGPCIUD2.js} +1 -1
  273. package/static/{chunk-O4AQBQBF.js → chunk-KQZJSEM3.js} +1 -1
  274. package/static/{chunk-MK7WZG3F.js → chunk-NPEMJJIU.js} +1 -1
  275. package/static/{chunk-4TEHM3AS.js → chunk-OEFBC4GG.js} +1 -1
  276. package/static/{chunk-O67RFAWU.js → chunk-P734A3XZ.js} +1 -1
  277. package/static/{chunk-SRLMFJ7C.js → chunk-RASR4CK6.js} +1 -1
  278. package/static/{chunk-S5WXHO6D.js → chunk-RFMOUC22.js} +1 -1
  279. package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
  280. package/static/{chunk-3FX6ISDY.js → chunk-SBOQGGZX.js} +1 -1
  281. package/static/{chunk-NV2MEIWP.js → chunk-SJAFPXQV.js} +1 -1
  282. package/static/{chunk-PYSFXLMV.js → chunk-XTYGMF2V.js} +1 -1
  283. package/static/{chunk-ZFKCGL6X.js → chunk-YCWMV2YR.js} +1 -1
  284. package/static/{chunk-LB7B5RIV.js → chunk-YGD22MWQ.js} +1 -1
  285. package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
  286. package/static/{chunk-SKDQM65G.js → chunk-ZVY37DKS.js} +1 -1
  287. package/static/index.html +2 -2
  288. package/static/main-N5CZRHAO.js +7 -0
  289. package/static/styles-FYUSO6OJ.css +1 -0
  290. package/static/chunk-AY2GOSJ2.js +0 -24
  291. package/static/chunk-RSNLYAN6.js +0 -560
  292. package/static/chunk-ZZ3LHYOY.js +0 -1
  293. package/static/main-RREKR34B.js +0 -10
  294. package/static/styles-3DONJ2Z4.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/webdav/services/webdav-spaces.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { SpacesBrowser } from '../../spaces/services/spaces-browser.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { WebDAVSpaces } from './webdav-spaces.service'\n\ndescribe(WebDAVSpaces.name, () => {\n let service: WebDAVSpaces\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n { provide: SpacesBrowser, useValue: {} },\n {\n provide: SpacesManager,\n useValue: {}\n },\n WebDAVSpaces\n ]\n }).compile()\n\n service = module.get<WebDAVSpaces>(WebDAVSpaces)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n})\n"],"names":["describe","WebDAVSpaces","name","service","beforeAll","module","Test","createTestingModule","providers","provide","SpacesBrowser","useValue","SpacesManager","compile","get","it","expect","toBeDefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;sCACN;sCACA;qCACD;AAE7BA,SAASC,iCAAY,CAACC,IAAI,EAAE;IAC1B,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACT;oBAAEC,SAASC,mCAAa;oBAAEC,UAAU,CAAC;gBAAE;gBACvC;oBACEF,SAASG,mCAAa;oBACtBD,UAAU,CAAC;gBACb;gBACAV,iCAAY;aACb;QACH,GAAGY,OAAO;QAEVV,UAAUE,OAAOS,GAAG,CAAeb,iCAAY;IACjD;IAEAc,GAAG,qBAAqB;QACtBC,OAAOb,SAASc,WAAW;IAC7B;AACF"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/webdav/services/webdav-spaces.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { getProps, isPathExists, isPathIsDir } from '../../files/utils/files'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpacesBrowser } from '../../spaces/services/spaces-browser.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { canAccessToSpaceUrl } from '../../spaces/utils/permissions'\nimport { WEBDAV_NS } from '../constants/routes'\nimport { DEPTH } from '../constants/webdav'\nimport type { FastifyDAVRequest } from '../interfaces/webdav.interface'\nimport { WebDAVSpaces } from './webdav-spaces.service'\n\n// mocks for file utils and permissions\njest.mock('../../files/utils/files', () => ({\n getProps: jest.fn(),\n isPathExists: jest.fn(),\n isPathIsDir: jest.fn()\n}))\njest.mock('../../spaces/utils/permissions', () => ({\n canAccessToSpaceUrl: jest.fn()\n}))\n// mock for WEBDAV path-to-space segments\njest.mock('../utils/routes', () => ({\n WEBDAV_PATH_TO_SPACE_SEGMENTS: jest.fn(() => ['files', 'personal'])\n}))\n\n// small helper to collect results from an AsyncGenerator\nasync function collectGenerator<T>(gen: AsyncGenerator<T>): Promise<T[]> {\n const all: T[] = []\n for await (const item of gen) {\n all.push(item)\n }\n return all\n}\n\ndescribe(WebDAVSpaces.name, () => {\n let service: WebDAVSpaces\n let spacesManager: jest.Mocked<SpacesManager>\n let spacesBrowser: jest.Mocked<SpacesBrowser>\n\n const user = { id: 1, login: 'john', isAdmin: false } as any\n\n beforeAll(async () => {\n const spacesManagerMock: Partial<jest.Mocked<SpacesManager>> = {\n spaceEnv: jest.fn(),\n listSpaces: jest.fn(),\n listTrashes: jest.fn()\n }\n const spacesBrowserMock: Partial<jest.Mocked<SpacesBrowser>> = {\n browse: jest.fn()\n }\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [{ provide: SpacesBrowser, useValue: spacesBrowserMock }, { provide: SpacesManager, useValue: spacesManagerMock }, WebDAVSpaces]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<WebDAVSpaces>(WebDAVSpaces)\n spacesManager = module.get(SpacesManager) as jest.Mocked<SpacesManager>\n spacesBrowser = module.get(SpacesBrowser) as jest.Mocked<SpacesBrowser>\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('spaceEnv', () => {\n it('returns space when manager resolves', async () => {\n const fakeSpace = { alias: 'personal', id: 0 } as any\n ;(spacesManager.spaceEnv as jest.Mock).mockResolvedValue(fakeSpace)\n\n const res = await service.spaceEnv(user as any, '/webdav/personal')\n expect(res).toBe(fakeSpace)\n expect(spacesManager.spaceEnv).toHaveBeenCalled()\n })\n\n it('returns null when manager throws', async () => {\n ;(spacesManager.spaceEnv as jest.Mock).mockRejectedValue(new Error('boom'))\n\n const res = await service.spaceEnv(user as any, '/webdav/personal')\n expect(res).toBeNull()\n })\n\n it('returns null when space not found', async () => {\n ;(spacesManager.spaceEnv as jest.Mock).mockResolvedValue(null)\n\n const res = await service.spaceEnv(user as any, '/webdav/personal')\n expect(res).toBeNull()\n })\n })\n\n describe('propfind - server root', () => {\n it('yields server root and webdav child when depth=1', async () => {\n const req = { user, dav: { url: '/', depth: DEPTH.MEMBERS } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.SERVER as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.SERVER, WEBDAV_NS.WEBDAV])\n })\n\n it('yields only server root when depth=0', async () => {\n const req = { user, dav: { url: '/', depth: DEPTH.RESOURCE } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.SERVER as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.SERVER])\n })\n })\n\n describe('propfind - webdav listing', () => {\n it('filters repositories by user access', async () => {\n ;(canAccessToSpaceUrl as jest.Mock).mockImplementation((_u: any, repos: string[]) => repos?.includes(SPACE_REPOSITORY.FILES))\n const req = { user, dav: { url: '/webdav', depth: DEPTH.MEMBERS } } as unknown as FastifyDAVRequest\n\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.WEBDAV as any))\n // should list only roots that include FILES in their repository (personal, spaces), not server/webdav\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.WEBDAV, 'personal', 'spaces'])\n })\n\n it('lists only itself when depth=0', async () => {\n const req = { user, dav: { url: '/webdav', depth: DEPTH.RESOURCE } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.WEBDAV as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.WEBDAV])\n })\n })\n\n describe('propfind - spaces listing', () => {\n it('yields spaces root then user spaces when depth=1', async () => {\n const now = new Date()\n ;(spacesManager.listSpaces as jest.Mock).mockResolvedValue([\n { id: 10, name: 'Team A', alias: 'team-a', createdAt: now.toISOString(), modifiedAt: now.toISOString() },\n { id: 11, name: 'Team B', alias: 'team-b', createdAt: now.toISOString(), modifiedAt: now.toISOString() }\n ])\n\n const req = { user, dav: { url: '/webdav/spaces', depth: DEPTH.MEMBERS } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.SPACES as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.SPACES, 'Team A', 'Team B'])\n })\n\n it('yields only spaces root when depth=0', async () => {\n ;(spacesManager.listSpaces as jest.Mock).mockResolvedValue([])\n const req = { user, dav: { url: '/webdav/spaces', depth: DEPTH.RESOURCE } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.SPACES as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.SPACES])\n })\n })\n\n describe('propfind - trashes listing', () => {\n it('yields trash root then each trash bucket when depth=1', async () => {\n ;(spacesManager.listTrashes as jest.Mock).mockResolvedValue([\n { id: 1, alias: 'personal', nb: 2, mtime: 3, ctime: 4, name: 'Personal files' },\n { id: 2, alias: 'team-a', nb: 5, mtime: 6, ctime: 7, name: 'Team A' }\n ])\n const req = { user, dav: { url: '/webdav/trash', depth: DEPTH.MEMBERS } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.TRASH as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.TRASH, 'personal (2)', 'team-a (5)'])\n })\n\n it('yields only trash root when depth=0', async () => {\n ;(spacesManager.listTrashes as jest.Mock).mockResolvedValue([])\n const req = { user, dav: { url: '/webdav/trash', depth: DEPTH.RESOURCE } } as unknown as FastifyDAVRequest\n const items = await collectGenerator(service.propfind(req, WEBDAV_NS.TRASH as any))\n expect(items.map((i: any) => i.name)).toEqual([WEBDAV_NS.TRASH])\n })\n })\n\n describe('propfind - files listing (shares list)', () => {\n it('yields shares root and children when inSharesList=true and depth=1', async () => {\n ;(spacesBrowser.browse as jest.Mock).mockResolvedValue({\n files: [{ id: 1, name: 'doc.txt', isDir: false, size: 12, ctime: 1, mtime: 2, mime: 'text/plain' }]\n })\n\n const req = {\n user,\n dav: { url: '/webdav/files/personal', depth: DEPTH.MEMBERS },\n space: { inSharesList: true, realPath: '/any/ignored' }\n } as unknown as FastifyDAVRequest\n\n const items = await collectGenerator(service.propfind(req, SPACE_REPOSITORY.FILES))\n expect(items.map((i: any) => i.name)).toEqual(['shares', 'doc.txt'])\n })\n })\n\n describe('propfind - files listing (path cases)', () => {\n it('throws 404 when path does not exist', async () => {\n ;(isPathExists as jest.Mock).mockResolvedValue(false)\n\n const req = {\n user,\n dav: { url: '/webdav/files/personal/current', depth: DEPTH.RESOURCE },\n space: { inSharesList: false, realPath: '/path/not/found' }\n } as unknown as FastifyDAVRequest\n\n await expect(collectGenerator(service.propfind(req, SPACE_REPOSITORY.FILES))).rejects.toBeInstanceOf(HttpException)\n await expect(collectGenerator(service.propfind(req, SPACE_REPOSITORY.FILES))).rejects.toMatchObject({ status: HttpStatus.NOT_FOUND })\n })\n\n it('yields current directory and children when path exists and is dir', async () => {\n ;(isPathExists as jest.Mock).mockResolvedValue(true)\n ;(getProps as jest.Mock).mockResolvedValue({\n id: 100,\n name: 'current',\n isDir: true,\n size: 0,\n ctime: Date.now(),\n mtime: Date.now(),\n mime: undefined\n })\n ;(isPathIsDir as jest.Mock).mockResolvedValue(true)\n ;(spacesBrowser.browse as jest.Mock).mockResolvedValue({\n files: [{ id: 2, name: 'child.txt', isDir: false, size: 1, ctime: 1, mtime: 2, mime: 'text/plain' }]\n })\n\n const req = {\n user,\n dav: { url: '/webdav/files/personal/current', depth: DEPTH.MEMBERS },\n space: { inSharesList: false, realPath: '/path/current' }\n } as unknown as FastifyDAVRequest\n\n const items = await collectGenerator(service.propfind(req, SPACE_REPOSITORY.FILES))\n expect(items.map((i: any) => i.name)).toEqual(['current', 'child.txt'])\n })\n\n it('does not list children when path exists but is not a directory', async () => {\n ;(isPathExists as jest.Mock).mockResolvedValue(true)\n ;(getProps as jest.Mock).mockResolvedValue({\n id: 101,\n name: 'current',\n isDir: false,\n size: 123,\n ctime: Date.now(),\n mtime: Date.now(),\n mime: 'text/plain'\n })\n ;(isPathIsDir as jest.Mock).mockResolvedValue(false)\n ;(spacesBrowser.browse as jest.Mock).mockResolvedValue({ files: [] })\n\n const req = {\n user,\n dav: { url: '/webdav/files/personal/current', depth: DEPTH.MEMBERS },\n space: { inSharesList: false, realPath: '/path/current' }\n } as unknown as FastifyDAVRequest\n\n const items = await collectGenerator(service.propfind(req, SPACE_REPOSITORY.FILES))\n expect(items.map((i: any) => i.name)).toEqual(['current'])\n expect(spacesBrowser.browse).not.toHaveBeenCalled()\n })\n })\n\n describe('propfind - unknown space', () => {\n it('throws not found for unknown space', () => {\n const req = { user, dav: { url: '/webdav/unknown', depth: DEPTH.RESOURCE } } as unknown as FastifyDAVRequest\n try {\n service.propfind(req, 'unknown' as any)\n fail('Expected HttpException to be thrown')\n } catch (err) {\n expect(err).toBeInstanceOf(HttpException)\n expect((err as HttpException).getStatus()).toBe(HttpStatus.NOT_FOUND)\n }\n })\n })\n})\n"],"names":["jest","mock","getProps","fn","isPathExists","isPathIsDir","canAccessToSpaceUrl","WEBDAV_PATH_TO_SPACE_SEGMENTS","collectGenerator","gen","all","item","push","describe","WebDAVSpaces","name","service","spacesManager","spacesBrowser","user","id","login","isAdmin","beforeAll","spacesManagerMock","spaceEnv","listSpaces","listTrashes","spacesBrowserMock","browse","module","Test","createTestingModule","providers","provide","SpacesBrowser","useValue","SpacesManager","compile","useLogger","get","beforeEach","clearAllMocks","it","expect","toBeDefined","fakeSpace","alias","mockResolvedValue","res","toBe","toHaveBeenCalled","mockRejectedValue","Error","toBeNull","req","dav","url","depth","DEPTH","MEMBERS","items","propfind","WEBDAV_NS","SERVER","map","i","toEqual","WEBDAV","RESOURCE","mockImplementation","_u","repos","includes","SPACE_REPOSITORY","FILES","now","Date","createdAt","toISOString","modifiedAt","SPACES","nb","mtime","ctime","TRASH","files","isDir","size","mime","space","inSharesList","realPath","rejects","toBeInstanceOf","HttpException","toMatchObject","status","HttpStatus","NOT_FOUND","undefined","not","fail","err","getStatus"],"mappings":"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"}
@@ -37,14 +37,14 @@ function _ts_param(paramIndex, decorator) {
37
37
  }
38
38
  let WebDAVController = class WebDAVController {
39
39
  serverOptions() {
40
- // OPTIONS method is handled in the `DavProtocolGuard`
40
+ // OPTIONS method is handled in the `DavProtocolGuard`, return empty response with headers
41
41
  return;
42
42
  }
43
43
  serverPropFind(req, res) {
44
44
  return this.webdavMethods.propfind(req, res, _routes.WEBDAV_NS.SERVER);
45
45
  }
46
46
  webdavOptions() {
47
- // OPTIONS method is handled in the `DavProtocolGuard`
47
+ // OPTIONS method is handled in the `DavProtocolGuard`, return empty response with headers
48
48
  return;
49
49
  }
50
50
  async webdavPropfind(req, res) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.controller.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 { All, Controller, HttpStatus, Options, Param, Propfind, Req, Res, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { HTTP_METHOD } from '../applications.constants'\nimport { SPACE_REPOSITORY } from '../spaces/constants/spaces'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { WEBDAV_BASE_PATH, WEBDAV_NS } from './constants/routes'\nimport { WebDAVEnvironment } from './decorators/webdav-context.decorator'\nimport { FastifyDAVRequest } from './interfaces/webdav.interface'\nimport { WebDAVMethods } from './services/webdav-methods.service'\n\n@Controller()\n@WebDAVEnvironment()\nexport class WebDAVController {\n constructor(private readonly webdavMethods: WebDAVMethods) {}\n\n @Options()\n serverOptions() {\n // OPTIONS method is handled in the `DavProtocolGuard`\n return\n }\n\n @Propfind()\n serverPropFind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.SERVER)\n }\n\n @Options(WEBDAV_BASE_PATH)\n webdavOptions() {\n // OPTIONS method is handled in the `DavProtocolGuard`\n return\n }\n\n @Propfind(WEBDAV_BASE_PATH)\n async webdavPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.WEBDAV)\n }\n\n @Options(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n repositoriesOptions() {\n // OPTIONS method is handled in the `DavProtocolGuard`\n return\n }\n\n @Propfind(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n async repositoriesPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply, @Param('repository') repository: string) {\n return this.webdavMethods.propfind(req, res, repository)\n }\n\n @All(`${WEBDAV_BASE_PATH}/*`)\n @UseGuards(SpaceGuard)\n async files(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n // OPTIONS method is handled in the `DavProtocolGuard`\n switch (req.method) {\n case HTTP_METHOD.PROPFIND:\n return this.webdavMethods.propfind(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.HEAD:\n case HTTP_METHOD.GET:\n return this.webdavMethods.headOrGet(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.PUT:\n return this.webdavMethods.put(req, res)\n case HTTP_METHOD.DELETE:\n return this.webdavMethods.delete(req, res)\n case HTTP_METHOD.LOCK:\n return this.webdavMethods.lock(req, res)\n case HTTP_METHOD.UNLOCK:\n return this.webdavMethods.unlock(req, res)\n case HTTP_METHOD.PROPPATCH:\n return this.webdavMethods.proppatch(req, res)\n case HTTP_METHOD.MKCOL:\n return this.webdavMethods.mkcol(req, res)\n case HTTP_METHOD.COPY:\n case HTTP_METHOD.MOVE:\n return this.webdavMethods.copyMove(req, res)\n default:\n return res.status(HttpStatus.METHOD_NOT_ALLOWED).send()\n }\n }\n}\n"],"names":["WebDAVController","serverOptions","serverPropFind","req","res","webdavMethods","propfind","WEBDAV_NS","SERVER","webdavOptions","webdavPropfind","WEBDAV","repositoriesOptions","repositoriesPropfind","repository","files","method","HTTP_METHOD","PROPFIND","SPACE_REPOSITORY","FILES","HEAD","GET","headOrGet","PUT","put","DELETE","delete","LOCK","lock","UNLOCK","unlock","PROPPATCH","proppatch","MKCOL","mkcol","COPY","MOVE","copyMove","status","HttpStatus","METHOD_NOT_ALLOWED","send","passthrough","WEBDAV_BASE_PATH","SPACES","TRASH"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.controller.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 { All, Controller, HttpStatus, Options, Param, Propfind, Req, Res, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { HTTP_METHOD } from '../applications.constants'\nimport { SPACE_REPOSITORY } from '../spaces/constants/spaces'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { WEBDAV_BASE_PATH, WEBDAV_NS } from './constants/routes'\nimport { WebDAVEnvironment } from './decorators/webdav-context.decorator'\nimport { FastifyDAVRequest } from './interfaces/webdav.interface'\nimport { WebDAVMethods } from './services/webdav-methods.service'\n\n@Controller()\n@WebDAVEnvironment()\nexport class WebDAVController {\n constructor(private readonly webdavMethods: WebDAVMethods) {}\n\n @Options()\n serverOptions() {\n // OPTIONS method is handled in the `DavProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind()\n serverPropFind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.SERVER)\n }\n\n @Options(WEBDAV_BASE_PATH)\n webdavOptions() {\n // OPTIONS method is handled in the `DavProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind(WEBDAV_BASE_PATH)\n async webdavPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.WEBDAV)\n }\n\n @Options(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n repositoriesOptions() {\n // OPTIONS method is handled in the `DavProtocolGuard`\n return\n }\n\n @Propfind(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n async repositoriesPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply, @Param('repository') repository: string) {\n return this.webdavMethods.propfind(req, res, repository)\n }\n\n @All(`${WEBDAV_BASE_PATH}/*`)\n @UseGuards(SpaceGuard)\n async files(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply) {\n // OPTIONS method is handled in the `DavProtocolGuard`\n switch (req.method) {\n case HTTP_METHOD.PROPFIND:\n return this.webdavMethods.propfind(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.HEAD:\n case HTTP_METHOD.GET:\n return this.webdavMethods.headOrGet(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.PUT:\n return this.webdavMethods.put(req, res)\n case HTTP_METHOD.DELETE:\n return this.webdavMethods.delete(req, res)\n case HTTP_METHOD.LOCK:\n return this.webdavMethods.lock(req, res)\n case HTTP_METHOD.UNLOCK:\n return this.webdavMethods.unlock(req, res)\n case HTTP_METHOD.PROPPATCH:\n return this.webdavMethods.proppatch(req, res)\n case HTTP_METHOD.MKCOL:\n return this.webdavMethods.mkcol(req, res)\n case HTTP_METHOD.COPY:\n case HTTP_METHOD.MOVE:\n return this.webdavMethods.copyMove(req, res)\n default:\n return res.status(HttpStatus.METHOD_NOT_ALLOWED).send()\n }\n }\n}\n"],"names":["WebDAVController","serverOptions","serverPropFind","req","res","webdavMethods","propfind","WEBDAV_NS","SERVER","webdavOptions","webdavPropfind","WEBDAV","repositoriesOptions","repositoriesPropfind","repository","files","method","HTTP_METHOD","PROPFIND","SPACE_REPOSITORY","FILES","HEAD","GET","headOrGet","PUT","put","DELETE","delete","LOCK","lock","UNLOCK","unlock","PROPPATCH","proppatch","MKCOL","mkcol","COPY","MOVE","copyMove","status","HttpStatus","METHOD_NOT_ALLOWED","send","passthrough","WEBDAV_BASE_PATH","SPACES","TRASH"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.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, Injectable, Logger } from '@nestjs/common'\nimport { AuthGuard } from '@nestjs/passport'\nimport { IAuthGuard } from '@nestjs/passport/dist/auth.guard'\nimport { FastifyRequest } from 'fastify'\nimport { HTTP_METHOD } from '../../applications/applications.constants'\nimport { WEBDAV_BASE_PATH } from '../../applications/webdav/constants/routes'\n\n@Injectable()\nexport class AuthBasicGuard extends AuthGuard('basic') implements IAuthGuard {\n private readonly logger = new Logger(AuthBasicGuard.name)\n\n canActivate(ctx: ExecutionContext) {\n // allow options method on server (webdav)\n const req: FastifyRequest = this.getRequest(ctx)\n if (req.method === HTTP_METHOD.OPTIONS) {\n // only allow options method to skip auth check on the server and webdav paths (including child uris)\n const segments = req.originalUrl.split('/').filter(Boolean)\n if (!segments.length || segments[0] === WEBDAV_BASE_PATH) {\n return true\n }\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":["AuthBasicGuard","AuthGuard","canActivate","ctx","req","getRequest","method","HTTP_METHOD","OPTIONS","segments","originalUrl","split","filter","Boolean","length","WEBDAV_BASE_PATH","handleRequest","err","user","info","status","raw","login","logger","warn","ip","Logger","name"],"mappings":"AAAA;;;;CAIC;;;;+BAUYA;;;eAAAA;;;wBARwC;0BAC3B;uCAGE;wBACK;;;;;;;AAG1B,IAAA,AAAMA,iBAAN,MAAMA,uBAAuBC,IAAAA,mBAAS,EAAC;IAG5CC,YAAYC,GAAqB,EAAE;QACjC,0CAA0C;QAC1C,MAAMC,MAAsB,IAAI,CAACC,UAAU,CAACF;QAC5C,IAAIC,IAAIE,MAAM,KAAKC,kCAAW,CAACC,OAAO,EAAE;YACtC,qGAAqG;YACrG,MAAMC,WAAWL,IAAIM,WAAW,CAACC,KAAK,CAAC,KAAKC,MAAM,CAACC;YACnD,IAAI,CAACJ,SAASK,MAAM,IAAIL,QAAQ,CAAC,EAAE,KAAKM,wBAAgB,EAAE;gBACxD,OAAO;YACT;QACF;QACA,OAAO,KAAK,CAACb,YAAYC;IAC3B;IAEAa,cAA2BC,GAAQ,EAAEC,IAAS,EAAEC,IAAW,EAAEhB,GAAqB,EAAEiB,MAAY,EAAS;QACvG,MAAMhB,MAAM,IAAI,CAACC,UAAU,CAACF;QAC5BC,IAAIiB,GAAG,CAACH,IAAI,GAAGA,MAAMI,SAAS;QAC9B,IAAIH,MAAM;YACR,IAAI,CAACI,MAAM,CAACC,IAAI,CAAC,CAAC,CAAC,EAAEpB,IAAIiB,GAAG,CAACH,IAAI,CAAC,GAAG,EAAEd,IAAIqB,EAAE,CAAC,EAAE,EAAEN,MAAM;QAC1D;QACA,OAAO,KAAK,CAACH,cAAcC,KAAKC,MAAMC,MAAMhB,KAAKiB;IACnD;;QAvBK,qBACYG,SAAS,IAAIG,cAAM,CAAC1B,eAAe2B,IAAI;;AAuB1D"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.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, Injectable, Logger } from '@nestjs/common'\nimport { AuthGuard, IAuthGuard } from '@nestjs/passport'\nimport { FastifyRequest } from 'fastify'\nimport { HTTP_METHOD } from '../../applications/applications.constants'\nimport { WEBDAV_BASE_PATH } from '../../applications/webdav/constants/routes'\n\n@Injectable()\nexport class AuthBasicGuard extends AuthGuard('basic') implements IAuthGuard {\n private readonly logger = new Logger(AuthBasicGuard.name)\n\n canActivate(ctx: ExecutionContext) {\n // allow options method on server (webdav)\n const req: FastifyRequest = this.getRequest(ctx)\n if (req.method === HTTP_METHOD.OPTIONS) {\n // only allow options method to skip auth check on the server and webdav paths (including child uris)\n const segments = req.originalUrl.split('/').filter(Boolean)\n if (!segments.length || segments[0] === WEBDAV_BASE_PATH) {\n return true\n }\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":["AuthBasicGuard","AuthGuard","canActivate","ctx","req","getRequest","method","HTTP_METHOD","OPTIONS","segments","originalUrl","split","filter","Boolean","length","WEBDAV_BASE_PATH","handleRequest","err","user","info","status","raw","login","logger","warn","ip","Logger","name"],"mappings":"AAAA;;;;CAIC;;;;+BASYA;;;eAAAA;;;wBAPwC;0BACf;uCAEV;wBACK;;;;;;;AAG1B,IAAA,AAAMA,iBAAN,MAAMA,uBAAuBC,IAAAA,mBAAS,EAAC;IAG5CC,YAAYC,GAAqB,EAAE;QACjC,0CAA0C;QAC1C,MAAMC,MAAsB,IAAI,CAACC,UAAU,CAACF;QAC5C,IAAIC,IAAIE,MAAM,KAAKC,kCAAW,CAACC,OAAO,EAAE;YACtC,qGAAqG;YACrG,MAAMC,WAAWL,IAAIM,WAAW,CAACC,KAAK,CAAC,KAAKC,MAAM,CAACC;YACnD,IAAI,CAACJ,SAASK,MAAM,IAAIL,QAAQ,CAAC,EAAE,KAAKM,wBAAgB,EAAE;gBACxD,OAAO;YACT;QACF;QACA,OAAO,KAAK,CAACb,YAAYC;IAC3B;IAEAa,cAA2BC,GAAQ,EAAEC,IAAS,EAAEC,IAAW,EAAEhB,GAAqB,EAAEiB,MAAY,EAAS;QACvG,MAAMhB,MAAM,IAAI,CAACC,UAAU,CAACF;QAC5BC,IAAIiB,GAAG,CAACH,IAAI,GAAGA,MAAMI,SAAS;QAC9B,IAAIH,MAAM;YACR,IAAI,CAACI,MAAM,CAACC,IAAI,CAAC,CAAC,CAAC,EAAEpB,IAAIiB,GAAG,CAACH,IAAI,CAAC,GAAG,EAAEd,IAAIqB,EAAE,CAAC,EAAE,EAAEN,MAAM;QAC1D;QACA,OAAO,KAAK,CAACH,cAAcC,KAAKC,MAAMC,MAAMhB,KAAKiB;IACnD;;QAvBK,qBACYG,SAAS,IAAIG,cAAM,CAAC1B,eAAe2B,IAAI;;AAuB1D"}
@@ -18,6 +18,7 @@ const _authbasicguard = require("./auth-basic.guard");
18
18
  const _authbasicstrategy = require("./auth-basic.strategy");
19
19
  describe(_authbasicguard.AuthBasicGuard.name, ()=>{
20
20
  let authBasicGuard;
21
+ let authBasicStrategy;
21
22
  let authMethod;
22
23
  let cache;
23
24
  let userTest;
@@ -37,7 +38,8 @@ describe(_authbasicguard.AuthBasicGuard.name, ()=>{
37
38
  {
38
39
  provide: _nestjspino.PinoLogger,
39
40
  useValue: {
40
- assign: ()=>undefined
41
+ assign: ()=>undefined,
42
+ error: jest.fn()
41
43
  }
42
44
  },
43
45
  {
@@ -51,6 +53,7 @@ describe(_authbasicguard.AuthBasicGuard.name, ()=>{
51
53
  ]
52
54
  }).compile();
53
55
  authBasicGuard = module.get(_authbasicguard.AuthBasicGuard);
56
+ authBasicStrategy = module.get(_authbasicstrategy.AuthBasicStrategy);
54
57
  authMethod = module.get(_authmethod.AuthMethod);
55
58
  cache = module.get(_cacheservice.Cache);
56
59
  userTest = new _usermodel.UserModel((0, _test.generateUserTest)(), false);
@@ -59,10 +62,12 @@ describe(_authbasicguard.AuthBasicGuard.name, ()=>{
59
62
  });
60
63
  it('should be defined', ()=>{
61
64
  expect(authBasicGuard).toBeDefined();
65
+ expect(authBasicStrategy).toBeDefined();
62
66
  expect(authMethod).toBeDefined();
63
67
  expect(cache).toBeDefined();
64
- expect(userTest).toBeDefined();
65
68
  expect(encodedAuth).toBeDefined();
69
+ expect(userTest).toBeDefined();
70
+ expect(userTest.password).toBeDefined();
66
71
  });
67
72
  it('should validate the user authentication', async ()=>{
68
73
  authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest);
@@ -75,6 +80,7 @@ describe(_authbasicguard.AuthBasicGuard.name, ()=>{
75
80
  }
76
81
  });
77
82
  expect(await authBasicGuard.canActivate(context)).toBe(true);
83
+ expect(userTest.password).toBeUndefined();
78
84
  });
79
85
  it('should validate the user authentication with cache', async ()=>{
80
86
  cache.get = jest.fn().mockReturnValueOnce(userTest);
@@ -88,6 +94,36 @@ describe(_authbasicguard.AuthBasicGuard.name, ()=>{
88
94
  });
89
95
  expect(await authBasicGuard.canActivate(context)).toBe(true);
90
96
  });
97
+ it('should not validate the user authentication when cache returns null (explicitly unauthorized)', async ()=>{
98
+ cache.get = jest.fn().mockReturnValueOnce(null);
99
+ context.switchToHttp().getRequest.mockReturnValue({
100
+ raw: {
101
+ user: ''
102
+ },
103
+ headers: {
104
+ authorization: `Basic ${encodedAuth}`
105
+ }
106
+ });
107
+ await expect(authBasicGuard.canActivate(context)).rejects.toThrow();
108
+ });
109
+ it('should not validate the user authentication when cache returns undefined and database return null', async ()=>{
110
+ cache.get = jest.fn().mockReturnValueOnce(undefined);
111
+ authMethod.validateUser = jest.fn().mockReturnValueOnce(null);
112
+ jest.spyOn(cache, 'set').mockRejectedValueOnce(new Error('cache failed'));
113
+ context.switchToHttp().getRequest.mockReturnValue({
114
+ raw: {
115
+ user: ''
116
+ },
117
+ headers: {
118
+ authorization: `Basic ${encodedAuth}`
119
+ }
120
+ });
121
+ const loggerSpy = jest.spyOn(authBasicStrategy['logger'], 'error') // <-- spy the SAME instance used in the class
122
+ .mockImplementation(()=>undefined);
123
+ await expect(authBasicGuard.canActivate(context)).rejects.toThrow();
124
+ expect(loggerSpy).toHaveBeenCalled();
125
+ expect(loggerSpy.mock.calls[0][0]).toEqual(expect.stringContaining('cache failed'));
126
+ });
91
127
  it('should not validate the user authentication', async ()=>{
92
128
  context.switchToHttp().getRequest.mockReturnValue({
93
129
  raw: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { generateUserTest } from '../../applications/users/utils/test'\nimport { WEBDAV_BASE_PATH } from '../../applications/webdav/constants/routes'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { AuthMethod } from '../models/auth-method'\nimport { AuthBasicGuard } from './auth-basic.guard'\nimport { AuthBasicStrategy } from './auth-basic.strategy'\n\ndescribe(AuthBasicGuard.name, () => {\n let authBasicGuard: AuthBasicGuard\n let authMethod: AuthMethod\n let cache: Cache\n let userTest: UserModel\n let encodedAuth: string\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthBasicGuard,\n AuthBasicStrategy,\n {\n provide: AuthMethod,\n useValue: {\n validateUser: async () => null\n }\n },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined\n }\n },\n {\n provide: Cache,\n useValue: {\n get: (_key: string) => undefined,\n set: async (_key: string, _value: string, _ttl: number) => undefined,\n genSlugKey: () => 'test'\n }\n }\n ]\n }).compile()\n\n authBasicGuard = module.get<AuthBasicGuard>(AuthBasicGuard)\n authMethod = module.get<AuthMethod>(AuthMethod)\n cache = module.get<Cache>(Cache)\n userTest = new UserModel(generateUserTest(), false)\n encodedAuth = Buffer.from(`${userTest.login}:${userTest.password}`).toString('base64')\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authBasicGuard).toBeDefined()\n expect(authMethod).toBeDefined()\n expect(cache).toBeDefined()\n expect(userTest).toBeDefined()\n expect(encodedAuth).toBeDefined()\n })\n\n it('should validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n })\n\n it('should validate the user authentication with cache', async () => {\n cache.get = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n })\n\n it('should not validate the user authentication', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should throw error due to malformed authorization header', async () => {\n // headers with capitals not working\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' },\n headers: { AUTHORIZATION: 'Basic foo' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it(`should valid OPTIONS method without authentication header on \"/\" and \"/${WEBDAV_BASE_PATH}/*\" paths `, async () => {\n for (const url of ['', `/${WEBDAV_BASE_PATH}`, `/${WEBDAV_BASE_PATH}/foo/bar`]) {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: url,\n raw: { user: '' }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n }\n })\n\n it('should not valid OPTIONS method with other paths', async () => {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: '/foo',\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n})\n"],"names":["describe","AuthBasicGuard","name","authBasicGuard","authMethod","cache","userTest","encodedAuth","context","beforeAll","module","Test","createTestingModule","providers","AuthBasicStrategy","provide","AuthMethod","useValue","validateUser","PinoLogger","assign","undefined","Cache","get","_key","set","_value","_ttl","genSlugKey","compile","UserModel","generateUserTest","Buffer","from","login","password","toString","createMock","it","expect","toBeDefined","jest","fn","mockReturnValueOnce","switchToHttp","getRequest","mockReturnValue","raw","user","headers","authorization","canActivate","toBe","rejects","toThrow","AUTHORIZATION","WEBDAV_BASE_PATH","url","method","originalUrl"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { generateUserTest } from '../../applications/users/utils/test'\nimport { WEBDAV_BASE_PATH } from '../../applications/webdav/constants/routes'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { AuthMethod } from '../models/auth-method'\nimport { AuthBasicGuard } from './auth-basic.guard'\nimport { AuthBasicStrategy } from './auth-basic.strategy'\n\ndescribe(AuthBasicGuard.name, () => {\n let authBasicGuard: AuthBasicGuard\n let authBasicStrategy: AuthBasicStrategy\n let authMethod: AuthMethod\n let cache: Cache\n let userTest: UserModel\n let encodedAuth: string\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthBasicGuard,\n AuthBasicStrategy,\n {\n provide: AuthMethod,\n useValue: {\n validateUser: async () => null\n }\n },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined,\n error: jest.fn()\n }\n },\n {\n provide: Cache,\n useValue: {\n get: (_key: string) => undefined,\n set: async (_key: string, _value: string, _ttl: number) => undefined,\n genSlugKey: () => 'test'\n }\n }\n ]\n }).compile()\n\n authBasicGuard = module.get<AuthBasicGuard>(AuthBasicGuard)\n authBasicStrategy = module.get<AuthBasicStrategy>(AuthBasicStrategy)\n authMethod = module.get<AuthMethod>(AuthMethod)\n cache = module.get<Cache>(Cache)\n userTest = new UserModel(generateUserTest(), false)\n encodedAuth = Buffer.from(`${userTest.login}:${userTest.password}`).toString('base64')\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authBasicGuard).toBeDefined()\n expect(authBasicStrategy).toBeDefined()\n expect(authMethod).toBeDefined()\n expect(cache).toBeDefined()\n expect(encodedAuth).toBeDefined()\n expect(userTest).toBeDefined()\n expect(userTest.password).toBeDefined()\n })\n\n it('should validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n expect(userTest.password).toBeUndefined()\n })\n\n it('should validate the user authentication with cache', async () => {\n cache.get = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n })\n\n it('should not validate the user authentication when cache returns null (explicitly unauthorized)', async () => {\n cache.get = jest.fn().mockReturnValueOnce(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should not validate the user authentication when cache returns undefined and database return null', async () => {\n cache.get = jest.fn().mockReturnValueOnce(undefined)\n authMethod.validateUser = jest.fn().mockReturnValueOnce(null)\n jest.spyOn(cache, 'set').mockRejectedValueOnce(new Error('cache failed'))\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n const loggerSpy = jest\n .spyOn(authBasicStrategy['logger'], 'error') // <-- spy the SAME instance used in the class\n .mockImplementation(() => undefined)\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0][0]).toEqual(expect.stringContaining('cache failed'))\n })\n\n it('should not validate the user authentication', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should throw error due to malformed authorization header', async () => {\n // headers with capitals not working\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' },\n headers: { AUTHORIZATION: 'Basic foo' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it(`should valid OPTIONS method without authentication header on \"/\" and \"/${WEBDAV_BASE_PATH}/*\" paths `, async () => {\n for (const url of ['', `/${WEBDAV_BASE_PATH}`, `/${WEBDAV_BASE_PATH}/foo/bar`]) {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: url,\n raw: { user: '' }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n }\n })\n\n it('should not valid OPTIONS method with other paths', async () => {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: '/foo',\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n})\n"],"names":["describe","AuthBasicGuard","name","authBasicGuard","authBasicStrategy","authMethod","cache","userTest","encodedAuth","context","beforeAll","module","Test","createTestingModule","providers","AuthBasicStrategy","provide","AuthMethod","useValue","validateUser","PinoLogger","assign","undefined","error","jest","fn","Cache","get","_key","set","_value","_ttl","genSlugKey","compile","UserModel","generateUserTest","Buffer","from","login","password","toString","createMock","it","expect","toBeDefined","mockReturnValueOnce","switchToHttp","getRequest","mockReturnValue","raw","user","headers","authorization","canActivate","toBe","toBeUndefined","rejects","toThrow","spyOn","mockRejectedValueOnce","Error","loggerSpy","mockImplementation","toHaveBeenCalled","mock","calls","toEqual","stringContaining","AUTHORIZATION","WEBDAV_BASE_PATH","url","method","originalUrl"],"mappings":"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"}
@@ -31,7 +31,6 @@ function _ts_metadata(k, v) {
31
31
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
32
32
  }
33
33
  let AuthBasicStrategy = class AuthBasicStrategy extends (0, _passport.PassportStrategy)(_passporthttp.BasicStrategy, 'basic') {
34
- // not declared properly: https://github.com/nestjs/passport/issues/929
35
34
  async validate(req, loginOrEmail, password) {
36
35
  this.logger.assign({
37
36
  user: loginOrEmail
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.strategy.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 } from '@nestjs/common'\nimport { PassportStrategy } from '@nestjs/passport'\nimport { instanceToPlain, plainToInstance } from 'class-transformer'\nimport { FastifyRequest } from 'fastify'\nimport { PinoLogger } from 'nestjs-pino'\nimport { BasicStrategy } from 'passport-http'\nimport { SERVER_NAME } from '../../app.constants'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { AuthMethod } from '../models/auth-method'\n\n@Injectable()\nexport class AuthBasicStrategy extends PassportStrategy(BasicStrategy, 'basic') {\n static readonly CACHE_TTL = 900\n\n constructor(\n private readonly authMethod: AuthMethod,\n private readonly cache: Cache,\n private readonly logger: PinoLogger\n ) {\n super({ passReqToCallback: true, realm: SERVER_NAME })\n }\n\n // not declared properly: https://github.com/nestjs/passport/issues/929\n async validate(req: FastifyRequest, loginOrEmail: string, password: string): Promise<Omit<UserModel, 'password'> | null> {\n this.logger.assign({ user: loginOrEmail })\n const authBasicUser = `auth-webdav-${req.headers['authorization'].split(' ').at(-1).toLowerCase()}`\n const userFromCache: any = await this.cache.get(authBasicUser)\n if (userFromCache === null) {\n // not authorized\n return null\n }\n if (userFromCache !== undefined) {\n // cached\n return plainToInstance(UserModel, userFromCache)\n }\n const userFromDB: UserModel = await this.authMethod.validateUser(loginOrEmail, password, req.ip)\n if (userFromDB !== null) {\n userFromDB.removePassword()\n }\n const userToCache: Record<string, any> | null = userFromDB ? instanceToPlain(userFromDB, { excludePrefixes: ['_'] }) : null\n this.cache.set(authBasicUser, userToCache, AuthBasicStrategy.CACHE_TTL).catch((e: Error) => this.logger.error(`${this.validate.name} - ${e}`))\n return userFromDB\n }\n}\n"],"names":["AuthBasicStrategy","PassportStrategy","BasicStrategy","validate","req","loginOrEmail","password","logger","assign","user","authBasicUser","headers","split","at","toLowerCase","userFromCache","cache","get","undefined","plainToInstance","UserModel","userFromDB","authMethod","validateUser","ip","removePassword","userToCache","instanceToPlain","excludePrefixes","set","CACHE_TTL","catch","e","error","name","passReqToCallback","realm","SERVER_NAME"],"mappings":"AAAA;;;;CAIC;;;;+BAcYA;;;eAAAA;;;wBAZc;0BACM;kCACgB;4BAEtB;8BACG;8BACF;2BACF;8BACJ;4BACK;;;;;;;;;;AAGpB,IAAA,AAAMA,oBAAN,MAAMA,0BAA0BC,IAAAA,0BAAgB,EAACC,2BAAa,EAAE;IAWrE,wEAAwE;IACxE,MAAMC,SAASC,GAAmB,EAAEC,YAAoB,EAAEC,QAAgB,EAA+C;QACvH,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMJ;QAAa;QACxC,MAAMK,gBAAgB,CAAC,YAAY,EAAEN,IAAIO,OAAO,CAAC,gBAAgB,CAACC,KAAK,CAAC,KAAKC,EAAE,CAAC,CAAC,GAAGC,WAAW,IAAI;QACnG,MAAMC,gBAAqB,MAAM,IAAI,CAACC,KAAK,CAACC,GAAG,CAACP;QAChD,IAAIK,kBAAkB,MAAM;YAC1B,iBAAiB;YACjB,OAAO;QACT;QACA,IAAIA,kBAAkBG,WAAW;YAC/B,SAAS;YACT,OAAOC,IAAAA,iCAAe,EAACC,oBAAS,EAAEL;QACpC;QACA,MAAMM,aAAwB,MAAM,IAAI,CAACC,UAAU,CAACC,YAAY,CAAClB,cAAcC,UAAUF,IAAIoB,EAAE;QAC/F,IAAIH,eAAe,MAAM;YACvBA,WAAWI,cAAc;QAC3B;QACA,MAAMC,cAA0CL,aAAaM,IAAAA,iCAAe,EAACN,YAAY;YAAEO,iBAAiB;gBAAC;aAAI;QAAC,KAAK;QACvH,IAAI,CAACZ,KAAK,CAACa,GAAG,CAACnB,eAAegB,aAAa1B,kBAAkB8B,SAAS,EAAEC,KAAK,CAAC,CAACC,IAAa,IAAI,CAACzB,MAAM,CAAC0B,KAAK,CAAC,GAAG,IAAI,CAAC9B,QAAQ,CAAC+B,IAAI,CAAC,GAAG,EAAEF,GAAG;QAC5I,OAAOX;IACT;IA5BA,YACE,AAAiBC,UAAsB,EACvC,AAAiBN,KAAY,EAC7B,AAAiBT,MAAkB,CACnC;QACA,KAAK,CAAC;YAAE4B,mBAAmB;YAAMC,OAAOC,yBAAW;QAAC,SAJnCf,aAAAA,iBACAN,QAAAA,YACAT,SAAAA;IAGnB;AAuBF;AAhCaP,kBACK8B,YAAY"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.strategy.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 } from '@nestjs/common'\nimport { AbstractStrategy, PassportStrategy } from '@nestjs/passport'\nimport { instanceToPlain, plainToInstance } from 'class-transformer'\nimport { FastifyRequest } from 'fastify'\nimport { PinoLogger } from 'nestjs-pino'\nimport { BasicStrategy } from 'passport-http'\nimport { SERVER_NAME } from '../../app.constants'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { AuthMethod } from '../models/auth-method'\n\n@Injectable()\nexport class AuthBasicStrategy extends PassportStrategy(BasicStrategy, 'basic') implements AbstractStrategy {\n static readonly CACHE_TTL = 900\n\n constructor(\n private readonly authMethod: AuthMethod,\n private readonly cache: Cache,\n private readonly logger: PinoLogger\n ) {\n super({ passReqToCallback: true, realm: SERVER_NAME })\n }\n\n async validate(req: FastifyRequest, loginOrEmail: string, password: string): Promise<Omit<UserModel, 'password'> | null> {\n this.logger.assign({ user: loginOrEmail })\n const authBasicUser = `auth-webdav-${req.headers['authorization'].split(' ').at(-1).toLowerCase()}`\n const userFromCache: any = await this.cache.get(authBasicUser)\n if (userFromCache === null) {\n // not authorized\n return null\n }\n if (userFromCache !== undefined) {\n // cached\n return plainToInstance(UserModel, userFromCache)\n }\n const userFromDB: UserModel = await this.authMethod.validateUser(loginOrEmail, password, req.ip)\n if (userFromDB !== null) {\n userFromDB.removePassword()\n }\n const userToCache: Record<string, any> | null = userFromDB ? instanceToPlain(userFromDB, { excludePrefixes: ['_'] }) : null\n this.cache.set(authBasicUser, userToCache, AuthBasicStrategy.CACHE_TTL).catch((e: Error) => this.logger.error(`${this.validate.name} - ${e}`))\n return userFromDB\n }\n}\n"],"names":["AuthBasicStrategy","PassportStrategy","BasicStrategy","validate","req","loginOrEmail","password","logger","assign","user","authBasicUser","headers","split","at","toLowerCase","userFromCache","cache","get","undefined","plainToInstance","UserModel","userFromDB","authMethod","validateUser","ip","removePassword","userToCache","instanceToPlain","excludePrefixes","set","CACHE_TTL","catch","e","error","name","passReqToCallback","realm","SERVER_NAME"],"mappings":"AAAA;;;;CAIC;;;;+BAcYA;;;eAAAA;;;wBAZc;0BACwB;kCACF;4BAEtB;8BACG;8BACF;2BACF;8BACJ;4BACK;;;;;;;;;;AAGpB,IAAA,AAAMA,oBAAN,MAAMA,0BAA0BC,IAAAA,0BAAgB,EAACC,2BAAa,EAAE;IAWrE,MAAMC,SAASC,GAAmB,EAAEC,YAAoB,EAAEC,QAAgB,EAA+C;QACvH,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMJ;QAAa;QACxC,MAAMK,gBAAgB,CAAC,YAAY,EAAEN,IAAIO,OAAO,CAAC,gBAAgB,CAACC,KAAK,CAAC,KAAKC,EAAE,CAAC,CAAC,GAAGC,WAAW,IAAI;QACnG,MAAMC,gBAAqB,MAAM,IAAI,CAACC,KAAK,CAACC,GAAG,CAACP;QAChD,IAAIK,kBAAkB,MAAM;YAC1B,iBAAiB;YACjB,OAAO;QACT;QACA,IAAIA,kBAAkBG,WAAW;YAC/B,SAAS;YACT,OAAOC,IAAAA,iCAAe,EAACC,oBAAS,EAAEL;QACpC;QACA,MAAMM,aAAwB,MAAM,IAAI,CAACC,UAAU,CAACC,YAAY,CAAClB,cAAcC,UAAUF,IAAIoB,EAAE;QAC/F,IAAIH,eAAe,MAAM;YACvBA,WAAWI,cAAc;QAC3B;QACA,MAAMC,cAA0CL,aAAaM,IAAAA,iCAAe,EAACN,YAAY;YAAEO,iBAAiB;gBAAC;aAAI;QAAC,KAAK;QACvH,IAAI,CAACZ,KAAK,CAACa,GAAG,CAACnB,eAAegB,aAAa1B,kBAAkB8B,SAAS,EAAEC,KAAK,CAAC,CAACC,IAAa,IAAI,CAACzB,MAAM,CAAC0B,KAAK,CAAC,GAAG,IAAI,CAAC9B,QAAQ,CAAC+B,IAAI,CAAC,GAAG,EAAEF,GAAG;QAC5I,OAAOX;IACT;IA3BA,YACE,AAAiBC,UAAsB,EACvC,AAAiBN,KAAY,EAC7B,AAAiBT,MAAkB,CACnC;QACA,KAAK,CAAC;YAAE4B,mBAAmB;YAAMC,OAAOC,yBAAW;QAAC,SAJnCf,aAAAA,iBACAN,QAAAA,YACAT,SAAAA;IAGnB;AAsBF;AA/BaP,kBACK8B,YAAY"}
@@ -3,8 +3,7 @@
3
3
  * This file is part of Sync-in | The open source file sync and share solution
4
4
  * See the LICENSE file for licensing details
5
5
  */ // import { ExecutionContext, Injectable, Logger } from '@nestjs/common'
6
- // import { AuthGuard } from '@nestjs/passport'
7
- // import { IAuthGuard } from '@nestjs/passport/dist/auth.guard'
6
+ // import { AuthGuard, IAuthGuard } from '@nestjs/passport'
8
7
  //
9
8
  // @Injectable()
10
9
  // export class AuthDigestGuard extends AuthGuard('digest') implements IAuthGuard {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-digest.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\n// import { ExecutionContext, Injectable, Logger } from '@nestjs/common'\n// import { AuthGuard } from '@nestjs/passport'\n// import { IAuthGuard } from '@nestjs/passport/dist/auth.guard'\n//\n// @Injectable()\n// export class AuthDigestGuard extends AuthGuard('digest') implements IAuthGuard {\n// private readonly logger = new Logger(AuthDigestGuard.name)\n//\n// handleRequest<TUser = any>(err: any, user: any, info: Error, ctx: ExecutionContext, status?: any): TUser {\n// const request = this.getRequest(ctx)\n// request.raw.user = user ? user.login : 'unauthorized'\n// if (info) {\n// this.logger.warn(`<${request.raw.user}> <${request.ip}> ${info}`)\n// }\n// return super.handleRequest(err, user, info, ctx, status)\n// }\n// }\n"],"names":[],"mappings":"AAAA;;;;CAIC,GAED,wEAAwE;AACxE,+CAA+C;AAC/C,gEAAgE;AAChE,EAAE;AACF,gBAAgB;AAChB,mFAAmF;AACnF,+DAA+D;AAC/D,EAAE;AACF,+GAA+G;AAC/G,2CAA2C;AAC3C,4DAA4D;AAC5D,kBAAkB;AAClB,0EAA0E;AAC1E,QAAQ;AACR,+DAA+D;AAC/D,MAAM;AACN,IAAI"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-digest.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\n// import { ExecutionContext, Injectable, Logger } from '@nestjs/common'\n// import { AuthGuard, IAuthGuard } from '@nestjs/passport'\n//\n// @Injectable()\n// export class AuthDigestGuard extends AuthGuard('digest') implements IAuthGuard {\n// private readonly logger = new Logger(AuthDigestGuard.name)\n//\n// handleRequest<TUser = any>(err: any, user: any, info: Error, ctx: ExecutionContext, status?: any): TUser {\n// const request = this.getRequest(ctx)\n// request.raw.user = user ? user.login : 'unauthorized'\n// if (info) {\n// this.logger.warn(`<${request.raw.user}> <${request.ip}> ${info}`)\n// }\n// return super.handleRequest(err, user, info, ctx, status)\n// }\n// }\n"],"names":[],"mappings":"AAAA;;;;CAIC,GAED,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,gBAAgB;AAChB,mFAAmF;AACnF,+DAA+D;AAC/D,EAAE;AACF,+GAA+G;AAC/G,2CAA2C;AAC3C,4DAA4D;AAC5D,kBAAkB;AAClB,0EAA0E;AAC1E,QAAQ;AACR,+DAA+D;AAC/D,MAAM;AACN,IAAI"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-local.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, Injectable, Logger } from '@nestjs/common'\nimport { AuthGuard } from '@nestjs/passport'\nimport { IAuthGuard } from '@nestjs/passport/dist/auth.guard'\n\n@Injectable()\nexport class AuthLocalGuard extends AuthGuard('local') implements IAuthGuard {\n private readonly logger = new Logger(AuthLocalGuard.name)\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":["AuthLocalGuard","AuthGuard","handleRequest","err","user","info","ctx","status","req","getRequest","raw","login","logger","warn","ip","Logger","name"],"mappings":"AAAA;;;;CAIC;;;;+BAOYA;;;eAAAA;;;wBALwC;0BAC3B;;;;;;;AAInB,IAAA,AAAMA,iBAAN,MAAMA,uBAAuBC,IAAAA,mBAAS,EAAC;IAG5CC,cAA2BC,GAAQ,EAAEC,IAAS,EAAEC,IAAW,EAAEC,GAAqB,EAAEC,MAAY,EAAS;QACvG,MAAMC,MAAM,IAAI,CAACC,UAAU,CAACH;QAC5BE,IAAIE,GAAG,CAACN,IAAI,GAAGA,MAAMO,SAAS;QAC9B,IAAIN,MAAM;YACR,IAAI,CAACO,MAAM,CAACC,IAAI,CAAC,CAAC,CAAC,EAAEL,IAAIE,GAAG,CAACN,IAAI,CAAC,GAAG,EAAEI,IAAIM,EAAE,CAAC,EAAE,EAAET,MAAM;QAC1D;QACA,OAAO,KAAK,CAACH,cAAcC,KAAKC,MAAMC,MAAMC,KAAKC;IACnD;;QAVK,qBACYK,SAAS,IAAIG,cAAM,CAACf,eAAegB,IAAI;;AAU1D"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-local.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, Injectable, Logger } from '@nestjs/common'\nimport { AuthGuard, IAuthGuard } from '@nestjs/passport'\n\n@Injectable()\nexport class AuthLocalGuard extends AuthGuard('local') implements IAuthGuard {\n private readonly logger = new Logger(AuthLocalGuard.name)\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":["AuthLocalGuard","AuthGuard","handleRequest","err","user","info","ctx","status","req","getRequest","raw","login","logger","warn","ip","Logger","name"],"mappings":"AAAA;;;;CAIC;;;;+BAMYA;;;eAAAA;;;wBAJwC;0BACf;;;;;;;AAG/B,IAAA,AAAMA,iBAAN,MAAMA,uBAAuBC,IAAAA,mBAAS,EAAC;IAG5CC,cAA2BC,GAAQ,EAAEC,IAAS,EAAEC,IAAW,EAAEC,GAAqB,EAAEC,MAAY,EAAS;QACvG,MAAMC,MAAM,IAAI,CAACC,UAAU,CAACH;QAC5BE,IAAIE,GAAG,CAACN,IAAI,GAAGA,MAAMO,SAAS;QAC9B,IAAIN,MAAM;YACR,IAAI,CAACO,MAAM,CAACC,IAAI,CAAC,CAAC,CAAC,EAAEL,IAAIE,GAAG,CAACN,IAAI,CAAC,GAAG,EAAEI,IAAIM,EAAE,CAAC,EAAE,EAAET,MAAM;QAC1D;QACA,OAAO,KAAK,CAACH,cAAcC,KAAKC,MAAMC,MAAMC,KAAKC;IACnD;;QAVK,qBACYK,SAAS,IAAIG,cAAM,CAACf,eAAegB,IAAI;;AAU1D"}
@@ -47,7 +47,7 @@ describe(_authlocalguard.AuthLocalGuard.name, ()=>{
47
47
  expect(userTest).toBeDefined();
48
48
  });
49
49
  it('should validate the user authentication', async ()=>{
50
- authMethod.validateUser = jest.fn().mockReturnValue(userTest);
50
+ authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest);
51
51
  context.switchToHttp().getRequest.mockReturnValue({
52
52
  raw: {
53
53
  user: ''
@@ -57,10 +57,12 @@ describe(_authlocalguard.AuthLocalGuard.name, ()=>{
57
57
  password: userTest.password
58
58
  }
59
59
  });
60
- expect(await authLocalGuard.canActivate(context)).toBeDefined();
60
+ expect(await authLocalGuard.canActivate(context)).toBe(true);
61
+ expect(userTest.password).toBeUndefined();
61
62
  });
62
63
  it('should not validate the user authentication', async ()=>{
63
- authMethod.validateUser = jest.fn().mockReturnValue(null);
64
+ userTest.password = 'password';
65
+ authMethod.validateUser = jest.fn().mockReturnValueOnce(null);
64
66
  context.switchToHttp().getRequest.mockReturnValue({
65
67
  raw: {
66
68
  user: ''
@@ -70,10 +72,10 @@ describe(_authlocalguard.AuthLocalGuard.name, ()=>{
70
72
  password: userTest.password
71
73
  }
72
74
  });
73
- await expect(authLocalGuard.canActivate(context)).rejects.toThrow();
75
+ await expect(authLocalGuard.canActivate(context)).rejects.toThrow(/password/i);
74
76
  });
75
77
  it('should throw error due to malformed body', async ()=>{
76
- authMethod.validateUser = jest.fn().mockReturnValue(null);
78
+ authMethod.validateUser = jest.fn().mockReturnValueOnce(null);
77
79
  context.switchToHttp().getRequest.mockReturnValue({
78
80
  raw: {
79
81
  user: ''
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-local.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { generateUserTest } from '../../applications/users/utils/test'\nimport { AuthMethod } from '../models/auth-method'\nimport { AuthLocalGuard } from './auth-local.guard'\nimport { AuthLocalStrategy } from './auth-local.strategy'\n\ndescribe(AuthLocalGuard.name, () => {\n let authLocalGuard: AuthLocalGuard\n let authMethod: AuthMethod\n let userTest: UserModel\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthLocalGuard,\n AuthLocalStrategy,\n { provide: AuthMethod, useValue: {} },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined\n }\n }\n ]\n }).compile()\n\n authLocalGuard = module.get<AuthLocalGuard>(AuthLocalGuard)\n authMethod = module.get<AuthMethod>(AuthMethod)\n userTest = new UserModel(generateUserTest(), false)\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authLocalGuard).toBeDefined()\n expect(authMethod).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValue(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n body: {\n login: userTest.login,\n password: userTest.password\n }\n })\n expect(await authLocalGuard.canActivate(context)).toBeDefined()\n })\n\n it('should not validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValue(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n body: {\n login: userTest.login,\n password: userTest.password\n }\n })\n await expect(authLocalGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should throw error due to malformed body', async () => {\n authMethod.validateUser = jest.fn().mockReturnValue(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n body: null\n })\n await expect(authLocalGuard.canActivate(context)).rejects.toThrow()\n })\n})\n"],"names":["describe","AuthLocalGuard","name","authLocalGuard","authMethod","userTest","context","beforeAll","module","Test","createTestingModule","providers","AuthLocalStrategy","provide","AuthMethod","useValue","PinoLogger","assign","undefined","compile","get","UserModel","generateUserTest","createMock","it","expect","toBeDefined","validateUser","jest","fn","mockReturnValue","switchToHttp","getRequest","raw","user","body","login","password","canActivate","rejects","toThrow"],"mappings":"AAAA;;;;CAIC;;;;wBAEsC;yBAEH;4BACT;2BACD;sBACO;4BACN;gCACI;mCACG;AAElCA,SAASC,8BAAc,CAACC,IAAI,EAAE;IAC5B,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTV,8BAAc;gBACdW,oCAAiB;gBACjB;oBAAEC,SAASC,sBAAU;oBAAEC,UAAU,CAAC;gBAAE;gBACpC;oBACEF,SAASG,sBAAU;oBACnBD,UAAU;wBACRE,QAAQ,IAAMC;oBAChB;gBACF;aACD;QACH,GAAGC,OAAO;QAEVhB,iBAAiBK,OAAOY,GAAG,CAAiBnB,8BAAc;QAC1DG,aAAaI,OAAOY,GAAG,CAAaN,sBAAU;QAC9CT,WAAW,IAAIgB,oBAAS,CAACC,IAAAA,sBAAgB,KAAI;QAC7ChB,UAAUiB,IAAAA,kBAAU;IACtB;IAEAC,GAAG,qBAAqB;QACtBC,OAAOtB,gBAAgBuB,WAAW;QAClCD,OAAOrB,YAAYsB,WAAW;QAC9BD,OAAOpB,UAAUqB,WAAW;IAC9B;IAEAF,GAAG,2CAA2C;QAC5CpB,WAAWuB,YAAY,GAAGC,KAAKC,EAAE,GAAGC,eAAe,CAACzB;QACpDC,QAAQyB,YAAY,GAAGC,UAAU,CAACF,eAAe,CAAC;YAChDG,KAAK;gBAAEC,MAAM;YAAG;YAChBC,MAAM;gBACJC,OAAO/B,SAAS+B,KAAK;gBACrBC,UAAUhC,SAASgC,QAAQ;YAC7B;QACF;QACAZ,OAAO,MAAMtB,eAAemC,WAAW,CAAChC,UAAUoB,WAAW;IAC/D;IAEAF,GAAG,+CAA+C;QAChDpB,WAAWuB,YAAY,GAAGC,KAAKC,EAAE,GAAGC,eAAe,CAAC;QACpDxB,QAAQyB,YAAY,GAAGC,UAAU,CAACF,eAAe,CAAC;YAChDG,KAAK;gBAAEC,MAAM;YAAG;YAChBC,MAAM;gBACJC,OAAO/B,SAAS+B,KAAK;gBACrBC,UAAUhC,SAASgC,QAAQ;YAC7B;QACF;QACA,MAAMZ,OAAOtB,eAAemC,WAAW,CAAChC,UAAUiC,OAAO,CAACC,OAAO;IACnE;IAEAhB,GAAG,4CAA4C;QAC7CpB,WAAWuB,YAAY,GAAGC,KAAKC,EAAE,GAAGC,eAAe,CAAC;QACpDxB,QAAQyB,YAAY,GAAGC,UAAU,CAACF,eAAe,CAAC;YAChDG,KAAK;gBAAEC,MAAM;YAAG;YAChBC,MAAM;QACR;QACA,MAAMV,OAAOtB,eAAemC,WAAW,CAAChC,UAAUiC,OAAO,CAACC,OAAO;IACnE;AACF"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-local.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { generateUserTest } from '../../applications/users/utils/test'\nimport { AuthMethod } from '../models/auth-method'\nimport { AuthLocalGuard } from './auth-local.guard'\nimport { AuthLocalStrategy } from './auth-local.strategy'\n\ndescribe(AuthLocalGuard.name, () => {\n let authLocalGuard: AuthLocalGuard\n let authMethod: AuthMethod\n let userTest: UserModel\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthLocalGuard,\n AuthLocalStrategy,\n { provide: AuthMethod, useValue: {} },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined\n }\n }\n ]\n }).compile()\n\n authLocalGuard = module.get<AuthLocalGuard>(AuthLocalGuard)\n authMethod = module.get<AuthMethod>(AuthMethod)\n userTest = new UserModel(generateUserTest(), false)\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authLocalGuard).toBeDefined()\n expect(authMethod).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n body: {\n login: userTest.login,\n password: userTest.password\n }\n })\n expect(await authLocalGuard.canActivate(context)).toBe(true)\n expect(userTest.password).toBeUndefined()\n })\n\n it('should not validate the user authentication', async () => {\n userTest.password = 'password'\n authMethod.validateUser = jest.fn().mockReturnValueOnce(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n body: {\n login: userTest.login,\n password: userTest.password\n }\n })\n await expect(authLocalGuard.canActivate(context)).rejects.toThrow(/password/i)\n })\n\n it('should throw error due to malformed body', async () => {\n authMethod.validateUser = jest.fn().mockReturnValueOnce(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n body: null\n })\n await expect(authLocalGuard.canActivate(context)).rejects.toThrow()\n })\n})\n"],"names":["describe","AuthLocalGuard","name","authLocalGuard","authMethod","userTest","context","beforeAll","module","Test","createTestingModule","providers","AuthLocalStrategy","provide","AuthMethod","useValue","PinoLogger","assign","undefined","compile","get","UserModel","generateUserTest","createMock","it","expect","toBeDefined","validateUser","jest","fn","mockReturnValueOnce","switchToHttp","getRequest","mockReturnValue","raw","user","body","login","password","canActivate","toBe","toBeUndefined","rejects","toThrow"],"mappings":"AAAA;;;;CAIC;;;;wBAEsC;yBAEH;4BACT;2BACD;sBACO;4BACN;gCACI;mCACG;AAElCA,SAASC,8BAAc,CAACC,IAAI,EAAE;IAC5B,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACTV,8BAAc;gBACdW,oCAAiB;gBACjB;oBAAEC,SAASC,sBAAU;oBAAEC,UAAU,CAAC;gBAAE;gBACpC;oBACEF,SAASG,sBAAU;oBACnBD,UAAU;wBACRE,QAAQ,IAAMC;oBAChB;gBACF;aACD;QACH,GAAGC,OAAO;QAEVhB,iBAAiBK,OAAOY,GAAG,CAAiBnB,8BAAc;QAC1DG,aAAaI,OAAOY,GAAG,CAAaN,sBAAU;QAC9CT,WAAW,IAAIgB,oBAAS,CAACC,IAAAA,sBAAgB,KAAI;QAC7ChB,UAAUiB,IAAAA,kBAAU;IACtB;IAEAC,GAAG,qBAAqB;QACtBC,OAAOtB,gBAAgBuB,WAAW;QAClCD,OAAOrB,YAAYsB,WAAW;QAC9BD,OAAOpB,UAAUqB,WAAW;IAC9B;IAEAF,GAAG,2CAA2C;QAC5CpB,WAAWuB,YAAY,GAAGC,KAAKC,EAAE,GAAGC,mBAAmB,CAACzB;QACxDC,QAAQyB,YAAY,GAAGC,UAAU,CAACC,eAAe,CAAC;YAChDC,KAAK;gBAAEC,MAAM;YAAG;YAChBC,MAAM;gBACJC,OAAOhC,SAASgC,KAAK;gBACrBC,UAAUjC,SAASiC,QAAQ;YAC7B;QACF;QACAb,OAAO,MAAMtB,eAAeoC,WAAW,CAACjC,UAAUkC,IAAI,CAAC;QACvDf,OAAOpB,SAASiC,QAAQ,EAAEG,aAAa;IACzC;IAEAjB,GAAG,+CAA+C;QAChDnB,SAASiC,QAAQ,GAAG;QACpBlC,WAAWuB,YAAY,GAAGC,KAAKC,EAAE,GAAGC,mBAAmB,CAAC;QACxDxB,QAAQyB,YAAY,GAAGC,UAAU,CAACC,eAAe,CAAC;YAChDC,KAAK;gBAAEC,MAAM;YAAG;YAChBC,MAAM;gBACJC,OAAOhC,SAASgC,KAAK;gBACrBC,UAAUjC,SAASiC,QAAQ;YAC7B;QACF;QACA,MAAMb,OAAOtB,eAAeoC,WAAW,CAACjC,UAAUoC,OAAO,CAACC,OAAO,CAAC;IACpE;IAEAnB,GAAG,4CAA4C;QAC7CpB,WAAWuB,YAAY,GAAGC,KAAKC,EAAE,GAAGC,mBAAmB,CAAC;QACxDxB,QAAQyB,YAAY,GAAGC,UAAU,CAACC,eAAe,CAAC;YAChDC,KAAK;gBAAEC,MAAM;YAAG;YAChBC,MAAM;QACR;QACA,MAAMX,OAAOtB,eAAeoC,WAAW,CAACjC,UAAUoC,OAAO,CAACC,OAAO;IACnE;AACF"}
@@ -27,7 +27,6 @@ function _ts_metadata(k, v) {
27
27
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
28
28
  }
29
29
  let AuthLocalStrategy = class AuthLocalStrategy extends (0, _passport.PassportStrategy)(_passportlocal.Strategy, 'local') {
30
- // not declared properly: https://github.com/nestjs/passport/issues/929
31
30
  async validate(req, loginOrEmail, password) {
32
31
  this.logger.assign({
33
32
  user: loginOrEmail
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-local.strategy.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, UnauthorizedException } from '@nestjs/common'\nimport { PassportStrategy } from '@nestjs/passport'\nimport type { FastifyRequest } from 'fastify'\nimport { PinoLogger } from 'nestjs-pino'\nimport { Strategy } from 'passport-local'\nimport type { UserModel } from '../../applications/users/models/user.model'\nimport { AuthMethod } from '../models/auth-method'\n\n@Injectable()\nexport class AuthLocalStrategy extends PassportStrategy(Strategy, 'local') implements Strategy {\n constructor(\n private readonly authMethod: AuthMethod,\n private readonly logger: PinoLogger\n ) {\n super({ usernameField: 'login', passwordField: 'password', passReqToCallback: true })\n }\n\n // not declared properly: https://github.com/nestjs/passport/issues/929\n async validate(req: FastifyRequest, loginOrEmail: string, password: string): Promise<UserModel> {\n this.logger.assign({ user: loginOrEmail })\n const user: UserModel = await this.authMethod.validateUser(loginOrEmail, password, req.ip)\n if (user) {\n user.removePassword()\n return user\n }\n throw new UnauthorizedException('Wrong login or password')\n }\n}\n"],"names":["AuthLocalStrategy","PassportStrategy","Strategy","validate","req","loginOrEmail","password","logger","assign","user","authMethod","validateUser","ip","removePassword","UnauthorizedException","usernameField","passwordField","passReqToCallback"],"mappings":"AAAA;;;;CAIC;;;;+BAWYA;;;eAAAA;;;wBATqC;0BACjB;4BAEN;+BACF;4BAEE;;;;;;;;;;AAGpB,IAAA,AAAMA,oBAAN,MAAMA,0BAA0BC,IAAAA,0BAAgB,EAACC,uBAAQ,EAAE;IAQhE,wEAAwE;IACxE,MAAMC,SAASC,GAAmB,EAAEC,YAAoB,EAAEC,QAAgB,EAAsB;QAC9F,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMJ;QAAa;QACxC,MAAMI,OAAkB,MAAM,IAAI,CAACC,UAAU,CAACC,YAAY,CAACN,cAAcC,UAAUF,IAAIQ,EAAE;QACzF,IAAIH,MAAM;YACRA,KAAKI,cAAc;YACnB,OAAOJ;QACT;QACA,MAAM,IAAIK,6BAAqB,CAAC;IAClC;IAhBA,YACE,AAAiBJ,UAAsB,EACvC,AAAiBH,MAAkB,CACnC;QACA,KAAK,CAAC;YAAEQ,eAAe;YAASC,eAAe;YAAYC,mBAAmB;QAAK,SAHlEP,aAAAA,iBACAH,SAAAA;IAGnB;AAYF"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-local.strategy.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, UnauthorizedException } from '@nestjs/common'\nimport { PassportStrategy, AbstractStrategy } from '@nestjs/passport'\nimport type { FastifyRequest } from 'fastify'\nimport { PinoLogger } from 'nestjs-pino'\nimport { Strategy } from 'passport-local'\nimport type { UserModel } from '../../applications/users/models/user.model'\nimport { AuthMethod } from '../models/auth-method'\n\n@Injectable()\nexport class AuthLocalStrategy extends PassportStrategy(Strategy, 'local') implements AbstractStrategy {\n constructor(\n private readonly authMethod: AuthMethod,\n private readonly logger: PinoLogger\n ) {\n super({ usernameField: 'login', passwordField: 'password', passReqToCallback: true })\n }\n\n async validate(req: FastifyRequest, loginOrEmail: string, password: string): Promise<UserModel> {\n this.logger.assign({ user: loginOrEmail })\n const user: UserModel = await this.authMethod.validateUser(loginOrEmail, password, req.ip)\n if (user) {\n user.removePassword()\n return user\n }\n throw new UnauthorizedException('Wrong login or password')\n }\n}\n"],"names":["AuthLocalStrategy","PassportStrategy","Strategy","validate","req","loginOrEmail","password","logger","assign","user","authMethod","validateUser","ip","removePassword","UnauthorizedException","usernameField","passwordField","passReqToCallback"],"mappings":"AAAA;;;;CAIC;;;;+BAWYA;;;eAAAA;;;wBATqC;0BACC;4BAExB;+BACF;4BAEE;;;;;;;;;;AAGpB,IAAA,AAAMA,oBAAN,MAAMA,0BAA0BC,IAAAA,0BAAgB,EAACC,uBAAQ,EAAE;IAQhE,MAAMC,SAASC,GAAmB,EAAEC,YAAoB,EAAEC,QAAgB,EAAsB;QAC9F,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMJ;QAAa;QACxC,MAAMI,OAAkB,MAAM,IAAI,CAACC,UAAU,CAACC,YAAY,CAACN,cAAcC,UAAUF,IAAIQ,EAAE;QACzF,IAAIH,MAAM;YACRA,KAAKI,cAAc;YACnB,OAAOJ;QACT;QACA,MAAM,IAAIK,6BAAqB,CAAC;IAClC;IAfA,YACE,AAAiBJ,UAAsB,EACvC,AAAiBH,MAAkB,CACnC;QACA,KAAK,CAAC;YAAEQ,eAAe;YAASC,eAAe;YAAYC,mBAAmB;QAAK,SAHlEP,aAAAA,iBACAH,SAAAA;IAGnB;AAWF"}
@@ -200,6 +200,36 @@ describe(_authtokenaccessguard.AuthTokenAccessGuard.name, ()=>{
200
200
  });
201
201
  await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(_auth.CSRF_ERROR.MISMATCH));
202
202
  });
203
+ it('should pass with method GET and a valid access token in cookies and a mismatch CSRF', async ()=>{
204
+ context.switchToHttp().getRequest.mockReturnValue({
205
+ method: 'GET',
206
+ raw: {
207
+ user: ''
208
+ },
209
+ headers: {
210
+ [authConfig.token.csrf.name]: csrfToken + '*'
211
+ },
212
+ cookies: {
213
+ [authConfig.token.access.name]: accessToken
214
+ }
215
+ });
216
+ await expect(authAccessGuard.canActivate(context)).resolves.not.toThrow();
217
+ });
218
+ it('should throw an error with method POST and a valid access token in cookies and a mismatch CSRF', async ()=>{
219
+ context.switchToHttp().getRequest.mockReturnValue({
220
+ method: 'POST',
221
+ raw: {
222
+ user: ''
223
+ },
224
+ headers: {
225
+ [authConfig.token.csrf.name]: csrfToken + '*'
226
+ },
227
+ cookies: {
228
+ [authConfig.token.access.name]: accessToken
229
+ }
230
+ });
231
+ await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(_auth.CSRF_ERROR.MISMATCH));
232
+ });
203
233
  it('should bypass access token when AuthTokenSkip decorator is applied to context', ()=>{
204
234
  context = (0, _tsjest.createMock)();
205
235
  (0, _authtokenskipdecorator.AuthTokenSkip)()(context.getHandler());
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-token-access.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { sign } from '@fastify/cookie'\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { ConfigModule, ConfigService } from '@nestjs/config'\nimport { Reflector } from '@nestjs/core'\nimport { JwtModule, JwtService } from '@nestjs/jwt'\nimport { PassportModule } from '@nestjs/passport'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport crypto from 'node:crypto'\nimport { UsersManager } from '../../applications/users/services/users-manager.service'\nimport { WEB_DAV_CONTEXT, WebDAVContext } from '../../applications/webdav/decorators/webdav-context.decorator'\nimport { exportConfiguration } from '../../configuration/config.environment'\nimport { AuthConfig } from '../auth.config'\nimport { CSRF_ERROR } from '../constants/auth'\nimport { AuthTokenOptional } from '../decorators/auth-token-optional.decorator'\nimport { AUTH_TOKEN_SKIP, AuthTokenSkip } from '../decorators/auth-token-skip.decorator'\nimport { JwtPayload } from '../interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from '../interfaces/token.interface'\nimport { AuthManager } from '../services/auth-manager.service'\nimport { AuthAnonymousGuard } from './auth-anonymous.guard'\nimport { AuthAnonymousStrategy } from './auth-anonymous.strategy'\nimport { AuthTokenAccessGuard } from './auth-token-access.guard'\nimport { AuthTokenAccessStrategy } from './auth-token-access.strategy'\n\ndescribe(AuthTokenAccessGuard.name, () => {\n const csrfToken: string = crypto.randomUUID()\n let authConfig: AuthConfig\n let jwtService: JwtService\n let authAccessGuard: AuthTokenAccessGuard\n let authAnonymousGuard: AuthAnonymousGuard\n let authAnonymousStrategy: AuthAnonymousStrategy\n let reflector: Reflector\n let accessTokenWithoutCSRF: string\n let accessToken: string\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n imports: [\n await ConfigModule.forRoot({\n load: [exportConfiguration],\n isGlobal: true\n }),\n JwtModule.register({ global: true }),\n PassportModule\n ],\n providers: [\n AuthTokenAccessStrategy,\n AuthAnonymousStrategy,\n AuthAnonymousGuard,\n AuthManager,\n { provide: UsersManager, useValue: {} },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined\n }\n }\n ]\n }).compile()\n\n authConfig = module.get<ConfigService>(ConfigService).get<AuthConfig>('auth')\n jwtService = module.get<JwtService>(JwtService)\n reflector = new Reflector()\n authAccessGuard = new AuthTokenAccessGuard(reflector)\n authAnonymousStrategy = module.get<AuthAnonymousStrategy>(AuthAnonymousStrategy)\n authAnonymousGuard = module.get<AuthAnonymousGuard>(AuthAnonymousGuard)\n accessToken = await jwtService.signAsync({ identity: { id: 1, login: 'foo' }, [TOKEN_TYPE.CSRF]: csrfToken } as JwtPayload, {\n secret: authConfig.token.access.secret,\n expiresIn: 30\n })\n accessTokenWithoutCSRF = await jwtService.signAsync({ identity: { id: 1, login: 'foo' } } as JwtPayload, {\n secret: authConfig.token.access.secret,\n expiresIn: 30\n })\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authConfig).toBeDefined()\n expect(jwtService).toBeDefined()\n expect(authAccessGuard).toBeDefined()\n expect(authAnonymousGuard).toBeDefined()\n expect(authAnonymousStrategy).toBeDefined()\n expect(accessToken).toBeDefined()\n expect(accessTokenWithoutCSRF).toBeDefined()\n expect(csrfToken).toBeDefined()\n })\n\n it('should pass with a valid access token in cookies with CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: sign(csrfToken, authConfig.token.csrf.secret) },\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n expect(await authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should pass with a valid access token in request header with no CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer ${accessToken}`\n }\n })\n expect(await authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should throw an error with an invalid access token in cookies', async () => {\n // Cookies test\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {},\n cookies: {\n [authConfig.token.access.name]: 'bar'\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow('Unauthorized')\n })\n\n it('should throw an error with an invalid access token in request header', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer bar`\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow('Unauthorized')\n })\n\n it('should throw an error with a valid access token in cookies and a missing CSRF in request header', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {},\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISSING_HEADERS))\n })\n\n it('should throw an error with a valid access token in cookies and a missing CSRF claim in the access token', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: csrfToken },\n cookies: {\n [authConfig.token.access.name]: accessTokenWithoutCSRF\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISSING_JWT))\n })\n\n it('should throw an error with a valid access token in cookies and a mismatch CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: csrfToken + '*' },\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISMATCH))\n })\n\n it('should bypass access token when AuthTokenSkip decorator is applied to context', () => {\n context = createMock<ExecutionContext>()\n AuthTokenSkip()(context.getHandler())\n expect(reflector.getAllAndOverride<boolean>(AUTH_TOKEN_SKIP, [context.getHandler(), context.getClass()])).toBe(true)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer bar`\n }\n })\n expect(authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should bypass access token with WebDAVContext decorator is applied to context', () => {\n context = createMock<ExecutionContext>()\n WebDAVContext()(context.getHandler())\n expect(reflector.getAllAndOverride<boolean>(AUTH_TOKEN_SKIP, [context.getHandler(), context.getClass()])).toBe(undefined)\n expect(reflector.getAllAndOverride<boolean>(WEB_DAV_CONTEXT, [context.getHandler(), context.getClass()])).toBe(true)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer bar`\n }\n })\n expect(authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should pass without a valid access token when AuthTokenOptional is applied to context', async () => {\n const spyAuthenticate = jest.spyOn(authAnonymousStrategy, 'authenticate')\n context = createMock<ExecutionContext>()\n AuthTokenOptional()(context.getHandler())\n expect(reflector.getAllAndOverride<boolean>(AUTH_TOKEN_SKIP, [context.getHandler(), context.getClass()])).toBe(true)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n authorization: `Bearer bar`\n })\n expect(authAccessGuard.canActivate(context)).toBe(true)\n expect(await authAnonymousGuard.canActivate(context)).toBe(true)\n expect(spyAuthenticate).toHaveBeenCalledTimes(1)\n spyAuthenticate.mockClear()\n })\n})\n"],"names":["describe","AuthTokenAccessGuard","name","csrfToken","crypto","randomUUID","authConfig","jwtService","authAccessGuard","authAnonymousGuard","authAnonymousStrategy","reflector","accessTokenWithoutCSRF","accessToken","context","beforeAll","module","Test","createTestingModule","imports","ConfigModule","forRoot","load","exportConfiguration","isGlobal","JwtModule","register","global","PassportModule","providers","AuthTokenAccessStrategy","AuthAnonymousStrategy","AuthAnonymousGuard","AuthManager","provide","UsersManager","useValue","PinoLogger","assign","undefined","compile","get","ConfigService","JwtService","Reflector","signAsync","identity","id","login","TOKEN_TYPE","CSRF","secret","token","access","expiresIn","createMock","it","expect","toBeDefined","switchToHttp","getRequest","mockReturnValue","raw","user","headers","csrf","sign","cookies","canActivate","toBe","authorization","rejects","toThrow","RegExp","CSRF_ERROR","MISSING_HEADERS","MISSING_JWT","MISMATCH","AuthTokenSkip","getHandler","getAllAndOverride","AUTH_TOKEN_SKIP","getClass","WebDAVContext","WEB_DAV_CONTEXT","spyAuthenticate","jest","spyOn","AuthTokenOptional","toHaveBeenCalledTimes","mockClear"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-token-access.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { sign } from '@fastify/cookie'\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { ConfigModule, ConfigService } from '@nestjs/config'\nimport { Reflector } from '@nestjs/core'\nimport { JwtModule, JwtService } from '@nestjs/jwt'\nimport { PassportModule } from '@nestjs/passport'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport crypto from 'node:crypto'\nimport { UsersManager } from '../../applications/users/services/users-manager.service'\nimport { WEB_DAV_CONTEXT, WebDAVContext } from '../../applications/webdav/decorators/webdav-context.decorator'\nimport { exportConfiguration } from '../../configuration/config.environment'\nimport { AuthConfig } from '../auth.config'\nimport { CSRF_ERROR } from '../constants/auth'\nimport { AuthTokenOptional } from '../decorators/auth-token-optional.decorator'\nimport { AUTH_TOKEN_SKIP, AuthTokenSkip } from '../decorators/auth-token-skip.decorator'\nimport { JwtPayload } from '../interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from '../interfaces/token.interface'\nimport { AuthManager } from '../services/auth-manager.service'\nimport { AuthAnonymousGuard } from './auth-anonymous.guard'\nimport { AuthAnonymousStrategy } from './auth-anonymous.strategy'\nimport { AuthTokenAccessGuard } from './auth-token-access.guard'\nimport { AuthTokenAccessStrategy } from './auth-token-access.strategy'\n\ndescribe(AuthTokenAccessGuard.name, () => {\n const csrfToken: string = crypto.randomUUID()\n let authConfig: AuthConfig\n let jwtService: JwtService\n let authAccessGuard: AuthTokenAccessGuard\n let authAnonymousGuard: AuthAnonymousGuard\n let authAnonymousStrategy: AuthAnonymousStrategy\n let reflector: Reflector\n let accessTokenWithoutCSRF: string\n let accessToken: string\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n imports: [\n await ConfigModule.forRoot({\n load: [exportConfiguration],\n isGlobal: true\n }),\n JwtModule.register({ global: true }),\n PassportModule\n ],\n providers: [\n AuthTokenAccessStrategy,\n AuthAnonymousStrategy,\n AuthAnonymousGuard,\n AuthManager,\n { provide: UsersManager, useValue: {} },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined\n }\n }\n ]\n }).compile()\n\n authConfig = module.get<ConfigService>(ConfigService).get<AuthConfig>('auth')\n jwtService = module.get<JwtService>(JwtService)\n reflector = new Reflector()\n authAccessGuard = new AuthTokenAccessGuard(reflector)\n authAnonymousStrategy = module.get<AuthAnonymousStrategy>(AuthAnonymousStrategy)\n authAnonymousGuard = module.get<AuthAnonymousGuard>(AuthAnonymousGuard)\n accessToken = await jwtService.signAsync({ identity: { id: 1, login: 'foo' }, [TOKEN_TYPE.CSRF]: csrfToken } as JwtPayload, {\n secret: authConfig.token.access.secret,\n expiresIn: 30\n })\n accessTokenWithoutCSRF = await jwtService.signAsync({ identity: { id: 1, login: 'foo' } } as JwtPayload, {\n secret: authConfig.token.access.secret,\n expiresIn: 30\n })\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authConfig).toBeDefined()\n expect(jwtService).toBeDefined()\n expect(authAccessGuard).toBeDefined()\n expect(authAnonymousGuard).toBeDefined()\n expect(authAnonymousStrategy).toBeDefined()\n expect(accessToken).toBeDefined()\n expect(accessTokenWithoutCSRF).toBeDefined()\n expect(csrfToken).toBeDefined()\n })\n\n it('should pass with a valid access token in cookies with CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: sign(csrfToken, authConfig.token.csrf.secret) },\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n expect(await authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should pass with a valid access token in request header with no CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer ${accessToken}`\n }\n })\n expect(await authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should throw an error with an invalid access token in cookies', async () => {\n // Cookies test\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {},\n cookies: {\n [authConfig.token.access.name]: 'bar'\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow('Unauthorized')\n })\n\n it('should throw an error with an invalid access token in request header', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer bar`\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow('Unauthorized')\n })\n\n it('should throw an error with a valid access token in cookies and a missing CSRF in request header', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {},\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISSING_HEADERS))\n })\n\n it('should throw an error with a valid access token in cookies and a missing CSRF claim in the access token', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: csrfToken },\n cookies: {\n [authConfig.token.access.name]: accessTokenWithoutCSRF\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISSING_JWT))\n })\n\n it('should throw an error with a valid access token in cookies and a mismatch CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: csrfToken + '*' },\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISMATCH))\n })\n\n it('should pass with method GET and a valid access token in cookies and a mismatch CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n method: 'GET',\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: csrfToken + '*' },\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n await expect(authAccessGuard.canActivate(context)).resolves.not.toThrow()\n })\n\n it('should throw an error with method POST and a valid access token in cookies and a mismatch CSRF', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n method: 'POST',\n raw: { user: '' },\n headers: { [authConfig.token.csrf.name]: csrfToken + '*' },\n cookies: {\n [authConfig.token.access.name]: accessToken\n }\n })\n await expect(authAccessGuard.canActivate(context)).rejects.toThrow(new RegExp(CSRF_ERROR.MISMATCH))\n })\n\n it('should bypass access token when AuthTokenSkip decorator is applied to context', () => {\n context = createMock<ExecutionContext>()\n AuthTokenSkip()(context.getHandler())\n expect(reflector.getAllAndOverride<boolean>(AUTH_TOKEN_SKIP, [context.getHandler(), context.getClass()])).toBe(true)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer bar`\n }\n })\n expect(authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should bypass access token with WebDAVContext decorator is applied to context', () => {\n context = createMock<ExecutionContext>()\n WebDAVContext()(context.getHandler())\n expect(reflector.getAllAndOverride<boolean>(AUTH_TOKEN_SKIP, [context.getHandler(), context.getClass()])).toBe(undefined)\n expect(reflector.getAllAndOverride<boolean>(WEB_DAV_CONTEXT, [context.getHandler(), context.getClass()])).toBe(true)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: {\n authorization: `Bearer bar`\n }\n })\n expect(authAccessGuard.canActivate(context)).toBe(true)\n })\n\n it('should pass without a valid access token when AuthTokenOptional is applied to context', async () => {\n const spyAuthenticate = jest.spyOn(authAnonymousStrategy, 'authenticate')\n context = createMock<ExecutionContext>()\n AuthTokenOptional()(context.getHandler())\n expect(reflector.getAllAndOverride<boolean>(AUTH_TOKEN_SKIP, [context.getHandler(), context.getClass()])).toBe(true)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n authorization: `Bearer bar`\n })\n expect(authAccessGuard.canActivate(context)).toBe(true)\n expect(await authAnonymousGuard.canActivate(context)).toBe(true)\n expect(spyAuthenticate).toHaveBeenCalledTimes(1)\n spyAuthenticate.mockClear()\n })\n})\n"],"names":["describe","AuthTokenAccessGuard","name","csrfToken","crypto","randomUUID","authConfig","jwtService","authAccessGuard","authAnonymousGuard","authAnonymousStrategy","reflector","accessTokenWithoutCSRF","accessToken","context","beforeAll","module","Test","createTestingModule","imports","ConfigModule","forRoot","load","exportConfiguration","isGlobal","JwtModule","register","global","PassportModule","providers","AuthTokenAccessStrategy","AuthAnonymousStrategy","AuthAnonymousGuard","AuthManager","provide","UsersManager","useValue","PinoLogger","assign","undefined","compile","get","ConfigService","JwtService","Reflector","signAsync","identity","id","login","TOKEN_TYPE","CSRF","secret","token","access","expiresIn","createMock","it","expect","toBeDefined","switchToHttp","getRequest","mockReturnValue","raw","user","headers","csrf","sign","cookies","canActivate","toBe","authorization","rejects","toThrow","RegExp","CSRF_ERROR","MISSING_HEADERS","MISSING_JWT","MISMATCH","method","resolves","not","AuthTokenSkip","getHandler","getAllAndOverride","AUTH_TOKEN_SKIP","getClass","WebDAVContext","WEB_DAV_CONTEXT","spyAuthenticate","jest","spyOn","AuthTokenOptional","toHaveBeenCalledTimes","mockClear"],"mappings":"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"}
@@ -29,7 +29,6 @@ function _ts_metadata(k, v) {
29
29
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
30
30
  }
31
31
  let AuthTokenAccessStrategy = class AuthTokenAccessStrategy extends (0, _passport.PassportStrategy)(_passportjwt.Strategy, 'tokenAccess') {
32
- // not declared properly: https://github.com/nestjs/passport/issues/929
33
32
  validate(req, jwtPayload) {
34
33
  this.logger.assign({
35
34
  user: jwtPayload.identity.login
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-token-access.strategy.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 } from '@nestjs/common'\nimport { PassportStrategy } from '@nestjs/passport'\nimport { FastifyRequest } from 'fastify'\nimport { PinoLogger } from 'nestjs-pino'\nimport { ExtractJwt, Strategy } from 'passport-jwt'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { JwtPayload } from '../interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from '../interfaces/token.interface'\nimport { AuthManager } from '../services/auth-manager.service'\n\n@Injectable()\nexport class AuthTokenAccessStrategy extends PassportStrategy(Strategy, 'tokenAccess') {\n private static accessCookieName: string\n\n constructor(\n private readonly authManager: AuthManager,\n private readonly logger: PinoLogger\n ) {\n super({\n jwtFromRequest: ExtractJwt.fromExtractors([AuthTokenAccessStrategy.extractJWTFromCookie, ExtractJwt.fromAuthHeaderAsBearerToken()]),\n secretOrKey: authManager.authConfig.token.access.secret,\n ignoreExpiration: false,\n passReqToCallback: true\n })\n AuthTokenAccessStrategy.accessCookieName = authManager.authConfig.token.access.name\n }\n\n // not declared properly: https://github.com/nestjs/passport/issues/929\n validate(req: FastifyRequest, jwtPayload: JwtPayload): UserModel {\n this.logger.assign({ user: jwtPayload.identity.login })\n this.authManager.csrfValidation(req, jwtPayload, TOKEN_TYPE.ACCESS)\n return new UserModel(jwtPayload.identity)\n }\n\n static extractJWTFromCookie(req: FastifyRequest): string | null {\n if (typeof req.cookies === 'object' && req.cookies[AuthTokenAccessStrategy.accessCookieName] !== undefined) {\n return req.cookies[AuthTokenAccessStrategy.accessCookieName]\n }\n return null\n }\n}\n"],"names":["AuthTokenAccessStrategy","PassportStrategy","Strategy","validate","req","jwtPayload","logger","assign","user","identity","login","authManager","csrfValidation","TOKEN_TYPE","ACCESS","UserModel","extractJWTFromCookie","cookies","accessCookieName","undefined","jwtFromRequest","ExtractJwt","fromExtractors","fromAuthHeaderAsBearerToken","secretOrKey","authConfig","token","access","secret","ignoreExpiration","passReqToCallback","name"],"mappings":"AAAA;;;;CAIC;;;;+BAaYA;;;eAAAA;;;wBAXc;0BACM;4BAEN;6BACU;2BACX;gCAEC;oCACC;;;;;;;;;;AAGrB,IAAA,AAAMA,0BAAN,MAAMA,gCAAgCC,IAAAA,0BAAgB,EAACC,qBAAQ,EAAE;IAgBtE,wEAAwE;IACxEC,SAASC,GAAmB,EAAEC,UAAsB,EAAa;QAC/D,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMH,WAAWI,QAAQ,CAACC,KAAK;QAAC;QACrD,IAAI,CAACC,WAAW,CAACC,cAAc,CAACR,KAAKC,YAAYQ,0BAAU,CAACC,MAAM;QAClE,OAAO,IAAIC,oBAAS,CAACV,WAAWI,QAAQ;IAC1C;IAEA,OAAOO,qBAAqBZ,GAAmB,EAAiB;QAC9D,IAAI,OAAOA,IAAIa,OAAO,KAAK,YAAYb,IAAIa,OAAO,CAACjB,wBAAwBkB,gBAAgB,CAAC,KAAKC,WAAW;YAC1G,OAAOf,IAAIa,OAAO,CAACjB,wBAAwBkB,gBAAgB,CAAC;QAC9D;QACA,OAAO;IACT;IAzBA,YACE,AAAiBP,WAAwB,EACzC,AAAiBL,MAAkB,CACnC;QACA,KAAK,CAAC;YACJc,gBAAgBC,uBAAU,CAACC,cAAc,CAAC;gBAACtB,wBAAwBgB,oBAAoB;gBAAEK,uBAAU,CAACE,2BAA2B;aAAG;YAClIC,aAAab,YAAYc,UAAU,CAACC,KAAK,CAACC,MAAM,CAACC,MAAM;YACvDC,kBAAkB;YAClBC,mBAAmB;QACrB,SARiBnB,cAAAA,kBACAL,SAAAA;QAQjBN,wBAAwBkB,gBAAgB,GAAGP,YAAYc,UAAU,CAACC,KAAK,CAACC,MAAM,CAACI,IAAI;IACrF;AAeF"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/guards/auth-token-access.strategy.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 } from '@nestjs/common'\nimport { AbstractStrategy, PassportStrategy } from '@nestjs/passport'\nimport { FastifyRequest } from 'fastify'\nimport { PinoLogger } from 'nestjs-pino'\nimport { ExtractJwt, Strategy } from 'passport-jwt'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { JwtPayload } from '../interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from '../interfaces/token.interface'\nimport { AuthManager } from '../services/auth-manager.service'\n\n@Injectable()\nexport class AuthTokenAccessStrategy extends PassportStrategy(Strategy, 'tokenAccess') implements AbstractStrategy {\n private static accessCookieName: string\n\n constructor(\n private readonly authManager: AuthManager,\n private readonly logger: PinoLogger\n ) {\n super({\n jwtFromRequest: ExtractJwt.fromExtractors([AuthTokenAccessStrategy.extractJWTFromCookie, ExtractJwt.fromAuthHeaderAsBearerToken()]),\n secretOrKey: authManager.authConfig.token.access.secret,\n ignoreExpiration: false,\n passReqToCallback: true\n })\n AuthTokenAccessStrategy.accessCookieName = authManager.authConfig.token.access.name\n }\n\n validate(req: FastifyRequest, jwtPayload: JwtPayload): UserModel {\n this.logger.assign({ user: jwtPayload.identity.login })\n this.authManager.csrfValidation(req, jwtPayload, TOKEN_TYPE.ACCESS)\n return new UserModel(jwtPayload.identity)\n }\n\n static extractJWTFromCookie(req: FastifyRequest): string | null {\n if (typeof req.cookies === 'object' && req.cookies[AuthTokenAccessStrategy.accessCookieName] !== undefined) {\n return req.cookies[AuthTokenAccessStrategy.accessCookieName]\n }\n return null\n }\n}\n"],"names":["AuthTokenAccessStrategy","PassportStrategy","Strategy","validate","req","jwtPayload","logger","assign","user","identity","login","authManager","csrfValidation","TOKEN_TYPE","ACCESS","UserModel","extractJWTFromCookie","cookies","accessCookieName","undefined","jwtFromRequest","ExtractJwt","fromExtractors","fromAuthHeaderAsBearerToken","secretOrKey","authConfig","token","access","secret","ignoreExpiration","passReqToCallback","name"],"mappings":"AAAA;;;;CAIC;;;;+BAaYA;;;eAAAA;;;wBAXc;0BACwB;4BAExB;6BACU;2BACX;gCAEC;oCACC;;;;;;;;;;AAGrB,IAAA,AAAMA,0BAAN,MAAMA,gCAAgCC,IAAAA,0BAAgB,EAACC,qBAAQ,EAAE;IAgBtEC,SAASC,GAAmB,EAAEC,UAAsB,EAAa;QAC/D,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMH,WAAWI,QAAQ,CAACC,KAAK;QAAC;QACrD,IAAI,CAACC,WAAW,CAACC,cAAc,CAACR,KAAKC,YAAYQ,0BAAU,CAACC,MAAM;QAClE,OAAO,IAAIC,oBAAS,CAACV,WAAWI,QAAQ;IAC1C;IAEA,OAAOO,qBAAqBZ,GAAmB,EAAiB;QAC9D,IAAI,OAAOA,IAAIa,OAAO,KAAK,YAAYb,IAAIa,OAAO,CAACjB,wBAAwBkB,gBAAgB,CAAC,KAAKC,WAAW;YAC1G,OAAOf,IAAIa,OAAO,CAACjB,wBAAwBkB,gBAAgB,CAAC;QAC9D;QACA,OAAO;IACT;IAxBA,YACE,AAAiBP,WAAwB,EACzC,AAAiBL,MAAkB,CACnC;QACA,KAAK,CAAC;YACJc,gBAAgBC,uBAAU,CAACC,cAAc,CAAC;gBAACtB,wBAAwBgB,oBAAoB;gBAAEK,uBAAU,CAACE,2BAA2B;aAAG;YAClIC,aAAab,YAAYc,UAAU,CAACC,KAAK,CAACC,MAAM,CAACC,MAAM;YACvDC,kBAAkB;YAClBC,mBAAmB;QACrB,SARiBnB,cAAAA,kBACAL,SAAAA;QAQjBN,wBAAwBkB,gBAAgB,GAAGP,YAAYc,UAAU,CAACC,KAAK,CAACC,MAAM,CAACI,IAAI;IACrF;AAcF"}
@@ -29,7 +29,6 @@ function _ts_metadata(k, v) {
29
29
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
30
30
  }
31
31
  let AuthTokenRefreshStrategy = class AuthTokenRefreshStrategy extends (0, _passport.PassportStrategy)(_passportjwt.Strategy, 'tokenRefresh') {
32
- // not declared properly: https://github.com/nestjs/passport/issues/929
33
32
  validate(req, jwtPayload) {
34
33
  this.logger.assign({
35
34
  user: jwtPayload.identity.login