@sync-in/server 1.9.6 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -4
- package/README.md +2 -2
- package/environment/environment.dist.yaml +15 -5
- package/package.json +14 -16
- package/server/app.bootstrap.js +4 -23
- 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/comments/services/comments-queries.service.js +5 -9
- package/server/applications/comments/services/comments-queries.service.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 +3 -1
- package/server/applications/files/services/files-methods.service.spec.js.map +1 -1
- package/server/applications/files/services/files-scheduler.service.js +2 -2
- 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/users/users.e2e-spec.js +0 -1
- package/server/applications/users/users.e2e-spec.js.map +1 -1
- package/server/applications/webdav/constants/webdav.js +11 -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/bootstrap.js +45 -0
- package/server/applications/webdav/utils/bootstrap.js.map +1 -0
- 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 +5 -5
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/applications/webdav/webdav.e2e-spec.js +131 -2
- package/server/applications/webdav/webdav.e2e-spec.js.map +1 -1
- package/server/authentication/auth.e2e-spec.js +12 -6
- package/server/authentication/auth.e2e-spec.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.spec.js +23 -0
- package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
- package/server/authentication/guards/auth-basic.strategy.js +3 -3
- package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
- package/server/authentication/guards/auth-digest.strategy.js +32 -11
- package/server/authentication/guards/auth-digest.strategy.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/guards/implementations/http-basic.strategy.js +76 -0
- package/server/authentication/guards/implementations/http-basic.strategy.js.map +1 -0
- package/server/authentication/guards/implementations/http-digest.strategy.js +155 -0
- package/server/authentication/guards/implementations/http-digest.strategy.js.map +1 -0
- package/server/authentication/services/auth-manager.service.js +1 -2
- package/server/authentication/services/auth-manager.service.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-2F42MZQ5.js → chunk-2GXOVGTD.js} +1 -1
- package/static/{chunk-HLKZCMKV.js → chunk-2RWLNKZH.js} +1 -1
- package/static/chunk-2YQ4SX3A.js +13 -0
- package/static/{chunk-LFAQLJZK.js → chunk-3MVPXC3U.js} +1 -1
- package/static/chunk-3QTROEHV.js +1 -0
- package/static/{chunk-JYHTSSKW.js → chunk-3VRUIWQG.js} +1 -1
- package/static/{chunk-2CAAJBRO.js → chunk-3ZBAQTHJ.js} +1 -1
- package/static/chunk-3ZLBVUCX.js +2 -0
- package/static/chunk-46TJLPJY.js +1 -0
- package/static/chunk-4NIYCYRS.js +2 -0
- package/static/chunk-6OEOADR6.js +1 -0
- package/static/{chunk-BJARRIS6.js → chunk-76M3BMK6.js} +11 -11
- package/static/{chunk-ANH4VNOS.js → chunk-76REYAEA.js} +1 -1
- package/static/{chunk-7HL5Z6PF.js → chunk-7HJFIMNF.js} +1 -1
- package/static/{chunk-XIQXRSZ2.js → chunk-7KAYOR3A.js} +1 -1
- package/static/chunk-AALPWGPB.js +3 -0
- package/static/{chunk-Z2KBIZ5D.js → chunk-ARS47O5X.js} +1 -1
- package/static/chunk-BCN4T5DO.js +2 -0
- package/static/{chunk-DU4Q4RWJ.js → chunk-CMNMPG6Z.js} +1 -1
- package/static/{chunk-UO7ATVQG.js → chunk-CN5YVRFT.js} +1 -1
- package/static/{chunk-BX3QZ7IL.js → chunk-CSVPAZHK.js} +1 -1
- package/static/chunk-CVXLHSO5.js +1 -0
- package/static/{chunk-O233BXWK.js → chunk-D2MLAO5N.js} +1 -1
- package/static/{chunk-NHMYAVJK.js → chunk-D5FQ72R4.js} +1 -1
- package/static/{chunk-IBC7CFBQ.js → chunk-DVCN3P7Q.js} +1 -1
- package/static/{chunk-25PWAXTJ.js → chunk-EKWB5W72.js} +1 -1
- package/static/{chunk-ZCOEP4O2.js → chunk-FTFEQDWH.js} +1 -1
- package/static/{chunk-EPDWJEPD.js → chunk-FWQJ4ZCD.js} +1 -1
- package/static/chunk-G7RZN7HN.js +1 -0
- package/static/{chunk-X5UDV4ZB.js → chunk-HZAB6F4Q.js} +1 -1
- package/static/{chunk-FEQUP26G.js → chunk-IHS5LSJJ.js} +1 -1
- package/static/{chunk-DQAQUSVW.js → chunk-IMFO2MI7.js} +1 -1
- package/static/{chunk-ODAQRAPO.js → chunk-J7474P3L.js} +1 -1
- package/static/{chunk-DK2LAJEL.js → chunk-JAJ7VXMB.js} +1 -1
- package/static/{chunk-AYYJZMBE.js → chunk-JNTNMIUH.js} +1 -1
- package/static/chunk-JRXG43AA.js +2 -0
- package/static/{chunk-3AR5VNJE.js → chunk-KAUCN24H.js} +1 -1
- package/static/{chunk-3WS72A6C.js → chunk-KDUAB76O.js} +1 -1
- package/static/chunk-KEZNIIFH.js +1 -0
- package/static/chunk-LTJNLOX2.js +1 -0
- package/static/chunk-LWSCODLD.js +1 -0
- package/static/{chunk-GRV44RYI.js → chunk-LZUHREOF.js} +1 -1
- package/static/chunk-NIKNG2FX.js +1 -0
- package/static/chunk-NNZWSNAW.js +1 -0
- package/static/chunk-NWKBB7J4.js +1 -0
- package/static/{chunk-B4TDS6AQ.js → chunk-PDG7DOEF.js} +1 -1
- package/static/{chunk-NQCKX2AD.js → chunk-PPJCVBJH.js} +1 -1
- package/static/chunk-PVYVY3GD.js +1 -0
- package/static/chunk-Q5X5TPAG.js +1 -0
- package/static/chunk-QGHNJVJ6.js +1 -0
- package/static/{chunk-5HYSNQR4.js → chunk-QJ22N76V.js} +1 -1
- package/static/{chunk-TOCCCZP2.js → chunk-QTPIEEZW.js} +1 -1
- package/static/{chunk-D6QWQHWE.js → chunk-R4VMWCM5.js} +1 -1
- package/static/{chunk-7H5O4BLV.js → chunk-R4VYKZVJ.js} +1 -1
- package/static/{chunk-QKMN3S4M.js → chunk-RBTLSPYJ.js} +1 -1
- package/static/chunk-RJULB733.js +1 -0
- package/static/{chunk-E5C4QRNQ.js → chunk-RNVPQQKT.js} +5 -5
- package/static/chunk-RTNEBRKJ.js +1 -0
- package/static/{chunk-IIKL33TV.js → chunk-S44QIK3G.js} +1 -1
- package/static/{chunk-SF6Q6VRC.js → chunk-S6H2ELRY.js} +1 -1
- package/static/{chunk-4GBA6EJ4.js → chunk-SDJNZULP.js} +1 -1
- package/static/chunk-SNOOCDJD.js +1 -0
- package/static/chunk-SPQH3ATC.js +5 -0
- package/static/{chunk-5KVI243T.js → chunk-TNCKNU6I.js} +1 -1
- package/static/{chunk-7QYALK5T.js → chunk-TTWMFWEC.js} +1 -1
- package/static/{chunk-OVUMPMVM.js → chunk-U5E5H2DD.js} +1 -1
- package/static/{chunk-5NFH4E2B.js → chunk-UOK3LKSX.js} +1 -1
- package/static/{chunk-5ATJIR5S.js → chunk-VBTZDHZ3.js} +1 -1
- package/static/{chunk-CHMDM2ZW.js → chunk-VD5JHSDS.js} +1 -1
- package/static/chunk-VZFZUI6D.js +1 -0
- package/static/{chunk-GYYJ4FWN.js → chunk-WFMEUST4.js} +1 -1
- package/static/{chunk-BVKDW5XO.js → chunk-WRK2FTKU.js} +1 -1
- package/static/{chunk-GLPKRULI.js → chunk-WZPF4LS2.js} +1 -1
- package/static/chunk-X7NHX5C7.js +1 -0
- package/static/{chunk-FSGT46LM.js → chunk-XSURUW7C.js} +1 -1
- package/static/{chunk-KAAFVHYE.js → chunk-XX3JPJUM.js} +1 -1
- package/static/{chunk-C5T7RZSD.js → chunk-XZHWESIY.js} +1 -1
- package/static/chunk-ZCSHU3D7.js +1 -0
- package/static/{chunk-QUUQOBTF.js → chunk-ZEJLIGAY.js} +1 -1
- package/static/{chunk-GENTF6JM.js → chunk-ZHUBWKA2.js} +1 -1
- package/static/chunk-ZOMRIN3G.js +2 -0
- package/static/{chunk-2U5VKTML.js → chunk-ZU5MQTFN.js} +1 -1
- package/static/index.html +2 -2
- package/static/main-5O3KLGIR.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-42L6C5MT.js +0 -1
- package/static/chunk-4ZKAVMB4.js +0 -1
- package/static/chunk-5GIWZKNS.js +0 -1
- package/static/chunk-5WCQBTXW.js +0 -1
- package/static/chunk-B2A4HNDC.js +0 -1
- package/static/chunk-BSB4VROD.js +0 -2
- package/static/chunk-CUC7R6C2.js +0 -1
- package/static/chunk-DHFQIFOF.js +0 -1
- package/static/chunk-DRHPEERW.js +0 -2
- package/static/chunk-FCGTI42I.js +0 -1
- package/static/chunk-FCR5AEHR.js +0 -3
- package/static/chunk-HB5DC7RJ.js +0 -1
- package/static/chunk-ITVA26X2.js +0 -2
- package/static/chunk-KWKZN53T.js +0 -1
- package/static/chunk-LBXOAKBD.js +0 -1
- package/static/chunk-LZKI5P5T.js +0 -1
- package/static/chunk-MGMDT4VN.js +0 -1
- package/static/chunk-MWUUM2NK.js +0 -13
- package/static/chunk-MYM43ENO.js +0 -1
- package/static/chunk-NAH4V2R6.js +0 -2
- package/static/chunk-PCFH5HCI.js +0 -2
- package/static/chunk-Q6B4OVER.js +0 -5
- package/static/chunk-QV5LQKTS.js +0 -1
- package/static/chunk-S4UTSOPV.js +0 -1
- package/static/chunk-SRBOO7AO.js +0 -1
- package/static/chunk-VZPCXSRG.js +0 -2
- package/static/chunk-XKEBQNQJ.js +0 -1
- package/static/chunk-YYTDPI5S.js +0 -1
- package/static/main-ODUA232E.js +0 -11
- /package/static/assets/pdfjs/web/images/{toolbarButton-sidebarToggle.svg → toolbarButton-viewsManagerToggle.svg} +0 -0
|
@@ -123,15 +123,15 @@ function LOCK_DISCOVERY(locks) {
|
|
|
123
123
|
[`${_webdav.NS_PREFIX}:write`]: null
|
|
124
124
|
},
|
|
125
125
|
[`${_webdav.NS_PREFIX}:lockscope`]: {
|
|
126
|
-
[`${_webdav.NS_PREFIX}:${lock.
|
|
126
|
+
[`${_webdav.NS_PREFIX}:${lock.options?.lockScope || _webdav.LOCK_SCOPE.EXCLUSIVE}`]: null
|
|
127
127
|
},
|
|
128
128
|
[`${_webdav.NS_PREFIX}:locktoken`]: {
|
|
129
|
-
[`${_webdav.NS_PREFIX}:href`]: lock.
|
|
129
|
+
[`${_webdav.NS_PREFIX}:href`]: lock.options?.lockToken || _shared.SERVER_NAME
|
|
130
130
|
},
|
|
131
131
|
[`${_webdav.NS_PREFIX}:lockroot`]: {
|
|
132
|
-
[`${_webdav.NS_PREFIX}:href`]: (0, _shared.encodeUrl)(lock.
|
|
132
|
+
[`${_webdav.NS_PREFIX}:href`]: (0, _shared.encodeUrl)(lock.options?.lockRoot || lock.dbFilePath)
|
|
133
133
|
},
|
|
134
|
-
[`${_webdav.NS_PREFIX}:owner`]: lock
|
|
134
|
+
[`${_webdav.NS_PREFIX}:owner`]: formatLockOwner(lock),
|
|
135
135
|
[`${_webdav.NS_PREFIX}:timeout`]: `Second-${Math.floor(lock.expiration - (0, _shared.currentTimeStamp)())}`,
|
|
136
136
|
[`${_webdav.NS_PREFIX}:depth`]: lock.depth
|
|
137
137
|
}
|
|
@@ -162,5 +162,9 @@ function DAV_ERROR(error, href) {
|
|
|
162
162
|
function DAV_ERROR_RES(code, error, res, href) {
|
|
163
163
|
return res.status(code).type(_webdav.XML_CONTENT_TYPE).send(DAV_ERROR(error, href));
|
|
164
164
|
}
|
|
165
|
+
function formatLockOwner(lock) {
|
|
166
|
+
const lockInfo = `${lock.options.lockInfo ? `${lock.options.lockInfo}` : ''}${lock.app ? ` ${lock.app}` : ''}`;
|
|
167
|
+
return `${lock.owner.fullName} (${lock.owner.email})${lockInfo ? ` - ${lockInfo}` : ''}`;
|
|
168
|
+
}
|
|
165
169
|
|
|
166
170
|
//# sourceMappingURL=webdav.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/webdav/utils/webdav.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 { FastifyReply } from 'fastify'\nimport http from 'node:http'\nimport { currentTimeStamp, encodeUrl, SERVER_NAME } from '../../../common/shared'\nimport { FileLock } from '../../files/interfaces/file-lock.interface'\nimport { LOCK_SCOPE, NS_DAV, NS_PREFIX, PROPSTAT, XML_CONTENT_TYPE } from '../constants/webdav'\nimport { XML_NS, xmlBuild } from './xml'\n\nexport const XML_DAV_NS = { [`${XML_NS}:${NS_PREFIX}`]: `${NS_DAV}` }\nexport const PROPFIND_COLLECTION = { [`${NS_PREFIX}:collection`]: null }\nexport const PROPFIND_ALL_PROP = {\n [`${NS_PREFIX}:propfind`]: {\n [`${NS_PREFIX}:${PROPSTAT.ALLPROP}`]: null,\n ...XML_DAV_NS\n }\n}\n\nexport const SUPPORTED_LOCKS = {\n [`${NS_PREFIX}:lockentry`]: [\n {\n [`${NS_PREFIX}:lockscope`]: {\n [`${NS_PREFIX}:exclusive`]: null\n },\n [`${NS_PREFIX}:locktype`]: {\n [`${NS_PREFIX}:write`]: null\n }\n },\n {\n [`${NS_PREFIX}:lockscope`]: {\n [`${NS_PREFIX}:shared`]: null\n },\n [`${NS_PREFIX}:locktype`]: {\n [`${NS_PREFIX}:write`]: null\n }\n }\n ]\n}\n\nexport function PROP(prop: any, httpVersion: string, httpStatus: number, description?: string) {\n return {\n [`${NS_PREFIX}:prop`]: prop,\n [`${NS_PREFIX}:status`]: `${httpVersion} ${httpStatus} ${http.STATUS_CODES[httpStatus]}`,\n [`${NS_PREFIX}:responsedescription`]: description ? { [`${NS_PREFIX}:error`]: { [`${NS_PREFIX}:${description}`]: null } } : undefined\n }\n}\n\nexport function PROP_STAT(href: string, props: any) {\n return {\n [`${NS_PREFIX}:href`]: href,\n [`${NS_PREFIX}:propstat`]: props\n }\n}\n\nexport function MULTI_STATUS(content: any) {\n return {\n [`${NS_PREFIX}:multistatus`]: { [`${NS_PREFIX}:response`]: content, ...XML_DAV_NS }\n }\n}\n\nexport function LOCK_DISCOVERY(locks: FileLock[]) {\n // only locktype write is currently implemented in RFC\n const activeLocks = []\n for (const lock of locks) {\n activeLocks.push({\n [`${NS_PREFIX}:activelock`]: {\n [`${NS_PREFIX}:locktype`]: { [`${NS_PREFIX}:write`]: null },\n [`${NS_PREFIX}:lockscope`]: { [`${NS_PREFIX}:${lock.
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/webdav/utils/webdav.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 { FastifyReply } from 'fastify'\nimport http from 'node:http'\nimport { currentTimeStamp, encodeUrl, SERVER_NAME } from '../../../common/shared'\nimport { FileLock } from '../../files/interfaces/file-lock.interface'\nimport { LOCK_SCOPE, NS_DAV, NS_PREFIX, PROPSTAT, XML_CONTENT_TYPE } from '../constants/webdav'\nimport { XML_NS, xmlBuild } from './xml'\n\nexport const XML_DAV_NS = { [`${XML_NS}:${NS_PREFIX}`]: `${NS_DAV}` }\nexport const PROPFIND_COLLECTION = { [`${NS_PREFIX}:collection`]: null }\nexport const PROPFIND_ALL_PROP = {\n [`${NS_PREFIX}:propfind`]: {\n [`${NS_PREFIX}:${PROPSTAT.ALLPROP}`]: null,\n ...XML_DAV_NS\n }\n}\n\nexport const SUPPORTED_LOCKS = {\n [`${NS_PREFIX}:lockentry`]: [\n {\n [`${NS_PREFIX}:lockscope`]: {\n [`${NS_PREFIX}:exclusive`]: null\n },\n [`${NS_PREFIX}:locktype`]: {\n [`${NS_PREFIX}:write`]: null\n }\n },\n {\n [`${NS_PREFIX}:lockscope`]: {\n [`${NS_PREFIX}:shared`]: null\n },\n [`${NS_PREFIX}:locktype`]: {\n [`${NS_PREFIX}:write`]: null\n }\n }\n ]\n}\n\nexport function PROP(prop: any, httpVersion: string, httpStatus: number, description?: string) {\n return {\n [`${NS_PREFIX}:prop`]: prop,\n [`${NS_PREFIX}:status`]: `${httpVersion} ${httpStatus} ${http.STATUS_CODES[httpStatus]}`,\n [`${NS_PREFIX}:responsedescription`]: description ? { [`${NS_PREFIX}:error`]: { [`${NS_PREFIX}:${description}`]: null } } : undefined\n }\n}\n\nexport function PROP_STAT(href: string, props: any) {\n return {\n [`${NS_PREFIX}:href`]: href,\n [`${NS_PREFIX}:propstat`]: props\n }\n}\n\nexport function MULTI_STATUS(content: any) {\n return {\n [`${NS_PREFIX}:multistatus`]: { [`${NS_PREFIX}:response`]: content, ...XML_DAV_NS }\n }\n}\n\nexport function LOCK_DISCOVERY(locks: FileLock[]) {\n // only locktype write is currently implemented in RFC\n const activeLocks = []\n for (const lock of locks) {\n activeLocks.push({\n [`${NS_PREFIX}:activelock`]: {\n [`${NS_PREFIX}:locktype`]: { [`${NS_PREFIX}:write`]: null },\n [`${NS_PREFIX}:lockscope`]: { [`${NS_PREFIX}:${lock.options?.lockScope || LOCK_SCOPE.EXCLUSIVE}`]: null },\n [`${NS_PREFIX}:locktoken`]: { [`${NS_PREFIX}:href`]: lock.options?.lockToken || SERVER_NAME },\n [`${NS_PREFIX}:lockroot`]: { [`${NS_PREFIX}:href`]: encodeUrl(lock.options?.lockRoot || lock.dbFilePath) },\n [`${NS_PREFIX}:owner`]: formatLockOwner(lock),\n [`${NS_PREFIX}:timeout`]: `Second-${Math.floor(lock.expiration - currentTimeStamp())}`,\n [`${NS_PREFIX}:depth`]: lock.depth\n }\n })\n }\n return activeLocks\n}\n\nexport function LOCK_PROP(locks: FileLock[]) {\n return { [`${NS_PREFIX}:prop`]: { [`${NS_PREFIX}:lockdiscovery`]: LOCK_DISCOVERY(locks), ...XML_DAV_NS } }\n}\n\nexport function DAV_ERROR(error: string, href?: string): string {\n return xmlBuild({\n 'ns0:error': { [`ns0:${error}`]: href ? [{ 'ns0:href': encodeUrl(href) }] : '', [`${XML_NS}:ns0`]: `${NS_DAV}` }\n })\n}\n\nexport function DAV_ERROR_RES(code: number, error: string, res: FastifyReply, href?: string): FastifyReply {\n return res.status(code).type(XML_CONTENT_TYPE).send(DAV_ERROR(error, href))\n}\n\nfunction formatLockOwner(lock: FileLock) {\n const lockInfo = `${lock.options.lockInfo ? `${lock.options.lockInfo}` : ''}${lock.app ? ` ${lock.app}` : ''}`\n return `${lock.owner.fullName} (${lock.owner.email})${lockInfo ? ` - ${lockInfo}` : ''}`\n}\n"],"names":["DAV_ERROR","DAV_ERROR_RES","LOCK_DISCOVERY","LOCK_PROP","MULTI_STATUS","PROP","PROPFIND_ALL_PROP","PROPFIND_COLLECTION","PROP_STAT","SUPPORTED_LOCKS","XML_DAV_NS","XML_NS","NS_PREFIX","NS_DAV","PROPSTAT","ALLPROP","prop","httpVersion","httpStatus","description","http","STATUS_CODES","undefined","href","props","content","locks","activeLocks","lock","push","options","lockScope","LOCK_SCOPE","EXCLUSIVE","lockToken","SERVER_NAME","encodeUrl","lockRoot","dbFilePath","formatLockOwner","Math","floor","expiration","currentTimeStamp","depth","error","xmlBuild","code","res","status","type","XML_CONTENT_TYPE","send","lockInfo","app","owner","fullName","email"],"mappings":"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"}
|
|
@@ -37,28 +37,28 @@ function _ts_param(paramIndex, decorator) {
|
|
|
37
37
|
}
|
|
38
38
|
let WebDAVController = class WebDAVController {
|
|
39
39
|
serverOptions() {
|
|
40
|
-
// OPTIONS method is handled in the `
|
|
40
|
+
// OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
serverPropFind(req, res) {
|
|
44
44
|
return this.webdavMethods.propfind(req, res, _routes.WEBDAV_NS.SERVER);
|
|
45
45
|
}
|
|
46
46
|
webdavOptions() {
|
|
47
|
-
// OPTIONS method is handled in the `
|
|
47
|
+
// OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
async webdavPropfind(req, res) {
|
|
51
51
|
return this.webdavMethods.propfind(req, res, _routes.WEBDAV_NS.WEBDAV);
|
|
52
52
|
}
|
|
53
53
|
repositoriesOptions() {
|
|
54
|
-
// OPTIONS method is handled in the `
|
|
54
|
+
// OPTIONS method is handled in the `WebDAVProtocolGuard`
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
async repositoriesPropfind(req, res, repository) {
|
|
58
58
|
return this.webdavMethods.propfind(req, res, repository);
|
|
59
59
|
}
|
|
60
60
|
async files(req, res) {
|
|
61
|
-
// OPTIONS method is handled in the `
|
|
61
|
+
// OPTIONS method is handled in the `WebDAVProtocolGuard`
|
|
62
62
|
switch(req.method){
|
|
63
63
|
case _applicationsconstants.HTTP_METHOD.PROPFIND:
|
|
64
64
|
return this.webdavMethods.propfind(req, res, _spaces.SPACE_REPOSITORY.FILES);
|
|
@@ -105,7 +105,7 @@ _ts_decorate([
|
|
|
105
105
|
typeof _webdavinterface.FastifyDAVRequest === "undefined" ? Object : _webdavinterface.FastifyDAVRequest,
|
|
106
106
|
typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply
|
|
107
107
|
]),
|
|
108
|
-
_ts_metadata("design:returntype",
|
|
108
|
+
_ts_metadata("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
109
109
|
], WebDAVController.prototype, "serverPropFind", null);
|
|
110
110
|
_ts_decorate([
|
|
111
111
|
(0, _common.Options)(_routes.WEBDAV_BASE_PATH),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.controller.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { All, Controller, HttpStatus, Options, Param, Propfind, Req, Res, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { HTTP_METHOD } from '../applications.constants'\nimport { SPACE_REPOSITORY } from '../spaces/constants/spaces'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { WEBDAV_BASE_PATH, WEBDAV_NS } from './constants/routes'\nimport { WebDAVEnvironment } from './decorators/webdav-context.decorator'\nimport { FastifyDAVRequest } from './interfaces/webdav.interface'\nimport { WebDAVMethods } from './services/webdav-methods.service'\n\n@Controller()\n@WebDAVEnvironment()\nexport class WebDAVController {\n constructor(private readonly webdavMethods: WebDAVMethods) {}\n\n @Options()\n serverOptions() {\n // OPTIONS method is handled in the `
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.controller.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { All, Controller, HttpStatus, Options, Param, Propfind, Req, Res, StreamableFile, UseGuards } from '@nestjs/common'\nimport { FastifyReply } from 'fastify'\nimport { HTTP_METHOD } from '../applications.constants'\nimport { SPACE_REPOSITORY } from '../spaces/constants/spaces'\nimport { SpaceGuard } from '../spaces/guards/space.guard'\nimport { WEBDAV_BASE_PATH, WEBDAV_NS } from './constants/routes'\nimport { WebDAVEnvironment } from './decorators/webdav-context.decorator'\nimport { FastifyDAVRequest } from './interfaces/webdav.interface'\nimport { WebDAVMethods } from './services/webdav-methods.service'\n\n@Controller()\n@WebDAVEnvironment()\nexport class WebDAVController {\n constructor(private readonly webdavMethods: WebDAVMethods) {}\n\n @Options()\n serverOptions(): void {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind()\n serverPropFind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<string> {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.SERVER)\n }\n\n @Options(WEBDAV_BASE_PATH)\n webdavOptions(): void {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`, return empty response with headers\n return\n }\n\n @Propfind(WEBDAV_BASE_PATH)\n async webdavPropfind(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<string> {\n return this.webdavMethods.propfind(req, res, WEBDAV_NS.WEBDAV)\n }\n\n @Options(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n repositoriesOptions(): void {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`\n return\n }\n\n @Propfind(`${WEBDAV_BASE_PATH}/:repository(^(${WEBDAV_NS.SPACES}|${WEBDAV_NS.TRASH})$)`)\n async repositoriesPropfind(\n @Req() req: FastifyDAVRequest,\n @Res({ passthrough: true }) res: FastifyReply,\n @Param('repository') repository: string\n ): Promise<string> {\n return this.webdavMethods.propfind(req, res, repository)\n }\n\n @All(`${WEBDAV_BASE_PATH}/*`)\n @UseGuards(SpaceGuard)\n async files(@Req() req: FastifyDAVRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<string | StreamableFile> {\n // OPTIONS method is handled in the `WebDAVProtocolGuard`\n switch (req.method) {\n case HTTP_METHOD.PROPFIND:\n return this.webdavMethods.propfind(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.HEAD:\n case HTTP_METHOD.GET:\n return this.webdavMethods.headOrGet(req, res, SPACE_REPOSITORY.FILES)\n case HTTP_METHOD.PUT:\n return this.webdavMethods.put(req, res)\n case HTTP_METHOD.DELETE:\n return this.webdavMethods.delete(req, res)\n case HTTP_METHOD.LOCK:\n return this.webdavMethods.lock(req, res)\n case HTTP_METHOD.UNLOCK:\n return this.webdavMethods.unlock(req, res)\n case HTTP_METHOD.PROPPATCH:\n return this.webdavMethods.proppatch(req, res)\n case HTTP_METHOD.MKCOL:\n return this.webdavMethods.mkcol(req, res)\n case HTTP_METHOD.COPY:\n case HTTP_METHOD.MOVE:\n return this.webdavMethods.copyMove(req, res)\n default:\n return res.status(HttpStatus.METHOD_NOT_ALLOWED).send()\n }\n }\n}\n"],"names":["WebDAVController","serverOptions","serverPropFind","req","res","webdavMethods","propfind","WEBDAV_NS","SERVER","webdavOptions","webdavPropfind","WEBDAV","repositoriesOptions","repositoriesPropfind","repository","files","method","HTTP_METHOD","PROPFIND","SPACE_REPOSITORY","FILES","HEAD","GET","headOrGet","PUT","put","DELETE","delete","LOCK","lock","UNLOCK","unlock","PROPPATCH","proppatch","MKCOL","mkcol","COPY","MOVE","copyMove","status","HttpStatus","METHOD_NOT_ALLOWED","send","passthrough","WEBDAV_BASE_PATH","SPACES","TRASH"],"mappings":"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"}
|
|
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
value: true
|
|
8
8
|
});
|
|
9
9
|
const _appbootstrap = require("../../app.bootstrap");
|
|
10
|
-
const _utils = require("../../infrastructure/database/utils");
|
|
11
10
|
const _webdav = require("./constants/webdav");
|
|
12
11
|
const XML_VERSION_STR = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>';
|
|
13
12
|
describe('WebDAV (e2e)', ()=>{
|
|
@@ -18,7 +17,6 @@ describe('WebDAV (e2e)', ()=>{
|
|
|
18
17
|
await app.getHttpAdapter().getInstance().ready();
|
|
19
18
|
});
|
|
20
19
|
afterAll(async ()=>{
|
|
21
|
-
await (0, _utils.dbCloseConnection)(app);
|
|
22
20
|
await app.close();
|
|
23
21
|
});
|
|
24
22
|
it('should be defined', ()=>{
|
|
@@ -64,6 +62,137 @@ describe('WebDAV (e2e)', ()=>{
|
|
|
64
62
|
});
|
|
65
63
|
expect(res.statusCode).toEqual(207);
|
|
66
64
|
});
|
|
65
|
+
describe('PUT with non-XML Content-Types (stream preservation)', ()=>{
|
|
66
|
+
const testFilePath = '/webdav/personal/test-content-type.txt';
|
|
67
|
+
const auth = 'Basic am86cGFzc3dvcmQ=';
|
|
68
|
+
afterEach(async ()=>{
|
|
69
|
+
// Cleanup: delete the test file if it exists
|
|
70
|
+
await app.inject({
|
|
71
|
+
method: 'DELETE',
|
|
72
|
+
url: testFilePath,
|
|
73
|
+
headers: {
|
|
74
|
+
authorization: auth
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
it('PUT with application/json should preserve stream and create file with content', async ()=>{
|
|
79
|
+
const jsonContent = '{"key":"value","number":42}';
|
|
80
|
+
const putRes = await app.inject({
|
|
81
|
+
method: 'PUT',
|
|
82
|
+
url: testFilePath,
|
|
83
|
+
headers: {
|
|
84
|
+
authorization: auth,
|
|
85
|
+
'content-type': 'application/json'
|
|
86
|
+
},
|
|
87
|
+
body: jsonContent
|
|
88
|
+
});
|
|
89
|
+
expect([
|
|
90
|
+
201,
|
|
91
|
+
204
|
|
92
|
+
]).toContain(putRes.statusCode);
|
|
93
|
+
// Verify the file was created with the correct content
|
|
94
|
+
const getRes = await app.inject({
|
|
95
|
+
method: 'GET',
|
|
96
|
+
url: testFilePath,
|
|
97
|
+
headers: {
|
|
98
|
+
authorization: auth
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
expect(getRes.statusCode).toEqual(200);
|
|
102
|
+
expect(getRes.body).toEqual(jsonContent);
|
|
103
|
+
expect(getRes.headers['content-length']).toEqual(String(jsonContent.length));
|
|
104
|
+
});
|
|
105
|
+
it('PUT with text/plain should preserve stream and create file with content', async ()=>{
|
|
106
|
+
const textContent = 'This is plain text content with special chars: éàù';
|
|
107
|
+
const putRes = await app.inject({
|
|
108
|
+
method: 'PUT',
|
|
109
|
+
url: testFilePath,
|
|
110
|
+
headers: {
|
|
111
|
+
authorization: auth,
|
|
112
|
+
'content-type': 'text/plain'
|
|
113
|
+
},
|
|
114
|
+
body: textContent
|
|
115
|
+
});
|
|
116
|
+
expect([
|
|
117
|
+
201,
|
|
118
|
+
204
|
|
119
|
+
]).toContain(putRes.statusCode);
|
|
120
|
+
// Verify the file was created with the correct content
|
|
121
|
+
const getRes = await app.inject({
|
|
122
|
+
method: 'GET',
|
|
123
|
+
url: testFilePath,
|
|
124
|
+
headers: {
|
|
125
|
+
authorization: auth
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
expect(getRes.statusCode).toEqual(200);
|
|
129
|
+
expect(getRes.body).toEqual(textContent);
|
|
130
|
+
expect(getRes.headers['content-length']).toEqual(String(Buffer.byteLength(textContent, 'utf8')));
|
|
131
|
+
});
|
|
132
|
+
it('PUT with text/plain; charset=utf-8 should preserve stream and create file with content', async ()=>{
|
|
133
|
+
const textContent = 'Text with charset and emoji: 🚀 ✅';
|
|
134
|
+
const putRes = await app.inject({
|
|
135
|
+
method: 'PUT',
|
|
136
|
+
url: testFilePath,
|
|
137
|
+
headers: {
|
|
138
|
+
authorization: auth,
|
|
139
|
+
'content-type': 'text/plain; charset=utf-8'
|
|
140
|
+
},
|
|
141
|
+
body: textContent
|
|
142
|
+
});
|
|
143
|
+
expect([
|
|
144
|
+
201,
|
|
145
|
+
204
|
|
146
|
+
]).toContain(putRes.statusCode);
|
|
147
|
+
// Verify the file was created with the correct content
|
|
148
|
+
const getRes = await app.inject({
|
|
149
|
+
method: 'GET',
|
|
150
|
+
url: testFilePath,
|
|
151
|
+
headers: {
|
|
152
|
+
authorization: auth
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
expect(getRes.statusCode).toEqual(200);
|
|
156
|
+
expect(getRes.body).toEqual(textContent);
|
|
157
|
+
expect(getRes.headers['content-length']).toEqual(String(Buffer.byteLength(textContent, 'utf8')));
|
|
158
|
+
});
|
|
159
|
+
it('PUT with application/octet-stream should work as expected', async ()=>{
|
|
160
|
+
const binaryContent = Buffer.from([
|
|
161
|
+
0x89,
|
|
162
|
+
0x50,
|
|
163
|
+
0x4e,
|
|
164
|
+
0x47,
|
|
165
|
+
0x0d,
|
|
166
|
+
0x0a,
|
|
167
|
+
0x1a,
|
|
168
|
+
0x0a
|
|
169
|
+
]);
|
|
170
|
+
const putRes = await app.inject({
|
|
171
|
+
method: 'PUT',
|
|
172
|
+
url: testFilePath,
|
|
173
|
+
headers: {
|
|
174
|
+
authorization: auth,
|
|
175
|
+
'content-type': 'application/octet-stream'
|
|
176
|
+
},
|
|
177
|
+
body: binaryContent
|
|
178
|
+
});
|
|
179
|
+
expect([
|
|
180
|
+
201,
|
|
181
|
+
204
|
|
182
|
+
]).toContain(putRes.statusCode);
|
|
183
|
+
// Verify the file was created with the correct content
|
|
184
|
+
const getRes = await app.inject({
|
|
185
|
+
method: 'GET',
|
|
186
|
+
url: testFilePath,
|
|
187
|
+
headers: {
|
|
188
|
+
authorization: auth
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
expect(getRes.statusCode).toEqual(200);
|
|
192
|
+
expect(Buffer.from(getRes.rawPayload)).toEqual(binaryContent);
|
|
193
|
+
expect(getRes.headers['content-length']).toEqual(String(binaryContent.length));
|
|
194
|
+
});
|
|
195
|
+
});
|
|
67
196
|
});
|
|
68
197
|
|
|
69
198
|
//# sourceMappingURL=webdav.e2e-spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.e2e-spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { appBootstrap } from '../../app.bootstrap'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/webdav/webdav.e2e-spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { appBootstrap } from '../../app.bootstrap'\nimport { XML_CONTENT_TYPE } from './constants/webdav'\n\nconst XML_VERSION_STR = '<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>'\n\ndescribe('WebDAV (e2e)', () => {\n let app: NestFastifyApplication\n\n beforeAll(async () => {\n app = await appBootstrap()\n await app.init()\n await app.getHttpAdapter().getInstance().ready()\n })\n\n afterAll(async () => {\n await app.close()\n })\n\n it('should be defined', () => {\n expect(app).toBeDefined()\n })\n\n it('PROPFIND ALLPROP /webdav => 207', async () => {\n const res = await app.inject({\n method: 'PROPFIND',\n url: '/webdav',\n headers: { authorization: 'Basic am86cGFzc3dvcmQ=', 'content-type': XML_CONTENT_TYPE, Depth: '1' },\n body: `${XML_VERSION_STR}\n <propfind xmlns:D=\"DAV:\">\n <allprop/>\n </propfind>`\n } as any)\n expect(res.statusCode).toEqual(207)\n })\n\n it('PROPFIND PROP /webdav => 207', async () => {\n const res = await app.inject({\n method: 'PROPFIND',\n url: '/webdav',\n headers: { authorization: 'Basic am86cGFzc3dvcmQ=', 'content-type': XML_CONTENT_TYPE, Depth: '1' },\n body: `${XML_VERSION_STR}\n <D:propfind xmlns:D=\"DAV:\">\n <D:prop>\n <D:creationdate/>\n <D:displayname/>\n <D:getcontentlength/>\n <D:getcontenttype/>\n <D:getetag/>\n <D:getlastmodified/>\n <D:resourcetype/>\n </D:prop>\n </D:propfind>`\n } as any)\n expect(res.statusCode).toEqual(207)\n })\n\n describe('PUT with non-XML Content-Types (stream preservation)', () => {\n const testFilePath = '/webdav/personal/test-content-type.txt'\n const auth = 'Basic am86cGFzc3dvcmQ='\n\n afterEach(async () => {\n // Cleanup: delete the test file if it exists\n await app.inject({\n method: 'DELETE',\n url: testFilePath,\n headers: { authorization: auth }\n } as any)\n })\n\n it('PUT with application/json should preserve stream and create file with content', async () => {\n const jsonContent = '{\"key\":\"value\",\"number\":42}'\n\n const putRes = await app.inject({\n method: 'PUT',\n url: testFilePath,\n headers: {\n authorization: auth,\n 'content-type': 'application/json'\n },\n body: jsonContent\n } as any)\n\n expect([201, 204]).toContain(putRes.statusCode)\n\n // Verify the file was created with the correct content\n const getRes = await app.inject({\n method: 'GET',\n url: testFilePath,\n headers: { authorization: auth }\n } as any)\n\n expect(getRes.statusCode).toEqual(200)\n expect(getRes.body).toEqual(jsonContent)\n expect(getRes.headers['content-length']).toEqual(String(jsonContent.length))\n })\n\n it('PUT with text/plain should preserve stream and create file with content', async () => {\n const textContent = 'This is plain text content with special chars: éàù'\n\n const putRes = await app.inject({\n method: 'PUT',\n url: testFilePath,\n headers: {\n authorization: auth,\n 'content-type': 'text/plain'\n },\n body: textContent\n } as any)\n\n expect([201, 204]).toContain(putRes.statusCode)\n\n // Verify the file was created with the correct content\n const getRes = await app.inject({\n method: 'GET',\n url: testFilePath,\n headers: { authorization: auth }\n } as any)\n\n expect(getRes.statusCode).toEqual(200)\n expect(getRes.body).toEqual(textContent)\n expect(getRes.headers['content-length']).toEqual(String(Buffer.byteLength(textContent, 'utf8')))\n })\n\n it('PUT with text/plain; charset=utf-8 should preserve stream and create file with content', async () => {\n const textContent = 'Text with charset and emoji: 🚀 ✅'\n\n const putRes = await app.inject({\n method: 'PUT',\n url: testFilePath,\n headers: {\n authorization: auth,\n 'content-type': 'text/plain; charset=utf-8'\n },\n body: textContent\n } as any)\n\n expect([201, 204]).toContain(putRes.statusCode)\n\n // Verify the file was created with the correct content\n const getRes = await app.inject({\n method: 'GET',\n url: testFilePath,\n headers: { authorization: auth }\n } as any)\n\n expect(getRes.statusCode).toEqual(200)\n expect(getRes.body).toEqual(textContent)\n expect(getRes.headers['content-length']).toEqual(String(Buffer.byteLength(textContent, 'utf8')))\n })\n\n it('PUT with application/octet-stream should work as expected', async () => {\n const binaryContent = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])\n\n const putRes = await app.inject({\n method: 'PUT',\n url: testFilePath,\n headers: {\n authorization: auth,\n 'content-type': 'application/octet-stream'\n },\n body: binaryContent\n } as any)\n\n expect([201, 204]).toContain(putRes.statusCode)\n\n // Verify the file was created with the correct content\n const getRes = await app.inject({\n method: 'GET',\n url: testFilePath,\n headers: { authorization: auth }\n } as any)\n\n expect(getRes.statusCode).toEqual(200)\n expect(Buffer.from(getRes.rawPayload)).toEqual(binaryContent)\n expect(getRes.headers['content-length']).toEqual(String(binaryContent.length))\n })\n })\n})\n"],"names":["XML_VERSION_STR","describe","app","beforeAll","appBootstrap","init","getHttpAdapter","getInstance","ready","afterAll","close","it","expect","toBeDefined","res","inject","method","url","headers","authorization","XML_CONTENT_TYPE","Depth","body","statusCode","toEqual","testFilePath","auth","afterEach","jsonContent","putRes","toContain","getRes","String","length","textContent","Buffer","byteLength","binaryContent","from","rawPayload"],"mappings":"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"}
|
|
@@ -42,7 +42,6 @@ describe('Auth (e2e)', ()=>{
|
|
|
42
42
|
deleteSpace: true,
|
|
43
43
|
isGuest: false
|
|
44
44
|
})).resolves.not.toThrow();
|
|
45
|
-
await (0, _utils.dbCloseConnection)(app);
|
|
46
45
|
await app.close();
|
|
47
46
|
});
|
|
48
47
|
it('should be defined', ()=>{
|
|
@@ -149,9 +148,8 @@ describe('Auth (e2e)', ()=>{
|
|
|
149
148
|
body: null
|
|
150
149
|
});
|
|
151
150
|
expect(res.statusCode).toEqual(201);
|
|
152
|
-
expect(res.headers['set-cookie']).toHaveLength(
|
|
153
|
-
|
|
154
|
-
/* Access cookie
|
|
151
|
+
expect(res.headers['set-cookie']).toHaveLength(5);
|
|
152
|
+
/* Access cookie
|
|
155
153
|
[
|
|
156
154
|
'sync-in-access=',
|
|
157
155
|
'Max-Age=0',
|
|
@@ -187,12 +185,20 @@ describe('Auth (e2e)', ()=>{
|
|
|
187
185
|
'Max-Age=0',
|
|
188
186
|
'Path=/api/auth/refresh',
|
|
189
187
|
'Expires=Thu, 01 Jan 1970 00:00:00 GMT',
|
|
188
|
+
'Secure',
|
|
189
|
+
'SameSite=Strict'
|
|
190
|
+
]
|
|
191
|
+
*/ /* Access cookie 2FA
|
|
192
|
+
[
|
|
193
|
+
'sync-in-access=',
|
|
194
|
+
'Max-Age=0',
|
|
195
|
+
'Path=/api/auth/2fa/login/verify',
|
|
196
|
+
'Expires=Thu, 01 Jan 1970 00:00:00 GMT',
|
|
190
197
|
'HttpOnly',
|
|
191
198
|
'Secure',
|
|
192
199
|
'SameSite=Strict'
|
|
193
200
|
]
|
|
194
|
-
*/
|
|
195
|
-
});
|
|
201
|
+
*/ });
|
|
196
202
|
it(`POST ${_routes.API_AUTH_REFRESH} => 201`, async ()=>{
|
|
197
203
|
const res = await app.inject({
|
|
198
204
|
method: 'POST',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../backend/src/authentication/auth.e2e-spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { ConfigService } from '@nestjs/config'\nimport { JwtService } from '@nestjs/jwt'\nimport { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { appBootstrap } from '../app.bootstrap'\nimport { USER_ROLE } from '../applications/users/constants/user'\nimport { DeleteUserDto } from '../applications/users/dto/delete-user.dto'\nimport { UserModel } from '../applications/users/models/user.model'\nimport { AdminUsersManager } from '../applications/users/services/admin-users-manager.service'\nimport { generateUserTest } from '../applications/users/utils/test'\nimport { convertHumanTimeToSeconds, transformAndValidate } from '../common/functions'\nimport { currentTimeStamp, decodeUrl } from '../common/shared'\nimport { dbCheckConnection, dbCloseConnection } from '../infrastructure/database/utils'\nimport { AuthConfig } from './auth.config'\nimport { CSRF_ERROR, TOKEN_PATHS, TOKEN_TYPES } from './constants/auth'\nimport { API_AUTH_LOGIN, API_AUTH_LOGOUT, API_AUTH_REFRESH, API_AUTH_TOKEN, API_AUTH_TOKEN_REFRESH } from './constants/routes'\nimport { TokenResponseDto } from './dto/token-response.dto'\nimport { JwtPayload } from './interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from './interfaces/token.interface'\n\ndescribe('Auth (e2e)', () => {\n let app: NestFastifyApplication\n let authConfig: AuthConfig\n let jwtService: JwtService\n let adminUsersManager: AdminUsersManager\n let userTest: UserModel\n let refreshToken: string\n let csrfToken: string\n\n beforeAll(async () => {\n app = await appBootstrap()\n await app.init()\n await app.getHttpAdapter().getInstance().ready()\n authConfig = app.get<ConfigService>(ConfigService).get<AuthConfig>('auth')\n jwtService = app.get<JwtService>(JwtService)\n adminUsersManager = app.get<AdminUsersManager>(AdminUsersManager)\n userTest = new UserModel(generateUserTest(false), false)\n })\n\n afterAll(async () => {\n await expect(\n adminUsersManager.deleteUserOrGuest(userTest.id, userTest.login, { deleteSpace: true, isGuest: false } satisfies DeleteUserDto)\n ).resolves.not.toThrow()\n await dbCloseConnection(app)\n await app.close()\n })\n\n it('should be defined', () => {\n expect(authConfig).toBeDefined()\n expect(jwtService).toBeDefined()\n expect(adminUsersManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should get the database connection', async () => {\n expect(await dbCheckConnection(app)).toBe(true)\n })\n\n it(`POST ${API_AUTH_LOGIN} => 401`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_LOGIN,\n body: { login: userTest.login, password: userTest.password }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_LOGIN} => 201`, async () => {\n const userId = (await adminUsersManager.createUserOrGuest({ ...userTest }, USER_ROLE.USER)).id\n expect(userId).toBeDefined()\n userTest.id = userId\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_LOGIN,\n body: { login: userTest.login, password: userTest.password }\n })\n expect(res.statusCode).toEqual(201)\n expect(Object.keys(res.json())).toEqual(expect.arrayContaining(['user', 'token']))\n expect(res.headers['set-cookie']).toHaveLength(4)\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = getCookies(res.headers['set-cookie'] as string[])\n /* Access cookie\n [\n 'sync-in-access=value,\n 'Max-Age=3600',\n 'Path=/',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* Refresh cookie\n [\n 'sync-in-refresh=value,\n 'Max-Age=14400',\n 'Path=/api/auth/refresh',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* WS cookie\n [\n 'sync-in-ws=value,\n 'Max-Age=14400',\n 'Path=/socket.io',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* CSRF cookie\n [\n 'sync-in-csrf=value,\n 'Max-Age=14400',\n 'Path=/',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n cookiesChecks(cookies)\n // Verify token\n for (const cookie of cookies) {\n const token = cookie.content[0].substring(cookie.content[0].indexOf('=') + 1)\n if (cookie.type === TOKEN_TYPE.CSRF) {\n // needed for the following tests\n csrfToken = decodeUrl(token)\n continue\n }\n const decodedToken: JwtPayload = await jwtService.verifyAsync(token, {\n secret: authConfig.token[cookie.type].secret\n })\n expect(decodedToken.iat).toBeCloseTo(currentTimeStamp(), -1)\n expect(decodedToken.exp).toBeCloseTo(currentTimeStamp() + convertHumanTimeToSeconds(authConfig.token[cookie.type].expiration), -1)\n expect(decodedToken.identity.id).toBe(userTest.id)\n if (cookie.type === TOKEN_TYPE.REFRESH) {\n // needed for the following tests\n refreshToken = token\n }\n }\n })\n\n it(`POST ${API_AUTH_LOGOUT} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_LOGOUT,\n body: null\n })\n expect(res.statusCode).toEqual(201)\n expect(res.headers['set-cookie']).toHaveLength(4)\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = getCookies(res.headers['set-cookie'] as string[])\n /* Access cookie\n [\n 'sync-in-access=',\n 'Max-Age=0',\n 'Path=/',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* Refresh cookie\n [\n 'sync-in-refresh=',\n 'Max-Age=0',\n 'Path=/api/auth/refresh',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* WS cookie\n [\n 'sync-in-ws=',\n 'Max-Age=0',\n 'Path=/socket.io',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* CSRF cookie\n [\n 'sync-in-csrf=',\n 'Max-Age=0',\n 'Path=/api/auth/refresh',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n cookiesChecks(cookies, true)\n })\n\n it(`POST ${API_AUTH_REFRESH} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n headers: { [authConfig.token.csrf.name]: csrfToken },\n url: API_AUTH_REFRESH,\n cookies: { [authConfig.token.refresh.name]: refreshToken }\n })\n expect(res.statusCode).toEqual(201)\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = getCookies(res.headers['set-cookie'] as string[])\n cookiesChecks(cookies)\n })\n\n it(`POST ${API_AUTH_REFRESH} => 401 (with CSRF)`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_REFRESH,\n headers: { [authConfig.token.csrf.name]: csrfToken },\n cookies: { [authConfig.token.refresh.name]: 'bar' }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_REFRESH} => 403 (without CSRF)`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_REFRESH,\n cookies: { [authConfig.token.refresh.name]: refreshToken }\n })\n expect(res.statusCode).toEqual(403)\n expect(res.json().message).toEqual(CSRF_ERROR.MISSING_HEADERS)\n })\n\n it(`POST ${API_AUTH_TOKEN} => 401`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN,\n body: { login: userTest.login, password: 'bar' }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_TOKEN} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN,\n body: { login: userTest.login, password: userTest.password }\n })\n expect(res.statusCode).toEqual(201)\n const content = res.json()\n expect(() => transformAndValidate(TokenResponseDto, content)).not.toThrow()\n for (const type of TOKEN_TYPES.filter((p) => p === TOKEN_TYPE.ACCESS || p === TOKEN_TYPE.REFRESH)) {\n expect(content[type]).toBeDefined()\n expect(content[`${type}_expiration`]).toBeCloseTo(currentTimeStamp() + convertHumanTimeToSeconds(authConfig.token[type].expiration), -1)\n }\n })\n\n it(`POST ${API_AUTH_TOKEN_REFRESH} => 401`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN_REFRESH,\n headers: { authorization: 'Bearer bar' }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_TOKEN_REFRESH} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN_REFRESH,\n headers: { authorization: `Bearer ${refreshToken}` }\n })\n expect(res.statusCode).toEqual(201)\n expect(() => transformAndValidate(TokenResponseDto, res.json())).not.toThrow()\n })\n\n function getCookies(setCookie: string[]): { type: TOKEN_TYPE; content: string[] }[] {\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = []\n for (const c of setCookie) {\n const cookieName = c.split('=')[0]\n const cookieValues = c.split('; ')\n switch (cookieName) {\n case authConfig.token.access.name:\n cookies.push({ type: TOKEN_TYPE.ACCESS, content: cookieValues })\n break\n case authConfig.token.refresh.name:\n cookies.push({ type: TOKEN_TYPE.REFRESH, content: cookieValues })\n break\n case authConfig.token.ws.name:\n cookies.push({ type: TOKEN_TYPE.WS, content: cookieValues })\n break\n case authConfig.token.csrf.name:\n cookies.push({ type: TOKEN_TYPE.CSRF, content: cookieValues })\n break\n }\n }\n return cookies\n }\n\n function cookiesChecks(cookies: { type: TOKEN_TYPE; content: string[] }[], clear = false) {\n for (const cookie of cookies) {\n expect(cookie.content[0].split('=')[0]).toBe(authConfig.token[cookie.type].name)\n expect(cookie.content[2].split('=')[1]).toBe(TOKEN_PATHS[cookie.type])\n if (cookie.type === TOKEN_TYPE.CSRF) {\n expect(cookie.content).not.toContain('HttpOnly')\n } else {\n expect(cookie.content).toContain('HttpOnly')\n }\n expect(cookie.content).not.toContain('Secure')\n expect(cookie.content[cookie.content.length - 1].split('=')[1].toLowerCase()).toBe(authConfig.cookieSameSite)\n if (clear) {\n expect(cookie.content[0].split('=')[1]).toBe('')\n expect(cookie.content[1].split('=')[1]).toBe('0')\n expect(cookie.content[3].split('=')[1]).toBe('Thu, 01 Jan 1970 00:00:00 GMT')\n } else {\n expect(parseInt(cookie.content[1].split('=')[1])).toBeCloseTo(convertHumanTimeToSeconds(authConfig.token[cookie.type].expiration), -1)\n expect(cookie.content[0].split('=')[1]).not.toBe('')\n }\n }\n }\n})\n"],"names":["describe","app","authConfig","jwtService","adminUsersManager","userTest","refreshToken","csrfToken","beforeAll","appBootstrap","init","getHttpAdapter","getInstance","ready","get","ConfigService","JwtService","AdminUsersManager","UserModel","generateUserTest","afterAll","expect","deleteUserOrGuest","id","login","deleteSpace","isGuest","resolves","not","toThrow","dbCloseConnection","close","it","toBeDefined","dbCheckConnection","toBe","API_AUTH_LOGIN","res","inject","method","url","body","password","statusCode","toEqual","userId","createUserOrGuest","USER_ROLE","USER","Object","keys","json","arrayContaining","headers","toHaveLength","cookies","getCookies","cookiesChecks","cookie","token","content","substring","indexOf","type","TOKEN_TYPE","CSRF","decodeUrl","decodedToken","verifyAsync","secret","iat","toBeCloseTo","currentTimeStamp","exp","convertHumanTimeToSeconds","expiration","identity","REFRESH","API_AUTH_LOGOUT","API_AUTH_REFRESH","csrf","name","refresh","message","CSRF_ERROR","MISSING_HEADERS","API_AUTH_TOKEN","transformAndValidate","TokenResponseDto","TOKEN_TYPES","filter","p","ACCESS","API_AUTH_TOKEN_REFRESH","authorization","setCookie","c","cookieName","split","cookieValues","access","push","ws","WS","clear","TOKEN_PATHS","toContain","length","toLowerCase","cookieSameSite","parseInt"],"mappings":"AAAA;;;;CAIC;;;;wBAE6B;qBACH;8BAEE;sBACH;2BAEA;0CACQ;sBACD;2BAC+B;wBACpB;uBACS;sBAEA;wBACqD;kCACzE;gCAEN;AAE3BA,SAAS,cAAc;IACrB,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,UAAU;QACRP,MAAM,MAAMQ,IAAAA,0BAAY;QACxB,MAAMR,IAAIS,IAAI;QACd,MAAMT,IAAIU,cAAc,GAAGC,WAAW,GAAGC,KAAK;QAC9CX,aAAaD,IAAIa,GAAG,CAAgBC,qBAAa,EAAED,GAAG,CAAa;QACnEX,aAAaF,IAAIa,GAAG,CAAaE,eAAU;QAC3CZ,oBAAoBH,IAAIa,GAAG,CAAoBG,2CAAiB;QAChEZ,WAAW,IAAIa,oBAAS,CAACC,IAAAA,sBAAgB,EAAC,QAAQ;IACpD;IAEAC,SAAS;QACP,MAAMC,OACJjB,kBAAkBkB,iBAAiB,CAACjB,SAASkB,EAAE,EAAElB,SAASmB,KAAK,EAAE;YAAEC,aAAa;YAAMC,SAAS;QAAM,IACrGC,QAAQ,CAACC,GAAG,CAACC,OAAO;QACtB,MAAMC,IAAAA,wBAAiB,EAAC7B;QACxB,MAAMA,IAAI8B,KAAK;IACjB;IAEAC,GAAG,qBAAqB;QACtBX,OAAOnB,YAAY+B,WAAW;QAC9BZ,OAAOlB,YAAY8B,WAAW;QAC9BZ,OAAOjB,mBAAmB6B,WAAW;QACrCZ,OAAOhB,UAAU4B,WAAW;IAC9B;IAEAD,GAAG,sCAAsC;QACvCX,OAAO,MAAMa,IAAAA,wBAAiB,EAACjC,MAAMkC,IAAI,CAAC;IAC5C;IAEAH,GAAG,CAAC,KAAK,EAAEI,sBAAc,CAAC,OAAO,CAAC,EAAE;QAClC,MAAMC,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKJ,sBAAc;YACnBK,MAAM;gBAAEjB,OAAOnB,SAASmB,KAAK;gBAAEkB,UAAUrC,SAASqC,QAAQ;YAAC;QAC7D;QACArB,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;IACjC;IAEAZ,GAAG,CAAC,KAAK,EAAEI,sBAAc,CAAC,OAAO,CAAC,EAAE;QAClC,MAAMS,SAAS,AAAC,CAAA,MAAMzC,kBAAkB0C,iBAAiB,CAAC;YAAE,GAAGzC,QAAQ;QAAC,GAAG0C,eAAS,CAACC,IAAI,CAAA,EAAGzB,EAAE;QAC9FF,OAAOwB,QAAQZ,WAAW;QAC1B5B,SAASkB,EAAE,GAAGsB;QACd,MAAMR,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKJ,sBAAc;YACnBK,MAAM;gBAAEjB,OAAOnB,SAASmB,KAAK;gBAAEkB,UAAUrC,SAASqC,QAAQ;YAAC;QAC7D;QACArB,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;QAC/BvB,OAAO4B,OAAOC,IAAI,CAACb,IAAIc,IAAI,KAAKP,OAAO,CAACvB,OAAO+B,eAAe,CAAC;YAAC;YAAQ;SAAQ;QAChF/B,OAAOgB,IAAIgB,OAAO,CAAC,aAAa,EAAEC,YAAY,CAAC;QAC/C,MAAMC,UAAqDC,WAAWnB,IAAIgB,OAAO,CAAC,aAAa;QAC/F;;;;;;;;;KASC,GACD;;;;;;;;;KASC,GACD;;;;;;;;;KASC,GACD;;;;;;;;KAQC,GACDI,cAAcF;QACd,eAAe;QACf,KAAK,MAAMG,UAAUH,QAAS;YAC5B,MAAMI,QAAQD,OAAOE,OAAO,CAAC,EAAE,CAACC,SAAS,CAACH,OAAOE,OAAO,CAAC,EAAE,CAACE,OAAO,CAAC,OAAO;YAC3E,IAAIJ,OAAOK,IAAI,KAAKC,0BAAU,CAACC,IAAI,EAAE;gBACnC,iCAAiC;gBACjC1D,YAAY2D,IAAAA,iBAAS,EAACP;gBACtB;YACF;YACA,MAAMQ,eAA2B,MAAMhE,WAAWiE,WAAW,CAACT,OAAO;gBACnEU,QAAQnE,WAAWyD,KAAK,CAACD,OAAOK,IAAI,CAAC,CAACM,MAAM;YAC9C;YACAhD,OAAO8C,aAAaG,GAAG,EAAEC,WAAW,CAACC,IAAAA,wBAAgB,KAAI,CAAC;YAC1DnD,OAAO8C,aAAaM,GAAG,EAAEF,WAAW,CAACC,IAAAA,wBAAgB,MAAKE,IAAAA,oCAAyB,EAACxE,WAAWyD,KAAK,CAACD,OAAOK,IAAI,CAAC,CAACY,UAAU,GAAG,CAAC;YAChItD,OAAO8C,aAAaS,QAAQ,CAACrD,EAAE,EAAEY,IAAI,CAAC9B,SAASkB,EAAE;YACjD,IAAImC,OAAOK,IAAI,KAAKC,0BAAU,CAACa,OAAO,EAAE;gBACtC,iCAAiC;gBACjCvE,eAAeqD;YACjB;QACF;IACF;IAEA3B,GAAG,CAAC,KAAK,EAAE8C,uBAAe,CAAC,OAAO,CAAC,EAAE;QACnC,MAAMzC,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKsC,uBAAe;YACpBrC,MAAM;QACR;QACApB,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;QAC/BvB,OAAOgB,IAAIgB,OAAO,CAAC,aAAa,EAAEC,YAAY,CAAC;QAC/C,MAAMC,UAAqDC,WAAWnB,IAAIgB,OAAO,CAAC,aAAa;QAC/F;;;;;;;;;;IAUA,GACA;;;;;;;;;;IAUA,GACA;;;;;;;;;;IAUA,GACA;;;;;;;;;;IAUA,GACAI,cAAcF,SAAS;IACzB;IAEAvB,GAAG,CAAC,KAAK,EAAE+C,wBAAgB,CAAC,OAAO,CAAC,EAAE;QACpC,MAAM1C,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRc,SAAS;gBAAE,CAACnD,WAAWyD,KAAK,CAACqB,IAAI,CAACC,IAAI,CAAC,EAAE1E;YAAU;YACnDiC,KAAKuC,wBAAgB;YACrBxB,SAAS;gBAAE,CAACrD,WAAWyD,KAAK,CAACuB,OAAO,CAACD,IAAI,CAAC,EAAE3E;YAAa;QAC3D;QACAe,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;QAC/B,MAAMW,UAAqDC,WAAWnB,IAAIgB,OAAO,CAAC,aAAa;QAC/FI,cAAcF;IAChB;IAEAvB,GAAG,CAAC,KAAK,EAAE+C,wBAAgB,CAAC,mBAAmB,CAAC,EAAE;QAChD,MAAM1C,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKuC,wBAAgB;YACrB1B,SAAS;gBAAE,CAACnD,WAAWyD,KAAK,CAACqB,IAAI,CAACC,IAAI,CAAC,EAAE1E;YAAU;YACnDgD,SAAS;gBAAE,CAACrD,WAAWyD,KAAK,CAACuB,OAAO,CAACD,IAAI,CAAC,EAAE;YAAM;QACpD;QACA5D,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;IACjC;IAEAZ,GAAG,CAAC,KAAK,EAAE+C,wBAAgB,CAAC,sBAAsB,CAAC,EAAE;QACnD,MAAM1C,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKuC,wBAAgB;YACrBxB,SAAS;gBAAE,CAACrD,WAAWyD,KAAK,CAACuB,OAAO,CAACD,IAAI,CAAC,EAAE3E;YAAa;QAC3D;QACAe,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;QAC/BvB,OAAOgB,IAAIc,IAAI,GAAGgC,OAAO,EAAEvC,OAAO,CAACwC,gBAAU,CAACC,eAAe;IAC/D;IAEArD,GAAG,CAAC,KAAK,EAAEsD,sBAAc,CAAC,OAAO,CAAC,EAAE;QAClC,MAAMjD,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAK8C,sBAAc;YACnB7C,MAAM;gBAAEjB,OAAOnB,SAASmB,KAAK;gBAAEkB,UAAU;YAAM;QACjD;QACArB,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;IACjC;IAEAZ,GAAG,CAAC,KAAK,EAAEsD,sBAAc,CAAC,OAAO,CAAC,EAAE;QAClC,MAAMjD,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAK8C,sBAAc;YACnB7C,MAAM;gBAAEjB,OAAOnB,SAASmB,KAAK;gBAAEkB,UAAUrC,SAASqC,QAAQ;YAAC;QAC7D;QACArB,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;QAC/B,MAAMgB,UAAUvB,IAAIc,IAAI;QACxB9B,OAAO,IAAMkE,IAAAA,+BAAoB,EAACC,kCAAgB,EAAE5B,UAAUhC,GAAG,CAACC,OAAO;QACzE,KAAK,MAAMkC,QAAQ0B,iBAAW,CAACC,MAAM,CAAC,CAACC,IAAMA,MAAM3B,0BAAU,CAAC4B,MAAM,IAAID,MAAM3B,0BAAU,CAACa,OAAO,EAAG;YACjGxD,OAAOuC,OAAO,CAACG,KAAK,EAAE9B,WAAW;YACjCZ,OAAOuC,OAAO,CAAC,GAAGG,KAAK,WAAW,CAAC,CAAC,EAAEQ,WAAW,CAACC,IAAAA,wBAAgB,MAAKE,IAAAA,oCAAyB,EAACxE,WAAWyD,KAAK,CAACI,KAAK,CAACY,UAAU,GAAG,CAAC;QACxI;IACF;IAEA3C,GAAG,CAAC,KAAK,EAAE6D,8BAAsB,CAAC,OAAO,CAAC,EAAE;QAC1C,MAAMxD,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKqD,8BAAsB;YAC3BxC,SAAS;gBAAEyC,eAAe;YAAa;QACzC;QACAzE,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;IACjC;IAEAZ,GAAG,CAAC,KAAK,EAAE6D,8BAAsB,CAAC,OAAO,CAAC,EAAE;QAC1C,MAAMxD,MAAM,MAAMpC,IAAIqC,MAAM,CAAC;YAC3BC,QAAQ;YACRC,KAAKqD,8BAAsB;YAC3BxC,SAAS;gBAAEyC,eAAe,CAAC,OAAO,EAAExF,cAAc;YAAC;QACrD;QACAe,OAAOgB,IAAIM,UAAU,EAAEC,OAAO,CAAC;QAC/BvB,OAAO,IAAMkE,IAAAA,+BAAoB,EAACC,kCAAgB,EAAEnD,IAAIc,IAAI,KAAKvB,GAAG,CAACC,OAAO;IAC9E;IAEA,SAAS2B,WAAWuC,SAAmB;QACrC,MAAMxC,UAAqD,EAAE;QAC7D,KAAK,MAAMyC,KAAKD,UAAW;YACzB,MAAME,aAAaD,EAAEE,KAAK,CAAC,IAAI,CAAC,EAAE;YAClC,MAAMC,eAAeH,EAAEE,KAAK,CAAC;YAC7B,OAAQD;gBACN,KAAK/F,WAAWyD,KAAK,CAACyC,MAAM,CAACnB,IAAI;oBAC/B1B,QAAQ8C,IAAI,CAAC;wBAAEtC,MAAMC,0BAAU,CAAC4B,MAAM;wBAAEhC,SAASuC;oBAAa;oBAC9D;gBACF,KAAKjG,WAAWyD,KAAK,CAACuB,OAAO,CAACD,IAAI;oBAChC1B,QAAQ8C,IAAI,CAAC;wBAAEtC,MAAMC,0BAAU,CAACa,OAAO;wBAAEjB,SAASuC;oBAAa;oBAC/D;gBACF,KAAKjG,WAAWyD,KAAK,CAAC2C,EAAE,CAACrB,IAAI;oBAC3B1B,QAAQ8C,IAAI,CAAC;wBAAEtC,MAAMC,0BAAU,CAACuC,EAAE;wBAAE3C,SAASuC;oBAAa;oBAC1D;gBACF,KAAKjG,WAAWyD,KAAK,CAACqB,IAAI,CAACC,IAAI;oBAC7B1B,QAAQ8C,IAAI,CAAC;wBAAEtC,MAAMC,0BAAU,CAACC,IAAI;wBAAEL,SAASuC;oBAAa;oBAC5D;YACJ;QACF;QACA,OAAO5C;IACT;IAEA,SAASE,cAAcF,OAAkD,EAAEiD,QAAQ,KAAK;QACtF,KAAK,MAAM9C,UAAUH,QAAS;YAC5BlC,OAAOqC,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE/D,IAAI,CAACjC,WAAWyD,KAAK,CAACD,OAAOK,IAAI,CAAC,CAACkB,IAAI;YAC/E5D,OAAOqC,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE/D,IAAI,CAACsE,iBAAW,CAAC/C,OAAOK,IAAI,CAAC;YACrE,IAAIL,OAAOK,IAAI,KAAKC,0BAAU,CAACC,IAAI,EAAE;gBACnC5C,OAAOqC,OAAOE,OAAO,EAAEhC,GAAG,CAAC8E,SAAS,CAAC;YACvC,OAAO;gBACLrF,OAAOqC,OAAOE,OAAO,EAAE8C,SAAS,CAAC;YACnC;YACArF,OAAOqC,OAAOE,OAAO,EAAEhC,GAAG,CAAC8E,SAAS,CAAC;YACrCrF,OAAOqC,OAAOE,OAAO,CAACF,OAAOE,OAAO,CAAC+C,MAAM,GAAG,EAAE,CAACT,KAAK,CAAC,IAAI,CAAC,EAAE,CAACU,WAAW,IAAIzE,IAAI,CAACjC,WAAW2G,cAAc;YAC5G,IAAIL,OAAO;gBACTnF,OAAOqC,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE/D,IAAI,CAAC;gBAC7Cd,OAAOqC,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE/D,IAAI,CAAC;gBAC7Cd,OAAOqC,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE/D,IAAI,CAAC;YAC/C,OAAO;gBACLd,OAAOyF,SAASpD,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG3B,WAAW,CAACG,IAAAA,oCAAyB,EAACxE,WAAWyD,KAAK,CAACD,OAAOK,IAAI,CAAC,CAACY,UAAU,GAAG,CAAC;gBACpItD,OAAOqC,OAAOE,OAAO,CAAC,EAAE,CAACsC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAEtE,GAAG,CAACO,IAAI,CAAC;YACnD;QACF;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../backend/src/authentication/auth.e2e-spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { ConfigService } from '@nestjs/config'\nimport { JwtService } from '@nestjs/jwt'\nimport { NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { appBootstrap } from '../app.bootstrap'\nimport { USER_ROLE } from '../applications/users/constants/user'\nimport { DeleteUserDto } from '../applications/users/dto/delete-user.dto'\nimport { UserModel } from '../applications/users/models/user.model'\nimport { AdminUsersManager } from '../applications/users/services/admin-users-manager.service'\nimport { generateUserTest } from '../applications/users/utils/test'\nimport { convertHumanTimeToSeconds, transformAndValidate } from '../common/functions'\nimport { currentTimeStamp, decodeUrl } from '../common/shared'\nimport { dbCheckConnection } from '../infrastructure/database/utils'\nimport { AuthConfig } from './auth.config'\nimport { CSRF_ERROR, TOKEN_PATHS, TOKEN_TYPES } from './constants/auth'\nimport { API_AUTH_LOGIN, API_AUTH_LOGOUT, API_AUTH_REFRESH, API_AUTH_TOKEN, API_AUTH_TOKEN_REFRESH } from './constants/routes'\nimport { TokenResponseDto } from './dto/token-response.dto'\nimport { JwtPayload } from './interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from './interfaces/token.interface'\n\ndescribe('Auth (e2e)', () => {\n let app: NestFastifyApplication\n let authConfig: AuthConfig\n let jwtService: JwtService\n let adminUsersManager: AdminUsersManager\n let userTest: UserModel\n let refreshToken: string\n let csrfToken: string\n\n beforeAll(async () => {\n app = await appBootstrap()\n await app.init()\n await app.getHttpAdapter().getInstance().ready()\n authConfig = app.get<ConfigService>(ConfigService).get<AuthConfig>('auth')\n jwtService = app.get<JwtService>(JwtService)\n adminUsersManager = app.get<AdminUsersManager>(AdminUsersManager)\n userTest = new UserModel(generateUserTest(false), false)\n })\n\n afterAll(async () => {\n await expect(\n adminUsersManager.deleteUserOrGuest(userTest.id, userTest.login, { deleteSpace: true, isGuest: false } satisfies DeleteUserDto)\n ).resolves.not.toThrow()\n await app.close()\n })\n\n it('should be defined', () => {\n expect(authConfig).toBeDefined()\n expect(jwtService).toBeDefined()\n expect(adminUsersManager).toBeDefined()\n expect(userTest).toBeDefined()\n })\n\n it('should get the database connection', async () => {\n expect(await dbCheckConnection(app)).toBe(true)\n })\n\n it(`POST ${API_AUTH_LOGIN} => 401`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_LOGIN,\n body: { login: userTest.login, password: userTest.password }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_LOGIN} => 201`, async () => {\n const userId = (await adminUsersManager.createUserOrGuest({ ...userTest }, USER_ROLE.USER)).id\n expect(userId).toBeDefined()\n userTest.id = userId\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_LOGIN,\n body: { login: userTest.login, password: userTest.password }\n })\n expect(res.statusCode).toEqual(201)\n expect(Object.keys(res.json())).toEqual(expect.arrayContaining(['user', 'token']))\n expect(res.headers['set-cookie']).toHaveLength(4)\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = getCookies(res.headers['set-cookie'] as string[])\n /* Access cookie\n [\n 'sync-in-access=value,\n 'Max-Age=3600',\n 'Path=/',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* Refresh cookie\n [\n 'sync-in-refresh=value,\n 'Max-Age=14400',\n 'Path=/api/auth/refresh',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* WS cookie\n [\n 'sync-in-ws=value,\n 'Max-Age=14400',\n 'Path=/socket.io',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* CSRF cookie\n [\n 'sync-in-csrf=value,\n 'Max-Age=14400',\n 'Path=/',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n cookiesChecks(cookies)\n // Verify token\n for (const cookie of cookies) {\n const token = cookie.content[0].substring(cookie.content[0].indexOf('=') + 1)\n if (cookie.type === TOKEN_TYPE.CSRF) {\n // needed for the following tests\n csrfToken = decodeUrl(token)\n continue\n }\n const decodedToken: JwtPayload = await jwtService.verifyAsync(token, {\n secret: authConfig.token[cookie.type].secret\n })\n expect(decodedToken.iat).toBeCloseTo(currentTimeStamp(), -1)\n expect(decodedToken.exp).toBeCloseTo(currentTimeStamp() + convertHumanTimeToSeconds(authConfig.token[cookie.type].expiration), -1)\n expect(decodedToken.identity.id).toBe(userTest.id)\n if (cookie.type === TOKEN_TYPE.REFRESH) {\n // needed for the following tests\n refreshToken = token\n }\n }\n })\n\n it(`POST ${API_AUTH_LOGOUT} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_LOGOUT,\n body: null\n })\n expect(res.statusCode).toEqual(201)\n expect(res.headers['set-cookie']).toHaveLength(5)\n /* Access cookie\n [\n 'sync-in-access=',\n 'Max-Age=0',\n 'Path=/',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* Refresh cookie\n [\n 'sync-in-refresh=',\n 'Max-Age=0',\n 'Path=/api/auth/refresh',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* WS cookie\n [\n 'sync-in-ws=',\n 'Max-Age=0',\n 'Path=/socket.io',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* CSRF cookie\n [\n 'sync-in-csrf=',\n 'Max-Age=0',\n 'Path=/api/auth/refresh',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n /* Access cookie 2FA\n [\n 'sync-in-access=',\n 'Max-Age=0',\n 'Path=/api/auth/2fa/login/verify',\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'HttpOnly',\n 'Secure',\n 'SameSite=Strict'\n ]\n */\n })\n\n it(`POST ${API_AUTH_REFRESH} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n headers: { [authConfig.token.csrf.name]: csrfToken },\n url: API_AUTH_REFRESH,\n cookies: { [authConfig.token.refresh.name]: refreshToken }\n })\n expect(res.statusCode).toEqual(201)\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = getCookies(res.headers['set-cookie'] as string[])\n cookiesChecks(cookies)\n })\n\n it(`POST ${API_AUTH_REFRESH} => 401 (with CSRF)`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_REFRESH,\n headers: { [authConfig.token.csrf.name]: csrfToken },\n cookies: { [authConfig.token.refresh.name]: 'bar' }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_REFRESH} => 403 (without CSRF)`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_REFRESH,\n cookies: { [authConfig.token.refresh.name]: refreshToken }\n })\n expect(res.statusCode).toEqual(403)\n expect(res.json().message).toEqual(CSRF_ERROR.MISSING_HEADERS)\n })\n\n it(`POST ${API_AUTH_TOKEN} => 401`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN,\n body: { login: userTest.login, password: 'bar' }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_TOKEN} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN,\n body: { login: userTest.login, password: userTest.password }\n })\n expect(res.statusCode).toEqual(201)\n const content = res.json()\n expect(() => transformAndValidate(TokenResponseDto, content)).not.toThrow()\n for (const type of TOKEN_TYPES.filter((p) => p === TOKEN_TYPE.ACCESS || p === TOKEN_TYPE.REFRESH)) {\n expect(content[type]).toBeDefined()\n expect(content[`${type}_expiration`]).toBeCloseTo(currentTimeStamp() + convertHumanTimeToSeconds(authConfig.token[type].expiration), -1)\n }\n })\n\n it(`POST ${API_AUTH_TOKEN_REFRESH} => 401`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN_REFRESH,\n headers: { authorization: 'Bearer bar' }\n })\n expect(res.statusCode).toEqual(401)\n })\n\n it(`POST ${API_AUTH_TOKEN_REFRESH} => 201`, async () => {\n const res = await app.inject({\n method: 'POST',\n url: API_AUTH_TOKEN_REFRESH,\n headers: { authorization: `Bearer ${refreshToken}` }\n })\n expect(res.statusCode).toEqual(201)\n expect(() => transformAndValidate(TokenResponseDto, res.json())).not.toThrow()\n })\n\n function getCookies(setCookie: string[]): { type: TOKEN_TYPE; content: string[] }[] {\n const cookies: { type: TOKEN_TYPE; content: string[] }[] = []\n for (const c of setCookie) {\n const cookieName = c.split('=')[0]\n const cookieValues = c.split('; ')\n switch (cookieName) {\n case authConfig.token.access.name:\n cookies.push({ type: TOKEN_TYPE.ACCESS, content: cookieValues })\n break\n case authConfig.token.refresh.name:\n cookies.push({ type: TOKEN_TYPE.REFRESH, content: cookieValues })\n break\n case authConfig.token.ws.name:\n cookies.push({ type: TOKEN_TYPE.WS, content: cookieValues })\n break\n case authConfig.token.csrf.name:\n cookies.push({ type: TOKEN_TYPE.CSRF, content: cookieValues })\n break\n }\n }\n return cookies\n }\n\n function cookiesChecks(cookies: { type: TOKEN_TYPE; content: string[] }[], clear = false) {\n for (const cookie of cookies) {\n expect(cookie.content[0].split('=')[0]).toBe(authConfig.token[cookie.type].name)\n expect(cookie.content[2].split('=')[1]).toBe(TOKEN_PATHS[cookie.type])\n if (cookie.type === TOKEN_TYPE.CSRF) {\n expect(cookie.content).not.toContain('HttpOnly')\n } else {\n expect(cookie.content).toContain('HttpOnly')\n }\n expect(cookie.content).not.toContain('Secure')\n expect(cookie.content[cookie.content.length - 1].split('=')[1].toLowerCase()).toBe(authConfig.cookieSameSite)\n if (clear) {\n expect(cookie.content[0].split('=')[1]).toBe('')\n expect(cookie.content[1].split('=')[1]).toBe('0')\n expect(cookie.content[3].split('=')[1]).toBe('Thu, 01 Jan 1970 00:00:00 GMT')\n } else {\n expect(parseInt(cookie.content[1].split('=')[1])).toBeCloseTo(convertHumanTimeToSeconds(authConfig.token[cookie.type].expiration), -1)\n expect(cookie.content[0].split('=')[1]).not.toBe('')\n }\n }\n }\n})\n"],"names":["describe","app","authConfig","jwtService","adminUsersManager","userTest","refreshToken","csrfToken","beforeAll","appBootstrap","init","getHttpAdapter","getInstance","ready","get","ConfigService","JwtService","AdminUsersManager","UserModel","generateUserTest","afterAll","expect","deleteUserOrGuest","id","login","deleteSpace","isGuest","resolves","not","toThrow","close","it","toBeDefined","dbCheckConnection","toBe","API_AUTH_LOGIN","res","inject","method","url","body","password","statusCode","toEqual","userId","createUserOrGuest","USER_ROLE","USER","Object","keys","json","arrayContaining","headers","toHaveLength","cookies","getCookies","cookiesChecks","cookie","token","content","substring","indexOf","type","TOKEN_TYPE","CSRF","decodeUrl","decodedToken","verifyAsync","secret","iat","toBeCloseTo","currentTimeStamp","exp","convertHumanTimeToSeconds","expiration","identity","REFRESH","API_AUTH_LOGOUT","API_AUTH_REFRESH","csrf","name","refresh","message","CSRF_ERROR","MISSING_HEADERS","API_AUTH_TOKEN","transformAndValidate","TokenResponseDto","TOKEN_TYPES","filter","p","ACCESS","API_AUTH_TOKEN_REFRESH","authorization","setCookie","c","cookieName","split","cookieValues","access","push","ws","WS","clear","TOKEN_PATHS","toContain","length","toLowerCase","cookieSameSite","parseInt"],"mappings":"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"}
|
|
@@ -82,6 +82,29 @@ describe(_authbasicguard.AuthBasicGuard.name, ()=>{
|
|
|
82
82
|
expect(await authBasicGuard.canActivate(context)).toBe(true);
|
|
83
83
|
expect(userTest.password).toBeUndefined();
|
|
84
84
|
});
|
|
85
|
+
it('should validate the user authentication with password containing colon', async ()=>{
|
|
86
|
+
const passwordWithColon = 'pass:word:123';
|
|
87
|
+
const userWithColonPassword = new _usermodel.UserModel({
|
|
88
|
+
...(0, _test.generateUserTest)(),
|
|
89
|
+
password: passwordWithColon
|
|
90
|
+
}, false);
|
|
91
|
+
const encodedAuthWithColon = Buffer.from(`${userWithColonPassword.login}:${passwordWithColon}`).toString('base64');
|
|
92
|
+
authMethod.validateUser = jest.fn().mockImplementation((login, password)=>{
|
|
93
|
+
expect(login).toBe(userWithColonPassword.login);
|
|
94
|
+
expect(password).toBe(passwordWithColon);
|
|
95
|
+
return userWithColonPassword;
|
|
96
|
+
});
|
|
97
|
+
context.switchToHttp().getRequest.mockReturnValue({
|
|
98
|
+
raw: {
|
|
99
|
+
user: ''
|
|
100
|
+
},
|
|
101
|
+
headers: {
|
|
102
|
+
authorization: `Basic ${encodedAuthWithColon}`
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
expect(await authBasicGuard.canActivate(context)).toBe(true);
|
|
106
|
+
expect(userWithColonPassword.password).toBeUndefined();
|
|
107
|
+
});
|
|
85
108
|
it('should validate the user authentication with cache', async ()=>{
|
|
86
109
|
cache.get = jest.fn().mockReturnValueOnce(userTest);
|
|
87
110
|
context.switchToHttp().getRequest.mockReturnValue({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { generateUserTest } from '../../applications/users/utils/test'\nimport { WEBDAV_BASE_PATH } from '../../applications/webdav/constants/routes'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { AuthMethod } from '../models/auth-method'\nimport { AuthBasicGuard } from './auth-basic.guard'\nimport { AuthBasicStrategy } from './auth-basic.strategy'\n\ndescribe(AuthBasicGuard.name, () => {\n let authBasicGuard: AuthBasicGuard\n let authBasicStrategy: AuthBasicStrategy\n let authMethod: AuthMethod\n let cache: Cache\n let userTest: UserModel\n let encodedAuth: string\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthBasicGuard,\n AuthBasicStrategy,\n {\n provide: AuthMethod,\n useValue: {\n validateUser: async () => null\n }\n },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined,\n error: jest.fn()\n }\n },\n {\n provide: Cache,\n useValue: {\n get: (_key: string) => undefined,\n set: async (_key: string, _value: string, _ttl: number) => undefined,\n genSlugKey: () => 'test'\n }\n }\n ]\n }).compile()\n\n authBasicGuard = module.get<AuthBasicGuard>(AuthBasicGuard)\n authBasicStrategy = module.get<AuthBasicStrategy>(AuthBasicStrategy)\n authMethod = module.get<AuthMethod>(AuthMethod)\n cache = module.get<Cache>(Cache)\n userTest = new UserModel(generateUserTest(), false)\n encodedAuth = Buffer.from(`${userTest.login}:${userTest.password}`).toString('base64')\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authBasicGuard).toBeDefined()\n expect(authBasicStrategy).toBeDefined()\n expect(authMethod).toBeDefined()\n expect(cache).toBeDefined()\n expect(encodedAuth).toBeDefined()\n expect(userTest).toBeDefined()\n expect(userTest.password).toBeDefined()\n })\n\n it('should validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n expect(userTest.password).toBeUndefined()\n })\n\n it('should validate the user authentication with cache', async () => {\n cache.get = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n })\n\n it('should not validate the user authentication when cache returns null (explicitly unauthorized)', async () => {\n cache.get = jest.fn().mockReturnValueOnce(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should not validate the user authentication when cache returns undefined and database return null', async () => {\n cache.get = jest.fn().mockReturnValueOnce(undefined)\n authMethod.validateUser = jest.fn().mockReturnValueOnce(null)\n jest.spyOn(cache, 'set').mockRejectedValueOnce(new Error('cache failed'))\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n const loggerSpy = jest\n .spyOn(authBasicStrategy['logger'], 'error') // <-- spy the SAME instance used in the class\n .mockImplementation(() => undefined)\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0][0]).toEqual(expect.stringContaining('cache failed'))\n })\n\n it('should not validate the user authentication', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should throw error due to malformed authorization header', async () => {\n // headers with capitals not working\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' },\n headers: { AUTHORIZATION: 'Basic foo' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it(`should valid OPTIONS method without authentication header on \"/\" and \"/${WEBDAV_BASE_PATH}/*\" paths `, async () => {\n for (const url of ['', `/${WEBDAV_BASE_PATH}`, `/${WEBDAV_BASE_PATH}/foo/bar`]) {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: url,\n raw: { user: '' }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n }\n })\n\n it('should not valid OPTIONS method with other paths', async () => {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: '/foo',\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n})\n"],"names":["describe","AuthBasicGuard","name","authBasicGuard","authBasicStrategy","authMethod","cache","userTest","encodedAuth","context","beforeAll","module","Test","createTestingModule","providers","AuthBasicStrategy","provide","AuthMethod","useValue","validateUser","PinoLogger","assign","undefined","error","jest","fn","Cache","get","_key","set","_value","_ttl","genSlugKey","compile","UserModel","generateUserTest","Buffer","from","login","password","toString","createMock","it","expect","toBeDefined","mockReturnValueOnce","switchToHttp","getRequest","mockReturnValue","raw","user","headers","authorization","canActivate","toBe","toBeUndefined","rejects","toThrow","spyOn","mockRejectedValueOnce","Error","loggerSpy","mockImplementation","toHaveBeenCalled","mock","calls","toEqual","stringContaining","AUTHORIZATION","WEBDAV_BASE_PATH","url","method","originalUrl"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/authentication/guards/auth-basic.guard.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { createMock, DeepMocked } from '@golevelup/ts-jest'\nimport { ExecutionContext } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { PinoLogger } from 'nestjs-pino'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { generateUserTest } from '../../applications/users/utils/test'\nimport { WEBDAV_BASE_PATH } from '../../applications/webdav/constants/routes'\nimport { Cache } from '../../infrastructure/cache/services/cache.service'\nimport { AuthMethod } from '../models/auth-method'\nimport { AuthBasicGuard } from './auth-basic.guard'\nimport { AuthBasicStrategy } from './auth-basic.strategy'\n\ndescribe(AuthBasicGuard.name, () => {\n let authBasicGuard: AuthBasicGuard\n let authBasicStrategy: AuthBasicStrategy\n let authMethod: AuthMethod\n let cache: Cache\n let userTest: UserModel\n let encodedAuth: string\n let context: DeepMocked<ExecutionContext>\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n AuthBasicGuard,\n AuthBasicStrategy,\n {\n provide: AuthMethod,\n useValue: {\n validateUser: async () => null\n }\n },\n {\n provide: PinoLogger,\n useValue: {\n assign: () => undefined,\n error: jest.fn()\n }\n },\n {\n provide: Cache,\n useValue: {\n get: (_key: string) => undefined,\n set: async (_key: string, _value: string, _ttl: number) => undefined,\n genSlugKey: () => 'test'\n }\n }\n ]\n }).compile()\n\n authBasicGuard = module.get<AuthBasicGuard>(AuthBasicGuard)\n authBasicStrategy = module.get<AuthBasicStrategy>(AuthBasicStrategy)\n authMethod = module.get<AuthMethod>(AuthMethod)\n cache = module.get<Cache>(Cache)\n userTest = new UserModel(generateUserTest(), false)\n encodedAuth = Buffer.from(`${userTest.login}:${userTest.password}`).toString('base64')\n context = createMock<ExecutionContext>()\n })\n\n it('should be defined', () => {\n expect(authBasicGuard).toBeDefined()\n expect(authBasicStrategy).toBeDefined()\n expect(authMethod).toBeDefined()\n expect(cache).toBeDefined()\n expect(encodedAuth).toBeDefined()\n expect(userTest).toBeDefined()\n expect(userTest.password).toBeDefined()\n })\n\n it('should validate the user authentication', async () => {\n authMethod.validateUser = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n expect(userTest.password).toBeUndefined()\n })\n\n it('should validate the user authentication with password containing colon', async () => {\n const passwordWithColon = 'pass:word:123'\n const userWithColonPassword = new UserModel({ ...generateUserTest(), password: passwordWithColon }, false)\n const encodedAuthWithColon = Buffer.from(`${userWithColonPassword.login}:${passwordWithColon}`).toString('base64')\n\n authMethod.validateUser = jest.fn().mockImplementation((login: string, password: string) => {\n expect(login).toBe(userWithColonPassword.login)\n expect(password).toBe(passwordWithColon)\n return userWithColonPassword\n })\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuthWithColon}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n expect(userWithColonPassword.password).toBeUndefined()\n })\n\n it('should validate the user authentication with cache', async () => {\n cache.get = jest.fn().mockReturnValueOnce(userTest)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n })\n\n it('should not validate the user authentication when cache returns null (explicitly unauthorized)', async () => {\n cache.get = jest.fn().mockReturnValueOnce(null)\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should not validate the user authentication when cache returns undefined and database return null', async () => {\n cache.get = jest.fn().mockReturnValueOnce(undefined)\n authMethod.validateUser = jest.fn().mockReturnValueOnce(null)\n jest.spyOn(cache, 'set').mockRejectedValueOnce(new Error('cache failed'))\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n const loggerSpy = jest\n .spyOn(authBasicStrategy['logger'], 'error') // <-- spy the SAME instance used in the class\n .mockImplementation(() => undefined)\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n expect(loggerSpy).toHaveBeenCalled()\n expect(loggerSpy.mock.calls[0][0]).toEqual(expect.stringContaining('cache failed'))\n })\n\n it('should not validate the user authentication', async () => {\n context.switchToHttp().getRequest.mockReturnValue({\n raw: { user: '' },\n headers: { authorization: `Basic ${encodedAuth}` }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it('should throw error due to malformed authorization header', async () => {\n // headers with capitals not working\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' },\n headers: { AUTHORIZATION: 'Basic foo' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n context.switchToHttp().getRequest.mockReturnValueOnce({\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n\n it(`should valid OPTIONS method without authentication header on \"/\" and \"/${WEBDAV_BASE_PATH}/*\" paths `, async () => {\n for (const url of ['', `/${WEBDAV_BASE_PATH}`, `/${WEBDAV_BASE_PATH}/foo/bar`]) {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: url,\n raw: { user: '' }\n })\n expect(await authBasicGuard.canActivate(context)).toBe(true)\n }\n })\n\n it('should not valid OPTIONS method with other paths', async () => {\n context.switchToHttp().getRequest.mockReturnValueOnce({\n method: 'OPTIONS',\n originalUrl: '/foo',\n raw: { user: '' }\n })\n await expect(authBasicGuard.canActivate(context)).rejects.toThrow()\n })\n})\n"],"names":["describe","AuthBasicGuard","name","authBasicGuard","authBasicStrategy","authMethod","cache","userTest","encodedAuth","context","beforeAll","module","Test","createTestingModule","providers","AuthBasicStrategy","provide","AuthMethod","useValue","validateUser","PinoLogger","assign","undefined","error","jest","fn","Cache","get","_key","set","_value","_ttl","genSlugKey","compile","UserModel","generateUserTest","Buffer","from","login","password","toString","createMock","it","expect","toBeDefined","mockReturnValueOnce","switchToHttp","getRequest","mockReturnValue","raw","user","headers","authorization","canActivate","toBe","toBeUndefined","passwordWithColon","userWithColonPassword","encodedAuthWithColon","mockImplementation","rejects","toThrow","spyOn","mockRejectedValueOnce","Error","loggerSpy","toHaveBeenCalled","mock","calls","toEqual","stringContaining","AUTHORIZATION","WEBDAV_BASE_PATH","url","method","originalUrl"],"mappings":"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"}
|
|
@@ -16,12 +16,12 @@ const _common = require("@nestjs/common");
|
|
|
16
16
|
const _passport = require("@nestjs/passport");
|
|
17
17
|
const _classtransformer = require("class-transformer");
|
|
18
18
|
const _nestjspino = require("nestjs-pino");
|
|
19
|
-
const _passporthttp = require("passport-http");
|
|
20
19
|
const _usermodel = require("../../applications/users/models/user.model");
|
|
21
20
|
const _shared = require("../../common/shared");
|
|
22
21
|
const _cacheservice = require("../../infrastructure/cache/services/cache.service");
|
|
23
22
|
const _scope = require("../constants/scope");
|
|
24
23
|
const _authmethod = require("../models/auth-method");
|
|
24
|
+
const _httpbasicstrategy = require("./implementations/http-basic.strategy");
|
|
25
25
|
function _ts_decorate(decorators, target, key, desc) {
|
|
26
26
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
27
27
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -31,7 +31,7 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
31
31
|
function _ts_metadata(k, v) {
|
|
32
32
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
33
33
|
}
|
|
34
|
-
let AuthBasicStrategy = class AuthBasicStrategy extends (0, _passport.PassportStrategy)(
|
|
34
|
+
let AuthBasicStrategy = class AuthBasicStrategy extends (0, _passport.PassportStrategy)(_httpbasicstrategy.HttpBasicStrategy, 'basic') {
|
|
35
35
|
async validate(req, loginOrEmail, password) {
|
|
36
36
|
loginOrEmail = loginOrEmail.trim();
|
|
37
37
|
password = password.trim();
|
|
@@ -46,7 +46,7 @@ let AuthBasicStrategy = class AuthBasicStrategy extends (0, _passport.PassportSt
|
|
|
46
46
|
}
|
|
47
47
|
if (userFromCache !== undefined) {
|
|
48
48
|
// cached
|
|
49
|
-
// warning: plainToInstance do not use constructor to instantiate class
|
|
49
|
+
// warning: plainToInstance do not use constructor to instantiate the class
|
|
50
50
|
return (0, _classtransformer.plainToInstance)(_usermodel.UserModel, userFromCache);
|
|
51
51
|
}
|
|
52
52
|
const userFromDB = await this.authMethod.validateUser(loginOrEmail, password, req.ip, _scope.AUTH_SCOPE.WEBDAV);
|