@sync-in/server 1.4.0 → 1.5.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 +26 -0
- package/README.md +2 -1
- package/package.json +5 -5
- package/server/applications/comments/comments.controller.spec.js +103 -4
- package/server/applications/comments/comments.controller.spec.js.map +1 -1
- package/server/applications/comments/services/comments-manager.service.spec.js +409 -9
- package/server/applications/comments/services/comments-manager.service.spec.js.map +1 -1
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js +333 -0
- package/server/applications/files/adapters/files-indexer-mysql.service.spec.js.map +1 -0
- package/server/applications/files/constants/routes.js +6 -1
- package/server/applications/files/constants/routes.js.map +1 -1
- package/server/applications/files/files-only-office.controller.js +11 -0
- package/server/applications/files/files-only-office.controller.js.map +1 -1
- package/server/applications/files/files-only-office.controller.spec.js +97 -3
- package/server/applications/files/files-only-office.controller.spec.js.map +1 -1
- package/server/applications/files/files-tasks.controller.spec.js +91 -1
- package/server/applications/files/files-tasks.controller.spec.js.map +1 -1
- package/server/applications/files/files.controller.spec.js +268 -46
- package/server/applications/files/files.controller.spec.js.map +1 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js +77 -1
- package/server/applications/files/guards/files-only-office.guard.spec.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +5 -0
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/links/links.controller.spec.js +91 -58
- package/server/applications/links/links.controller.spec.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +4 -6
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +378 -14
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/links/services/links-queries.service.js +1 -1
- package/server/applications/links/services/links-queries.service.js.map +1 -1
- package/server/applications/notifications/notifications.controller.spec.js +56 -1
- package/server/applications/notifications/notifications.controller.spec.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.spec.js +461 -5
- package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.spec.js +590 -14
- package/server/applications/shares/services/shares-manager.service.spec.js.map +1 -1
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js +120 -0
- package/server/applications/sync/interceptors/sync-diff-gzip-body.interceptor.spec.js.map +1 -0
- package/server/applications/sync/services/sync-clients-manager.service.spec.js +548 -8
- package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-manager.service.spec.js +837 -5
- package/server/applications/sync/services/sync-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-paths-manager.service.spec.js +900 -7
- package/server/applications/sync/services/sync-paths-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +22 -24
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +763 -17
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +1 -1
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +938 -49
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/webdav/decorators/if-header.decorator.js +4 -1
- package/server/applications/webdav/decorators/if-header.decorator.js.map +1 -1
- package/server/applications/webdav/filters/webdav.filter.spec.js +77 -0
- package/server/applications/webdav/filters/webdav.filter.spec.js.map +1 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.js +3 -7
- package/server/applications/webdav/guards/webdav-protocol.guard.js.map +1 -1
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js +580 -0
- package/server/applications/webdav/guards/webdav-protocol.guard.spec.js.map +1 -0
- package/server/applications/webdav/services/webdav-methods.service.spec.js +1582 -3
- package/server/applications/webdav/services/webdav-methods.service.spec.js.map +1 -1
- package/server/applications/webdav/services/webdav-spaces.service.spec.js +390 -2
- package/server/applications/webdav/services/webdav-spaces.service.spec.js.map +1 -1
- package/server/applications/webdav/webdav.controller.js +2 -2
- package/server/applications/webdav/webdav.controller.js.map +1 -1
- package/server/authentication/guards/auth-basic.guard.js.map +1 -1
- package/server/authentication/guards/auth-digest.guard.js +1 -2
- package/server/authentication/guards/auth-digest.guard.js.map +1 -1
- package/server/authentication/guards/auth-local.guard.js.map +1 -1
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js +135 -0
- package/server/infrastructure/context/interceptors/context.interceptor.spec.js.map +1 -0
- package/static/3rdpartylicenses.txt +26 -26
- package/static/assets/pdfjs/build/pdf.mjs +1177 -255
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +25 -2
- package/static/assets/pdfjs/build/pdf.sandbox.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.worker.mjs +140 -16
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/debugger.css +31 -0
- package/static/assets/pdfjs/web/debugger.mjs +144 -2
- package/static/assets/pdfjs/web/images/comment-editButton.svg +6 -1
- package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +22 -0
- package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -0
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -6
- package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -57
- package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -37
- package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/gl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -49
- package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +31 -0
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +48 -10
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +5 -0
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -75
- package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -3
- package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +44 -6
- package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +45 -1
- package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -31
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +39 -1
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +355 -1
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -54
- package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -38
- package/static/assets/pdfjs/web/locale/scn/viewer.ftl +0 -92
- package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -51
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -27
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +8 -0
- package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -33
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -63
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +40 -2
- package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -72
- package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -60
- package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/wo/viewer.ftl +0 -77
- package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -71
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +38 -0
- package/static/assets/pdfjs/web/viewer.css +649 -120
- package/static/assets/pdfjs/web/viewer.html +19 -0
- package/static/assets/pdfjs/web/viewer.mjs +489 -38
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/chunk-22EANI6R.js +1 -0
- package/static/{chunk-N2LYWNTC.js → chunk-2456KVFZ.js} +1 -1
- package/static/{chunk-YCINY2YI.js → chunk-2LVCLKCK.js} +1 -1
- package/static/{chunk-5YKWZT33.js → chunk-2V5S7DWD.js} +1 -1
- package/static/{chunk-3GC2BQZD.js → chunk-44YDXGNZ.js} +1 -1
- package/static/{chunk-W3QXNDI5.js → chunk-4LSJLWYV.js} +1 -1
- package/static/{chunk-T55FAU2O.js → chunk-4UT5VH7R.js} +1 -1
- package/static/{chunk-VMQMD36Z.js → chunk-5GOMMRRE.js} +1 -1
- package/static/{chunk-TXPODW5Q.js → chunk-5J4VRDKB.js} +1 -1
- package/static/{chunk-FQ4AFNGE.js → chunk-6PVKNZ7Q.js} +1 -1
- package/static/{chunk-XE5YHU5J.js → chunk-BIUNUYZ5.js} +1 -1
- package/static/{chunk-X43VWRFP.js → chunk-DFQKHCDR.js} +1 -1
- package/static/{chunk-TDQAEVZN.js → chunk-EE2TDTY4.js} +1 -1
- package/static/{chunk-MOVWEZ7J.js → chunk-ESNDJ5T6.js} +1 -1
- package/static/{chunk-TCFKH6K6.js → chunk-GDKKLLEU.js} +1 -1
- package/static/{chunk-VHYIXL7R.js → chunk-GSR2MCQG.js} +1 -1
- package/static/{chunk-LJIGRUEF.js → chunk-HR7KS5BR.js} +1 -1
- package/static/chunk-HW2H3ISM.js +559 -0
- package/static/{chunk-HZA7R43P.js → chunk-IMB3C547.js} +1 -1
- package/static/{chunk-B2Y2RNFP.js → chunk-J4ALHUDX.js} +1 -1
- package/static/{chunk-PF4K7MVG.js → chunk-KP6LSQTK.js} +1 -1
- package/static/{chunk-C23BPTJZ.js → chunk-LUZCOHFN.js} +1 -1
- package/static/{chunk-GBCYYDCI.js → chunk-MHSCCXVL.js} +1 -1
- package/static/{chunk-PY3BGNJN.js → chunk-OMRQYBXV.js} +1 -1
- package/static/chunk-P7CTJ5BG.js +27 -0
- package/static/{chunk-Y2CDUS4J.js → chunk-P7PX67IR.js} +4 -4
- package/static/{chunk-VMUOUCEI.js → chunk-PPO7DBVO.js} +1 -1
- package/static/{chunk-TTQ37MUV.js → chunk-RSS6GYNE.js} +1 -1
- package/static/{chunk-WWIC7UW3.js → chunk-SLGGINMR.js} +1 -1
- package/static/{chunk-KZQCFEPT.js → chunk-UHD5XD3G.js} +1 -1
- package/static/{chunk-TNW2CGK6.js → chunk-UPYYAJCJ.js} +1 -1
- package/static/{chunk-6F55D74O.js → chunk-VHYPQ3D4.js} +1 -1
- package/static/{chunk-DGVNNICG.js → chunk-YQSDS6BO.js} +1 -1
- package/static/{chunk-MTRNPGS4.js → chunk-ZC5NIT55.js} +1 -1
- package/static/index.html +1 -1
- package/static/main-FYD34UEC.js +7 -0
- package/static/chunk-RSNLYAN6.js +0 -560
- package/static/chunk-WHMS3PJ3.js +0 -24
- package/static/chunk-ZZ3LHYOY.js +0 -1
- package/static/main-7LDKYVXO.js +0 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/shares/services/shares-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { LinksQueries } from '../../links/services/links-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { SharesManager } from './shares-manager.service'\nimport { SharesQueries } from './shares-queries.service'\n\ndescribe(SharesManager.name, () => {\n let service: SharesManager\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n {\n provide: Cache,\n useValue: {}\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n SpacesQueries,\n FilesQueries,\n UsersQueries,\n SharesManager,\n SharesQueries,\n LinksQueries\n ]\n }).compile()\n\n service = module.get<SharesManager>(SharesManager)\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n})\n"],"names":["describe","SharesManager","name","service","beforeAll","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","ContextManager","NotificationsManager","SpacesQueries","FilesQueries","UsersQueries","SharesQueries","LinksQueries","compile","get","it","expect","toBeDefined"],"mappings":"AAAA;;;;CAIC;;;;yBAEmC;8BACd;uCACS;2BACG;qCACL;qCACA;6CACQ;sCACP;qCACD;sCACC;sCACA;AAE9BA,SAASC,mCAAa,CAACC,IAAI,EAAE;IAC3B,IAAIC;IAEJC,UAAU;QACR,MAAMC,SAAwB,MAAMC,aAAI,CAACC,mBAAmB,CAAC;YAC3DC,WAAW;gBACT;oBAAEC,SAASC,4BAAiB;oBAAEC,UAAU,CAAC;gBAAE;gBAC3C;oBACEF,SAASG,mBAAK;oBACdD,UAAU,CAAC;gBACb;gBACA;oBAAEF,SAASI,qCAAc;oBAAEF,UAAU,CAAC;gBAAE;gBACxC;oBACEF,SAASK,iDAAoB;oBAC7BH,UAAU,CAAC;gBACb;gBACAI,mCAAa;gBACbC,iCAAY;gBACZC,iCAAY;gBACZhB,mCAAa;gBACbiB,mCAAa;gBACbC,iCAAY;aACb;QACH,GAAGC,OAAO;QAEVjB,UAAUE,OAAOgB,GAAG,CAAgBpB,mCAAa;IACnD;IAEAqB,GAAG,qBAAqB;QACtBC,OAAOpB,SAASqB,WAAW;IAC7B;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/shares/services/shares-manager.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport * as commonFunctions from '../../../common/functions'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { DB_TOKEN_PROVIDER } from '../../../infrastructure/database/constants'\nimport { LINK_TYPE } from '../../links/constants/links'\nimport { LinksQueries } from '../../links/services/links-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport * as permissionsUtils from '../../spaces/utils/permissions'\nimport { GUEST_PERMISSION } from '../../users/constants/user'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { SHARE_ALL_OPERATIONS } from '../constants/shares'\nimport { SharesManager } from './shares-manager.service'\nimport { SharesQueries } from './shares-queries.service'\n\n// Mock classes and utility modules used by SharesManager\njest.mock('../../spaces/models/space-env.model', () => ({\n SpaceEnv: jest.fn().mockImplementation(() => ({\n setPermissions: jest.fn(),\n envPermissions: 'ENV_PERMS'\n }))\n}))\n\njest.mock('../../spaces/utils/permissions', () => ({\n havePermission: jest.fn(),\n haveSpacePermission: jest.fn(),\n removePermissions: jest.fn(() => 'trimmed')\n}))\n\njest.mock('../../../common/functions', () => {\n const actual = jest.requireActual('../../../common/functions')\n return {\n ...actual,\n generateShortUUID: jest.fn(),\n hashPassword: jest.fn(),\n intersectPermissions: jest.fn()\n }\n})\n\ndescribe(SharesManager.name, () => {\n let service: SharesManager\n\n // Mocks\n const contextManagerMock = {\n get: jest.fn()\n }\n\n const notificationsManagerMock = {\n create: jest.fn().mockResolvedValue(undefined),\n sendEmailNotification: jest.fn().mockResolvedValue(undefined)\n }\n\n const spacesQueriesMock = {\n permissions: jest.fn()\n }\n\n const usersQueriesMock = {\n createUserOrGuest: jest.fn(),\n deleteGuestLink: jest.fn(),\n usersWhitelist: jest.fn().mockResolvedValue([]),\n groupsWhitelist: jest.fn().mockResolvedValue([]),\n allUserIdsFromGroupsAndSubGroups: jest.fn().mockResolvedValue([])\n }\n\n const linksQueriesMock = {\n isUniqueUUID: jest.fn(),\n isReservedUUID: jest.fn(),\n allLinksFromSpaceOrShare: jest.fn(),\n createLinkToSpaceOrShare: jest.fn(),\n updateLinkFromSpaceOrShare: jest.fn(),\n linkFromShare: jest.fn(),\n linkFromSpace: jest.fn()\n }\n\n const sharesQueriesMock = {\n permissions: jest.fn(),\n listShareLinks: jest.fn(),\n getShareWithMembers: jest.fn(),\n createShare: jest.fn(),\n updateShare: jest.fn(),\n selectShares: jest.fn(),\n deleteShare: jest.fn(),\n updateMember: jest.fn(),\n updateMembers: jest.fn(),\n shareExistsForOwner: jest.fn(),\n childExistsForShareOwner: jest.fn()\n }\n\n const user = { id: 1, isAdmin: false } as any\n\n beforeAll(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n { provide: DB_TOKEN_PROVIDER, useValue: {} },\n { provide: ContextManager, useValue: contextManagerMock },\n { provide: NotificationsManager, useValue: notificationsManagerMock },\n { provide: SpacesQueries, useValue: spacesQueriesMock },\n { provide: UsersQueries, useValue: usersQueriesMock },\n { provide: LinksQueries, useValue: linksQueriesMock },\n { provide: SharesQueries, useValue: sharesQueriesMock },\n SharesManager\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<SharesManager>(SharesManager)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('setAllowedPermissions', () => {\n it('sets all operations when the user is the file owner (personal space case)', async () => {\n const share: any = { file: { ownerId: user.id, permissions: '' } }\n await service.setAllowedPermissions(user, share)\n expect(share.file.permissions).toBe(SHARE_ALL_OPERATIONS)\n })\n\n it('uses space permissions when file has a space alias', async () => {\n spacesQueriesMock.permissions.mockResolvedValueOnce({ any: 'thing' })\n const share: any = {\n file: { ownerId: 999, space: { alias: 'space-1', root: { alias: 'root' } }, permissions: undefined }\n }\n await service.setAllowedPermissions(user, share)\n expect(spacesQueriesMock.permissions).toHaveBeenCalledWith(user.id, 'space-1', 'root')\n expect(share.file.ownerId).toBeNull()\n expect(share.file.permissions).toBe('ENV_PERMS')\n })\n\n it('uses parent share permissions when parent alias is present', async () => {\n sharesQueriesMock.permissions.mockResolvedValueOnce({ permissions: 'PARENT_PERMS' })\n const share: any = {\n ownerId: 77,\n parent: { alias: 'parent-share' },\n file: { permissions: undefined }\n }\n await service.setAllowedPermissions(user, share)\n expect(sharesQueriesMock.permissions).toHaveBeenCalledWith(user.id, 'parent-share', +user.isAdmin)\n expect(share.file.permissions).toBe('PARENT_PERMS')\n })\n\n it('throws Bad Request when missing required information', async () => {\n const share: any = { file: {}, parent: {} }\n await expect(service.setAllowedPermissions(user, share)).rejects.toEqual(new HttpException('Missing information', HttpStatus.BAD_REQUEST))\n })\n })\n\n describe('getShareWithMembers', () => {\n it('returns the share and calls setAllowedPermissions', async () => {\n const share: any = { id: 10, file: {} }\n sharesQueriesMock.getShareWithMembers.mockResolvedValueOnce(share)\n const spy = jest.spyOn(service, 'setAllowedPermissions').mockResolvedValueOnce(void 0)\n\n const result = await service.getShareWithMembers(user, 10, true)\n\n expect(result).toBe(share)\n expect(spy).toHaveBeenCalledWith(user, share, true)\n })\n\n it('throws Forbidden when share is not found or not authorized', async () => {\n sharesQueriesMock.getShareWithMembers.mockResolvedValueOnce(null)\n await expect(service.getShareWithMembers(user, 99, false)).rejects.toEqual(new HttpException('Not authorized', HttpStatus.FORBIDDEN))\n })\n })\n\n describe('generateLinkUUID', () => {\n it('loops until a unique UUID is found', async () => {\n ;(commonFunctions.generateShortUUID as jest.Mock).mockReturnValueOnce('aaa').mockReturnValueOnce('bbb')\n\n linksQueriesMock.isUniqueUUID.mockResolvedValueOnce(false).mockResolvedValueOnce(true)\n\n const { uuid } = await service.generateLinkUUID(user.id)\n\n expect(linksQueriesMock.isUniqueUUID).toHaveBeenCalledTimes(2)\n expect(linksQueriesMock.isUniqueUUID).toHaveBeenNthCalledWith(1, user.id, 'aaa')\n expect(linksQueriesMock.isUniqueUUID).toHaveBeenNthCalledWith(2, user.id, 'bbb')\n expect(uuid).toBe('bbb')\n })\n })\n\n describe('getShareLink', () => {\n it('returns the share link and trims unsupported permissions', async () => {\n const shareLink: any = { id: 5, file: { permissions: 'ORIG' } }\n sharesQueriesMock.listShareLinks.mockResolvedValueOnce(shareLink)\n const spy = jest.spyOn(service, 'setAllowedPermissions').mockResolvedValueOnce(void 0)\n\n const result = await service.getShareLink(user, 5)\n\n expect(spy).toHaveBeenCalledWith(user, shareLink)\n expect(result).toBe(shareLink)\n expect(result.file.permissions).toBe('trimmed')\n expect((permissionsUtils.removePermissions as jest.Mock).mock.calls[0][0]).toBe('ORIG')\n })\n\n it('throws Forbidden when link is not found', async () => {\n sharesQueriesMock.listShareLinks.mockResolvedValueOnce(null)\n await expect(service.getShareLink(user, 123)).rejects.toEqual(new HttpException('Not authorized', HttpStatus.FORBIDDEN))\n })\n })\n\n describe('updateLinkFromSpaceOrShare (from API)', () => {\n it('intersects permissions and returns updated link object', async () => {\n const baseLink: any = {\n id: 42,\n name: 'old',\n email: 'x@x',\n requireAuth: false,\n limitAccess: null,\n expiresAt: null,\n permissions: 'OLD',\n shareName: 'OldShare',\n shareDescription: 'OldDesc'\n }\n jest.spyOn(service, 'getLinkFromSpaceOrShare').mockResolvedValueOnce(baseLink)\n jest.spyOn(service, 'getShareLink').mockResolvedValueOnce({ file: { permissions: 'SHARE_PERMS' } } as any)\n ;(commonFunctions.intersectPermissions as jest.Mock).mockReturnValue('INTERSECTED')\n linksQueriesMock.updateLinkFromSpaceOrShare.mockResolvedValueOnce(undefined)\n\n const dto: any = {\n permissions: 'NEW_PERMS',\n language: 'fr',\n isActive: false\n }\n\n const result = await service.updateLinkFromSpaceOrShare(user, 7, 55, 1 as any, dto, true)\n\n expect(linksQueriesMock.updateLinkFromSpaceOrShare).toHaveBeenCalled()\n expect(result.permissions).toBe('INTERSECTED')\n expect(result.language).toBe('fr')\n expect(result.isActive).toBe(false)\n })\n })\n\n describe('createGuestLink', () => {\n it('creates guest link with hashed password and returns created user info', async () => {\n ;(commonFunctions.hashPassword as jest.Mock).mockResolvedValue('HASHED')\n ;(commonFunctions.generateShortUUID as jest.Mock).mockReturnValue('RANDOMSEQ')\n usersQueriesMock.createUserOrGuest.mockResolvedValueOnce(99)\n\n const guest = await service.createGuestLink(GUEST_PERMISSION.SHARES, 'plaintext', 'en', true)\n\n expect(usersQueriesMock.createUserOrGuest).toHaveBeenCalled()\n expect(guest.id).toBe(99)\n expect(guest.password).toBe('HASHED')\n expect(guest.role).toBeDefined()\n expect(guest.permissions).toBe(GUEST_PERMISSION.SHARES)\n expect(guest.language).toBe('en')\n expect(guest.isActive).toBe(true)\n })\n\n it('generates a random password and defaults isActive when not provided', async () => {\n ;(commonFunctions.hashPassword as jest.Mock).mockResolvedValue('HASHED-RAND')\n ;(commonFunctions.generateShortUUID as jest.Mock).mockReturnValueOnce('RANDOMSEQ')\n usersQueriesMock.createUserOrGuest.mockResolvedValueOnce(123)\n\n const guest = await service.createGuestLink(GUEST_PERMISSION.SPACES)\n\n expect(commonFunctions.hashPassword).toHaveBeenCalled()\n expect(guest.id).toBe(123)\n expect(guest.isActive).toBe(true)\n expect(guest.language).toBeNull()\n })\n })\n\n describe('getLinkFromSpaceOrShare', () => {\n it('returns a link guest for SPACE type', async () => {\n const lg = { id: 1 }\n linksQueriesMock.linkFromSpace.mockResolvedValueOnce(lg)\n\n const res = await service.getLinkFromSpaceOrShare(user, 11, 22, LINK_TYPE.SPACE)\n\n expect(res).toBe(lg)\n expect(linksQueriesMock.linkFromSpace).toHaveBeenCalledWith(user.id, 11, 22)\n expect(linksQueriesMock.linkFromShare).not.toHaveBeenCalled()\n })\n\n it('returns a link guest for SHARE type', async () => {\n const lg = { id: 2 }\n linksQueriesMock.linkFromShare.mockResolvedValueOnce(lg)\n\n const res = await service.getLinkFromSpaceOrShare(user, 33, 44, LINK_TYPE.SHARE)\n\n expect(res).toBe(lg)\n expect(linksQueriesMock.linkFromShare).toHaveBeenCalledWith(user.id, 33, 44, +user.isAdmin)\n expect(linksQueriesMock.linkFromSpace).not.toHaveBeenCalled()\n })\n\n it('throws when link not found', async () => {\n linksQueriesMock.linkFromSpace.mockResolvedValueOnce(null)\n\n await expect(service.getLinkFromSpaceOrShare(user, 55, 66, LINK_TYPE.SPACE)).rejects.toEqual(\n new HttpException('Link not found', HttpStatus.NOT_FOUND)\n )\n })\n })\n\n describe('updateLinkFromSpaceOrShare (additional branches)', () => {\n it('returns null when no diff and not from API', async () => {\n const link: any = { id: 1, name: 'n', email: 'e', requireAuth: false, limitAccess: null, expiresAt: null }\n jest.spyOn(service, 'getLinkFromSpaceOrShare').mockResolvedValueOnce(link)\n\n const result = await service.updateLinkFromSpaceOrShare(user, 1, 2, LINK_TYPE.SHARE, {}, false)\n\n expect(result).toBeNull()\n expect(linksQueriesMock.updateLinkFromSpaceOrShare).not.toHaveBeenCalled()\n })\n\n it('hashes password and does not leak it when fromAPI is true', async () => {\n const link: any = { id: 1 }\n jest.spyOn(service, 'getLinkFromSpaceOrShare').mockResolvedValueOnce(link)\n ;(commonFunctions.hashPassword as jest.Mock).mockResolvedValueOnce('HASHED')\n ;(linksQueriesMock.updateLinkFromSpaceOrShare as jest.Mock).mockImplementation(async (_link: any, _spaceOrShareId: number, updateUser: any) => {\n // Assert at call time before the service deletes the password\n expect(updateUser).toMatchObject({ password: 'HASHED' })\n return\n })\n\n const result = await service.updateLinkFromSpaceOrShare(user, 1, 2, LINK_TYPE.SHARE, { password: 'secret' }, true)\n\n expect(linksQueriesMock.updateLinkFromSpaceOrShare).toHaveBeenCalled()\n // The returned link must not leak password\n expect(result).toBe(link)\n expect((result as any).password).toBeUndefined()\n })\n\n it('updates multiple link/user fields and ignores equal expiresAt', async () => {\n const base = {\n id: 9,\n name: 'a',\n email: 'b',\n requireAuth: false,\n limitAccess: null,\n expiresAt: { date: '2025-01-01' }\n }\n jest.spyOn(service, 'getLinkFromSpaceOrShare').mockResolvedValueOnce(base as any)\n linksQueriesMock.updateLinkFromSpaceOrShare.mockResolvedValueOnce(undefined)\n\n const dto = {\n name: 'a2',\n email: 'b2',\n requireAuth: true,\n limitAccess: 5,\n expiresAt: { date: '2025-01-01' } // equal, should be ignored\n }\n\n await service.updateLinkFromSpaceOrShare(user, 9, 99, LINK_TYPE.SHARE, dto as any, false)\n\n const [, , , updateLink] = (linksQueriesMock.updateLinkFromSpaceOrShare as jest.Mock).mock.calls[0].slice(0, 5)\n expect(updateLink).toMatchObject({\n name: 'a2',\n email: 'b2',\n requireAuth: true,\n limitAccess: 5\n })\n expect(updateLink.expiresAt).toBeUndefined()\n })\n })\n\n describe('setAllowedPermissions (additional branches)', () => {\n it('sets all operations when share has externalPath and user is admin', async () => {\n const admin = { id: 10, isAdmin: true } as any\n const share: any = { externalPath: '/ext', file: {} }\n await service.setAllowedPermissions(admin, share)\n expect(share.file.permissions).toBe(SHARE_ALL_OPERATIONS)\n })\n\n it('throws NOT_FOUND when space permissions are missing', async () => {\n spacesQueriesMock.permissions.mockResolvedValueOnce(null)\n const share: any = { file: { space: { alias: 'space-x', root: { alias: 'r' } } } }\n\n await expect(service.setAllowedPermissions(user, share)).rejects.toEqual(new HttpException('Space not found', HttpStatus.NOT_FOUND))\n })\n\n it('throws NOT_FOUND when parent share permissions are missing', async () => {\n sharesQueriesMock.permissions.mockResolvedValueOnce(null)\n const share: any = { ownerId: 42, parent: { alias: 'parent' }, file: {} }\n\n await expect(service.setAllowedPermissions(user, share)).rejects.toEqual(new HttpException('Share not found', HttpStatus.NOT_FOUND))\n })\n\n it('uses owner permissions when asAdmin is true', async () => {\n const asAdminUser = { id: 3, isAdmin: false } as any\n sharesQueriesMock.permissions.mockResolvedValueOnce({ permissions: 'ADMIN_PARENT' })\n const share: any = { ownerId: 77, parent: { alias: 'pa' }, file: {} }\n\n await service.setAllowedPermissions(asAdminUser, share, true)\n\n expect(sharesQueriesMock.permissions).toHaveBeenCalledWith(77, 'pa', +asAdminUser.isAdmin)\n expect(share.file.permissions).toBe('ADMIN_PARENT')\n })\n })\n\n describe('getShareLink (additional branch)', () => {\n it('does not trim permissions if file.permissions is falsy', async () => {\n const shareLink: any = { id: 7, file: {} }\n sharesQueriesMock.listShareLinks.mockResolvedValueOnce(shareLink)\n const spy = jest.spyOn(service, 'setAllowedPermissions').mockResolvedValueOnce(void 0)\n\n const res = await service.getShareLink(user, 7)\n\n expect(spy).toHaveBeenCalled()\n expect(res).toBe(shareLink)\n expect(permissionsUtils.removePermissions).not.toHaveBeenCalled()\n })\n })\n\n describe('deleteShare', () => {\n it('throws Forbidden when user is not admin and not owner', async () => {\n sharesQueriesMock.shareExistsForOwner.mockResolvedValueOnce(false)\n\n await expect(service.deleteShare({ id: 2, isAdmin: false } as any, 123)).rejects.toEqual(\n new HttpException('Not authorized', HttpStatus.FORBIDDEN)\n )\n })\n\n it('deletes links and removes shares when authorized (asAdmin)', async () => {\n const deleteLinksSpy = jest.spyOn(service, 'deleteAllLinkMembers').mockResolvedValue(void 0)\n const removeSpy = jest.spyOn<any, any>(service as any, 'removeShareFromOwners').mockResolvedValue(void 0)\n\n await service.deleteShare(user, 456, true)\n\n expect(deleteLinksSpy).toHaveBeenCalledWith(456, expect.anything())\n expect(removeSpy).toHaveBeenCalledWith(456, 'all', false, user.id)\n })\n })\n\n describe('child share wrappers', () => {\n it('getChildShare returns share link when isLink = true', async () => {\n sharesQueriesMock.childExistsForShareOwner.mockResolvedValueOnce(99)\n const getShareLinkSpy = jest.spyOn(service, 'getShareLink').mockResolvedValueOnce({ id: 99 } as any)\n\n const res = await service.getChildShare(user, 1, 99, true)\n expect(res).toEqual({ id: 99 })\n expect(getShareLinkSpy).toHaveBeenCalledWith(user, 99, true)\n })\n\n it('getChildShare returns child share when isLink = false', async () => {\n sharesQueriesMock.childExistsForShareOwner.mockResolvedValueOnce(100)\n const getShareSpy = jest.spyOn(service, 'getShareWithMembers').mockResolvedValueOnce({ id: 100 } as any)\n\n const res = await service.getChildShare(user, 1, 100, false)\n expect(res).toEqual({ id: 100 })\n expect(getShareSpy).toHaveBeenCalledWith(user, 100, true)\n })\n\n it('updateChildShare forwards update and deleteChildShare forwards delete', async () => {\n sharesQueriesMock.childExistsForShareOwner.mockResolvedValue(200)\n const updateSpy = jest.spyOn(service, 'updateShare').mockResolvedValueOnce({ id: 200 } as any)\n const deleteSpy = jest.spyOn(service, 'deleteShare').mockResolvedValueOnce(void 0)\n\n await service.updateChildShare(user, 1, 200, {} as any)\n expect(updateSpy).toHaveBeenCalledWith(user, 200, {} as any, true)\n\n await service.deleteChildShare(user, 1, 200)\n expect(deleteSpy).toHaveBeenCalledWith(user, 200, true)\n })\n\n it('throws Forbidden when not allowed to manage child share', async () => {\n sharesQueriesMock.childExistsForShareOwner.mockResolvedValueOnce(null)\n await expect(service.getChildShare(user, 1, 2, false)).rejects.toEqual(new HttpException('Not authorized', HttpStatus.FORBIDDEN))\n })\n })\n\n describe('createOrUpdateLinksAsMembers', () => {\n it('creates new links for id < 0 and notifies guest', async () => {\n const createLinkSpy = jest.spyOn<any, any>(service as any, 'createLinkFromSpaceOrShare').mockResolvedValue(void 0)\n const notifySpy = jest.spyOn<any, any>(service as any, 'notifyGuestLink').mockResolvedValue(void 0)\n\n const links = [{ id: -1, linkSettings: { uuid: 'u', email: 'e', permissions: 'p' }, permissions: 'p' }] as any\n\n const res = await service.createOrUpdateLinksAsMembers(user, { id: 1, name: 'S' } as any, LINK_TYPE.SHARE, links)\n\n expect(res).toEqual([])\n expect(createLinkSpy).toHaveBeenCalled()\n expect(notifySpy).toHaveBeenCalled()\n })\n\n it('updates modified links and returns them along with unmodified ones', async () => {\n const updateLinkSpy = jest.spyOn(service, 'updateLinkFromSpaceOrShare').mockResolvedValue(void 0)\n\n const members = await service.createOrUpdateLinksAsMembers(user, { id: 1, name: 'S' } as any, LINK_TYPE.SHARE, [\n { id: 2, linkId: 2, permissions: 'p', linkSettings: { name: 'new' } },\n { id: 3, linkId: 3, permissions: 'q' } // unmodified\n ] as any)\n\n expect(updateLinkSpy).toHaveBeenCalledWith(user, 2, 1, LINK_TYPE.SHARE, { name: 'new' })\n expect(members).toHaveLength(2)\n expect(members.map((m: any) => m.id)).toEqual([2, 3])\n })\n })\n\n describe('generateLinkUUID (additional)', () => {\n it('returns immediately when the first UUID is unique', async () => {\n ;(commonFunctions.generateShortUUID as jest.Mock).mockReturnValueOnce('only-one')\n linksQueriesMock.isUniqueUUID.mockResolvedValueOnce(true)\n\n const { uuid } = await service.generateLinkUUID(user.id)\n\n expect(uuid).toBe('only-one')\n expect(linksQueriesMock.isUniqueUUID).toHaveBeenCalledTimes(1)\n expect(linksQueriesMock.isUniqueUUID).toHaveBeenCalledWith(user.id, 'only-one')\n })\n })\n})\n"],"names":["jest","mock","SpaceEnv","fn","mockImplementation","setPermissions","envPermissions","havePermission","haveSpacePermission","removePermissions","actual","requireActual","generateShortUUID","hashPassword","intersectPermissions","describe","SharesManager","name","service","contextManagerMock","get","notificationsManagerMock","create","mockResolvedValue","undefined","sendEmailNotification","spacesQueriesMock","permissions","usersQueriesMock","createUserOrGuest","deleteGuestLink","usersWhitelist","groupsWhitelist","allUserIdsFromGroupsAndSubGroups","linksQueriesMock","isUniqueUUID","isReservedUUID","allLinksFromSpaceOrShare","createLinkToSpaceOrShare","updateLinkFromSpaceOrShare","linkFromShare","linkFromSpace","sharesQueriesMock","listShareLinks","getShareWithMembers","createShare","updateShare","selectShares","deleteShare","updateMember","updateMembers","shareExistsForOwner","childExistsForShareOwner","user","id","isAdmin","beforeAll","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","ContextManager","NotificationsManager","SpacesQueries","UsersQueries","LinksQueries","SharesQueries","compile","useLogger","beforeEach","clearAllMocks","it","expect","toBeDefined","share","file","ownerId","setAllowedPermissions","toBe","SHARE_ALL_OPERATIONS","mockResolvedValueOnce","any","space","alias","root","toHaveBeenCalledWith","toBeNull","parent","rejects","toEqual","HttpException","HttpStatus","BAD_REQUEST","spy","spyOn","result","FORBIDDEN","commonFunctions","mockReturnValueOnce","uuid","generateLinkUUID","toHaveBeenCalledTimes","toHaveBeenNthCalledWith","shareLink","getShareLink","permissionsUtils","calls","baseLink","email","requireAuth","limitAccess","expiresAt","shareName","shareDescription","mockReturnValue","dto","language","isActive","toHaveBeenCalled","guest","createGuestLink","GUEST_PERMISSION","SHARES","password","role","SPACES","lg","res","getLinkFromSpaceOrShare","LINK_TYPE","SPACE","not","SHARE","NOT_FOUND","link","_link","_spaceOrShareId","updateUser","toMatchObject","toBeUndefined","base","date","updateLink","slice","admin","externalPath","asAdminUser","deleteLinksSpy","removeSpy","anything","getShareLinkSpy","getChildShare","getShareSpy","updateSpy","deleteSpy","updateChildShare","deleteChildShare","createLinkSpy","notifySpy","links","linkSettings","createOrUpdateLinksAsMembers","updateLinkSpy","members","linkId","toHaveLength","map","m"],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
|
|
3
|
+
* This file is part of Sync-in | The open source file sync and share solution
|
|
4
|
+
* See the LICENSE file for licensing details
|
|
5
|
+
*/ "use strict";
|
|
6
|
+
Object.defineProperty(exports, "__esModule", {
|
|
7
|
+
value: true
|
|
8
|
+
});
|
|
9
|
+
const _common = require("@nestjs/common");
|
|
10
|
+
const _testing = require("@nestjs/testing");
|
|
11
|
+
const _rxjs = require("rxjs");
|
|
12
|
+
const _stream = require("stream");
|
|
13
|
+
const _zlib = /*#__PURE__*/ _interop_require_default(require("zlib"));
|
|
14
|
+
const _syncdiffgzipbodyinterceptor = require("./sync-diff-gzip-body.interceptor");
|
|
15
|
+
function _interop_require_default(obj) {
|
|
16
|
+
return obj && obj.__esModule ? obj : {
|
|
17
|
+
default: obj
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
describe('SyncDiffGzipBodyInterceptor', ()=>{
|
|
21
|
+
let interceptor;
|
|
22
|
+
const createReadableFrom = (data)=>{
|
|
23
|
+
const stream = new _stream.Readable();
|
|
24
|
+
stream.push(data);
|
|
25
|
+
stream.push(null);
|
|
26
|
+
return stream;
|
|
27
|
+
};
|
|
28
|
+
const createExecutionContextWithRequest = (req)=>{
|
|
29
|
+
return {
|
|
30
|
+
switchToHttp: ()=>({
|
|
31
|
+
getRequest: ()=>req
|
|
32
|
+
})
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const createCallHandler = (value = 'ok')=>{
|
|
36
|
+
return {
|
|
37
|
+
handle: jest.fn(()=>(0, _rxjs.of)(value))
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
beforeEach(async ()=>{
|
|
41
|
+
const module = await _testing.Test.createTestingModule({
|
|
42
|
+
providers: [
|
|
43
|
+
_syncdiffgzipbodyinterceptor.SyncDiffGzipBodyInterceptor
|
|
44
|
+
]
|
|
45
|
+
}).compile();
|
|
46
|
+
interceptor = module.get(_syncdiffgzipbodyinterceptor.SyncDiffGzipBodyInterceptor);
|
|
47
|
+
});
|
|
48
|
+
it('should gunzip and parse JSON body when Content-Encoding is gzip', async ()=>{
|
|
49
|
+
const originalBody = {
|
|
50
|
+
a: 1,
|
|
51
|
+
b: 'two'
|
|
52
|
+
};
|
|
53
|
+
const gzipped = _zlib.default.gzipSync(Buffer.from(JSON.stringify(originalBody)));
|
|
54
|
+
const req = {
|
|
55
|
+
headers: {
|
|
56
|
+
'content-encoding': 'gzip'
|
|
57
|
+
},
|
|
58
|
+
raw: createReadableFrom(gzipped),
|
|
59
|
+
body: undefined
|
|
60
|
+
};
|
|
61
|
+
const ctx = createExecutionContextWithRequest(req);
|
|
62
|
+
const next = createCallHandler('handled');
|
|
63
|
+
const result$ = await interceptor.intercept(ctx, next);
|
|
64
|
+
const result = await (0, _rxjs.lastValueFrom)(result$);
|
|
65
|
+
expect(result).toBe('handled');
|
|
66
|
+
expect(next.handle).toHaveBeenCalledTimes(1);
|
|
67
|
+
expect(req.body).toEqual(originalBody);
|
|
68
|
+
});
|
|
69
|
+
it('should pass through without modifying body when Content-Encoding is not gzip', async ()=>{
|
|
70
|
+
const req = {
|
|
71
|
+
headers: {},
|
|
72
|
+
raw: createReadableFrom(Buffer.from('no use in this case')),
|
|
73
|
+
body: 'initial'
|
|
74
|
+
};
|
|
75
|
+
const ctx = createExecutionContextWithRequest(req);
|
|
76
|
+
const next = createCallHandler('passthrough');
|
|
77
|
+
const result$ = await interceptor.intercept(ctx, next);
|
|
78
|
+
const result = await (0, _rxjs.lastValueFrom)(result$);
|
|
79
|
+
expect(result).toBe('passthrough');
|
|
80
|
+
expect(next.handle).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(req.body).toBe('initial');
|
|
82
|
+
});
|
|
83
|
+
it('should throw BadRequest when gzip body is invalid', async ()=>{
|
|
84
|
+
const invalidGzip = Buffer.from('this-is-not-gzip');
|
|
85
|
+
const req = {
|
|
86
|
+
headers: {
|
|
87
|
+
'content-encoding': 'gzip'
|
|
88
|
+
},
|
|
89
|
+
raw: createReadableFrom(invalidGzip)
|
|
90
|
+
};
|
|
91
|
+
const ctx = createExecutionContextWithRequest(req);
|
|
92
|
+
const next = createCallHandler();
|
|
93
|
+
await expect(interceptor.intercept(ctx, next)).rejects.toEqual(new _common.HttpException('Invalid gzip body', _common.HttpStatus.BAD_REQUEST));
|
|
94
|
+
expect(next.handle).not.toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
it('should throw BadRequest when decoded JSON is invalid', async ()=>{
|
|
97
|
+
// gzip-compressed invalid JSON (plain text)
|
|
98
|
+
const gzippedInvalidJson = _zlib.default.gzipSync(Buffer.from('not-json'));
|
|
99
|
+
const req = {
|
|
100
|
+
headers: {
|
|
101
|
+
'content-encoding': 'gzip'
|
|
102
|
+
},
|
|
103
|
+
raw: createReadableFrom(gzippedInvalidJson)
|
|
104
|
+
};
|
|
105
|
+
const ctx = createExecutionContextWithRequest(req);
|
|
106
|
+
const next = createCallHandler();
|
|
107
|
+
try {
|
|
108
|
+
await interceptor.intercept(ctx, next);
|
|
109
|
+
fail('Expected interceptor to throw for invalid JSON');
|
|
110
|
+
} catch (e) {
|
|
111
|
+
expect(e).toBeInstanceOf(_common.HttpException);
|
|
112
|
+
const ex = e;
|
|
113
|
+
expect(ex.getStatus()).toBe(_common.HttpStatus.BAD_REQUEST);
|
|
114
|
+
expect(String(ex.getResponse())).toContain('Invalid JSON');
|
|
115
|
+
expect(next.handle).not.toHaveBeenCalled();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
//# sourceMappingURL=sync-diff-gzip-body.interceptor.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/sync/interceptors/sync-diff-gzip-body.interceptor.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 { CallHandler, ExecutionContext, HttpException, HttpStatus } from '@nestjs/common'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { lastValueFrom, of } from 'rxjs'\nimport { Readable } from 'stream'\nimport zlib from 'zlib'\nimport { SyncDiffGzipBodyInterceptor } from './sync-diff-gzip-body.interceptor'\n\ndescribe('SyncDiffGzipBodyInterceptor', () => {\n let interceptor: SyncDiffGzipBodyInterceptor\n\n const createReadableFrom = (data: Buffer | string): Readable => {\n const stream = new Readable()\n stream.push(data)\n stream.push(null)\n return stream\n }\n\n const createExecutionContextWithRequest = (req: any): ExecutionContext => {\n return {\n switchToHttp: () => ({\n getRequest: () => req\n })\n } as ExecutionContext\n }\n\n const createCallHandler = <T = any>(value: T = 'ok' as unknown as T): CallHandler => {\n return {\n handle: jest.fn(() => of(value))\n }\n }\n\n beforeEach(async () => {\n const module: TestingModule = await Test.createTestingModule({\n providers: [SyncDiffGzipBodyInterceptor]\n }).compile()\n\n interceptor = module.get(SyncDiffGzipBodyInterceptor)\n })\n\n it('should gunzip and parse JSON body when Content-Encoding is gzip', async () => {\n const originalBody = { a: 1, b: 'two' }\n const gzipped = zlib.gzipSync(Buffer.from(JSON.stringify(originalBody)))\n const req: any = {\n headers: { 'content-encoding': 'gzip' },\n raw: createReadableFrom(gzipped),\n body: undefined\n }\n const ctx = createExecutionContextWithRequest(req)\n const next = createCallHandler('handled')\n\n const result$ = await interceptor.intercept(ctx, next)\n const result = await lastValueFrom(result$)\n\n expect(result).toBe('handled')\n expect(next.handle).toHaveBeenCalledTimes(1)\n expect(req.body).toEqual(originalBody)\n })\n\n it('should pass through without modifying body when Content-Encoding is not gzip', async () => {\n const req: any = {\n headers: {},\n raw: createReadableFrom(Buffer.from('no use in this case')),\n body: 'initial'\n }\n const ctx = createExecutionContextWithRequest(req)\n const next = createCallHandler('passthrough')\n\n const result$ = await interceptor.intercept(ctx, next)\n const result = await lastValueFrom(result$)\n\n expect(result).toBe('passthrough')\n expect(next.handle).toHaveBeenCalledTimes(1)\n expect(req.body).toBe('initial')\n })\n\n it('should throw BadRequest when gzip body is invalid', async () => {\n const invalidGzip = Buffer.from('this-is-not-gzip')\n const req: any = {\n headers: { 'content-encoding': 'gzip' },\n raw: createReadableFrom(invalidGzip)\n }\n const ctx = createExecutionContextWithRequest(req)\n const next = createCallHandler()\n\n await expect(interceptor.intercept(ctx, next)).rejects.toEqual(new HttpException('Invalid gzip body', HttpStatus.BAD_REQUEST))\n expect(next.handle).not.toHaveBeenCalled()\n })\n\n it('should throw BadRequest when decoded JSON is invalid', async () => {\n // gzip-compressed invalid JSON (plain text)\n const gzippedInvalidJson = zlib.gzipSync(Buffer.from('not-json'))\n const req: any = {\n headers: { 'content-encoding': 'gzip' },\n raw: createReadableFrom(gzippedInvalidJson)\n }\n const ctx = createExecutionContextWithRequest(req)\n const next = createCallHandler()\n\n try {\n await interceptor.intercept(ctx, next)\n fail('Expected interceptor to throw for invalid JSON')\n } catch (e) {\n expect(e).toBeInstanceOf(HttpException)\n const ex = e as HttpException\n expect(ex.getStatus()).toBe(HttpStatus.BAD_REQUEST)\n expect(String(ex.getResponse())).toContain('Invalid JSON')\n expect(next.handle).not.toHaveBeenCalled()\n }\n })\n})\n"],"names":["describe","interceptor","createReadableFrom","data","stream","Readable","push","createExecutionContextWithRequest","req","switchToHttp","getRequest","createCallHandler","value","handle","jest","fn","of","beforeEach","module","Test","createTestingModule","providers","SyncDiffGzipBodyInterceptor","compile","get","it","originalBody","a","b","gzipped","zlib","gzipSync","Buffer","from","JSON","stringify","headers","raw","body","undefined","ctx","next","result$","intercept","result","lastValueFrom","expect","toBe","toHaveBeenCalledTimes","toEqual","invalidGzip","rejects","HttpException","HttpStatus","BAD_REQUEST","not","toHaveBeenCalled","gzippedInvalidJson","fail","e","toBeInstanceOf","ex","getStatus","String","getResponse","toContain"],"mappings":"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"}
|