@sync-in/server 1.9.3 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -4
- package/environment/environment.dist.yaml +15 -5
- package/package.json +18 -19
- package/server/app.bootstrap.js +1 -1
- package/server/app.bootstrap.js.map +1 -1
- package/server/app.constants.js +3 -2
- package/server/app.constants.js.map +1 -1
- package/server/applications/files/constants/cache.js +2 -5
- package/server/applications/files/constants/cache.js.map +1 -1
- package/server/applications/files/constants/files.js +4 -0
- package/server/applications/files/constants/files.js.map +1 -1
- package/server/applications/files/constants/operations.js +4 -0
- package/server/applications/files/constants/operations.js.map +1 -1
- package/server/applications/files/constants/routes.js +1 -26
- package/server/applications/files/constants/routes.js.map +1 -1
- package/server/applications/files/files.config.js +15 -39
- package/server/applications/files/files.config.js.map +1 -1
- package/server/applications/files/files.controller.js +4 -4
- package/server/applications/files/files.controller.js.map +1 -1
- package/server/applications/files/files.module.js +12 -9
- package/server/applications/files/files.module.js.map +1 -1
- package/server/applications/files/interfaces/file-lock.interface.js.map +1 -1
- package/server/applications/files/interfaces/file-props.interface.js.map +1 -1
- package/server/applications/files/modules/collabora-online/collabora-online-environment.decorator.js +32 -0
- package/server/applications/files/modules/collabora-online/collabora-online-environment.decorator.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online-manager.service.js +280 -0
- package/server/applications/files/modules/collabora-online/collabora-online-manager.service.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online-manager.service.spec.js +552 -0
- package/server/applications/files/modules/collabora-online/collabora-online-manager.service.spec.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.config.js +40 -0
- package/server/applications/files/modules/collabora-online/collabora-online.config.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.constants.js +110 -0
- package/server/applications/files/modules/collabora-online/collabora-online.constants.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.controller.js +128 -0
- package/server/applications/files/modules/collabora-online/collabora-online.controller.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.controller.spec.js +47 -0
- package/server/applications/files/modules/collabora-online/collabora-online.controller.spec.js.map +1 -0
- package/server/applications/files/{interfaces/only-office-config.interface.js → modules/collabora-online/collabora-online.dtos.js} +1 -1
- package/server/applications/files/modules/collabora-online/collabora-online.dtos.js.map +1 -0
- package/server/applications/files/{guards/files-only-office.guard.js → modules/collabora-online/collabora-online.guard.js} +7 -21
- package/server/applications/files/modules/collabora-online/collabora-online.guard.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.guard.spec.js +86 -0
- package/server/applications/files/modules/collabora-online/collabora-online.guard.spec.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.interface.js +10 -0
- package/server/applications/files/modules/collabora-online/collabora-online.interface.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.module.js +41 -0
- package/server/applications/files/modules/collabora-online/collabora-online.module.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.routes.js +35 -0
- package/server/applications/files/modules/collabora-online/collabora-online.routes.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.strategy.js +59 -0
- package/server/applications/files/modules/collabora-online/collabora-online.strategy.js.map +1 -0
- package/server/applications/files/modules/collabora-online/collabora-online.utils.js +28 -0
- package/server/applications/files/modules/collabora-online/collabora-online.utils.js.map +1 -0
- package/server/applications/files/{decorators → modules/only-office}/only-office-environment.decorator.js +5 -5
- package/server/applications/files/modules/only-office/only-office-environment.decorator.js.map +1 -0
- package/server/applications/files/{services/files-only-office-manager.service.js → modules/only-office/only-office-manager.service.js} +101 -97
- package/server/applications/files/modules/only-office/only-office-manager.service.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office-manager.service.spec.js +477 -0
- package/server/applications/files/modules/only-office/only-office-manager.service.spec.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.config.js +51 -0
- package/server/applications/files/modules/only-office/only-office.config.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.constants.js +417 -0
- package/server/applications/files/modules/only-office/only-office.constants.js.map +1 -0
- package/server/applications/files/{files-only-office.controller.js → modules/only-office/only-office.controller.js} +35 -52
- package/server/applications/files/modules/only-office/only-office.controller.js.map +1 -0
- package/server/applications/files/{files-only-office.controller.spec.js → modules/only-office/only-office.controller.spec.js} +24 -21
- package/server/applications/files/modules/only-office/only-office.controller.spec.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.dtos.js +10 -0
- package/server/applications/files/modules/only-office/only-office.dtos.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.guard.js +40 -0
- package/server/applications/files/modules/only-office/only-office.guard.js.map +1 -0
- package/server/applications/files/{guards/files-only-office.guard.spec.js → modules/only-office/only-office.guard.spec.js} +15 -21
- package/server/applications/files/modules/only-office/only-office.guard.spec.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.interface.js +10 -0
- package/server/applications/files/modules/only-office/only-office.interface.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.module.js +41 -0
- package/server/applications/files/modules/only-office/only-office.module.js.map +1 -0
- package/server/applications/files/modules/only-office/only-office.routes.js +45 -0
- package/server/applications/files/modules/only-office/only-office.routes.js.map +1 -0
- package/server/applications/files/{guards/files-only-office.strategy.js → modules/only-office/only-office.strategy.js} +11 -11
- package/server/applications/files/modules/only-office/only-office.strategy.js.map +1 -0
- package/server/applications/files/services/files-lock-manager.service.js +25 -33
- package/server/applications/files/services/files-lock-manager.service.js.map +1 -1
- package/server/applications/files/services/files-manager.service.js +17 -16
- package/server/applications/files/services/files-manager.service.js.map +1 -1
- package/server/applications/files/services/files-methods.service.js +2 -2
- package/server/applications/files/services/files-methods.service.js.map +1 -1
- package/server/applications/files/services/files-methods.service.spec.js +5 -5
- package/server/applications/files/services/files-methods.service.spec.js.map +1 -1
- package/server/applications/files/services/files-recents.service.js +4 -0
- package/server/applications/files/services/files-recents.service.js.map +1 -1
- package/server/applications/files/services/files-scheduler.service.js +24 -5
- package/server/applications/files/services/files-scheduler.service.js.map +1 -1
- package/server/applications/files/utils/files.js +10 -2
- package/server/applications/files/utils/files.js.map +1 -1
- package/server/applications/links/constants/routes.js +5 -0
- package/server/applications/links/constants/routes.js.map +1 -1
- package/server/applications/links/interfaces/link-space.interface.js.map +1 -1
- package/server/applications/links/links.controller.js +25 -5
- package/server/applications/links/links.controller.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +43 -21
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +4 -3
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/links/services/links-queries.service.js +9 -2
- package/server/applications/links/services/links-queries.service.js.map +1 -1
- package/server/applications/shares/interfaces/share-link.interface.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.js +3 -0
- package/server/applications/shares/services/shares-manager.service.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.spec.js +2 -1
- package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
- package/server/applications/shares/services/shares-queries.service.js +1 -0
- package/server/applications/shares/services/shares-queries.service.js.map +1 -1
- package/server/applications/spaces/constants/spaces.js +2 -2
- package/server/applications/spaces/constants/spaces.js.map +1 -1
- package/server/applications/spaces/decorators/space-override-permission.decorator.js +18 -0
- package/server/applications/spaces/decorators/space-override-permission.decorator.js.map +1 -0
- package/server/applications/spaces/guards/space.guard.js +40 -33
- package/server/applications/spaces/guards/space.guard.js.map +1 -1
- package/server/applications/spaces/guards/space.guard.spec.js +10 -15
- package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
- package/server/applications/spaces/services/spaces-scheduler.service.js +9 -1
- package/server/applications/spaces/services/spaces-scheduler.service.js.map +1 -1
- package/server/applications/webdav/constants/webdav.js +4 -0
- package/server/applications/webdav/constants/webdav.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.js +9 -8
- package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -1
- package/server/applications/webdav/interfaces/webdav.interface.js.map +1 -1
- package/server/applications/webdav/services/webdav-methods.service.js +40 -17
- package/server/applications/webdav/services/webdav-methods.service.js.map +1 -1
- package/server/applications/webdav/services/webdav-methods.service.spec.js +2157 -1289
- package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
- package/server/applications/webdav/utils/webdav.js +8 -4
- package/server/applications/webdav/utils/webdav.js.map +1 -1
- package/server/applications/webdav/webdav.controller.js +4 -4
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/authentication/guards/auth-token-access.guard.js +8 -3
- package/server/authentication/guards/auth-token-access.guard.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.js +1 -1
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js +350 -4
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js.map +1 -1
- package/server/configuration/config.environment.js +5 -1
- package/server/configuration/config.environment.js.map +1 -1
- package/server/configuration/config.interfaces.js.map +1 -1
- package/static/3rdpartylicenses.txt +507 -507
- package/static/assets/pdfjs/build/pdf.mjs +93 -33
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +3 -3
- package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.worker.mjs +166 -54
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/images/checkmark.svg +5 -0
- package/static/assets/pdfjs/web/images/pages_closeButton.svg +3 -0
- package/static/assets/pdfjs/web/images/pages_selected.svg +7 -0
- package/static/assets/pdfjs/web/images/pages_viewArrow.svg +3 -0
- package/static/assets/pdfjs/web/images/pages_viewButton.svg +3 -0
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -5
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +4 -6
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +6 -2
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +82 -17
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/eu/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -5
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +3 -5
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/hr/viewer.ftl +66 -0
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +3 -8
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/id/viewer.ftl +0 -5
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -5
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +0 -14
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +4 -6
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -5
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +1 -3
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +4 -2
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/pt-PT/viewer.ftl +35 -0
- package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -5
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +4 -6
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +3 -5
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/sq/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/th/viewer.ftl +2 -2
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -2
- package/static/assets/pdfjs/web/viewer.css +1778 -835
- package/static/assets/pdfjs/web/viewer.html +167 -86
- package/static/assets/pdfjs/web/viewer.mjs +1106 -801
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/chunk-27V66YJV.js +2 -0
- package/static/{chunk-WJYVS27M.js → chunk-27Z3SYRL.js} +1 -1
- package/static/{chunk-NFIES7BC.js → chunk-2RWLNKZH.js} +1 -1
- package/static/chunk-2YQ4SX3A.js +13 -0
- package/static/{chunk-GENTF6JM.js → chunk-3JYMJQYT.js} +1 -1
- package/static/chunk-3QTROEHV.js +1 -0
- package/static/{chunk-ZPI7RQ2S.js → chunk-3RPUQ22U.js} +1 -1
- package/static/{chunk-R6VB3INJ.js → chunk-3WZ6F3LC.js} +1 -1
- package/static/chunk-3ZLBVUCX.js +2 -0
- package/static/{chunk-5HCVWZMA.js → chunk-45AZ6ZML.js} +1 -1
- package/static/chunk-46TJLPJY.js +1 -0
- package/static/chunk-4NIYCYRS.js +2 -0
- package/static/{chunk-XXYMVRSH.js → chunk-4TPFERL6.js} +1 -1
- package/static/{chunk-CAZSNVMS.js → chunk-5O66CLTD.js} +1 -1
- package/static/chunk-6OEOADR6.js +1 -0
- package/static/chunk-6WMXMIE4.js +1 -0
- package/static/{chunk-NK2NMAJI.js → chunk-7VRYTDX4.js} +1 -1
- package/static/{chunk-ASBPYTLT.js → chunk-ARS47O5X.js} +1 -1
- package/static/chunk-B6HQYQYG.js +1 -0
- package/static/chunk-BCN4T5DO.js +2 -0
- package/static/{chunk-PKU4IIIR.js → chunk-CCZWPM7Q.js} +1 -1
- package/static/{chunk-QUSS6SUC.js → chunk-CMNMPG6Z.js} +1 -1
- package/static/{chunk-GDPJRUVU.js → chunk-CSVPAZHK.js} +1 -1
- package/static/{chunk-BJARRIS6.js → chunk-D55YR5X7.js} +4 -4
- package/static/{chunk-Z6RJZIDG.js → chunk-D5FQ72R4.js} +1 -1
- package/static/{chunk-4DF2SQD4.js → chunk-DGCVA6BM.js} +1 -1
- package/static/{chunk-TVJQXN73.js → chunk-DVCN3P7Q.js} +1 -1
- package/static/chunk-E32J777S.js +5 -0
- package/static/{chunk-5NHB7SV3.js → chunk-FIUF2JM4.js} +1 -1
- package/static/{chunk-RJOHDAPM.js → chunk-G3PL6YX3.js} +1 -1
- package/static/chunk-G7RZN7HN.js +1 -0
- package/static/{chunk-DDRGLHOP.js → chunk-GQHXYX6Z.js} +1 -1
- package/static/{chunk-5HYSNQR4.js → chunk-GWRAGN3M.js} +1 -1
- package/static/{chunk-ZC5ZDCDC.js → chunk-GXWGB7WO.js} +1 -1
- package/static/{chunk-25PWAXTJ.js → chunk-HGODIZTV.js} +1 -1
- package/static/{chunk-4KXJ6C4N.js → chunk-HZAB6F4Q.js} +1 -1
- package/static/chunk-I3FR3A45.js +1 -0
- package/static/{chunk-A6J6SOM6.js → chunk-I5SPA4G2.js} +1 -1
- package/static/{chunk-TGHBDJZA.js → chunk-IMFO2MI7.js} +1 -1
- package/static/{chunk-CURVLK7L.js → chunk-JNTNMIUH.js} +1 -1
- package/static/chunk-JRXG43AA.js +2 -0
- package/static/{chunk-XAIOGRBO.js → chunk-KAUCN24H.js} +1 -1
- package/static/chunk-KDUAB76O.js +1 -0
- package/static/chunk-KPOQLDWF.js +1 -0
- package/static/{chunk-HE6EDXWI.js → chunk-KWFELZTM.js} +1 -1
- package/static/{chunk-2CAAJBRO.js → chunk-L3BIP4AA.js} +1 -1
- package/static/{chunk-U75PLYIJ.js → chunk-LGIVVJDD.js} +1 -1
- package/static/{chunk-JEVBUJQ4.js → chunk-LNLBIJZD.js} +1 -1
- package/static/chunk-LTJNLOX2.js +1 -0
- package/static/{chunk-SDR3UG2F.js → chunk-LZUHREOF.js} +1 -1
- package/static/{chunk-VO4WVT6K.js → chunk-NIR4YE2E.js} +1 -1
- package/static/{chunk-S6YKBWJE.js → chunk-NJJURHX4.js} +1 -1
- package/static/chunk-NNZWSNAW.js +1 -0
- package/static/chunk-NWKBB7J4.js +1 -0
- package/static/chunk-O3YLAEVE.js +3 -0
- package/static/chunk-OUHCDDT6.js +1 -0
- package/static/{chunk-ZRBLCAOK.js → chunk-PDG7DOEF.js} +1 -1
- package/static/chunk-POUWUMC4.js +1 -0
- package/static/{chunk-YTBSB2GE.js → chunk-PPJCVBJH.js} +1 -1
- package/static/{chunk-K3MOXDU5.js → chunk-PQZLR4P3.js} +1 -1
- package/static/chunk-PVYVY3GD.js +1 -0
- package/static/chunk-Q5X5TPAG.js +1 -0
- package/static/{chunk-LFAQLJZK.js → chunk-QHJT5H4M.js} +1 -1
- package/static/{chunk-A7DSX7VP.js → chunk-R4VMWCM5.js} +1 -1
- package/static/{chunk-27XEAHMV.js → chunk-R7PLNX75.js} +1 -1
- package/static/chunk-RJULB733.js +1 -0
- package/static/{chunk-MBFMTBVJ.js → chunk-RNVPQQKT.js} +5 -5
- package/static/chunk-RTNEBRKJ.js +1 -0
- package/static/{chunk-FXM7XXWA.js → chunk-S3TTWPQA.js} +1 -1
- package/static/{chunk-6VJI4X2A.js → chunk-SDJNZULP.js} +1 -1
- package/static/chunk-SNOOCDJD.js +1 -0
- package/static/chunk-T42BV6TR.js +1 -0
- package/static/{chunk-4OV3SAUS.js → chunk-TNCKNU6I.js} +1 -1
- package/static/{chunk-2LHHXDD5.js → chunk-ULSPQ3HP.js} +1 -1
- package/static/{chunk-4EUHBTWV.js → chunk-UOK3LKSX.js} +1 -1
- package/static/{chunk-7NI353LS.js → chunk-VD5JHSDS.js} +1 -1
- package/static/{chunk-YXWF2DGF.js → chunk-XBKCQCBI.js} +1 -1
- package/static/{chunk-KBWK65KM.js → chunk-XEWLBWFF.js} +1 -1
- package/static/{chunk-FLPZB3OX.js → chunk-XTVNHFKX.js} +1 -1
- package/static/chunk-ZCSHU3D7.js +1 -0
- package/static/{chunk-FRBTL2ER.js → chunk-ZEJLIGAY.js} +1 -1
- package/static/{chunk-7H5O4BLV.js → chunk-ZHOE5VEY.js} +1 -1
- package/static/chunk-ZOMRIN3G.js +2 -0
- package/static/index.html +2 -2
- package/static/main-YKDNJ7LK.js +11 -0
- package/static/{styles-S5HVK4H5.css → styles-XLLEY5Y3.css} +1 -1
- package/server/applications/files/constants/only-office.js +0 -531
- package/server/applications/files/constants/only-office.js.map +0 -1
- package/server/applications/files/decorators/only-office-environment.decorator.js.map +0 -1
- package/server/applications/files/files-only-office.controller.js.map +0 -1
- package/server/applications/files/files-only-office.controller.spec.js.map +0 -1
- package/server/applications/files/guards/files-only-office.guard.js.map +0 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js.map +0 -1
- package/server/applications/files/guards/files-only-office.strategy.js.map +0 -1
- package/server/applications/files/interfaces/only-office-config.interface.js.map +0 -1
- package/server/applications/files/services/files-only-office-manager.service.js.map +0 -1
- package/server/applications/files/services/files-only-office-manager.service.spec.js +0 -58
- package/server/applications/files/services/files-only-office-manager.service.spec.js.map +0 -1
- package/static/chunk-2XY4PMI5.js +0 -1
- package/static/chunk-33WFRCUP.js +0 -1
- package/static/chunk-3LVFDMTN.js +0 -1
- package/static/chunk-42L6C5MT.js +0 -1
- package/static/chunk-5WCQBTXW.js +0 -1
- package/static/chunk-A7R246NW.js +0 -1
- package/static/chunk-BSB4VROD.js +0 -2
- package/static/chunk-DHFQIFOF.js +0 -1
- package/static/chunk-DRHPEERW.js +0 -2
- package/static/chunk-FCGTI42I.js +0 -1
- package/static/chunk-H4RLHI3Y.js +0 -1
- package/static/chunk-ITVA26X2.js +0 -2
- package/static/chunk-IUJ4IK26.js +0 -1
- package/static/chunk-L3PDWJZ3.js +0 -3
- package/static/chunk-LBXOAKBD.js +0 -1
- package/static/chunk-LZKI5P5T.js +0 -1
- package/static/chunk-MYM43ENO.js +0 -1
- package/static/chunk-MZBO5PAR.js +0 -1
- package/static/chunk-NAH4V2R6.js +0 -2
- package/static/chunk-O7UXVNR2.js +0 -1
- package/static/chunk-PCFH5HCI.js +0 -2
- package/static/chunk-SRBOO7AO.js +0 -1
- package/static/chunk-UUX3M6DC.js +0 -1
- package/static/chunk-VJ2HWQRJ.js +0 -5
- package/static/chunk-VZPCXSRG.js +0 -2
- package/static/chunk-W72JYHOH.js +0 -1
- package/static/chunk-XHQEF2IX.js +0 -1
- package/static/chunk-XKEBQNQJ.js +0 -1
- package/static/chunk-ZERBTNFW.js +0 -13
- package/static/main-FE6GWZXU.js +0 -11
- /package/static/assets/pdfjs/web/images/{toolbarButton-sidebarToggle.svg → toolbarButton-viewsManagerToggle.svg} +0 -0
|
@@ -171,24 +171,25 @@ let WebDAVProtocolGuard = class WebDAVProtocolGuard {
|
|
|
171
171
|
}
|
|
172
172
|
this.parseBody(req);
|
|
173
173
|
if (req.dav.body) {
|
|
174
|
-
if (!req.dav.body
|
|
174
|
+
if (!req.dav.body.lockinfo) {
|
|
175
175
|
this.logger.warn(`Missing lockinfo : ${JSON.stringify(req.dav.body)}`);
|
|
176
176
|
throw new _common.HttpException('Missing lockinfo', _common.HttpStatus.BAD_REQUEST);
|
|
177
177
|
}
|
|
178
178
|
try {
|
|
179
|
-
req.dav.lock.lockscope = Object.keys(req.dav.body
|
|
179
|
+
req.dav.lock.lockscope = Object.keys(req.dav.body.lockinfo.lockscope)[0];
|
|
180
180
|
} catch (e) {
|
|
181
|
-
this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body
|
|
181
|
+
this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body.lockinfo)} : ${e}`);
|
|
182
182
|
throw new _common.HttpException('Invalid or undefined lockscope', _common.HttpStatus.BAD_REQUEST);
|
|
183
183
|
}
|
|
184
184
|
if (Object.values(_webdav.LOCK_SCOPE).indexOf(req.dav.lock.lockscope) === -1) {
|
|
185
|
-
this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body
|
|
185
|
+
this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body.lockinfo)}`);
|
|
186
186
|
throw new _common.HttpException('Invalid or undefined lockscope', _common.HttpStatus.BAD_REQUEST);
|
|
187
187
|
}
|
|
188
|
-
if (req.dav.body
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
188
|
+
if (req.dav.body.lockinfo.owner) {
|
|
189
|
+
const owner = typeof req.dav.body?.lockinfo?.owner === 'string' ? req.dav.body.lockinfo.owner : req.dav.body?.lockinfo?.owner?.href;
|
|
190
|
+
if (typeof owner === 'string') {
|
|
191
|
+
req.dav.lock.owner = owner.trim();
|
|
192
|
+
}
|
|
192
193
|
}
|
|
193
194
|
const depth = (req.headers[_webdav.HEADER.DEPTH] || '').toLowerCase();
|
|
194
195
|
req.dav.depth = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/webdav/guards/webdav-protocol.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 { CanActivate, ExecutionContext, HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { ValidationError } from 'fast-xml-parser'\nimport { FastifyReply } from 'fastify'\nimport { urlToPath } from '../../../common/functions'\nimport { decodeUrl } from '../../../common/shared'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { CACHE_LOCK_DEFAULT_TTL } from '../../files/constants/cache'\nimport { USER_PERMISSION } from '../../users/constants/user'\nimport {\n ALLOW_EMPTY_BODY_METHODS,\n DEPTH,\n HEADER,\n LOCK_SCOPE,\n OPTIONS_HEADERS,\n PROPPATCH_PROP_UPDATE,\n PROPSTAT,\n REGEX_BASE_PATH\n} from '../constants/webdav'\nimport { IfHeader } from '../interfaces/if-header.interface'\nimport { FastifyDAVRequest, WebDAVContext } from '../interfaces/webdav.interface'\nimport { parseIfHeader } from '../utils/if-header'\nimport { PROPFIND_ALL_PROP } from '../utils/webdav'\nimport { xmlIsValid, xmlParse } from '../utils/xml'\n\n@Injectable()\nexport class WebDAVProtocolGuard implements CanActivate {\n private readonly logger = new Logger(WebDAVProtocolGuard.name)\n\n async canActivate(ctx: ExecutionContext): Promise<boolean> {\n const req: FastifyDAVRequest = ctx.switchToHttp().getRequest()\n const res: FastifyReply = ctx.switchToHttp().getResponse()\n this.checkUserPermission(req)\n this.setDAVContext(req)\n switch (req.method) {\n case HTTP_METHOD.OPTIONS:\n // hook to stop propagation and return headers on all webdav routes\n res.headers(OPTIONS_HEADERS)\n throw new HttpException(null, HttpStatus.OK)\n case HTTP_METHOD.PROPFIND:\n return this.propfindMethod(req)\n case HTTP_METHOD.LOCK:\n return this.lockMethod(req)\n case HTTP_METHOD.UNLOCK:\n return this.unlockMethod(req)\n case HTTP_METHOD.PUT:\n return this.putMethod(req)\n case HTTP_METHOD.DELETE:\n return this.deleteMethod(req)\n case HTTP_METHOD.PROPPATCH:\n return this.proppatchMethod(req)\n case HTTP_METHOD.MKCOL:\n return this.mkcolMethod(req)\n case HTTP_METHOD.COPY:\n return this.copyMoveMethod(req)\n case HTTP_METHOD.MOVE:\n return this.copyMoveMethod(req, true)\n default:\n return true\n }\n }\n\n private checkUserPermission(req: FastifyDAVRequest) {\n if (req.method !== HTTP_METHOD.OPTIONS && !req.user.havePermission(USER_PERMISSION.WEBDAV)) {\n this.logger.warn(`does not have permission : ${USER_PERMISSION.WEBDAV}`)\n throw new HttpException('Missing permission', HttpStatus.FORBIDDEN)\n }\n }\n\n private setDAVContext(req: FastifyDAVRequest) {\n req.dav = {\n url: decodeUrl(req.originalUrl),\n depth: DEPTH.RESOURCE\n } as WebDAVContext\n }\n\n private parseBody(req: FastifyDAVRequest) {\n let body = null\n let valid: true | ValidationError\n try {\n valid = xmlIsValid(req.body.toString())\n } catch (e) {\n valid = { err: { code: e.code, msg: `Invalid body content: ${e.message}`, line: 0, col: 0 } }\n }\n if (valid === true) {\n body = xmlParse(req.body)\n } else if (valid.err.code === undefined && ALLOW_EMPTY_BODY_METHODS.indexOf(req.method) > -1) {\n body = null\n } else {\n throw new HttpException(`${valid.err.code} : ${valid.err.msg}`, HttpStatus.BAD_REQUEST)\n }\n req.dav.httpVersion = `${req.protocol.toUpperCase()}/${req.raw['httpVersion']}`\n req.dav.body = body\n return true\n }\n\n private parseIfHeader(req: FastifyDAVRequest) {\n // stores if headers, examine it later\n if (req.headers[HEADER.IF]) {\n this.logger.verbose(`If header before : ${JSON.stringify(req.headers[HEADER.IF])}`)\n const ifHeaders: IfHeader[] = parseIfHeader(req.headers[HEADER.IF] as string)\n this.logger.verbose(`If header after : ${JSON.stringify(ifHeaders)}`)\n if (ifHeaders.length) req.dav.ifHeaders = ifHeaders\n }\n }\n\n private propfindMethod(req: FastifyDAVRequest) {\n req.dav.depth = (req.headers[HEADER.DEPTH] as string | undefined)?.toLowerCase()\n if (!req.dav.depth || (req.dav.depth !== DEPTH.MEMBERS && req.dav.depth !== DEPTH.RESOURCE)) {\n if (!req.dav.depth) {\n this.logger.warn('Missing propfind depth, default value 1 was set')\n } else if (req.dav.depth === DEPTH.INFINITY) {\n this.logger.warn('Infinite depth is disabled for security reasons, default value 1 was set')\n } else {\n this.logger.warn(`Invalid propfind depth header : ${req.dav.depth}, default value 1 was set`)\n }\n req.dav.depth = DEPTH.MEMBERS\n }\n if (this.parseBody(req)) {\n if (req.dav.body) {\n for (const propType in req.dav.body.propfind) {\n if (Object.values(PROPSTAT).indexOf(propType as PROPSTAT) > -1) {\n req.dav.propfindMode = propType as PROPSTAT\n break\n }\n }\n if (!req.dav.propfindMode) {\n this.logger.warn(`Invalid propfind mode : ${JSON.stringify(Object.keys(req.dav.body.propfind))}`)\n throw new HttpException('Invalid propfind mode', HttpStatus.BAD_REQUEST)\n }\n } else {\n // propfind request allow empty body\n req.dav.body = PROPFIND_ALL_PROP\n req.dav.propfindMode = PROPSTAT.ALLPROP\n }\n }\n this.parseIfHeader(req)\n return true\n }\n\n private proppatchMethod(req: FastifyDAVRequest) {\n req.dav.depth = ((req.headers[HEADER.DEPTH] as any) || DEPTH.RESOURCE).toLowerCase()\n this.parseBody(req)\n if (!req.dav.body || Object.keys(req.dav.body).indexOf(PROPPATCH_PROP_UPDATE) === -1) {\n this.logger.debug(`'${PROPPATCH_PROP_UPDATE}' is missing : ${JSON.stringify(req.dav.body)}`)\n throw new HttpException(`'${PROPPATCH_PROP_UPDATE}' is missing`, HttpStatus.BAD_REQUEST)\n }\n this.parseIfHeader(req)\n return true\n }\n\n private lockMethod(req: FastifyDAVRequest) {\n req.dav.lock = {}\n if (req.headers[HEADER.TIMEOUT]) {\n // timeout: 'Infinite, Second-4100000000' | 'Second-4100000000' | 'Infinite'\n const timeout = req.headers[HEADER.TIMEOUT] as string\n if (timeout.toLowerCase() === 'infinite') {\n req.dav.lock.timeout = CACHE_LOCK_DEFAULT_TTL\n } else {\n try {\n const timeoutSplit = timeout.split('-')\n const seconds = parseInt(timeoutSplit[timeoutSplit.length - 1], 10)\n req.dav.lock.timeout = seconds > CACHE_LOCK_DEFAULT_TTL ? CACHE_LOCK_DEFAULT_TTL : seconds\n } catch (e) {\n this.logger.warn(`${this.lockMethod.name} - unable to set timeout, use the default value : ${e}`)\n req.dav.lock.timeout = CACHE_LOCK_DEFAULT_TTL\n }\n }\n }\n this.parseBody(req)\n if (req.dav.body) {\n if (!req.dav.body['lockinfo']) {\n this.logger.warn(`Missing lockinfo : ${JSON.stringify(req.dav.body)}`)\n throw new HttpException('Missing lockinfo', HttpStatus.BAD_REQUEST)\n }\n try {\n req.dav.lock.lockscope = Object.keys(req.dav.body['lockinfo']['lockscope'])[0] as LOCK_SCOPE\n } catch (e) {\n this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body['lockinfo'])} : ${e}`)\n throw new HttpException('Invalid or undefined lockscope', HttpStatus.BAD_REQUEST)\n }\n if (Object.values(LOCK_SCOPE).indexOf(req.dav.lock.lockscope) === -1) {\n this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body['lockinfo'])}`)\n throw new HttpException('Invalid or undefined lockscope', HttpStatus.BAD_REQUEST)\n }\n if (req.dav.body['lockinfo']['owner'] && typeof req.dav.body['lockinfo']['owner'] === 'string') {\n req.dav.lock.owner = `${req.dav.body['lockinfo']['owner']} ${req.user.fullName} (${req.user.email})`\n } else {\n req.dav.lock.owner = `WebDAV - ${req.user.fullName} (${req.user.email})`\n }\n const depth: DEPTH = ((req.headers[HEADER.DEPTH] as any) || '').toLowerCase()\n req.dav.depth = [DEPTH.INFINITY, DEPTH.RESOURCE].indexOf(depth) === -1 ? DEPTH.INFINITY : depth\n } else {\n // must ignore depth header on lock refresh request\n req.dav.depth = null\n }\n this.parseIfHeader(req)\n return true\n }\n\n private unlockMethod(req: FastifyDAVRequest) {\n if (!req.headers[HEADER.LOCK_TOKEN]) {\n throw new HttpException('Missing lock token', HttpStatus.BAD_REQUEST)\n }\n req.dav.lock = { token: (req.headers[HEADER.LOCK_TOKEN] as string).replace('<', '').replace('>', '').trim() }\n this.parseIfHeader(req)\n return true\n }\n\n private putMethod(req: FastifyDAVRequest) {\n req.dav.depth = DEPTH.RESOURCE\n this.parseIfHeader(req)\n return true\n }\n\n private deleteMethod(req: FastifyDAVRequest) {\n this.parseIfHeader(req)\n return true\n }\n\n private mkcolMethod(req: FastifyDAVRequest) {\n if (req.headers['content-length'] && req.headers['content-length'] !== '0') {\n throw new HttpException('no body content required', HttpStatus.UNSUPPORTED_MEDIA_TYPE)\n }\n req.dav.depth = DEPTH.RESOURCE\n this.parseIfHeader(req)\n return true\n }\n\n private copyMoveMethod(req: FastifyDAVRequest, isMove = false) {\n if (!req.headers[HEADER.DESTINATION]) {\n throw new HttpException(`Missing ${HEADER.DESTINATION} header`, HttpStatus.BAD_REQUEST)\n }\n const destination = decodeUrl(urlToPath(req.headers[HEADER.DESTINATION] as string))\n if (!REGEX_BASE_PATH.test(destination)) {\n this.logger.warn(`The destination does not match the webdav base path : ${destination}`)\n throw new HttpException('The destination does not match', HttpStatus.BAD_REQUEST)\n }\n req.dav.depth = ((req.headers[HEADER.DEPTH] as any) || DEPTH.INFINITY).toLowerCase()\n req.dav.copyMove = {\n overwrite: ((req.headers[HEADER.OVERWRITE] as any) || 't').toLowerCase() === 't',\n destination: destination,\n isMove: isMove\n }\n this.parseIfHeader(req)\n return true\n }\n}\n"],"names":["WebDAVProtocolGuard","canActivate","ctx","req","switchToHttp","getRequest","res","getResponse","checkUserPermission","setDAVContext","method","HTTP_METHOD","OPTIONS","headers","OPTIONS_HEADERS","HttpException","HttpStatus","OK","PROPFIND","propfindMethod","LOCK","lockMethod","UNLOCK","unlockMethod","PUT","putMethod","DELETE","deleteMethod","PROPPATCH","proppatchMethod","MKCOL","mkcolMethod","COPY","copyMoveMethod","MOVE","user","havePermission","USER_PERMISSION","WEBDAV","logger","warn","FORBIDDEN","dav","url","decodeUrl","originalUrl","depth","DEPTH","RESOURCE","parseBody","body","valid","xmlIsValid","toString","e","err","code","msg","message","line","col","xmlParse","undefined","ALLOW_EMPTY_BODY_METHODS","indexOf","BAD_REQUEST","httpVersion","protocol","toUpperCase","raw","parseIfHeader","HEADER","IF","verbose","JSON","stringify","ifHeaders","length","toLowerCase","MEMBERS","INFINITY","propType","propfind","Object","values","PROPSTAT","propfindMode","keys","PROPFIND_ALL_PROP","ALLPROP","PROPPATCH_PROP_UPDATE","debug","lock","TIMEOUT","timeout","CACHE_LOCK_DEFAULT_TTL","timeoutSplit","split","seconds","parseInt","name","lockscope","LOCK_SCOPE","owner","fullName","email","LOCK_TOKEN","token","replace","trim","UNSUPPORTED_MEDIA_TYPE","isMove","DESTINATION","destination","urlToPath","REGEX_BASE_PATH","test","copyMove","overwrite","OVERWRITE","Logger"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/webdav/guards/webdav-protocol.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 { CanActivate, ExecutionContext, HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { ValidationError } from 'fast-xml-parser'\nimport { FastifyReply } from 'fastify'\nimport { urlToPath } from '../../../common/functions'\nimport { decodeUrl } from '../../../common/shared'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { CACHE_LOCK_DEFAULT_TTL } from '../../files/constants/cache'\nimport { USER_PERMISSION } from '../../users/constants/user'\nimport {\n ALLOW_EMPTY_BODY_METHODS,\n DEPTH,\n HEADER,\n LOCK_SCOPE,\n OPTIONS_HEADERS,\n PROPPATCH_PROP_UPDATE,\n PROPSTAT,\n REGEX_BASE_PATH\n} from '../constants/webdav'\nimport { IfHeader } from '../interfaces/if-header.interface'\nimport { FastifyDAVRequest, WebDAVContext } from '../interfaces/webdav.interface'\nimport { parseIfHeader } from '../utils/if-header'\nimport { PROPFIND_ALL_PROP } from '../utils/webdav'\nimport { xmlIsValid, xmlParse } from '../utils/xml'\n\n@Injectable()\nexport class WebDAVProtocolGuard implements CanActivate {\n private readonly logger = new Logger(WebDAVProtocolGuard.name)\n\n async canActivate(ctx: ExecutionContext): Promise<boolean> {\n const req: FastifyDAVRequest = ctx.switchToHttp().getRequest()\n const res: FastifyReply = ctx.switchToHttp().getResponse()\n this.checkUserPermission(req)\n this.setDAVContext(req)\n switch (req.method) {\n case HTTP_METHOD.OPTIONS:\n // hook to stop propagation and return headers on all webdav routes\n res.headers(OPTIONS_HEADERS)\n throw new HttpException(null, HttpStatus.OK)\n case HTTP_METHOD.PROPFIND:\n return this.propfindMethod(req)\n case HTTP_METHOD.LOCK:\n return this.lockMethod(req)\n case HTTP_METHOD.UNLOCK:\n return this.unlockMethod(req)\n case HTTP_METHOD.PUT:\n return this.putMethod(req)\n case HTTP_METHOD.DELETE:\n return this.deleteMethod(req)\n case HTTP_METHOD.PROPPATCH:\n return this.proppatchMethod(req)\n case HTTP_METHOD.MKCOL:\n return this.mkcolMethod(req)\n case HTTP_METHOD.COPY:\n return this.copyMoveMethod(req)\n case HTTP_METHOD.MOVE:\n return this.copyMoveMethod(req, true)\n default:\n return true\n }\n }\n\n private checkUserPermission(req: FastifyDAVRequest) {\n if (req.method !== HTTP_METHOD.OPTIONS && !req.user.havePermission(USER_PERMISSION.WEBDAV)) {\n this.logger.warn(`does not have permission : ${USER_PERMISSION.WEBDAV}`)\n throw new HttpException('Missing permission', HttpStatus.FORBIDDEN)\n }\n }\n\n private setDAVContext(req: FastifyDAVRequest) {\n req.dav = {\n url: decodeUrl(req.originalUrl),\n depth: DEPTH.RESOURCE\n } as WebDAVContext\n }\n\n private parseBody(req: FastifyDAVRequest) {\n let body = null\n let valid: true | ValidationError\n try {\n valid = xmlIsValid(req.body.toString())\n } catch (e) {\n valid = { err: { code: e.code, msg: `Invalid body content: ${e.message}`, line: 0, col: 0 } }\n }\n if (valid === true) {\n body = xmlParse(req.body)\n } else if (valid.err.code === undefined && ALLOW_EMPTY_BODY_METHODS.indexOf(req.method) > -1) {\n body = null\n } else {\n throw new HttpException(`${valid.err.code} : ${valid.err.msg}`, HttpStatus.BAD_REQUEST)\n }\n req.dav.httpVersion = `${req.protocol.toUpperCase()}/${req.raw['httpVersion']}`\n req.dav.body = body\n return true\n }\n\n private parseIfHeader(req: FastifyDAVRequest) {\n // stores if headers, examine it later\n if (req.headers[HEADER.IF]) {\n this.logger.verbose(`If header before : ${JSON.stringify(req.headers[HEADER.IF])}`)\n const ifHeaders: IfHeader[] = parseIfHeader(req.headers[HEADER.IF] as string)\n this.logger.verbose(`If header after : ${JSON.stringify(ifHeaders)}`)\n if (ifHeaders.length) req.dav.ifHeaders = ifHeaders\n }\n }\n\n private propfindMethod(req: FastifyDAVRequest) {\n req.dav.depth = (req.headers[HEADER.DEPTH] as string | undefined)?.toLowerCase()\n if (!req.dav.depth || (req.dav.depth !== DEPTH.MEMBERS && req.dav.depth !== DEPTH.RESOURCE)) {\n if (!req.dav.depth) {\n this.logger.warn('Missing propfind depth, default value 1 was set')\n } else if (req.dav.depth === DEPTH.INFINITY) {\n this.logger.warn('Infinite depth is disabled for security reasons, default value 1 was set')\n } else {\n this.logger.warn(`Invalid propfind depth header : ${req.dav.depth}, default value 1 was set`)\n }\n req.dav.depth = DEPTH.MEMBERS\n }\n if (this.parseBody(req)) {\n if (req.dav.body) {\n for (const propType in req.dav.body.propfind) {\n if (Object.values(PROPSTAT).indexOf(propType as PROPSTAT) > -1) {\n req.dav.propfindMode = propType as PROPSTAT\n break\n }\n }\n if (!req.dav.propfindMode) {\n this.logger.warn(`Invalid propfind mode : ${JSON.stringify(Object.keys(req.dav.body.propfind))}`)\n throw new HttpException('Invalid propfind mode', HttpStatus.BAD_REQUEST)\n }\n } else {\n // propfind request allow empty body\n req.dav.body = PROPFIND_ALL_PROP\n req.dav.propfindMode = PROPSTAT.ALLPROP\n }\n }\n this.parseIfHeader(req)\n return true\n }\n\n private proppatchMethod(req: FastifyDAVRequest) {\n req.dav.depth = ((req.headers[HEADER.DEPTH] as any) || DEPTH.RESOURCE).toLowerCase()\n this.parseBody(req)\n if (!req.dav.body || Object.keys(req.dav.body).indexOf(PROPPATCH_PROP_UPDATE) === -1) {\n this.logger.debug(`'${PROPPATCH_PROP_UPDATE}' is missing : ${JSON.stringify(req.dav.body)}`)\n throw new HttpException(`'${PROPPATCH_PROP_UPDATE}' is missing`, HttpStatus.BAD_REQUEST)\n }\n this.parseIfHeader(req)\n return true\n }\n\n private lockMethod(req: FastifyDAVRequest) {\n req.dav.lock = {}\n if (req.headers[HEADER.TIMEOUT]) {\n // timeout: 'Infinite, Second-4100000000' | 'Second-4100000000' | 'Infinite'\n const timeout = req.headers[HEADER.TIMEOUT] as string\n if (timeout.toLowerCase() === 'infinite') {\n req.dav.lock.timeout = CACHE_LOCK_DEFAULT_TTL\n } else {\n try {\n const timeoutSplit = timeout.split('-')\n const seconds = parseInt(timeoutSplit[timeoutSplit.length - 1], 10)\n req.dav.lock.timeout = seconds > CACHE_LOCK_DEFAULT_TTL ? CACHE_LOCK_DEFAULT_TTL : seconds\n } catch (e) {\n this.logger.warn(`${this.lockMethod.name} - unable to set timeout, use the default value : ${e}`)\n req.dav.lock.timeout = CACHE_LOCK_DEFAULT_TTL\n }\n }\n }\n this.parseBody(req)\n if (req.dav.body) {\n if (!req.dav.body.lockinfo) {\n this.logger.warn(`Missing lockinfo : ${JSON.stringify(req.dav.body)}`)\n throw new HttpException('Missing lockinfo', HttpStatus.BAD_REQUEST)\n }\n try {\n req.dav.lock.lockscope = Object.keys(req.dav.body.lockinfo.lockscope)[0] as LOCK_SCOPE\n } catch (e) {\n this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body.lockinfo)} : ${e}`)\n throw new HttpException('Invalid or undefined lockscope', HttpStatus.BAD_REQUEST)\n }\n if (Object.values(LOCK_SCOPE).indexOf(req.dav.lock.lockscope) === -1) {\n this.logger.warn(`${this.parseBody.name} - invalid or undefined lockscope : ${JSON.stringify(req.dav.body.lockinfo)}`)\n throw new HttpException('Invalid or undefined lockscope', HttpStatus.BAD_REQUEST)\n }\n if (req.dav.body.lockinfo.owner) {\n const owner = typeof req.dav.body?.lockinfo?.owner === 'string' ? req.dav.body.lockinfo.owner : req.dav.body?.lockinfo?.owner?.href\n if (typeof owner === 'string') {\n req.dav.lock.owner = owner.trim()\n }\n }\n const depth: DEPTH = ((req.headers[HEADER.DEPTH] as any) || '').toLowerCase()\n req.dav.depth = [DEPTH.INFINITY, DEPTH.RESOURCE].indexOf(depth) === -1 ? DEPTH.INFINITY : depth\n } else {\n // must ignore depth header on lock refresh request\n req.dav.depth = null\n }\n this.parseIfHeader(req)\n return true\n }\n\n private unlockMethod(req: FastifyDAVRequest) {\n if (!req.headers[HEADER.LOCK_TOKEN]) {\n throw new HttpException('Missing lock token', HttpStatus.BAD_REQUEST)\n }\n req.dav.lock = { token: (req.headers[HEADER.LOCK_TOKEN] as string).replace('<', '').replace('>', '').trim() }\n this.parseIfHeader(req)\n return true\n }\n\n private putMethod(req: FastifyDAVRequest) {\n req.dav.depth = DEPTH.RESOURCE\n this.parseIfHeader(req)\n return true\n }\n\n private deleteMethod(req: FastifyDAVRequest) {\n this.parseIfHeader(req)\n return true\n }\n\n private mkcolMethod(req: FastifyDAVRequest) {\n if (req.headers['content-length'] && req.headers['content-length'] !== '0') {\n throw new HttpException('no body content required', HttpStatus.UNSUPPORTED_MEDIA_TYPE)\n }\n req.dav.depth = DEPTH.RESOURCE\n this.parseIfHeader(req)\n return true\n }\n\n private copyMoveMethod(req: FastifyDAVRequest, isMove = false) {\n if (!req.headers[HEADER.DESTINATION]) {\n throw new HttpException(`Missing ${HEADER.DESTINATION} header`, HttpStatus.BAD_REQUEST)\n }\n const destination = decodeUrl(urlToPath(req.headers[HEADER.DESTINATION] as string))\n if (!REGEX_BASE_PATH.test(destination)) {\n this.logger.warn(`The destination does not match the webdav base path : ${destination}`)\n throw new HttpException('The destination does not match', HttpStatus.BAD_REQUEST)\n }\n req.dav.depth = ((req.headers[HEADER.DEPTH] as any) || DEPTH.INFINITY).toLowerCase()\n req.dav.copyMove = {\n overwrite: ((req.headers[HEADER.OVERWRITE] as any) || 't').toLowerCase() === 't',\n destination: destination,\n isMove: isMove\n }\n this.parseIfHeader(req)\n return true\n }\n}\n"],"names":["WebDAVProtocolGuard","canActivate","ctx","req","switchToHttp","getRequest","res","getResponse","checkUserPermission","setDAVContext","method","HTTP_METHOD","OPTIONS","headers","OPTIONS_HEADERS","HttpException","HttpStatus","OK","PROPFIND","propfindMethod","LOCK","lockMethod","UNLOCK","unlockMethod","PUT","putMethod","DELETE","deleteMethod","PROPPATCH","proppatchMethod","MKCOL","mkcolMethod","COPY","copyMoveMethod","MOVE","user","havePermission","USER_PERMISSION","WEBDAV","logger","warn","FORBIDDEN","dav","url","decodeUrl","originalUrl","depth","DEPTH","RESOURCE","parseBody","body","valid","xmlIsValid","toString","e","err","code","msg","message","line","col","xmlParse","undefined","ALLOW_EMPTY_BODY_METHODS","indexOf","BAD_REQUEST","httpVersion","protocol","toUpperCase","raw","parseIfHeader","HEADER","IF","verbose","JSON","stringify","ifHeaders","length","toLowerCase","MEMBERS","INFINITY","propType","propfind","Object","values","PROPSTAT","propfindMode","keys","PROPFIND_ALL_PROP","ALLPROP","PROPPATCH_PROP_UPDATE","debug","lock","TIMEOUT","timeout","CACHE_LOCK_DEFAULT_TTL","timeoutSplit","split","seconds","parseInt","name","lockinfo","lockscope","LOCK_SCOPE","owner","href","trim","LOCK_TOKEN","token","replace","UNSUPPORTED_MEDIA_TYPE","isMove","DESTINATION","destination","urlToPath","REGEX_BASE_PATH","test","copyMove","overwrite","OVERWRITE","Logger"],"mappings":"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"}
|
|
@@ -298,7 +298,7 @@ describe(_webdavprotocolguard.WebDAVProtocolGuard.name, ()=>{
|
|
|
298
298
|
await expect(guard.canActivate(ctx)).resolves.toBe(true);
|
|
299
299
|
expect(req.dav.lock.timeout).toBe(10);
|
|
300
300
|
expect(req.dav.lock.lockscope).toBe(_webdav.LOCK_SCOPE.SHARED);
|
|
301
|
-
expect(req.dav.lock.owner).toMatch(/^
|
|
301
|
+
expect(req.dav.lock.owner).toMatch(/^me/);
|
|
302
302
|
expect(req.dav.depth).toBe(_webdav.DEPTH.INFINITY);
|
|
303
303
|
});
|
|
304
304
|
it('clamps timeout Second-N to default when N exceeds default', async ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/webdav/guards/webdav-protocol.guard.spec.ts"],"sourcesContent":["import { HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { FastifyReply } from 'fastify'\nimport { urlToPath } from '../../../common/functions'\nimport { decodeUrl } from '../../../common/shared'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { CACHE_LOCK_DEFAULT_TTL } from '../../files/constants/cache'\nimport { DEPTH, HEADER, LOCK_SCOPE, OPTIONS_HEADERS, PROPSTAT } from '../constants/webdav'\nimport { FastifyDAVRequest } from '../interfaces/webdav.interface'\nimport * as IfHeaderUtils from '../utils/if-header'\nimport { PROPFIND_ALL_PROP } from '../utils/webdav'\nimport { WebDAVProtocolGuard } from './webdav-protocol.guard'\n\n// Keep these mocks to control path transforms in COPY/MOVE tests\njest.mock('../../../common/shared', () => ({\n decodeUrl: jest.fn((s: string) => s)\n}))\njest.mock('../../../common/functions', () => ({\n urlToPath: jest.fn((s: string) => s)\n}))\n\ndescribe(WebDAVProtocolGuard.name, () => {\n let guard: WebDAVProtocolGuard\n\n const makeUser = (hasPerm = true) => ({\n havePermission: jest.fn(() => hasPerm),\n fullName: 'John Doe',\n email: 'john@doe.tld'\n })\n\n const makeRes = (): FastifyReply =>\n ({\n headers: jest.fn()\n }) as unknown as FastifyReply\n\n const baseReq = (method: string, overrides: Partial<FastifyDAVRequest> = {}): FastifyDAVRequest =>\n ({\n method,\n headers: {},\n // undefined body allows to hit the \"allowed empty body\" branch for PROPFIND/LOCK\n body: undefined as any,\n originalUrl: '/webdav/base/path',\n protocol: 'http',\n raw: { httpVersion: '1.1' } as any,\n user: makeUser(),\n ...overrides\n }) as unknown as FastifyDAVRequest\n\n const makeCtx = (req: FastifyDAVRequest, res: FastifyReply) =>\n ({\n switchToHttp: () => ({\n getRequest: () => req,\n getResponse: () => res\n })\n }) as any\n\n const expectIfHeadersParsed = (req: FastifyDAVRequest) => {\n expect(Array.isArray(req.dav.ifHeaders)).toBe(true)\n expect(req.dav.ifHeaders.length).toBeGreaterThan(0)\n }\n\n beforeEach(async () => {\n jest.clearAllMocks()\n const module: TestingModule = await Test.createTestingModule({\n providers: [WebDAVProtocolGuard]\n }).compile()\n\n guard = module.get(WebDAVProtocolGuard)\n })\n\n describe('Permissions', () => {\n it('allows OPTIONS even without WEBDAV permission (responds headers + 200)', async () => {\n const req = baseReq(HTTP_METHOD.OPTIONS, { user: makeUser(false) as any })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).rejects.toThrow(HttpException)\n try {\n await guard.canActivate(ctx)\n } catch (e) {\n const ex = e as HttpException\n expect(res.headers).toHaveBeenCalledWith(OPTIONS_HEADERS)\n expect(ex.getStatus()).toBe(HttpStatus.OK)\n }\n })\n\n it('forbids non-OPTIONS when the user lacks WEBDAV permission', async () => {\n const req = baseReq(HTTP_METHOD.GET, { user: makeUser(false) as any })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.FORBIDDEN })\n })\n\n it('falls through for a method not handled by the switch', async () => {\n const req = baseReq('VIEW', {})\n const res = makeRes()\n const ctx = makeCtx(req, res)\n const spy = jest.spyOn(guard as any, 'setDAVContext')\n\n const result = await guard.canActivate(ctx)\n expect(result).toBe(true)\n expect(spy).toHaveBeenCalled()\n spy.mockRestore()\n })\n })\n\n describe('PROPFIND', () => {\n it('defaults depth=1 (members) when header is missing, and sets ALLPROP with empty body', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.url).toBe(req.originalUrl)\n expect(req.dav.depth).toBe(DEPTH.MEMBERS)\n expect(req.dav.body).toBe(PROPFIND_ALL_PROP)\n expect(req.dav.propfindMode).toBe(PROPSTAT.ALLPROP)\n expect(req.dav.ifHeaders === undefined || req.dav.ifHeaders.length === 0).toBe(true)\n })\n\n it.each([\n { title: 'depth \"infinity\" normalized to 1 (members)', depth: DEPTH.INFINITY as any },\n { title: 'invalid depth normalized to 1 (members)', depth: 'bad' as any }\n ])('depth normalization: $title', async ({ depth }) => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.DEPTH]: depth },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.MEMBERS)\n })\n\n it('valid XML body with propname and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.DEPTH]: DEPTH.RESOURCE, [HEADER.IF]: '(<urn:uuid:abc> [\"W/\\\\\"ETag\\\\\"\"])' },\n body: '<propfind xmlns=\"DAV:\"><propname/></propfind>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expect(req.dav.propfindMode).toBe(PROPSTAT.PROPNAME)\n expectIfHeadersParsed(req)\n })\n\n it('invalid propfind mode -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: '<propfind xmlns=\"DAV:\"><unknown/></propfind>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('invalid XML (with code) -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: '<bad'\n } as any)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('specific XML validation error handled -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: 'this is not XML at all'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toHaveProperty('status', HttpStatus.BAD_REQUEST)\n })\n\n it('skips body when parseBody returns false, still parses If header', async () => {\n const spyParse = jest.spyOn(guard as any, 'parseBody').mockReturnValue(false as any)\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.body).toBeUndefined()\n expect(req.dav.propfindMode).toBeUndefined()\n expectIfHeadersParsed(req)\n } finally {\n spyParse.mockRestore()\n }\n })\n })\n\n describe('PROPPATCH', () => {\n it('requires \"propertyupdate\" in body', async () => {\n const req = baseReq(HTTP_METHOD.PROPPATCH, {\n headers: {},\n body: '<xml/>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('valid body and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PROPPATCH, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)', [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: '<propertyupdate xmlns=\"DAV:\"><set/></propertyupdate>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('LOCK', () => {\n it('timeout=Infinite -> default timeout, owner from string, depth=resource', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Infinite', [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope><owner>Custom Owner</owner></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(CACHE_LOCK_DEFAULT_TTL)\n expect(req.dav.lock.lockscope).toBe(LOCK_SCOPE.EXCLUSIVE)\n expect(req.dav.lock.owner).toContain('Custom Owner')\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n })\n\n it('timeout Second-10 + non-string owner -> default WebDAV owner, depth=infinity', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Second-10', [HEADER.DEPTH]: DEPTH.INFINITY },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><shared/></lockscope><owner><href>me</href></owner></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(10)\n expect(req.dav.lock.lockscope).toBe(LOCK_SCOPE.SHARED)\n expect(req.dav.lock.owner).toMatch(/^WebDAV - /)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n })\n\n it('clamps timeout Second-N to default when N exceeds default', async () => {\n const big = CACHE_LOCK_DEFAULT_TTL + 1000\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: `Second-${big}` },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(CACHE_LOCK_DEFAULT_TTL)\n })\n\n it('invalid timeout -> NaN (no fallback), depth=infinity', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Bad-Token', [HEADER.DEPTH]: 'x' as any },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(Number.isNaN(req.dav.lock.timeout)).toBe(true)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n })\n\n it('handles parseInt exception during timeout parsing', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Second-' },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n const originalParseInt = global.parseInt\n global.parseInt = jest.fn().mockImplementation(() => {\n throw new Error('Forced parseInt error')\n })\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock).toBeDefined()\n } finally {\n global.parseInt = originalParseInt\n }\n })\n\n it('timeout Infinite + empty IfHeader -> default timeout and ifHeaders undefined', async () => {\n const spyIf = jest.spyOn(IfHeaderUtils, 'parseIfHeader').mockReturnValue([] as any)\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Infinite', [HEADER.IF]: '(<any>)' },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(CACHE_LOCK_DEFAULT_TTL)\n expect(req.dav.ifHeaders).toBeUndefined()\n } finally {\n spyIf.mockRestore()\n }\n })\n\n it('missing lockinfo -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<notlockinfo xmlns=\"DAV:\"/>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('invalid lockscope -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><invalid/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('handles Object.keys(lockscope) exception with malformed lockscope -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n jest.spyOn(guard as any, 'parseBody').mockImplementation(() => {\n req.dav.body = {\n lockinfo: {\n lockscope: null\n }\n }\n return true\n })\n\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Invalid or undefined lockscope'\n })\n })\n\n it('refresh (no body) -> dav.depth = null', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBeNull()\n })\n\n it('no timeout header -> lock.timeout is undefined', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock).toBeDefined()\n expect(req.dav.lock.timeout).toBeUndefined()\n })\n })\n\n describe('UNLOCK', () => {\n it('missing lock-token -> 400', async () => {\n const req = baseReq(HTTP_METHOD.UNLOCK)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('sets token in dav.lock and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.UNLOCK, {\n headers: { [HEADER.LOCK_TOKEN]: ' <abc> ', [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.token).toBe('abc')\n expectIfHeadersParsed(req)\n })\n })\n\n describe('PUT / DELETE', () => {\n it('PUT: depth=0 and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PUT, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n\n it('DELETE: parses If header', async () => {\n const req = baseReq(HTTP_METHOD.DELETE, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('MKCOL', () => {\n it('non-zero content-length -> 415', async () => {\n const req = baseReq(HTTP_METHOD.MKCOL, {\n headers: { 'content-length': '3' }\n } as any)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.UNSUPPORTED_MEDIA_TYPE })\n })\n\n it('zero/absent content-length -> depth=0 and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.MKCOL, {\n headers: { 'content-length': '0', [HEADER.IF]: '(<urn:uuid:abc>)' } as any\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('COPY / MOVE', () => {\n it('COPY: missing Destination -> 400', async () => {\n const req = baseReq(HTTP_METHOD.COPY)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('COPY: invalid Destination base path -> 400', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((s: string) => '/not-webdav' + s)\n\n const req = baseReq(HTTP_METHOD.COPY, {\n headers: { [HEADER.DESTINATION]: '/wrong' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('COPY: valid Destination -> overwrite=true, move=false, depth=infinity and parses If header', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((_s: string) => '/webdav/base/path/target')\n\n const req = baseReq(HTTP_METHOD.COPY, {\n headers: { [HEADER.DESTINATION]: '/webdav/base/path/target', [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n expect(req.dav.copyMove).toEqual({\n overwrite: true,\n destination: '/webdav/base/path/target',\n isMove: false\n })\n expectIfHeadersParsed(req)\n })\n\n it('MOVE: isMove=true and overwrite=false when OVERWRITE header is \"f\", respects depth header', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((_s: string) => '/webdav/base/path/target2')\n\n const req = baseReq(HTTP_METHOD.MOVE, {\n headers: {\n [HEADER.DESTINATION]: '/webdav/base/path/target2',\n [HEADER.OVERWRITE]: 'f',\n [HEADER.DEPTH]: DEPTH.RESOURCE\n }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expect(req.dav.copyMove).toEqual({\n overwrite: false,\n destination: '/webdav/base/path/target2',\n isMove: true\n })\n })\n })\n})\n"],"names":["jest","mock","decodeUrl","fn","s","urlToPath","describe","WebDAVProtocolGuard","name","guard","makeUser","hasPerm","havePermission","fullName","email","makeRes","headers","baseReq","method","overrides","body","undefined","originalUrl","protocol","raw","httpVersion","user","makeCtx","req","res","switchToHttp","getRequest","getResponse","expectIfHeadersParsed","expect","Array","isArray","dav","ifHeaders","toBe","length","toBeGreaterThan","beforeEach","clearAllMocks","module","Test","createTestingModule","providers","compile","get","it","HTTP_METHOD","OPTIONS","ctx","canActivate","rejects","toThrow","HttpException","e","ex","toHaveBeenCalledWith","OPTIONS_HEADERS","getStatus","HttpStatus","OK","GET","toMatchObject","status","FORBIDDEN","spy","spyOn","result","toHaveBeenCalled","mockRestore","PROPFIND","resolves","url","depth","DEPTH","MEMBERS","PROPFIND_ALL_PROP","propfindMode","PROPSTAT","ALLPROP","each","title","INFINITY","HEADER","RESOURCE","IF","PROPNAME","BAD_REQUEST","toHaveProperty","spyParse","mockReturnValue","toBeUndefined","PROPPATCH","LOCK","TIMEOUT","lock","timeout","CACHE_LOCK_DEFAULT_TTL","lockscope","LOCK_SCOPE","EXCLUSIVE","owner","toContain","SHARED","toMatch","big","Number","isNaN","originalParseInt","global","parseInt","mockImplementation","Error","toBeDefined","spyIf","IfHeaderUtils","lockinfo","message","toBeNull","UNLOCK","LOCK_TOKEN","token","PUT","DELETE","MKCOL","UNSUPPORTED_MEDIA_TYPE","COPY","DESTINATION","_s","copyMove","toEqual","overwrite","destination","isMove","MOVE","OVERWRITE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/webdav/guards/webdav-protocol.guard.spec.ts"],"sourcesContent":["import { HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { FastifyReply } from 'fastify'\nimport { urlToPath } from '../../../common/functions'\nimport { decodeUrl } from '../../../common/shared'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { CACHE_LOCK_DEFAULT_TTL } from '../../files/constants/cache'\nimport { DEPTH, HEADER, LOCK_SCOPE, OPTIONS_HEADERS, PROPSTAT } from '../constants/webdav'\nimport { FastifyDAVRequest } from '../interfaces/webdav.interface'\nimport * as IfHeaderUtils from '../utils/if-header'\nimport { PROPFIND_ALL_PROP } from '../utils/webdav'\nimport { WebDAVProtocolGuard } from './webdav-protocol.guard'\n\n// Keep these mocks to control path transforms in COPY/MOVE tests\njest.mock('../../../common/shared', () => ({\n decodeUrl: jest.fn((s: string) => s)\n}))\njest.mock('../../../common/functions', () => ({\n urlToPath: jest.fn((s: string) => s)\n}))\n\ndescribe(WebDAVProtocolGuard.name, () => {\n let guard: WebDAVProtocolGuard\n\n const makeUser = (hasPerm = true) => ({\n havePermission: jest.fn(() => hasPerm),\n fullName: 'John Doe',\n email: 'john@doe.tld'\n })\n\n const makeRes = (): FastifyReply =>\n ({\n headers: jest.fn()\n }) as unknown as FastifyReply\n\n const baseReq = (method: string, overrides: Partial<FastifyDAVRequest> = {}): FastifyDAVRequest =>\n ({\n method,\n headers: {},\n // undefined body allows to hit the \"allowed empty body\" branch for PROPFIND/LOCK\n body: undefined as any,\n originalUrl: '/webdav/base/path',\n protocol: 'http',\n raw: { httpVersion: '1.1' } as any,\n user: makeUser(),\n ...overrides\n }) as unknown as FastifyDAVRequest\n\n const makeCtx = (req: FastifyDAVRequest, res: FastifyReply) =>\n ({\n switchToHttp: () => ({\n getRequest: () => req,\n getResponse: () => res\n })\n }) as any\n\n const expectIfHeadersParsed = (req: FastifyDAVRequest) => {\n expect(Array.isArray(req.dav.ifHeaders)).toBe(true)\n expect(req.dav.ifHeaders.length).toBeGreaterThan(0)\n }\n\n beforeEach(async () => {\n jest.clearAllMocks()\n const module: TestingModule = await Test.createTestingModule({\n providers: [WebDAVProtocolGuard]\n }).compile()\n\n guard = module.get(WebDAVProtocolGuard)\n })\n\n describe('Permissions', () => {\n it('allows OPTIONS even without WEBDAV permission (responds headers + 200)', async () => {\n const req = baseReq(HTTP_METHOD.OPTIONS, { user: makeUser(false) as any })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).rejects.toThrow(HttpException)\n try {\n await guard.canActivate(ctx)\n } catch (e) {\n const ex = e as HttpException\n expect(res.headers).toHaveBeenCalledWith(OPTIONS_HEADERS)\n expect(ex.getStatus()).toBe(HttpStatus.OK)\n }\n })\n\n it('forbids non-OPTIONS when the user lacks WEBDAV permission', async () => {\n const req = baseReq(HTTP_METHOD.GET, { user: makeUser(false) as any })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.FORBIDDEN })\n })\n\n it('falls through for a method not handled by the switch', async () => {\n const req = baseReq('VIEW', {})\n const res = makeRes()\n const ctx = makeCtx(req, res)\n const spy = jest.spyOn(guard as any, 'setDAVContext')\n\n const result = await guard.canActivate(ctx)\n expect(result).toBe(true)\n expect(spy).toHaveBeenCalled()\n spy.mockRestore()\n })\n })\n\n describe('PROPFIND', () => {\n it('defaults depth=1 (members) when header is missing, and sets ALLPROP with empty body', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.url).toBe(req.originalUrl)\n expect(req.dav.depth).toBe(DEPTH.MEMBERS)\n expect(req.dav.body).toBe(PROPFIND_ALL_PROP)\n expect(req.dav.propfindMode).toBe(PROPSTAT.ALLPROP)\n expect(req.dav.ifHeaders === undefined || req.dav.ifHeaders.length === 0).toBe(true)\n })\n\n it.each([\n { title: 'depth \"infinity\" normalized to 1 (members)', depth: DEPTH.INFINITY as any },\n { title: 'invalid depth normalized to 1 (members)', depth: 'bad' as any }\n ])('depth normalization: $title', async ({ depth }) => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.DEPTH]: depth },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.MEMBERS)\n })\n\n it('valid XML body with propname and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.DEPTH]: DEPTH.RESOURCE, [HEADER.IF]: '(<urn:uuid:abc> [\"W/\\\\\"ETag\\\\\"\"])' },\n body: '<propfind xmlns=\"DAV:\"><propname/></propfind>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expect(req.dav.propfindMode).toBe(PROPSTAT.PROPNAME)\n expectIfHeadersParsed(req)\n })\n\n it('invalid propfind mode -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: '<propfind xmlns=\"DAV:\"><unknown/></propfind>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('invalid XML (with code) -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: '<bad'\n } as any)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('specific XML validation error handled -> 400', async () => {\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: {},\n body: 'this is not XML at all'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toHaveProperty('status', HttpStatus.BAD_REQUEST)\n })\n\n it('skips body when parseBody returns false, still parses If header', async () => {\n const spyParse = jest.spyOn(guard as any, 'parseBody').mockReturnValue(false as any)\n const req = baseReq(HTTP_METHOD.PROPFIND, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.body).toBeUndefined()\n expect(req.dav.propfindMode).toBeUndefined()\n expectIfHeadersParsed(req)\n } finally {\n spyParse.mockRestore()\n }\n })\n })\n\n describe('PROPPATCH', () => {\n it('requires \"propertyupdate\" in body', async () => {\n const req = baseReq(HTTP_METHOD.PROPPATCH, {\n headers: {},\n body: '<xml/>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('valid body and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PROPPATCH, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)', [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: '<propertyupdate xmlns=\"DAV:\"><set/></propertyupdate>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('LOCK', () => {\n it('timeout=Infinite -> default timeout, owner from string, depth=resource', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Infinite', [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope><owner>Custom Owner</owner></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(CACHE_LOCK_DEFAULT_TTL)\n expect(req.dav.lock.lockscope).toBe(LOCK_SCOPE.EXCLUSIVE)\n expect(req.dav.lock.owner).toContain('Custom Owner')\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n })\n\n it('timeout Second-10 + non-string owner -> default WebDAV owner, depth=infinity', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Second-10', [HEADER.DEPTH]: DEPTH.INFINITY },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><shared/></lockscope><owner><href>me</href></owner></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(10)\n expect(req.dav.lock.lockscope).toBe(LOCK_SCOPE.SHARED)\n expect(req.dav.lock.owner).toMatch(/^me/)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n })\n\n it('clamps timeout Second-N to default when N exceeds default', async () => {\n const big = CACHE_LOCK_DEFAULT_TTL + 1000\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: `Second-${big}` },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(CACHE_LOCK_DEFAULT_TTL)\n })\n\n it('invalid timeout -> NaN (no fallback), depth=infinity', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Bad-Token', [HEADER.DEPTH]: 'x' as any },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(Number.isNaN(req.dav.lock.timeout)).toBe(true)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n })\n\n it('handles parseInt exception during timeout parsing', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Second-' },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n const originalParseInt = global.parseInt\n global.parseInt = jest.fn().mockImplementation(() => {\n throw new Error('Forced parseInt error')\n })\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock).toBeDefined()\n } finally {\n global.parseInt = originalParseInt\n }\n })\n\n it('timeout Infinite + empty IfHeader -> default timeout and ifHeaders undefined', async () => {\n const spyIf = jest.spyOn(IfHeaderUtils, 'parseIfHeader').mockReturnValue([] as any)\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.TIMEOUT]: 'Infinite', [HEADER.IF]: '(<any>)' },\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n try {\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.timeout).toBe(CACHE_LOCK_DEFAULT_TTL)\n expect(req.dav.ifHeaders).toBeUndefined()\n } finally {\n spyIf.mockRestore()\n }\n })\n\n it('missing lockinfo -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<notlockinfo xmlns=\"DAV:\"/>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('invalid lockscope -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><invalid/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('handles Object.keys(lockscope) exception with malformed lockscope -> 400', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n\n jest.spyOn(guard as any, 'parseBody').mockImplementation(() => {\n req.dav.body = {\n lockinfo: {\n lockscope: null\n }\n }\n return true\n })\n\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({\n status: HttpStatus.BAD_REQUEST,\n message: 'Invalid or undefined lockscope'\n })\n })\n\n it('refresh (no body) -> dav.depth = null', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: { [HEADER.DEPTH]: DEPTH.RESOURCE },\n body: undefined\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBeNull()\n })\n\n it('no timeout header -> lock.timeout is undefined', async () => {\n const req = baseReq(HTTP_METHOD.LOCK, {\n headers: {},\n body: '<lockinfo xmlns=\"DAV:\"><lockscope><exclusive/></lockscope></lockinfo>'\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock).toBeDefined()\n expect(req.dav.lock.timeout).toBeUndefined()\n })\n })\n\n describe('UNLOCK', () => {\n it('missing lock-token -> 400', async () => {\n const req = baseReq(HTTP_METHOD.UNLOCK)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('sets token in dav.lock and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.UNLOCK, {\n headers: { [HEADER.LOCK_TOKEN]: ' <abc> ', [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.lock.token).toBe('abc')\n expectIfHeadersParsed(req)\n })\n })\n\n describe('PUT / DELETE', () => {\n it('PUT: depth=0 and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.PUT, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n\n it('DELETE: parses If header', async () => {\n const req = baseReq(HTTP_METHOD.DELETE, {\n headers: { [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('MKCOL', () => {\n it('non-zero content-length -> 415', async () => {\n const req = baseReq(HTTP_METHOD.MKCOL, {\n headers: { 'content-length': '3' }\n } as any)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.UNSUPPORTED_MEDIA_TYPE })\n })\n\n it('zero/absent content-length -> depth=0 and parses If header', async () => {\n const req = baseReq(HTTP_METHOD.MKCOL, {\n headers: { 'content-length': '0', [HEADER.IF]: '(<urn:uuid:abc>)' } as any\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expectIfHeadersParsed(req)\n })\n })\n\n describe('COPY / MOVE', () => {\n it('COPY: missing Destination -> 400', async () => {\n const req = baseReq(HTTP_METHOD.COPY)\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('COPY: invalid Destination base path -> 400', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((s: string) => '/not-webdav' + s)\n\n const req = baseReq(HTTP_METHOD.COPY, {\n headers: { [HEADER.DESTINATION]: '/wrong' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).rejects.toMatchObject({ status: HttpStatus.BAD_REQUEST })\n })\n\n it('COPY: valid Destination -> overwrite=true, move=false, depth=infinity and parses If header', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((_s: string) => '/webdav/base/path/target')\n\n const req = baseReq(HTTP_METHOD.COPY, {\n headers: { [HEADER.DESTINATION]: '/webdav/base/path/target', [HEADER.IF]: '(<urn:uuid:abc>)' }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.INFINITY)\n expect(req.dav.copyMove).toEqual({\n overwrite: true,\n destination: '/webdav/base/path/target',\n isMove: false\n })\n expectIfHeadersParsed(req)\n })\n\n it('MOVE: isMove=true and overwrite=false when OVERWRITE header is \"f\", respects depth header', async () => {\n ;(decodeUrl as jest.Mock).mockImplementation((s: string) => s)\n ;(urlToPath as jest.Mock).mockImplementation((_s: string) => '/webdav/base/path/target2')\n\n const req = baseReq(HTTP_METHOD.MOVE, {\n headers: {\n [HEADER.DESTINATION]: '/webdav/base/path/target2',\n [HEADER.OVERWRITE]: 'f',\n [HEADER.DEPTH]: DEPTH.RESOURCE\n }\n })\n const res = makeRes()\n const ctx = makeCtx(req, res)\n await expect(guard.canActivate(ctx)).resolves.toBe(true)\n expect(req.dav.depth).toBe(DEPTH.RESOURCE)\n expect(req.dav.copyMove).toEqual({\n overwrite: false,\n destination: '/webdav/base/path/target2',\n isMove: true\n })\n })\n })\n})\n"],"names":["jest","mock","decodeUrl","fn","s","urlToPath","describe","WebDAVProtocolGuard","name","guard","makeUser","hasPerm","havePermission","fullName","email","makeRes","headers","baseReq","method","overrides","body","undefined","originalUrl","protocol","raw","httpVersion","user","makeCtx","req","res","switchToHttp","getRequest","getResponse","expectIfHeadersParsed","expect","Array","isArray","dav","ifHeaders","toBe","length","toBeGreaterThan","beforeEach","clearAllMocks","module","Test","createTestingModule","providers","compile","get","it","HTTP_METHOD","OPTIONS","ctx","canActivate","rejects","toThrow","HttpException","e","ex","toHaveBeenCalledWith","OPTIONS_HEADERS","getStatus","HttpStatus","OK","GET","toMatchObject","status","FORBIDDEN","spy","spyOn","result","toHaveBeenCalled","mockRestore","PROPFIND","resolves","url","depth","DEPTH","MEMBERS","PROPFIND_ALL_PROP","propfindMode","PROPSTAT","ALLPROP","each","title","INFINITY","HEADER","RESOURCE","IF","PROPNAME","BAD_REQUEST","toHaveProperty","spyParse","mockReturnValue","toBeUndefined","PROPPATCH","LOCK","TIMEOUT","lock","timeout","CACHE_LOCK_DEFAULT_TTL","lockscope","LOCK_SCOPE","EXCLUSIVE","owner","toContain","SHARED","toMatch","big","Number","isNaN","originalParseInt","global","parseInt","mockImplementation","Error","toBeDefined","spyIf","IfHeaderUtils","lockinfo","message","toBeNull","UNLOCK","LOCK_TOKEN","token","PUT","DELETE","MKCOL","UNSUPPORTED_MEDIA_TYPE","COPY","DESTINATION","_s","copyMove","toEqual","overwrite","destination","isMove","MOVE","OVERWRITE"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/webdav/interfaces/webdav.interface.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { DEPTH, LOCK_SCOPE, PROPSTAT } from '../constants/webdav'\nimport { IfHeader } from './if-header.interface'\n\nexport interface WebDAVContext {\n url: string\n body?: any // xml content\n httpVersion?: string\n ifHeaders?: IfHeader[]\n depth?: DEPTH | string\n propfindMode?: PROPSTAT\n lock?: { timeout?: number; lockscope?: LOCK_SCOPE; owner?: any; token?: string }\n proppatch?: { props: Record<string, string>; errors: any[] }\n copyMove?: { overwrite: boolean; destination: string; isMove: boolean }\n}\n\nexport interface
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/webdav/interfaces/webdav.interface.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { DEPTH, LOCK_SCOPE, PROPSTAT } from '../constants/webdav'\nimport { IfHeader } from './if-header.interface'\n\nexport interface WebDAVContext {\n url: string\n body?: any // xml content\n httpVersion?: string\n ifHeaders?: IfHeader[]\n depth?: DEPTH | string\n propfindMode?: PROPSTAT\n lock?: { timeout?: number; lockscope?: LOCK_SCOPE; owner?: any; token?: string }\n proppatch?: { props: Record<string, string>; errors: any[] }\n copyMove?: { overwrite: boolean; destination: string; isMove: boolean }\n}\n\nexport interface FastifyDAVRequest extends FastifyAuthenticatedRequest {\n body: any\n dav?: WebDAVContext\n space?: SpaceEnv\n}\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
|
|
@@ -42,6 +42,10 @@ function _ts_metadata(k, v) {
|
|
|
42
42
|
let WebDAVMethods = class WebDAVMethods {
|
|
43
43
|
async headOrGet(req, res, repository) {
|
|
44
44
|
if (repository === _spaces.SPACE_REPOSITORY.FILES && !req.space.inSharesList) {
|
|
45
|
+
if (await (0, _files.isPathExists)(req.space.realPath) && await (0, _files.isPathIsDir)(req.space.realPath)) {
|
|
46
|
+
// Directory case
|
|
47
|
+
return res.header('DAV', _webdav.OPTIONS_HEADERS.DAV).header('Content-Type', 'httpd/unix-directory').header('Content-Length', '0').status(_common.HttpStatus.OK).send();
|
|
48
|
+
}
|
|
45
49
|
const sendFile = this.filesManager.sendFileFromSpace(req.space);
|
|
46
50
|
try {
|
|
47
51
|
await sendFile.checks();
|
|
@@ -73,26 +77,31 @@ let WebDAVMethods = class WebDAVMethods {
|
|
|
73
77
|
return res.status(_common.HttpStatus.CONFLICT).send('Parent must exists');
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
const lockOptions = {
|
|
81
|
+
lockRoot: req.dav.url,
|
|
82
|
+
lockToken: this.filesLockManager.genDAVToken(),
|
|
83
|
+
lockScope: req.dav.lock.lockscope,
|
|
84
|
+
lockInfo: req.dav.lock?.owner
|
|
81
85
|
};
|
|
82
|
-
const [ok, fileLock] = await this.filesLockManager.create(req.user, req.space.dbFile, req.dav.depth,
|
|
86
|
+
const [ok, fileLock] = await this.filesLockManager.create(req.user, req.space.dbFile, _webdav.WEBDAV_APP_LOCK, req.dav.depth, lockOptions, req.dav.lock.timeout);
|
|
83
87
|
if (ok) {
|
|
84
88
|
// Locking unmapped URLs: must create an empty resource (that is not a collection)
|
|
85
89
|
if (!rExists) {
|
|
86
|
-
// checkLocks set to false because the conflicts are already checked in `filesLockManager.create` method
|
|
90
|
+
// checkLocks set to false because the conflicts are already checked in the `filesLockManager.create` method
|
|
87
91
|
await this.filesManager.mkFile(req.user, req.space, false, false, false);
|
|
88
92
|
}
|
|
89
93
|
const lockProp = (0, _webdav1.LOCK_PROP)([
|
|
90
94
|
fileLock
|
|
91
95
|
]);
|
|
92
|
-
return res.header(
|
|
93
|
-
}
|
|
94
|
-
|
|
96
|
+
return res.header(_webdav.HEADER.LOCK_TOKEN, `<${lockOptions.lockToken}>`).type(_webdav.XML_CONTENT_TYPE).status(rExists ? _common.HttpStatus.OK : _common.HttpStatus.CREATED).send((0, _xml.xmlBuild)(lockProp));
|
|
97
|
+
}
|
|
98
|
+
if (fileLock) {
|
|
99
|
+
const lockProp = (0, _webdav1.LOCK_PROP)([
|
|
100
|
+
fileLock
|
|
101
|
+
]);
|
|
102
|
+
return res.type(_webdav.XML_CONTENT_TYPE).status(_common.HttpStatus.LOCKED).send((0, _xml.xmlBuild)(lockProp));
|
|
95
103
|
}
|
|
104
|
+
return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.LOCKED, _webdav.PRECONDITION.LOCK_CONFLICT, res, fileLock.options?.lockRoot || fileLock.dbFilePath);
|
|
96
105
|
}
|
|
97
106
|
async unlock(req, res) {
|
|
98
107
|
if (!await (0, _files.isPathExists)(req.space.realPath)) {
|
|
@@ -149,9 +158,23 @@ let WebDAVMethods = class WebDAVMethods {
|
|
|
149
158
|
for (const p of requestedProps){
|
|
150
159
|
let fP;
|
|
151
160
|
if (p === _webdav.LOCK_DISCOVERY_PROP) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
161
|
+
let lockDiscovery = null;
|
|
162
|
+
if (repository === _spaces.SPACE_REPOSITORY.FILES) {
|
|
163
|
+
if (f.name in locks) {
|
|
164
|
+
lockDiscovery = (0, _webdav1.LOCK_DISCOVERY)([
|
|
165
|
+
locks[f.name]
|
|
166
|
+
]);
|
|
167
|
+
} else {
|
|
168
|
+
// The lock name may correspond to the original file at the space root.
|
|
169
|
+
const fName = (0, _files.fileName)(req.space.dbFile.path);
|
|
170
|
+
if (fName in locks) {
|
|
171
|
+
lockDiscovery = (0, _webdav1.LOCK_DISCOVERY)([
|
|
172
|
+
locks[fName]
|
|
173
|
+
]);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
fP = lockDiscovery;
|
|
155
178
|
} else {
|
|
156
179
|
fP = f[p];
|
|
157
180
|
}
|
|
@@ -307,7 +330,7 @@ let WebDAVMethods = class WebDAVMethods {
|
|
|
307
330
|
space: dstSpace
|
|
308
331
|
};
|
|
309
332
|
if (!await this.evaluateIfHeaders(fakeDstReq, res)) {
|
|
310
|
-
// if there is an error the response is generated inside the `evaluateIfHeaders` function
|
|
333
|
+
// if there is an error, the response is generated inside the `evaluateIfHeaders` function
|
|
311
334
|
return;
|
|
312
335
|
}
|
|
313
336
|
try {
|
|
@@ -359,12 +382,12 @@ let WebDAVMethods = class WebDAVMethods {
|
|
|
359
382
|
}
|
|
360
383
|
if (condition.token) {
|
|
361
384
|
const token = await this.filesLockManager.getLockByToken(condition.token.value);
|
|
362
|
-
const match = token && lastPath.startsWith(token.
|
|
385
|
+
const match = token && lastPath.startsWith(token.options?.lockRoot);
|
|
363
386
|
if (condition.token.mustMatch !== match) {
|
|
364
387
|
if (!token) {
|
|
365
388
|
errors.push(`lock token not found`);
|
|
366
389
|
} else {
|
|
367
|
-
errors.push(`lock token url mismatch (${lastPath} is not a child of ${token.
|
|
390
|
+
errors.push(`lock token url mismatch (${lastPath} is not a child of ${token.options?.lockRoot})`);
|
|
368
391
|
}
|
|
369
392
|
continue;
|
|
370
393
|
}
|
|
@@ -423,7 +446,7 @@ let WebDAVMethods = class WebDAVMethods {
|
|
|
423
446
|
// Remove the last part to avoid exposing the path
|
|
424
447
|
const errorMsg = e.message.split(',')[0];
|
|
425
448
|
if (e instanceof _filelockerror.LockConflict) {
|
|
426
|
-
return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.LOCKED, _webdav.PRECONDITION.LOCK_CONFLICT, res, e.lock.
|
|
449
|
+
return (0, _webdav1.DAV_ERROR_RES)(_common.HttpStatus.LOCKED, _webdav.PRECONDITION.LOCK_CONFLICT, res, e.lock.options?.lockRoot || e.lock.dbFilePath);
|
|
427
450
|
} else if (e instanceof _fileerror.FileError) {
|
|
428
451
|
return res.status(e.httpCode).send(errorMsg);
|
|
429
452
|
}
|