@sync-in/server 1.5.2 → 1.6.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 +28 -0
- package/README.md +2 -1
- package/environment/environment.dist.min.yaml +1 -0
- package/environment/environment.dist.yaml +88 -30
- package/migrations/0002_sleepy_korath.sql +1 -0
- package/migrations/meta/0002_snapshot.json +2424 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +14 -12
- package/server/app.bootstrap.js +1 -1
- package/server/app.bootstrap.js.map +1 -1
- package/server/applications/files/services/files-manager.service.js +1 -2
- package/server/applications/files/services/files-manager.service.js.map +1 -1
- package/server/applications/files/services/files-only-office-manager.service.js +5 -6
- package/server/applications/files/services/files-only-office-manager.service.js.map +1 -1
- package/server/applications/files/utils/files.js +6 -4
- package/server/applications/files/utils/files.js.map +1 -1
- package/server/applications/links/links.controller.js +2 -2
- package/server/applications/links/links.controller.js.map +1 -1
- package/server/applications/links/services/links-manager.service.js +2 -1
- package/server/applications/links/services/links-manager.service.js.map +1 -1
- package/server/applications/links/services/links-manager.service.spec.js +6 -3
- package/server/applications/links/services/links-manager.service.spec.js.map +1 -1
- package/server/applications/notifications/constants/notifications.js +9 -0
- package/server/applications/notifications/constants/notifications.js.map +1 -1
- package/server/applications/notifications/i18n/fr.js +10 -1
- package/server/applications/notifications/i18n/fr.js.map +1 -1
- package/server/applications/notifications/interfaces/notification-properties.interface.js.map +1 -1
- package/server/applications/notifications/mails/models.js +41 -3
- package/server/applications/notifications/mails/models.js.map +1 -1
- package/server/applications/notifications/mails/templates.js +1 -1
- package/server/applications/notifications/mails/templates.js.map +1 -1
- package/server/applications/notifications/schemas/notifications.schema.js +2 -1
- package/server/applications/notifications/schemas/notifications.schema.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.js +16 -13
- package/server/applications/notifications/services/notifications-manager.service.js.map +1 -1
- package/server/applications/notifications/services/notifications-manager.service.spec.js +9 -8
- package/server/applications/notifications/services/notifications-manager.service.spec.js.map +1 -1
- package/server/applications/notifications/services/notifications-queries.service.js +1 -1
- package/server/applications/notifications/services/notifications-queries.service.js.map +1 -1
- package/server/applications/shares/services/shares-manager.service.js +3 -2
- package/server/applications/shares/services/shares-manager.service.js.map +1 -1
- package/server/applications/sync/constants/auth.js +2 -2
- package/server/applications/sync/constants/auth.js.map +1 -1
- package/server/applications/sync/dtos/sync-client-registration.dto.js +5 -0
- package/server/applications/sync/dtos/sync-client-registration.dto.js.map +1 -1
- package/server/applications/sync/dtos/sync-operations.dto.js +1 -2
- package/server/applications/sync/dtos/sync-operations.dto.js.map +1 -1
- package/server/applications/sync/schemas/sync-clients.schema.js +2 -1
- package/server/applications/sync/schemas/sync-clients.schema.js.map +1 -1
- package/server/applications/sync/schemas/sync-paths.schema.js +2 -1
- package/server/applications/sync/schemas/sync-paths.schema.js.map +1 -1
- package/server/applications/sync/services/sync-clients-manager.service.js +28 -20
- package/server/applications/sync/services/sync-clients-manager.service.js.map +1 -1
- package/server/applications/sync/services/sync-clients-manager.service.spec.js +24 -18
- package/server/applications/sync/services/sync-clients-manager.service.spec.js.map +1 -1
- package/server/applications/sync/services/sync-queries.service.js +5 -5
- package/server/applications/sync/services/sync-queries.service.js.map +1 -1
- package/server/applications/users/admin-users.controller.js +48 -37
- package/server/applications/users/admin-users.controller.js.map +1 -1
- package/server/applications/users/admin-users.controller.spec.js +15 -0
- package/server/applications/users/admin-users.controller.spec.js.map +1 -1
- package/server/applications/users/constants/routes.js +5 -0
- package/server/applications/users/constants/routes.js.map +1 -1
- package/server/applications/users/constants/user.js +8 -0
- package/server/applications/users/constants/user.js.map +1 -1
- package/server/applications/users/dto/delete-user.dto.js +5 -23
- package/server/applications/users/dto/delete-user.dto.js.map +1 -1
- package/server/applications/users/dto/user-properties.dto.js +38 -3
- package/server/applications/users/dto/user-properties.dto.js.map +1 -1
- package/server/applications/users/interfaces/admin-user.interface.js.map +1 -1
- package/server/applications/users/interfaces/user-secrets.interface.js +10 -0
- package/server/applications/users/interfaces/user-secrets.interface.js.map +1 -0
- package/server/applications/users/models/user.model.js +84 -50
- package/server/applications/users/models/user.model.js.map +1 -1
- package/server/applications/users/schemas/user.interface.js.map +1 -1
- package/server/applications/users/schemas/users.schema.js +2 -0
- package/server/applications/users/schemas/users.schema.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.js +7 -19
- package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
- package/server/applications/users/services/admin-users-manager.service.spec.js +7 -26
- package/server/applications/users/services/admin-users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/admin-users-queries.service.js +1 -0
- package/server/applications/users/services/admin-users-queries.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.js +138 -28
- package/server/applications/users/services/users-manager.service.js.map +1 -1
- package/server/applications/users/services/users-manager.service.spec.js +11 -9
- package/server/applications/users/services/users-manager.service.spec.js.map +1 -1
- package/server/applications/users/services/users-queries.service.js +63 -57
- package/server/applications/users/services/users-queries.service.js.map +1 -1
- package/server/applications/users/users.controller.js +48 -1
- package/server/applications/users/users.controller.js.map +1 -1
- package/server/applications/users/users.controller.spec.js +8 -1
- package/server/applications/users/users.controller.spec.js.map +1 -1
- package/server/applications/users/users.e2e-spec.js +2 -1
- package/server/applications/users/users.e2e-spec.js.map +1 -1
- package/server/applications/users/utils/avatar.js +48 -0
- package/server/applications/users/utils/avatar.js.map +1 -0
- package/server/authentication/auth.config.js +89 -26
- package/server/authentication/auth.config.js.map +1 -1
- package/server/authentication/auth.controller.js +117 -9
- package/server/authentication/auth.controller.js.map +1 -1
- package/server/authentication/auth.controller.spec.js +16 -1
- package/server/authentication/auth.controller.spec.js.map +1 -1
- package/server/authentication/auth.e2e-spec.js +4 -3
- package/server/authentication/auth.e2e-spec.js.map +1 -1
- package/server/authentication/auth.module.js +4 -1
- package/server/authentication/auth.module.js.map +1 -1
- package/server/authentication/constants/auth-ldap.js +44 -0
- package/server/authentication/constants/auth-ldap.js.map +1 -0
- package/server/authentication/constants/auth.js +37 -4
- package/server/authentication/constants/auth.js.map +1 -1
- package/server/authentication/constants/routes.js +21 -0
- package/server/authentication/constants/routes.js.map +1 -1
- package/server/authentication/constants/scope.js +20 -0
- package/server/authentication/constants/scope.js.map +1 -0
- package/server/authentication/dto/login-response.dto.js +27 -4
- package/server/authentication/dto/login-response.dto.js.map +1 -1
- package/server/authentication/dto/token-response.dto.js +5 -0
- package/server/authentication/dto/token-response.dto.js.map +1 -1
- package/server/{applications/users/dto/user-password.dto.js → authentication/dto/two-fa-verify.dto.js} +27 -9
- package/server/authentication/dto/two-fa-verify.dto.js.map +1 -0
- package/server/authentication/guards/auth-basic.strategy.js +6 -5
- package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
- package/server/authentication/guards/auth-token-access.strategy.js +3 -2
- package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
- package/server/authentication/guards/auth-token-refresh.strategy.js +3 -2
- package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
- package/server/authentication/guards/auth-two-fa-guard.js +81 -0
- package/server/authentication/guards/auth-two-fa-guard.js.map +1 -0
- package/server/authentication/interfaces/jwt-payload.interface.js +5 -0
- package/server/authentication/interfaces/jwt-payload.interface.js.map +1 -1
- package/server/authentication/interfaces/token.interface.js +2 -0
- package/server/authentication/interfaces/token.interface.js.map +1 -1
- package/server/authentication/interfaces/two-fa-setup.interface.js +10 -0
- package/server/authentication/interfaces/two-fa-setup.interface.js.map +1 -0
- package/server/authentication/models/auth-method.js.map +1 -1
- package/server/authentication/services/auth-manager.service.js +72 -49
- package/server/authentication/services/auth-manager.service.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-database.service.js +3 -3
- package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +5 -0
- package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-ldap.service.js +151 -66
- package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +52 -50
- package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.js +251 -0
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.js.map +1 -0
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js +41 -0
- package/server/authentication/services/auth-methods/auth-method-two-fa.service.spec.js.map +1 -0
- package/server/authentication/utils/crypt-secret.js +68 -0
- package/server/authentication/utils/crypt-secret.js.map +1 -0
- package/server/common/functions.js +18 -2
- package/server/common/functions.js.map +1 -1
- package/server/common/qrcode.js +34 -0
- package/server/common/qrcode.js.map +1 -0
- package/server/common/shared.js +18 -0
- package/server/common/shared.js.map +1 -1
- package/server/configuration/config.environment.js +23 -6
- package/server/configuration/config.environment.js.map +1 -1
- package/server/configuration/config.interfaces.js +10 -0
- package/server/configuration/config.interfaces.js.map +1 -0
- package/server/configuration/config.loader.js.map +1 -1
- package/server/configuration/config.validation.js +13 -13
- package/server/configuration/config.validation.js.map +1 -1
- package/server/infrastructure/cache/adapters/mysql-cache.adapter.js +6 -6
- package/server/infrastructure/cache/adapters/mysql-cache.adapter.js.map +1 -1
- package/server/infrastructure/cache/schemas/mysql-cache.schema.js +2 -1
- package/server/infrastructure/cache/schemas/mysql-cache.schema.js.map +1 -1
- package/server/infrastructure/cache/services/cache.service.js.map +1 -1
- package/server/infrastructure/database/columns.js +39 -0
- package/server/infrastructure/database/columns.js.map +1 -0
- package/server/infrastructure/database/database.config.js +0 -1
- package/server/infrastructure/database/database.config.js.map +1 -1
- package/server/infrastructure/mailer/interfaces/mail.interface.js.map +1 -1
- package/server/infrastructure/mailer/mailer.config.js +12 -0
- package/server/infrastructure/mailer/mailer.config.js.map +1 -1
- package/server/infrastructure/mailer/mailer.service.js +2 -1
- package/server/infrastructure/mailer/mailer.service.js.map +1 -1
- package/static/assets/mimes/text-x-c.svg +1 -0
- package/static/assets/pdfjs/build/pdf.mjs +2522 -914
- package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
- package/static/assets/pdfjs/build/pdf.sandbox.mjs +2 -2
- package/static/assets/pdfjs/build/pdf.worker.mjs +1024 -566
- package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
- package/static/assets/pdfjs/version +1 -1
- package/static/assets/pdfjs/web/debugger.mjs +116 -37
- package/static/assets/pdfjs/web/images/comment-popup-editButton.svg +5 -0
- package/static/assets/pdfjs/web/locale/ach/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/af/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/an/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/ar/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/ast/viewer.ftl +0 -19
- package/static/assets/pdfjs/web/locale/az/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/be/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/bg/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/bn/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/bo/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/br/viewer.ftl +0 -22
- package/static/assets/pdfjs/web/locale/brx/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/ca/viewer.ftl +12 -23
- package/static/assets/pdfjs/web/locale/cak/viewer.ftl +0 -23
- package/static/assets/pdfjs/web/locale/ckb/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/cs/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/cy/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/da/viewer.ftl +3 -35
- package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/el/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/en-US/viewer.ftl +25 -13
- package/static/assets/pdfjs/web/locale/eo/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +5 -32
- package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/et/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/eu/viewer.ftl +38 -32
- package/static/assets/pdfjs/web/locale/fa/viewer.ftl +0 -19
- package/static/assets/pdfjs/web/locale/ff/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/ga-IE/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/gd/viewer.ftl +0 -23
- package/static/assets/pdfjs/web/locale/gl/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/gn/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/gu-IN/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/hi-IN/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/hr/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +372 -16
- package/static/assets/pdfjs/web/locale/hye/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/id/viewer.ftl +38 -32
- package/static/assets/pdfjs/web/locale/is/viewer.ftl +27 -32
- package/static/assets/pdfjs/web/locale/it/viewer.ftl +0 -33
- package/static/assets/pdfjs/web/locale/ja/viewer.ftl +31 -33
- package/static/assets/pdfjs/web/locale/ka/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/kk/viewer.ftl +31 -32
- package/static/assets/pdfjs/web/locale/km/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/kn/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/lij/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/lo/viewer.ftl +0 -23
- package/static/assets/pdfjs/web/locale/lt/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/ltg/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/lv/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/meh/viewer.ftl +0 -14
- package/static/assets/pdfjs/web/locale/mk/viewer.ftl +0 -19
- package/static/assets/pdfjs/web/locale/ml/viewer.ftl +0 -31
- package/static/assets/pdfjs/web/locale/mr/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/ms/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/my/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/ne-NP/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/oc/viewer.ftl +0 -24
- package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/pl/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/pt-PT/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/ro/viewer.ftl +5 -37
- package/static/assets/pdfjs/web/locale/ru/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/sat/viewer.ftl +0 -23
- package/static/assets/pdfjs/web/locale/sc/viewer.ftl +8 -27
- package/static/assets/pdfjs/web/locale/sco/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/si/viewer.ftl +0 -22
- package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/skr/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/sl/viewer.ftl +30 -32
- package/static/assets/pdfjs/web/locale/son/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/sq/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/sr/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/szl/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/ta/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/te/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/tg/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/th/viewer.ftl +38 -32
- package/static/assets/pdfjs/web/locale/tl/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/tr/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/trs/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/uk/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/ur/viewer.ftl +0 -16
- package/static/assets/pdfjs/web/locale/uz/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/xh/viewer.ftl +0 -12
- package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -32
- package/static/assets/pdfjs/web/viewer.css +586 -437
- package/static/assets/pdfjs/web/viewer.html +12 -23
- package/static/assets/pdfjs/web/viewer.mjs +955 -514
- package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
- package/static/assets/pdfjs/web/wasm/openjpeg.wasm +0 -0
- package/static/assets/pdfjs/web/wasm/openjpeg_nowasm_fallback.js +10 -22
- package/static/{chunk-SPTF6FSM.js → chunk-27YQB3TE.js} +1 -1
- package/static/chunk-2I4CUFUA.js +1 -0
- package/static/chunk-2MTM6SWN.js +4 -0
- package/static/{chunk-7VRUZRJG.js → chunk-34MKICK5.js} +2 -2
- package/static/chunk-5O3DIUU3.js +1 -0
- package/static/{chunk-VJRTMDEJ.js → chunk-6NMVZIIT.js} +1 -1
- package/static/{chunk-L6MU6S2V.js → chunk-7DN7ZAPU.js} +1 -1
- package/static/{chunk-MVO4WZLK.js → chunk-7FUM3JGM.js} +1 -1
- package/static/{chunk-RSS6GYNE.js → chunk-7ITZXYYJ.js} +1 -1
- package/static/chunk-7P27WBGC.js +4 -0
- package/static/chunk-ATP3BFHV.js +562 -0
- package/static/chunk-AWQ2YTVC.js +1 -0
- package/static/chunk-DSOE3FEP.js +1 -0
- package/static/{chunk-2R6HHGUR.js → chunk-EFKMBLRE.js} +1 -1
- package/static/chunk-FUFKVHPU.js +1 -0
- package/static/{chunk-MRSWNAVB.js → chunk-HCDLWTMW.js} +1 -1
- package/static/chunk-IPAC4VAF.js +1 -0
- package/static/{chunk-ZC5NIT55.js → chunk-IQOALFYU.js} +1 -1
- package/static/chunk-JASU3CIH.js +1 -0
- package/static/{chunk-6OJZWYRZ.js → chunk-JQ5FTO2M.js} +1 -1
- package/static/chunk-JUNZFADM.js +1 -0
- package/static/{chunk-LLWSLOSX.js → chunk-LJUKI4SQ.js} +1 -1
- package/static/{chunk-WI7FOANP.js → chunk-LUWQFIWR.js} +1 -1
- package/static/{chunk-BIUNUYZ5.js → chunk-ORMRCEGT.js} +1 -1
- package/static/{chunk-IZL7JPTS.js → chunk-Q7D6RN4N.js} +1 -1
- package/static/{chunk-JYXLQRHG.js → chunk-QJX6ITLW.js} +1 -1
- package/static/{chunk-YJMN3B4N.js → chunk-QQ6UQQBR.js} +1 -1
- package/static/chunk-S2HDY3OL.js +1 -0
- package/static/{chunk-NE4NDO45.js → chunk-S75P2FFI.js} +1 -1
- package/static/{chunk-CRQNEHTX.js → chunk-T3EYFSVZ.js} +1 -1
- package/static/{chunk-MCLQFZ3S.js → chunk-U34OZUZ7.js} +1 -1
- package/static/chunk-Y7EH7G5K.js +1 -0
- package/static/{chunk-MGGT6MIJ.js → chunk-ZQQPUYLU.js} +1 -1
- package/static/index.html +2 -2
- package/static/main-7SQDDVMD.js +9 -0
- package/static/{styles-FYUSO6OJ.css → styles-A5VYX3CE.css} +1 -1
- package/server/applications/users/dto/user-password.dto.js.map +0 -1
- package/static/chunk-4U5A2DEP.js +0 -4
- package/static/chunk-54EAZ2UD.js +0 -1
- package/static/chunk-7ZRXJONB.js +0 -1
- package/static/chunk-F2J2IIJE.js +0 -1
- package/static/chunk-FNFGUIQH.js +0 -4
- package/static/chunk-GGLK52CG.js +0 -1
- package/static/chunk-HW2H3ISM.js +0 -559
- package/static/chunk-HX6BBYVD.js +0 -1
- package/static/chunk-JF7S3UYQ.js +0 -1
- package/static/chunk-KSHPKI4G.js +0 -1
- package/static/chunk-VPJ2V27B.js +0 -1
- package/static/chunk-VUI3KV7V.js +0 -1
- package/static/chunk-ZXS4V7J2.js +0 -1
- package/static/main-FFIWFD2F.js +0 -7
|
@@ -225,18 +225,20 @@ function touchFile(rPath, mtime) {
|
|
|
225
225
|
if (!mtime) mtime = (0, _shared.currentTimeStamp)();
|
|
226
226
|
return _promises.default.utimes(rPath, mtime, mtime);
|
|
227
227
|
}
|
|
228
|
-
async function copyFiles(srcPath, dstPath, overwrite = false, recursive = true) {
|
|
228
|
+
async function copyFiles(srcPath, dstPath, overwrite = false, recursive = true, preserveTimestamps = true) {
|
|
229
229
|
/*
|
|
230
230
|
If src is a directory it will copy everything inside of this directory, not the entire directory itself
|
|
231
231
|
If src is a file, dest cannot be a directory
|
|
232
232
|
*/ if (!recursive && await isPathIsDir(srcPath)) {
|
|
233
|
-
const stat = await _promises.default.stat(srcPath);
|
|
234
233
|
await _promises.default.mkdir(dstPath);
|
|
235
|
-
|
|
234
|
+
if (preserveTimestamps) {
|
|
235
|
+
const stat = await _promises.default.stat(srcPath);
|
|
236
|
+
await _promises.default.utimes(dstPath, stat.atime, stat.mtime);
|
|
237
|
+
}
|
|
236
238
|
} else {
|
|
237
239
|
await _fsextra.default.copy(srcPath, dstPath, {
|
|
238
240
|
overwrite,
|
|
239
|
-
preserveTimestamps:
|
|
241
|
+
preserveTimestamps: preserveTimestamps
|
|
240
242
|
});
|
|
241
243
|
}
|
|
242
244
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/files/utils/files.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 { HttpStatus } from '@nestjs/common'\nimport { WriteStream } from 'fs'\nimport fse from 'fs-extra'\nimport mime from 'mime-types'\nimport crypto from 'node:crypto'\nimport { createReadStream, createWriteStream, Dirent, statSync } from 'node:fs'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { formatDateISOString } from '../../../common/functions'\nimport { currentTimeStamp, isValidFileName, regExpPreventPathTraversal } from '../../../common/shared'\nimport { DEFAULT_HIGH_WATER_MARK, EXTRA_MIMES_TYPE } from '../constants/files'\nimport type { FileProps } from '../interfaces/file-props.interface'\nimport { FileError } from '../models/file-error'\n\nexport function sanitizePath(fPath: string): string {\n return path.normalize(fPath).replace(regExpPreventPathTraversal, '')\n}\n\nexport function sanitizeName(name: string): string {\n return name\n .replace(/^\\s+|[. ]+$/g, '') // trimStart + trimEnd + strip trailing dots\n .replace(/[/\\\\]/g, '') // remove slashes\n .replace(/\\.\\./g, '') // remove '..'\n}\n\nexport function checkFileName(fPath: string): string {\n const fName = fileName(fPath)\n try {\n isValidFileName(fName)\n return fName\n } catch {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Forbidden characters')\n }\n}\n\nexport function isPathExists(rPath: string): Promise<boolean> {\n return fse.pathExists(rPath)\n}\n\nexport async function isPathIsReadable(rPath: string): Promise<boolean> {\n try {\n await fs.access(rPath, fs.constants.R_OK)\n } catch {\n return false\n }\n return true\n}\n\nexport async function isPathIsWriteable(rPath: string): Promise<boolean> {\n try {\n await fs.access(rPath, fs.constants.W_OK)\n } catch {\n return false\n }\n return true\n}\n\nexport async function isPathIsDir(rPath: string): Promise<boolean> {\n return (await fs.stat(rPath)).isDirectory()\n}\n\nexport function fileName(fPath: string): string {\n return path.posix.basename(fPath)\n}\n\nexport function dirName(fPath: string): string {\n return path.dirname(fPath)\n}\n\nexport async function fileSize(rPath: string): Promise<number> {\n return (await fs.stat(rPath)).size\n}\n\nexport function createEmptyFile(rPath: string): Promise<void> {\n return fs.writeFile(rPath, '')\n}\n\nexport function makeDir(rPath: string, recursive?: boolean): Promise<string> {\n return fs.mkdir(rPath, { recursive: recursive })\n}\n\nexport function getMimeType(fPath: string, isDir: boolean): string {\n if (isDir) {\n return 'directory'\n }\n const extName: string = path.extname(fPath)\n if (EXTRA_MIMES_TYPE.has(extName)) {\n return EXTRA_MIMES_TYPE.get(extName)\n }\n const m = mime.lookup(extName)\n if (m) {\n return m.replace('/', '-')\n }\n return 'file'\n}\n\nexport function genEtag(file?: Pick<FileProps, 'size' | 'mtime'>, rPath?: string): string {\n if (!file) {\n if (!rPath) throw new Error('File or path are missing')\n const stats = statSync(rPath)\n file = { size: stats.size, mtime: stats.mtime.getTime() }\n }\n return `W/\"${file.size.toString(16)}-${file.mtime.toString(16)}\"`\n}\n\nexport function removeFiles(rPath: string): Promise<void> {\n // if the file does not exist, no error is thrown\n return fse.remove(rPath)\n}\n\nexport async function getProps(rPath: string, fPath?: string, isDir?: boolean): Promise<FileProps> {\n const stats = await fs.stat(rPath)\n const isDirectory = isDir === undefined ? stats.isDirectory() : isDir\n return {\n id: -stats.ino, // use negative number to avoid conflicts with existing database ids\n path: dirName(fPath !== undefined ? fPath : rPath),\n name: fileName(fPath !== undefined ? fPath : rPath),\n isDir: isDirectory,\n size: isDirectory ? 0 : stats.size,\n ctime: stats.birthtime.getTime(),\n mtime: stats.mtime.getTime(),\n mime: getMimeType(rPath, isDirectory)\n }\n}\n\nexport function touchFile(rPath: string, mtime?: number): Promise<void> {\n if (!mtime) mtime = currentTimeStamp()\n return fs.utimes(rPath, mtime, mtime)\n}\n\nexport async function copyFiles(srcPath: string, dstPath: string, overwrite = false, recursive = true): Promise<void> {\n /*\n If src is a directory it will copy everything inside of this directory, not the entire directory itself\n If src is a file, dest cannot be a directory\n */\n if (!recursive && (await isPathIsDir(srcPath))) {\n const stat = await fs.stat(srcPath)\n await fs.mkdir(dstPath)\n await fs.utimes(dstPath, stat.atime, stat.mtime)\n } else {\n await fse.copy(srcPath, dstPath, { overwrite, preserveTimestamps: true })\n }\n}\n\nexport function moveFiles(srcPath: string, dstPath: string, overwrite = false): Promise<void> {\n /*\n If src is a file, dest must be a file and when src is a directory, dest must be a directory\n */\n return fse.move(srcPath, dstPath, { overwrite })\n}\n\nexport async function checksumFile(filePath: string, alg: string): Promise<string> {\n const hash = crypto.createHash(alg)\n const stream = createReadStream(filePath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n await pipeline(stream, hash)\n return hash.digest('hex')\n}\n\nexport function writeFromStream(rPath: string, stream: Readable, start: number = 0): Promise<void> {\n const dst: WriteStream = createWriteStream(rPath, { flags: start ? 'a' : 'w', start: start, highWaterMark: DEFAULT_HIGH_WATER_MARK })\n return pipeline(stream, dst)\n}\n\nexport async function writeFromStreamAndChecksum(rPath: string, stream: Readable, hasRange: number, alg: string): Promise<string> {\n const hash = crypto.createHash(alg)\n if (hasRange) {\n const src = createReadStream(rPath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n await pipeline(src, hash, { end: false })\n }\n const dst = createWriteStream(rPath, { flags: hasRange ? 'a' : 'w', highWaterMark: DEFAULT_HIGH_WATER_MARK })\n await pipeline(\n stream,\n async function* (source) {\n for await (const chunk of source) {\n hash.update(chunk)\n yield chunk\n }\n },\n dst\n )\n hash.end()\n return hash.digest('hex')\n}\n\nexport function copyFileContent(srcPath: string, dstPath: string): Promise<void> {\n const srcStream = createReadStream(srcPath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n return writeFromStream(dstPath, srcStream)\n}\n\nexport async function dirSize(rPath: string): Promise<[number, any]> {\n let size = 0\n const errors: Record<string, string> = {}\n for (const f of await fs.readdir(rPath, { withFileTypes: true, recursive: true })) {\n if (f.isFile()) {\n const p = path.join(f.parentPath, f.name)\n try {\n size += (await fs.stat(p)).size\n } catch (e: any) {\n errors[p] = e.message\n }\n }\n }\n return [size, errors]\n}\n\nexport async function dirListFileNames(rPath: string): Promise<string[]> {\n return (await fs.readdir(rPath)).map((path: string) => fileName(path))\n}\n\nexport async function countDirEntries(rPath: string): Promise<{ files: number; directories: number }> {\n return (await fs.readdir(rPath, { withFileTypes: true, recursive: true })).reduce(\n (acc, f: Dirent) => {\n if (f.isDirectory()) {\n acc.directories++\n } else {\n acc.files++\n }\n return acc\n },\n { files: 0, directories: 0 }\n )\n}\n\nexport async function dirHasChildren(rPath: string, mustContainsDirs = true): Promise<boolean> {\n for await (const file of await fs.opendir(rPath)) {\n if (mustContainsDirs) {\n if (file.isDirectory()) return true\n } else {\n return true\n }\n }\n return false\n}\n\nexport async function uniqueFilePathFromDir(rPath: string): Promise<string> {\n if (await isPathExists(rPath)) {\n const parentDir = path.dirname(rPath)\n const extension = path.extname(rPath)\n const nameWithoutExtension = path.basename(rPath, extension)\n let count = 1\n while (await isPathExists(path.join(parentDir, `${nameWithoutExtension} (${count})${extension}`))) {\n count++\n }\n return path.join(parentDir, `${nameWithoutExtension} (${count})${extension}`)\n }\n return rPath\n}\n\nexport async function uniqueDatedFilePath(rPath: string): Promise<{ isDir: boolean; path: string }> {\n const date = formatDateISOString(new Date())\n if (await isPathIsDir(rPath)) {\n return { isDir: true, path: `${rPath}-${date}` }\n } else {\n const extension = path.extname(rPath)\n const nameWithoutExtension = path.basename(rPath, extension)\n return { isDir: true, path: path.join(path.dirname(rPath), `${nameWithoutExtension}-${date}${extension}`) }\n }\n}\n\nexport async function checkExternalPath(rPath: string) {\n if (!(await isPathExists(rPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'The location does not exist')\n }\n if (!(await isPathIsReadable(rPath))) {\n throw new FileError(HttpStatus.NOT_ACCEPTABLE, 'The location is not readable')\n }\n if (!(await isPathIsWriteable(rPath))) {\n throw new FileError(HttpStatus.NOT_ACCEPTABLE, 'The location is not writeable')\n }\n}\n"],"names":["checkExternalPath","checkFileName","checksumFile","copyFileContent","copyFiles","countDirEntries","createEmptyFile","dirHasChildren","dirListFileNames","dirName","dirSize","fileName","fileSize","genEtag","getMimeType","getProps","isPathExists","isPathIsDir","isPathIsReadable","isPathIsWriteable","makeDir","moveFiles","removeFiles","sanitizeName","sanitizePath","touchFile","uniqueDatedFilePath","uniqueFilePathFromDir","writeFromStream","writeFromStreamAndChecksum","fPath","path","normalize","replace","regExpPreventPathTraversal","name","fName","isValidFileName","FileError","HttpStatus","BAD_REQUEST","rPath","fse","pathExists","fs","access","constants","R_OK","W_OK","stat","isDirectory","posix","basename","dirname","size","writeFile","recursive","mkdir","isDir","extName","extname","EXTRA_MIMES_TYPE","has","get","m","mime","lookup","file","Error","stats","statSync","mtime","getTime","toString","remove","undefined","id","ino","ctime","birthtime","currentTimeStamp","utimes","srcPath","dstPath","overwrite","atime","copy","preserveTimestamps","move","filePath","alg","hash","crypto","createHash","stream","createReadStream","highWaterMark","DEFAULT_HIGH_WATER_MARK","pipeline","digest","start","dst","createWriteStream","flags","hasRange","src","end","source","chunk","update","srcStream","errors","f","readdir","withFileTypes","isFile","p","join","parentPath","e","message","map","reduce","acc","directories","files","mustContainsDirs","opendir","parentDir","extension","nameWithoutExtension","count","date","formatDateISOString","Date","NOT_FOUND","NOT_ACCEPTABLE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/files/utils/files.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 { HttpStatus } from '@nestjs/common'\nimport { WriteStream } from 'fs'\nimport fse from 'fs-extra'\nimport mime from 'mime-types'\nimport crypto from 'node:crypto'\nimport { createReadStream, createWriteStream, Dirent, statSync } from 'node:fs'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { formatDateISOString } from '../../../common/functions'\nimport { currentTimeStamp, isValidFileName, regExpPreventPathTraversal } from '../../../common/shared'\nimport { DEFAULT_HIGH_WATER_MARK, EXTRA_MIMES_TYPE } from '../constants/files'\nimport type { FileProps } from '../interfaces/file-props.interface'\nimport { FileError } from '../models/file-error'\n\nexport function sanitizePath(fPath: string): string {\n return path.normalize(fPath).replace(regExpPreventPathTraversal, '')\n}\n\nexport function sanitizeName(name: string): string {\n return name\n .replace(/^\\s+|[. ]+$/g, '') // trimStart + trimEnd + strip trailing dots\n .replace(/[/\\\\]/g, '') // remove slashes\n .replace(/\\.\\./g, '') // remove '..'\n}\n\nexport function checkFileName(fPath: string): string {\n const fName = fileName(fPath)\n try {\n isValidFileName(fName)\n return fName\n } catch {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Forbidden characters')\n }\n}\n\nexport function isPathExists(rPath: string): Promise<boolean> {\n return fse.pathExists(rPath)\n}\n\nexport async function isPathIsReadable(rPath: string): Promise<boolean> {\n try {\n await fs.access(rPath, fs.constants.R_OK)\n } catch {\n return false\n }\n return true\n}\n\nexport async function isPathIsWriteable(rPath: string): Promise<boolean> {\n try {\n await fs.access(rPath, fs.constants.W_OK)\n } catch {\n return false\n }\n return true\n}\n\nexport async function isPathIsDir(rPath: string): Promise<boolean> {\n return (await fs.stat(rPath)).isDirectory()\n}\n\nexport function fileName(fPath: string): string {\n return path.posix.basename(fPath)\n}\n\nexport function dirName(fPath: string): string {\n return path.dirname(fPath)\n}\n\nexport async function fileSize(rPath: string): Promise<number> {\n return (await fs.stat(rPath)).size\n}\n\nexport function createEmptyFile(rPath: string): Promise<void> {\n return fs.writeFile(rPath, '')\n}\n\nexport function makeDir(rPath: string, recursive?: boolean): Promise<string> {\n return fs.mkdir(rPath, { recursive: recursive })\n}\n\nexport function getMimeType(fPath: string, isDir: boolean): string {\n if (isDir) {\n return 'directory'\n }\n const extName: string = path.extname(fPath)\n if (EXTRA_MIMES_TYPE.has(extName)) {\n return EXTRA_MIMES_TYPE.get(extName)\n }\n const m = mime.lookup(extName)\n if (m) {\n return m.replace('/', '-')\n }\n return 'file'\n}\n\nexport function genEtag(file?: Pick<FileProps, 'size' | 'mtime'>, rPath?: string): string {\n if (!file) {\n if (!rPath) throw new Error('File or path are missing')\n const stats = statSync(rPath)\n file = { size: stats.size, mtime: stats.mtime.getTime() }\n }\n return `W/\"${file.size.toString(16)}-${file.mtime.toString(16)}\"`\n}\n\nexport function removeFiles(rPath: string): Promise<void> {\n // if the file does not exist, no error is thrown\n return fse.remove(rPath)\n}\n\nexport async function getProps(rPath: string, fPath?: string, isDir?: boolean): Promise<FileProps> {\n const stats = await fs.stat(rPath)\n const isDirectory = isDir === undefined ? stats.isDirectory() : isDir\n return {\n id: -stats.ino, // use negative number to avoid conflicts with existing database ids\n path: dirName(fPath !== undefined ? fPath : rPath),\n name: fileName(fPath !== undefined ? fPath : rPath),\n isDir: isDirectory,\n size: isDirectory ? 0 : stats.size,\n ctime: stats.birthtime.getTime(),\n mtime: stats.mtime.getTime(),\n mime: getMimeType(rPath, isDirectory)\n }\n}\n\nexport function touchFile(rPath: string, mtime?: number): Promise<void> {\n if (!mtime) mtime = currentTimeStamp()\n return fs.utimes(rPath, mtime, mtime)\n}\n\nexport async function copyFiles(srcPath: string, dstPath: string, overwrite = false, recursive = true, preserveTimestamps = true): Promise<void> {\n /*\n If src is a directory it will copy everything inside of this directory, not the entire directory itself\n If src is a file, dest cannot be a directory\n */\n if (!recursive && (await isPathIsDir(srcPath))) {\n await fs.mkdir(dstPath)\n if (preserveTimestamps) {\n const stat = await fs.stat(srcPath)\n await fs.utimes(dstPath, stat.atime, stat.mtime)\n }\n } else {\n await fse.copy(srcPath, dstPath, { overwrite, preserveTimestamps: preserveTimestamps })\n }\n}\n\nexport function moveFiles(srcPath: string, dstPath: string, overwrite = false): Promise<void> {\n /*\n If src is a file, dest must be a file and when src is a directory, dest must be a directory\n */\n return fse.move(srcPath, dstPath, { overwrite })\n}\n\nexport async function checksumFile(filePath: string, alg: string): Promise<string> {\n const hash = crypto.createHash(alg)\n const stream = createReadStream(filePath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n await pipeline(stream, hash)\n return hash.digest('hex')\n}\n\nexport function writeFromStream(rPath: string, stream: Readable, start: number = 0): Promise<void> {\n const dst: WriteStream = createWriteStream(rPath, { flags: start ? 'a' : 'w', start: start, highWaterMark: DEFAULT_HIGH_WATER_MARK })\n return pipeline(stream, dst)\n}\n\nexport async function writeFromStreamAndChecksum(rPath: string, stream: Readable, hasRange: number, alg: string): Promise<string> {\n const hash = crypto.createHash(alg)\n if (hasRange) {\n const src = createReadStream(rPath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n await pipeline(src, hash, { end: false })\n }\n const dst = createWriteStream(rPath, { flags: hasRange ? 'a' : 'w', highWaterMark: DEFAULT_HIGH_WATER_MARK })\n await pipeline(\n stream,\n async function* (source) {\n for await (const chunk of source) {\n hash.update(chunk)\n yield chunk\n }\n },\n dst\n )\n hash.end()\n return hash.digest('hex')\n}\n\nexport function copyFileContent(srcPath: string, dstPath: string): Promise<void> {\n const srcStream = createReadStream(srcPath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n return writeFromStream(dstPath, srcStream)\n}\n\nexport async function dirSize(rPath: string): Promise<[number, any]> {\n let size = 0\n const errors: Record<string, string> = {}\n for (const f of await fs.readdir(rPath, { withFileTypes: true, recursive: true })) {\n if (f.isFile()) {\n const p = path.join(f.parentPath, f.name)\n try {\n size += (await fs.stat(p)).size\n } catch (e: any) {\n errors[p] = e.message\n }\n }\n }\n return [size, errors]\n}\n\nexport async function dirListFileNames(rPath: string): Promise<string[]> {\n return (await fs.readdir(rPath)).map((path: string) => fileName(path))\n}\n\nexport async function countDirEntries(rPath: string): Promise<{ files: number; directories: number }> {\n return (await fs.readdir(rPath, { withFileTypes: true, recursive: true })).reduce(\n (acc, f: Dirent) => {\n if (f.isDirectory()) {\n acc.directories++\n } else {\n acc.files++\n }\n return acc\n },\n { files: 0, directories: 0 }\n )\n}\n\nexport async function dirHasChildren(rPath: string, mustContainsDirs = true): Promise<boolean> {\n for await (const file of await fs.opendir(rPath)) {\n if (mustContainsDirs) {\n if (file.isDirectory()) return true\n } else {\n return true\n }\n }\n return false\n}\n\nexport async function uniqueFilePathFromDir(rPath: string): Promise<string> {\n if (await isPathExists(rPath)) {\n const parentDir = path.dirname(rPath)\n const extension = path.extname(rPath)\n const nameWithoutExtension = path.basename(rPath, extension)\n let count = 1\n while (await isPathExists(path.join(parentDir, `${nameWithoutExtension} (${count})${extension}`))) {\n count++\n }\n return path.join(parentDir, `${nameWithoutExtension} (${count})${extension}`)\n }\n return rPath\n}\n\nexport async function uniqueDatedFilePath(rPath: string): Promise<{ isDir: boolean; path: string }> {\n const date = formatDateISOString(new Date())\n if (await isPathIsDir(rPath)) {\n return { isDir: true, path: `${rPath}-${date}` }\n } else {\n const extension = path.extname(rPath)\n const nameWithoutExtension = path.basename(rPath, extension)\n return { isDir: true, path: path.join(path.dirname(rPath), `${nameWithoutExtension}-${date}${extension}`) }\n }\n}\n\nexport async function checkExternalPath(rPath: string) {\n if (!(await isPathExists(rPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'The location does not exist')\n }\n if (!(await isPathIsReadable(rPath))) {\n throw new FileError(HttpStatus.NOT_ACCEPTABLE, 'The location is not readable')\n }\n if (!(await isPathIsWriteable(rPath))) {\n throw new FileError(HttpStatus.NOT_ACCEPTABLE, 'The location is not writeable')\n }\n}\n"],"names":["checkExternalPath","checkFileName","checksumFile","copyFileContent","copyFiles","countDirEntries","createEmptyFile","dirHasChildren","dirListFileNames","dirName","dirSize","fileName","fileSize","genEtag","getMimeType","getProps","isPathExists","isPathIsDir","isPathIsReadable","isPathIsWriteable","makeDir","moveFiles","removeFiles","sanitizeName","sanitizePath","touchFile","uniqueDatedFilePath","uniqueFilePathFromDir","writeFromStream","writeFromStreamAndChecksum","fPath","path","normalize","replace","regExpPreventPathTraversal","name","fName","isValidFileName","FileError","HttpStatus","BAD_REQUEST","rPath","fse","pathExists","fs","access","constants","R_OK","W_OK","stat","isDirectory","posix","basename","dirname","size","writeFile","recursive","mkdir","isDir","extName","extname","EXTRA_MIMES_TYPE","has","get","m","mime","lookup","file","Error","stats","statSync","mtime","getTime","toString","remove","undefined","id","ino","ctime","birthtime","currentTimeStamp","utimes","srcPath","dstPath","overwrite","preserveTimestamps","atime","copy","move","filePath","alg","hash","crypto","createHash","stream","createReadStream","highWaterMark","DEFAULT_HIGH_WATER_MARK","pipeline","digest","start","dst","createWriteStream","flags","hasRange","src","end","source","chunk","update","srcStream","errors","f","readdir","withFileTypes","isFile","p","join","parentPath","e","message","map","reduce","acc","directories","files","mustContainsDirs","opendir","parentDir","extension","nameWithoutExtension","count","date","formatDateISOString","Date","NOT_FOUND","NOT_ACCEPTABLE"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ const _common = require("@nestjs/common");
|
|
|
16
16
|
const _fastify = require("fastify");
|
|
17
17
|
const _authtokenoptionaldecorator = require("../../authentication/decorators/auth-token-optional.decorator");
|
|
18
18
|
const _userdecorator = require("../users/decorators/user.decorator");
|
|
19
|
-
const
|
|
19
|
+
const _userpropertiesdto = require("../users/dto/user-properties.dto");
|
|
20
20
|
const _usermodel = require("../users/models/user.model");
|
|
21
21
|
const _routes = require("./constants/routes");
|
|
22
22
|
const _linksmanagerservice = require("./services/links-manager.service");
|
|
@@ -89,7 +89,7 @@ _ts_decorate([
|
|
|
89
89
|
_ts_metadata("design:paramtypes", [
|
|
90
90
|
typeof _usermodel.UserModel === "undefined" ? Object : _usermodel.UserModel,
|
|
91
91
|
String,
|
|
92
|
-
typeof
|
|
92
|
+
typeof _userpropertiesdto.UserPasswordDto === "undefined" ? Object : _userpropertiesdto.UserPasswordDto,
|
|
93
93
|
typeof _fastify.FastifyRequest === "undefined" ? Object : _fastify.FastifyRequest,
|
|
94
94
|
typeof _fastify.FastifyReply === "undefined" ? Object : _fastify.FastifyReply
|
|
95
95
|
]),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../backend/src/applications/links/links.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 { Body, Controller, Get, Param, Post, Req, Res, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { AuthTokenOptional } from '../../authentication/decorators/auth-token-optional.decorator'\nimport { LoginResponseDto } from '../../authentication/dto/login-response.dto'\nimport { GetUser } from '../users/decorators/user.decorator'\nimport { UserPasswordDto } from '../users/dto/user-
|
|
1
|
+
{"version":3,"sources":["../../../../backend/src/applications/links/links.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 { Body, Controller, Get, Param, Post, Req, Res, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { AuthTokenOptional } from '../../authentication/decorators/auth-token-optional.decorator'\nimport { LoginResponseDto } from '../../authentication/dto/login-response.dto'\nimport { GetUser } from '../users/decorators/user.decorator'\nimport { UserPasswordDto } from '../users/dto/user-properties.dto'\nimport { UserModel } from '../users/models/user.model'\nimport { PUBLIC_LINKS_ROUTE } from './constants/routes'\nimport { SpaceLink } from './interfaces/link-space.interface'\nimport { LinksManager } from './services/links-manager.service'\n\n@Controller(PUBLIC_LINKS_ROUTE.BASE)\n@AuthTokenOptional()\nexport class LinksController {\n constructor(private readonly linksPublicManager: LinksManager) {}\n\n @Get(`${PUBLIC_LINKS_ROUTE.VALIDATION}/:uuid`)\n linkValidation(\n @GetUser() user: UserModel,\n @Param('uuid') uuid: string\n ): Promise<{\n error: string | true\n ok: boolean\n link: SpaceLink\n }> {\n return this.linksPublicManager.linkValidation(user, uuid)\n }\n\n @Get(`${PUBLIC_LINKS_ROUTE.ACCESS}/:uuid`)\n linkAccess(\n @GetUser() user: UserModel,\n @Param('uuid') uuid: string,\n @Req() req: FastifyRequest,\n @Res({ passthrough: true }) res: FastifyReply\n ): Promise<StreamableFile | LoginResponseDto> {\n return this.linksPublicManager.linkAccess(user, uuid, req, res)\n }\n\n @Post(`${PUBLIC_LINKS_ROUTE.AUTH}/:uuid`)\n linkAuthentication(\n @GetUser() user: UserModel,\n @Param('uuid') uuid: string,\n @Body() linkPasswordDto: UserPasswordDto,\n @Req() req: FastifyRequest,\n @Res({ passthrough: true }) res: FastifyReply\n ): Promise<LoginResponseDto> {\n return this.linksPublicManager.linkAuthentication(user, uuid, linkPasswordDto, req, res)\n }\n}\n"],"names":["LinksController","linkValidation","user","uuid","linksPublicManager","linkAccess","req","res","linkAuthentication","linkPasswordDto","PUBLIC_LINKS_ROUTE","VALIDATION","ACCESS","passthrough","AUTH","BASE"],"mappings":"AAAA;;;;CAIC;;;;+BAeYA;;;eAAAA;;;wBAbgE;yBAChC;4CACX;+BAEV;mCACQ;2BACN;wBACS;qCAEN;;;;;;;;;;;;;;;AAItB,IAAA,AAAMA,kBAAN,MAAMA;IAIXC,eACE,AAAWC,IAAe,EAC1B,AAAeC,IAAY,EAK1B;QACD,OAAO,IAAI,CAACC,kBAAkB,CAACH,cAAc,CAACC,MAAMC;IACtD;IAGAE,WACE,AAAWH,IAAe,EAC1B,AAAeC,IAAY,EAC3B,AAAOG,GAAmB,EAC1B,AAA4BC,GAAiB,EACD;QAC5C,OAAO,IAAI,CAACH,kBAAkB,CAACC,UAAU,CAACH,MAAMC,MAAMG,KAAKC;IAC7D;IAGAC,mBACE,AAAWN,IAAe,EAC1B,AAAeC,IAAY,EAC3B,AAAQM,eAAgC,EACxC,AAAOH,GAAmB,EAC1B,AAA4BC,GAAiB,EAClB;QAC3B,OAAO,IAAI,CAACH,kBAAkB,CAACI,kBAAkB,CAACN,MAAMC,MAAMM,iBAAiBH,KAAKC;IACtF;IAjCA,YAAY,AAAiBH,kBAAgC,CAAE;aAAlCA,qBAAAA;IAAmC;AAkClE;;wBAhCUM,0BAAkB,CAACC,UAAU,CAAC,MAAM;;;;;;;;;;;wBAYpCD,0BAAkB,CAACE,MAAM,CAAC,MAAM;;;;;QAK/BC,aAAa;;;;;;;;;;;;yBAKbH,0BAAkB,CAACI,IAAI,CAAC,MAAM;;;;;;QAM9BD,aAAa;;;;;;;;;;;;;uDAjCOE"}
|
|
@@ -19,6 +19,7 @@ const _spaces = require("../../spaces/constants/spaces");
|
|
|
19
19
|
const _spacesmanagerservice = require("../../spaces/services/spaces-manager.service");
|
|
20
20
|
const _usermodel = require("../../users/models/user.model");
|
|
21
21
|
const _usersmanagerservice = require("../../users/services/users-manager.service");
|
|
22
|
+
const _avatar = require("../../users/utils/avatar");
|
|
22
23
|
const _links = require("../constants/links");
|
|
23
24
|
const _linksqueriesservice = require("./links-queries.service");
|
|
24
25
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -38,7 +39,7 @@ let LinksManager = class LinksManager {
|
|
|
38
39
|
}
|
|
39
40
|
const spaceLink = ok ? await this.linksQueries.spaceLink(uuid) : null;
|
|
40
41
|
if (spaceLink?.owner?.login) {
|
|
41
|
-
spaceLink.owner.avatar = await
|
|
42
|
+
spaceLink.owner.avatar = await (0, _avatar.getAvatarBase64)(spaceLink.owner.login);
|
|
42
43
|
// for security reasons
|
|
43
44
|
delete spaceLink.owner.login;
|
|
44
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/links/services/links-manager.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus, Injectable, Logger, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { LoginResponseDto } from '../../../authentication/dto/login-response.dto'\nimport { JwtIdentityPayload } from '../../../authentication/interfaces/jwt-payload.interface'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { SendFile } from '../../files/utils/send-file'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { UserPasswordDto } from '../../users/dto/user-password.dto'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { LINK_ERROR } from '../constants/links'\nimport { LinkAsUser } from '../interfaces/link-guest.interface'\nimport { SpaceLink } from '../interfaces/link-space.interface'\nimport { LinksQueries } from './links-queries.service'\n\n@Injectable()\nexport class LinksManager {\n private logger = new Logger(LinksManager.name)\n\n constructor(\n private readonly authManager: AuthManager,\n private readonly usersManager: UsersManager,\n private readonly filesManager: FilesManager,\n private readonly spacesManager: SpacesManager,\n private readonly linksQueries: LinksQueries\n ) {}\n\n async linkValidation(identity: JwtIdentityPayload, uuid: string): Promise<{ ok: boolean; error: string | true; link: SpaceLink }> {\n const [_link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkValidation.name} - ${uuid} : ${check}`)\n }\n const spaceLink: SpaceLink = ok ? await this.linksQueries.spaceLink(uuid) : null\n if (spaceLink?.owner?.login) {\n spaceLink.owner.avatar = await this.usersManager.getAvatarBase64(spaceLink.owner.login)\n // for security reasons\n delete spaceLink.owner.login\n }\n return { ok: ok, error: ok ? null : check, link: spaceLink }\n }\n\n async linkAccess(identity: JwtIdentityPayload, uuid: string, req: FastifyRequest, res: FastifyReply): Promise<StreamableFile | LoginResponseDto> {\n const [link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkAccess.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const user = new UserModel(link.user)\n const spaceLink: SpaceLink = await this.linksQueries.spaceLink(uuid)\n if (!spaceLink.space && !spaceLink.share.isDir) {\n // download the file (authentication has been verified before)\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) downloading ${spaceLink.share.name}`)\n this.incrementLinkNbAccess(link)\n const spaceEnv: SpaceEnv = await this.spaceEnvFromLink(user, spaceLink)\n const sendFile: SendFile = this.filesManager.sendFileFromSpace(spaceEnv, true, spaceLink.share.name)\n try {\n await sendFile.checks()\n return await sendFile.stream(req, res)\n } catch (e) {\n this.logger.error(`${this.linkAccess.name} - unable to send file : ${e}`)\n throw new HttpException('Unable to download file', HttpStatus.INTERNAL_SERVER_ERROR)\n }\n } else if (link.user.id !== identity.id) {\n // authenticate user to allow access to the directory\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) is logged`)\n this.incrementLinkNbAccess(link)\n this.usersManager.updateAccesses(user, req.ip, true).catch((e: Error) => this.logger.error(`${this.linkAccess.name} - ${e}`))\n return this.authManager.setCookies(user, res)\n }\n // already authenticated\n }\n\n async linkAuthentication(identity: JwtIdentityPayload, uuid: string, linkPasswordDto: UserPasswordDto, req: FastifyRequest, res: FastifyReply) {\n const [link, check, ok] = await this.linkEnv(identity, uuid, true)\n if (!ok) {\n this.logger.warn(`${this.linkAuthentication.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const authSuccess: boolean = await this.usersManager.compareUserPassword(link.user.id, linkPasswordDto.password)\n const user = new UserModel(link.user)\n this.usersManager.updateAccesses(user, req.ip, authSuccess).catch((e: Error) => this.logger.error(`${this.linkAuthentication.name} - ${e}`))\n if (!authSuccess) {\n this.logger.warn(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) : auth failed`)\n throw new HttpException(LINK_ERROR.UNAUTHORIZED, HttpStatus.FORBIDDEN)\n }\n // authenticate user to allow access\n this.logger.log(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) is logged`)\n return this.authManager.setCookies(user, res)\n }\n\n private spaceEnvFromLink(user: UserModel, link: SpaceLink): Promise<SpaceEnv> {\n return this.spacesManager.spaceEnv(user, [\n link.space ? SPACE_REPOSITORY.FILES : SPACE_REPOSITORY.SHARES,\n link.space ? link.space.alias : link.share.alias\n ])\n }\n\n private async linkEnv(identity: JwtIdentityPayload, uuid: string, ignoreAuth: boolean = false): Promise<[LinkAsUser, string | true, boolean]> {\n const link: LinkAsUser = await this.linksQueries.linkFromUUID(uuid)\n const check: string | true = this.checkLink(identity, link, ignoreAuth)\n const ok: boolean = check === true\n return [link, check, ok]\n }\n\n private checkLink(identity: JwtIdentityPayload, link: LinkAsUser, ignoreAuth: boolean = false): string | true {\n if (!link) {\n return LINK_ERROR.NOT_FOUND\n }\n if (!link.user.isActive) {\n return LINK_ERROR.DISABLED\n }\n if (link.limitAccess !== 0 && link.nbAccess >= link.limitAccess) {\n return LINK_ERROR.EXCEEDED\n }\n if (link.expiresAt && new Date() >= link.expiresAt) {\n return LINK_ERROR.EXPIRED\n }\n if (!ignoreAuth && link.requireAuth && link.user.id !== identity.id) {\n return LINK_ERROR.UNAUTHORIZED\n }\n return true\n }\n\n private incrementLinkNbAccess(link: LinkAsUser) {\n this.linksQueries.incrementLinkNbAccess(link.uuid).catch((e: Error) => this.logger.error(`${this.incrementLinkNbAccess.name} - ${e}`))\n }\n}\n"],"names":["LinksManager","linkValidation","identity","uuid","_link","check","ok","linkEnv","logger","warn","name","spaceLink","linksQueries","owner","login","avatar","usersManager","getAvatarBase64","error","link","linkAccess","req","res","user","id","HttpException","HttpStatus","BAD_REQUEST","UserModel","space","share","isDir","log","incrementLinkNbAccess","spaceEnv","spaceEnvFromLink","sendFile","filesManager","sendFileFromSpace","checks","stream","e","INTERNAL_SERVER_ERROR","updateAccesses","ip","catch","authManager","setCookies","linkAuthentication","linkPasswordDto","authSuccess","compareUserPassword","password","LINK_ERROR","UNAUTHORIZED","FORBIDDEN","spacesManager","SPACE_REPOSITORY","FILES","SHARES","alias","ignoreAuth","linkFromUUID","checkLink","NOT_FOUND","isActive","DISABLED","limitAccess","nbAccess","EXCEEDED","expiresAt","Date","EXPIRED","requireAuth","Logger"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/links/services/links-manager.service.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { HttpException, HttpStatus, Injectable, Logger, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { LoginResponseDto } from '../../../authentication/dto/login-response.dto'\nimport { JwtIdentityPayload } from '../../../authentication/interfaces/jwt-payload.interface'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { SendFile } from '../../files/utils/send-file'\nimport { SPACE_REPOSITORY } from '../../spaces/constants/spaces'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { UserPasswordDto } from '../../users/dto/user-properties.dto'\nimport { UserModel } from '../../users/models/user.model'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { getAvatarBase64 } from '../../users/utils/avatar'\nimport { LINK_ERROR } from '../constants/links'\nimport { LinkAsUser } from '../interfaces/link-guest.interface'\nimport { SpaceLink } from '../interfaces/link-space.interface'\nimport { LinksQueries } from './links-queries.service'\n\n@Injectable()\nexport class LinksManager {\n private logger = new Logger(LinksManager.name)\n\n constructor(\n private readonly authManager: AuthManager,\n private readonly usersManager: UsersManager,\n private readonly filesManager: FilesManager,\n private readonly spacesManager: SpacesManager,\n private readonly linksQueries: LinksQueries\n ) {}\n\n async linkValidation(identity: JwtIdentityPayload, uuid: string): Promise<{ ok: boolean; error: string | true; link: SpaceLink }> {\n const [_link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkValidation.name} - ${uuid} : ${check}`)\n }\n const spaceLink: SpaceLink = ok ? await this.linksQueries.spaceLink(uuid) : null\n if (spaceLink?.owner?.login) {\n spaceLink.owner.avatar = await getAvatarBase64(spaceLink.owner.login)\n // for security reasons\n delete spaceLink.owner.login\n }\n return { ok: ok, error: ok ? null : check, link: spaceLink }\n }\n\n async linkAccess(identity: JwtIdentityPayload, uuid: string, req: FastifyRequest, res: FastifyReply): Promise<StreamableFile | LoginResponseDto> {\n const [link, check, ok] = await this.linkEnv(identity, uuid)\n if (!ok) {\n this.logger.warn(`${this.linkAccess.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const user = new UserModel(link.user)\n const spaceLink: SpaceLink = await this.linksQueries.spaceLink(uuid)\n if (!spaceLink.space && !spaceLink.share.isDir) {\n // download the file (authentication has been verified before)\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) downloading ${spaceLink.share.name}`)\n this.incrementLinkNbAccess(link)\n const spaceEnv: SpaceEnv = await this.spaceEnvFromLink(user, spaceLink)\n const sendFile: SendFile = this.filesManager.sendFileFromSpace(spaceEnv, true, spaceLink.share.name)\n try {\n await sendFile.checks()\n return await sendFile.stream(req, res)\n } catch (e) {\n this.logger.error(`${this.linkAccess.name} - unable to send file : ${e}`)\n throw new HttpException('Unable to download file', HttpStatus.INTERNAL_SERVER_ERROR)\n }\n } else if (link.user.id !== identity.id) {\n // authenticate user to allow access to the directory\n this.logger.log(`${this.linkAccess.name} - *${user.login}* (${user.id}) is logged`)\n this.incrementLinkNbAccess(link)\n this.usersManager.updateAccesses(user, req.ip, true).catch((e: Error) => this.logger.error(`${this.linkAccess.name} - ${e}`))\n return this.authManager.setCookies(user, res)\n }\n // already authenticated\n }\n\n async linkAuthentication(identity: JwtIdentityPayload, uuid: string, linkPasswordDto: UserPasswordDto, req: FastifyRequest, res: FastifyReply) {\n const [link, check, ok] = await this.linkEnv(identity, uuid, true)\n if (!ok) {\n this.logger.warn(`${this.linkAuthentication.name} - *${link.user.login}* (${link.user.id}) : ${check}`)\n throw new HttpException(check as string, HttpStatus.BAD_REQUEST)\n }\n const authSuccess: boolean = await this.usersManager.compareUserPassword(link.user.id, linkPasswordDto.password)\n const user = new UserModel(link.user)\n this.usersManager.updateAccesses(user, req.ip, authSuccess).catch((e: Error) => this.logger.error(`${this.linkAuthentication.name} - ${e}`))\n if (!authSuccess) {\n this.logger.warn(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) : auth failed`)\n throw new HttpException(LINK_ERROR.UNAUTHORIZED, HttpStatus.FORBIDDEN)\n }\n // authenticate user to allow access\n this.logger.log(`${this.linkAuthentication.name} - *${user.login}* (${user.id}) is logged`)\n return this.authManager.setCookies(user, res)\n }\n\n private spaceEnvFromLink(user: UserModel, link: SpaceLink): Promise<SpaceEnv> {\n return this.spacesManager.spaceEnv(user, [\n link.space ? SPACE_REPOSITORY.FILES : SPACE_REPOSITORY.SHARES,\n link.space ? link.space.alias : link.share.alias\n ])\n }\n\n private async linkEnv(identity: JwtIdentityPayload, uuid: string, ignoreAuth: boolean = false): Promise<[LinkAsUser, string | true, boolean]> {\n const link: LinkAsUser = await this.linksQueries.linkFromUUID(uuid)\n const check: string | true = this.checkLink(identity, link, ignoreAuth)\n const ok: boolean = check === true\n return [link, check, ok]\n }\n\n private checkLink(identity: JwtIdentityPayload, link: LinkAsUser, ignoreAuth: boolean = false): string | true {\n if (!link) {\n return LINK_ERROR.NOT_FOUND\n }\n if (!link.user.isActive) {\n return LINK_ERROR.DISABLED\n }\n if (link.limitAccess !== 0 && link.nbAccess >= link.limitAccess) {\n return LINK_ERROR.EXCEEDED\n }\n if (link.expiresAt && new Date() >= link.expiresAt) {\n return LINK_ERROR.EXPIRED\n }\n if (!ignoreAuth && link.requireAuth && link.user.id !== identity.id) {\n return LINK_ERROR.UNAUTHORIZED\n }\n return true\n }\n\n private incrementLinkNbAccess(link: LinkAsUser) {\n this.linksQueries.incrementLinkNbAccess(link.uuid).catch((e: Error) => this.logger.error(`${this.incrementLinkNbAccess.name} - ${e}`))\n }\n}\n"],"names":["LinksManager","linkValidation","identity","uuid","_link","check","ok","linkEnv","logger","warn","name","spaceLink","linksQueries","owner","login","avatar","getAvatarBase64","error","link","linkAccess","req","res","user","id","HttpException","HttpStatus","BAD_REQUEST","UserModel","space","share","isDir","log","incrementLinkNbAccess","spaceEnv","spaceEnvFromLink","sendFile","filesManager","sendFileFromSpace","checks","stream","e","INTERNAL_SERVER_ERROR","usersManager","updateAccesses","ip","catch","authManager","setCookies","linkAuthentication","linkPasswordDto","authSuccess","compareUserPassword","password","LINK_ERROR","UNAUTHORIZED","FORBIDDEN","spacesManager","SPACE_REPOSITORY","FILES","SHARES","alias","ignoreAuth","linkFromUUID","checkLink","NOT_FOUND","isActive","DISABLED","limitAccess","nbAccess","EXCEEDED","expiresAt","Date","EXPIRED","requireAuth","Logger"],"mappings":"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"}
|
|
@@ -27,8 +27,12 @@ const _adminusersmanagerservice = require("../../users/services/admin-users-mana
|
|
|
27
27
|
const _adminusersqueriesservice = require("../../users/services/admin-users-queries.service");
|
|
28
28
|
const _usersmanagerservice = require("../../users/services/users-manager.service");
|
|
29
29
|
const _usersqueriesservice = require("../../users/services/users-queries.service");
|
|
30
|
+
const _avatar = require("../../users/utils/avatar");
|
|
30
31
|
const _linksmanagerservice = require("./links-manager.service");
|
|
31
32
|
const _linksqueriesservice = require("./links-queries.service");
|
|
33
|
+
jest.mock('../../users/utils/avatar', ()=>({
|
|
34
|
+
getAvatarBase64: jest.fn()
|
|
35
|
+
}));
|
|
32
36
|
describe(_linksmanagerservice.LinksManager.name, ()=>{
|
|
33
37
|
let service;
|
|
34
38
|
let linksQueriesMock;
|
|
@@ -59,7 +63,6 @@ describe(_linksmanagerservice.LinksManager.name, ()=>{
|
|
|
59
63
|
incrementLinkNbAccess: jest.fn().mockResolvedValue(undefined)
|
|
60
64
|
};
|
|
61
65
|
usersManagerMock = {
|
|
62
|
-
getAvatarBase64: jest.fn(),
|
|
63
66
|
compareUserPassword: jest.fn(),
|
|
64
67
|
updateAccesses: jest.fn()
|
|
65
68
|
};
|
|
@@ -186,14 +189,14 @@ describe(_linksmanagerservice.LinksManager.name, ()=>{
|
|
|
186
189
|
space: null
|
|
187
190
|
};
|
|
188
191
|
linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink);
|
|
189
|
-
|
|
192
|
+
_avatar.getAvatarBase64.mockResolvedValueOnce('base64-xxx');
|
|
190
193
|
const res = await service.linkValidation(identity, link.uuid);
|
|
191
194
|
expect(res.ok).toBe(true);
|
|
192
195
|
expect(res.error).toBeNull();
|
|
193
196
|
expect(res.link).toBe(spaceLink);
|
|
194
|
-
expect(spaceLink.owner.avatar).toBe('base64-avatar');
|
|
195
197
|
expect(spaceLink.owner.login).toBeUndefined();
|
|
196
198
|
expect(linksQueriesMock.spaceLink).toHaveBeenCalledWith(link.uuid);
|
|
199
|
+
expect(_avatar.getAvatarBase64).toHaveBeenCalledWith('jane');
|
|
197
200
|
// extra coverage: directly assert private checkLink with default ignoreAuth=false
|
|
198
201
|
const directCheck = service.checkLink(identity, link);
|
|
199
202
|
expect(directCheck).toBe(true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/links/services/links-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 { HttpService } from '@nestjs/axios'\nimport { ConfigService } from '@nestjs/config'\nimport { JwtService } from '@nestjs/jwt'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\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 { FilesLockManager } from '../../files/services/files-lock-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { AdminUsersManager } from '../../users/services/admin-users-manager.service'\nimport { AdminUsersQueries } from '../../users/services/admin-users-queries.service'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { LinksManager } from './links-manager.service'\nimport { LinksQueries } from './links-queries.service'\n\ndescribe(LinksManager.name, () => {\n let service: LinksManager\n let linksQueriesMock: jest.Mocked<LinksQueries>\n let usersManagerMock: jest.Mocked<UsersManager>\n let filesManagerMock: jest.Mocked<FilesManager>\n let spacesManagerMock: jest.Mocked<SpacesManager>\n let authManagerMock: jest.Mocked<AuthManager>\n\n const identity: any = { id: 42, login: 'visitor' }\n const baseLink: any = {\n uuid: 'uuid-123',\n user: { id: 7, login: 'john', isActive: true },\n requireAuth: false,\n limitAccess: 0,\n nbAccess: 0,\n expiresAt: null\n }\n\n beforeAll(async () => {\n linksQueriesMock = {\n linkFromUUID: jest.fn(),\n spaceLink: jest.fn(),\n incrementLinkNbAccess: jest.fn().mockResolvedValue(undefined)\n } as any\n\n usersManagerMock = {\n getAvatarBase64: jest.fn(),\n compareUserPassword: jest.fn(),\n updateAccesses: jest.fn()\n } as any\n\n filesManagerMock = {\n sendFileFromSpace: jest.fn()\n } as any\n\n spacesManagerMock = {\n spaceEnv: jest.fn()\n } as any\n\n authManagerMock = {\n setCookies: jest.fn()\n } as any\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: DB_TOKEN_PROVIDER,\n useValue: {}\n },\n {\n provide: Cache,\n useValue: {}\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n { provide: HttpService, useValue: {} },\n { provide: FilesLockManager, useValue: {} },\n { provide: ConfigService, useValue: {} },\n { provide: JwtService, useValue: {} },\n { provide: AuthManager, useValue: authManagerMock },\n { provide: UsersManager, useValue: usersManagerMock },\n { provide: UsersQueries, useValue: {} },\n { provide: AdminUsersManager, useValue: {} },\n { provide: AdminUsersQueries, useValue: {} },\n { provide: FilesQueries, useValue: {} },\n { provide: FilesManager, useValue: filesManagerMock },\n { provide: SpacesQueries, useValue: {} },\n { provide: SpacesManager, useValue: spacesManagerMock },\n { provide: SharesQueries, useValue: {} },\n { provide: SharesManager, useValue: {} },\n { provide: LinksQueries, useValue: linksQueriesMock },\n LinksManager\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<LinksManager>(LinksManager)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('linkValidation', () => {\n it('returns ok with sanitized owner and avatar when link is valid', async () => {\n const link = { ...baseLink }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n owner: { login: 'jane' },\n share: { isDir: true, alias: 's-alias', name: 'Docs' },\n space: null\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n usersManagerMock.getAvatarBase64.mockResolvedValueOnce('base64-avatar')\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(true)\n expect(res.error).toBeNull()\n expect(res.link).toBe(spaceLink)\n expect(spaceLink.owner.avatar).toBe('base64-avatar')\n expect((spaceLink.owner as any).login).toBeUndefined()\n expect(linksQueriesMock.spaceLink).toHaveBeenCalledWith(link.uuid)\n\n // extra coverage: directly assert private checkLink with default ignoreAuth=false\n const directCheck = (service as any).checkLink(identity, link)\n expect(directCheck).toBe(true)\n })\n\n it('returns error and null link when uuid is not found', async () => {\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(null)\n\n const res = await service.linkValidation(identity, 'missing-uuid')\n\n expect(res.ok).toBe(false)\n expect(res.error).toBeDefined()\n expect(res.link).toBeNull()\n })\n\n it('returns unauthorized when auth is required and identity differs', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(false)\n expect(String(res.error).toLowerCase()).toContain('unauthorized')\n expect(res.link).toBeNull()\n\n // extra coverage: directly assert private checkLink with default ignoreAuth=false\n const directCheck = (service as any).checkLink(identity, link)\n expect(String(directCheck).toLowerCase()).toContain('unauthorized')\n })\n\n it('returns exceeded when nbAccess >= limitAccess', async () => {\n const link = { ...baseLink, limitAccess: 5, nbAccess: 5 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(false)\n expect(String(res.error).toLowerCase()).toContain('exceeded')\n })\n })\n\n describe('linkAccess', () => {\n const req: any = { ip: '127.0.0.1' }\n const res: any = {}\n\n it('streams a file when link targets a single file', async () => {\n const link = { ...baseLink, limitAccess: 10 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: null,\n share: { isDir: false, name: 'file.txt', alias: 'share-alias' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n spacesManagerMock.spaceEnv.mockResolvedValueOnce({} as any)\n const streamable: any = { some: 'stream' }\n filesManagerMock.sendFileFromSpace.mockReturnValueOnce({\n checks: jest.fn().mockResolvedValueOnce(undefined),\n stream: jest.fn().mockResolvedValueOnce(streamable)\n } as any)\n\n // cover: incrementLinkNbAccess.catch(...) should log an error when the query rejects\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n linksQueriesMock.incrementLinkNbAccess.mockRejectedValueOnce(new Error('increment boom'))\n\n const result = await service.linkAccess(identity, link.uuid, req, res)\n\n expect(result).toBe(streamable)\n expect(filesManagerMock.sendFileFromSpace).toHaveBeenCalled()\n expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid)\n // Assert repository selection for a share file (space falsy)\n // should call spacesManager.spaceEnv with SHARES and share alias when link.space is falsy\n expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), ['shares', 'share-alias'])\n // should log error when increment fails\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('authenticates and returns cookies when link targets a directory and user is different', async () => {\n const link = { ...baseLink, requireAuth: false, user: { id: 7, login: 'john', isActive: true } }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: { alias: 'files', name: 'My Space' },\n share: { isDir: true, name: 'ignored', alias: 'ignored' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n const loginDto: any = { token: 'jwt' }\n authManagerMock.setCookies.mockResolvedValueOnce(loginDto)\n\n // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses boom'))\n\n const result = await service.linkAccess(identity, link.uuid, req, res)\n\n expect(result).toBe(loginDto)\n expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true)\n expect(authManagerMock.setCookies).toHaveBeenCalled()\n // additionally cover the \"space truthy\" branch by calling the private helper directly\n // should call spacesManager.spaceEnv with FILES and space alias when link.space is truthy\n await (service as any).spaceEnvFromLink(new UserModel(link.user as any), spaceLink as any)\n expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), ['files', 'files'])\n // should log error when updateAccesses fails\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('throws BAD_REQUEST when link is invalid', async () => {\n const disabledLink = { ...baseLink, user: { id: 7, login: 'john', isActive: false } }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(disabledLink)\n\n await expect(service.linkAccess(identity, disabledLink.uuid, req, res)).rejects.toMatchObject({\n status: 400\n })\n })\n\n it('returns undefined for already authenticated directory access (same user) and does not set cookies or increment', async () => {\n const sameUserIdentity = { id: baseLink.user.id, login: 'john' }\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: { alias: 'files', name: 'Space' },\n share: { isDir: true, name: 'dir', alias: 'share' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n const result = await service.linkAccess(sameUserIdentity as any, link.uuid, req, res)\n\n expect(result).toBeUndefined()\n expect(authManagerMock.setCookies).not.toHaveBeenCalled()\n expect(linksQueriesMock.incrementLinkNbAccess).not.toHaveBeenCalled()\n })\n\n it('throws INTERNAL_SERVER_ERROR when file checks fail during streaming', async () => {\n const link = { ...baseLink, limitAccess: 10 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: null,\n share: { isDir: false, name: 'bad.txt', alias: 'share' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n spacesManagerMock.spaceEnv.mockResolvedValueOnce({} as any)\n filesManagerMock.sendFileFromSpace.mockReturnValueOnce({\n checks: jest.fn().mockRejectedValueOnce(new Error('disk error')),\n stream: jest.fn()\n } as any)\n\n await expect(service.linkAccess(identity, link.uuid, req, res)).rejects.toMatchObject({\n status: 500\n })\n expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid)\n })\n })\n\n describe('linkAuthentication', () => {\n const req: any = { ip: '10.0.0.1' }\n const res: any = {}\n\n it('returns cookies when password is correct', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n usersManagerMock.compareUserPassword.mockResolvedValueOnce(true)\n // usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined) // removed to ensure rejection is hit\n const loginDto: any = { token: 'abc' }\n authManagerMock.setCookies.mockResolvedValueOnce(loginDto)\n\n // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects (success flow)\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses auth success boom'))\n\n const result = await service.linkAuthentication(identity, link.uuid, { password: 'secret' } as any, req, res)\n\n expect(result).toBe(loginDto)\n expect(usersManagerMock.compareUserPassword).toHaveBeenCalledWith(link.user.id, 'secret')\n expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true)\n expect(authManagerMock.setCookies).toHaveBeenCalled()\n // should log error when updateAccesses fails in successful authentication\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('throws FORBIDDEN when password is incorrect', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n usersManagerMock.compareUserPassword.mockResolvedValueOnce(false)\n usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined)\n\n await expect(service.linkAuthentication(identity, link.uuid, { password: 'bad' } as any, req, res)).rejects.toMatchObject({ status: 403 })\n })\n\n it('throws BAD_REQUEST when link is invalid (e.g., expired)', async () => {\n const expired = { ...baseLink, expiresAt: new Date(Date.now() - 60_000) }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(expired)\n\n await expect(service.linkAuthentication(identity, expired.uuid, { password: 'whatever' } as any, req, res)).rejects.toMatchObject({\n status: 400\n })\n })\n })\n})\n"],"names":["describe","LinksManager","name","service","linksQueriesMock","usersManagerMock","filesManagerMock","spacesManagerMock","authManagerMock","identity","id","login","baseLink","uuid","user","isActive","requireAuth","limitAccess","nbAccess","expiresAt","beforeAll","linkFromUUID","jest","fn","spaceLink","incrementLinkNbAccess","mockResolvedValue","undefined","getAvatarBase64","compareUserPassword","updateAccesses","sendFileFromSpace","spaceEnv","setCookies","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","ContextManager","NotificationsManager","HttpService","FilesLockManager","ConfigService","JwtService","AuthManager","UsersManager","UsersQueries","AdminUsersManager","AdminUsersQueries","FilesQueries","FilesManager","SpacesQueries","SpacesManager","SharesQueries","SharesManager","LinksQueries","compile","useLogger","get","beforeEach","clearAllMocks","it","expect","toBeDefined","link","mockResolvedValueOnce","owner","share","isDir","alias","space","res","linkValidation","ok","toBe","error","toBeNull","avatar","toBeUndefined","toHaveBeenCalledWith","directCheck","checkLink","String","toLowerCase","toContain","req","ip","streamable","some","mockReturnValueOnce","checks","stream","logErrorSpy","spyOn","logger","mockImplementation","mockRejectedValueOnce","Error","result","linkAccess","toHaveBeenCalled","anything","loginDto","token","spaceEnvFromLink","UserModel","disabledLink","rejects","toMatchObject","status","sameUserIdentity","not","linkAuthentication","password","expired","Date","now"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/links/services/links-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 { HttpService } from '@nestjs/axios'\nimport { ConfigService } from '@nestjs/config'\nimport { JwtService } from '@nestjs/jwt'\nimport { Test, TestingModule } from '@nestjs/testing'\nimport { AuthManager } from '../../../authentication/services/auth-manager.service'\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 { FilesLockManager } from '../../files/services/files-lock-manager.service'\nimport { FilesManager } from '../../files/services/files-manager.service'\nimport { FilesQueries } from '../../files/services/files-queries.service'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SharesManager } from '../../shares/services/shares-manager.service'\nimport { SharesQueries } from '../../shares/services/shares-queries.service'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { SpacesQueries } from '../../spaces/services/spaces-queries.service'\nimport { UserModel } from '../../users/models/user.model'\nimport { AdminUsersManager } from '../../users/services/admin-users-manager.service'\nimport { AdminUsersQueries } from '../../users/services/admin-users-queries.service'\nimport { UsersManager } from '../../users/services/users-manager.service'\nimport { UsersQueries } from '../../users/services/users-queries.service'\nimport { getAvatarBase64 } from '../../users/utils/avatar'\nimport { LinksManager } from './links-manager.service'\nimport { LinksQueries } from './links-queries.service'\n\njest.mock('../../users/utils/avatar', () => ({\n getAvatarBase64: jest.fn()\n}))\n\ndescribe(LinksManager.name, () => {\n let service: LinksManager\n let linksQueriesMock: jest.Mocked<LinksQueries>\n let usersManagerMock: jest.Mocked<UsersManager>\n let filesManagerMock: jest.Mocked<FilesManager>\n let spacesManagerMock: jest.Mocked<SpacesManager>\n let authManagerMock: jest.Mocked<AuthManager>\n\n const identity: any = { id: 42, login: 'visitor' }\n const baseLink: any = {\n uuid: 'uuid-123',\n user: { id: 7, login: 'john', isActive: true },\n requireAuth: false,\n limitAccess: 0,\n nbAccess: 0,\n expiresAt: null\n }\n\n beforeAll(async () => {\n linksQueriesMock = {\n linkFromUUID: jest.fn(),\n spaceLink: jest.fn(),\n incrementLinkNbAccess: jest.fn().mockResolvedValue(undefined)\n } as any\n\n usersManagerMock = {\n compareUserPassword: jest.fn(),\n updateAccesses: jest.fn()\n } as any\n\n filesManagerMock = {\n sendFileFromSpace: jest.fn()\n } as any\n\n spacesManagerMock = {\n spaceEnv: jest.fn()\n } as any\n\n authManagerMock = {\n setCookies: jest.fn()\n } as any\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: DB_TOKEN_PROVIDER,\n useValue: {}\n },\n {\n provide: Cache,\n useValue: {}\n },\n { provide: ContextManager, useValue: {} },\n {\n provide: NotificationsManager,\n useValue: {}\n },\n { provide: HttpService, useValue: {} },\n { provide: FilesLockManager, useValue: {} },\n { provide: ConfigService, useValue: {} },\n { provide: JwtService, useValue: {} },\n { provide: AuthManager, useValue: authManagerMock },\n { provide: UsersManager, useValue: usersManagerMock },\n { provide: UsersQueries, useValue: {} },\n { provide: AdminUsersManager, useValue: {} },\n { provide: AdminUsersQueries, useValue: {} },\n { provide: FilesQueries, useValue: {} },\n { provide: FilesManager, useValue: filesManagerMock },\n { provide: SpacesQueries, useValue: {} },\n { provide: SpacesManager, useValue: spacesManagerMock },\n { provide: SharesQueries, useValue: {} },\n { provide: SharesManager, useValue: {} },\n { provide: LinksQueries, useValue: linksQueriesMock },\n LinksManager\n ]\n }).compile()\n\n module.useLogger(['fatal'])\n service = module.get<LinksManager>(LinksManager)\n })\n\n beforeEach(() => {\n jest.clearAllMocks()\n })\n\n it('should be defined', () => {\n expect(service).toBeDefined()\n })\n\n describe('linkValidation', () => {\n it('returns ok with sanitized owner and avatar when link is valid', async () => {\n const link = { ...baseLink }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n owner: { login: 'jane' },\n share: { isDir: true, alias: 's-alias', name: 'Docs' },\n space: null\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n ;(getAvatarBase64 as jest.Mock).mockResolvedValueOnce('base64-xxx')\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(true)\n expect(res.error).toBeNull()\n expect(res.link).toBe(spaceLink)\n expect((spaceLink.owner as any).login).toBeUndefined()\n expect(linksQueriesMock.spaceLink).toHaveBeenCalledWith(link.uuid)\n expect(getAvatarBase64).toHaveBeenCalledWith('jane')\n\n // extra coverage: directly assert private checkLink with default ignoreAuth=false\n const directCheck = (service as any).checkLink(identity, link)\n expect(directCheck).toBe(true)\n })\n\n it('returns error and null link when uuid is not found', async () => {\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(null)\n\n const res = await service.linkValidation(identity, 'missing-uuid')\n\n expect(res.ok).toBe(false)\n expect(res.error).toBeDefined()\n expect(res.link).toBeNull()\n })\n\n it('returns unauthorized when auth is required and identity differs', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(false)\n expect(String(res.error).toLowerCase()).toContain('unauthorized')\n expect(res.link).toBeNull()\n\n // extra coverage: directly assert private checkLink with default ignoreAuth=false\n const directCheck = (service as any).checkLink(identity, link)\n expect(String(directCheck).toLowerCase()).toContain('unauthorized')\n })\n\n it('returns exceeded when nbAccess >= limitAccess', async () => {\n const link = { ...baseLink, limitAccess: 5, nbAccess: 5 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n\n const res = await service.linkValidation(identity, link.uuid)\n\n expect(res.ok).toBe(false)\n expect(String(res.error).toLowerCase()).toContain('exceeded')\n })\n })\n\n describe('linkAccess', () => {\n const req: any = { ip: '127.0.0.1' }\n const res: any = {}\n\n it('streams a file when link targets a single file', async () => {\n const link = { ...baseLink, limitAccess: 10 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: null,\n share: { isDir: false, name: 'file.txt', alias: 'share-alias' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n spacesManagerMock.spaceEnv.mockResolvedValueOnce({} as any)\n const streamable: any = { some: 'stream' }\n filesManagerMock.sendFileFromSpace.mockReturnValueOnce({\n checks: jest.fn().mockResolvedValueOnce(undefined),\n stream: jest.fn().mockResolvedValueOnce(streamable)\n } as any)\n\n // cover: incrementLinkNbAccess.catch(...) should log an error when the query rejects\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n linksQueriesMock.incrementLinkNbAccess.mockRejectedValueOnce(new Error('increment boom'))\n\n const result = await service.linkAccess(identity, link.uuid, req, res)\n\n expect(result).toBe(streamable)\n expect(filesManagerMock.sendFileFromSpace).toHaveBeenCalled()\n expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid)\n // Assert repository selection for a share file (space falsy)\n // should call spacesManager.spaceEnv with SHARES and share alias when link.space is falsy\n expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), ['shares', 'share-alias'])\n // should log error when increment fails\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('authenticates and returns cookies when link targets a directory and user is different', async () => {\n const link = { ...baseLink, requireAuth: false, user: { id: 7, login: 'john', isActive: true } }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: { alias: 'files', name: 'My Space' },\n share: { isDir: true, name: 'ignored', alias: 'ignored' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n const loginDto: any = { token: 'jwt' }\n authManagerMock.setCookies.mockResolvedValueOnce(loginDto)\n\n // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses boom'))\n\n const result = await service.linkAccess(identity, link.uuid, req, res)\n\n expect(result).toBe(loginDto)\n expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true)\n expect(authManagerMock.setCookies).toHaveBeenCalled()\n // additionally cover the \"space truthy\" branch by calling the private helper directly\n // should call spacesManager.spaceEnv with FILES and space alias when link.space is truthy\n await (service as any).spaceEnvFromLink(new UserModel(link.user as any), spaceLink as any)\n expect(spacesManagerMock.spaceEnv).toHaveBeenCalledWith(expect.anything(), ['files', 'files'])\n // should log error when updateAccesses fails\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('throws BAD_REQUEST when link is invalid', async () => {\n const disabledLink = { ...baseLink, user: { id: 7, login: 'john', isActive: false } }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(disabledLink)\n\n await expect(service.linkAccess(identity, disabledLink.uuid, req, res)).rejects.toMatchObject({\n status: 400\n })\n })\n\n it('returns undefined for already authenticated directory access (same user) and does not set cookies or increment', async () => {\n const sameUserIdentity = { id: baseLink.user.id, login: 'john' }\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: { alias: 'files', name: 'Space' },\n share: { isDir: true, name: 'dir', alias: 'share' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n const result = await service.linkAccess(sameUserIdentity as any, link.uuid, req, res)\n\n expect(result).toBeUndefined()\n expect(authManagerMock.setCookies).not.toHaveBeenCalled()\n expect(linksQueriesMock.incrementLinkNbAccess).not.toHaveBeenCalled()\n })\n\n it('throws INTERNAL_SERVER_ERROR when file checks fail during streaming', async () => {\n const link = { ...baseLink, limitAccess: 10 }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n const spaceLink = {\n space: null,\n share: { isDir: false, name: 'bad.txt', alias: 'share' }\n } as any\n linksQueriesMock.spaceLink.mockResolvedValueOnce(spaceLink)\n\n spacesManagerMock.spaceEnv.mockResolvedValueOnce({} as any)\n filesManagerMock.sendFileFromSpace.mockReturnValueOnce({\n checks: jest.fn().mockRejectedValueOnce(new Error('disk error')),\n stream: jest.fn()\n } as any)\n\n await expect(service.linkAccess(identity, link.uuid, req, res)).rejects.toMatchObject({\n status: 500\n })\n expect(linksQueriesMock.incrementLinkNbAccess).toHaveBeenCalledWith(link.uuid)\n })\n })\n\n describe('linkAuthentication', () => {\n const req: any = { ip: '10.0.0.1' }\n const res: any = {}\n\n it('returns cookies when password is correct', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n usersManagerMock.compareUserPassword.mockResolvedValueOnce(true)\n // usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined) // removed to ensure rejection is hit\n const loginDto: any = { token: 'abc' }\n authManagerMock.setCookies.mockResolvedValueOnce(loginDto)\n\n // cover: usersManager.updateAccesses.catch(...) should log an error when updateAccesses rejects (success flow)\n const logErrorSpy = jest.spyOn((service as any).logger, 'error').mockImplementation(() => undefined as any)\n usersManagerMock.updateAccesses.mockRejectedValueOnce(new Error('updateAccesses auth success boom'))\n\n const result = await service.linkAuthentication(identity, link.uuid, { password: 'secret' } as any, req, res)\n\n expect(result).toBe(loginDto)\n expect(usersManagerMock.compareUserPassword).toHaveBeenCalledWith(link.user.id, 'secret')\n expect(usersManagerMock.updateAccesses).toHaveBeenCalledWith(expect.anything(), req.ip, true)\n expect(authManagerMock.setCookies).toHaveBeenCalled()\n // should log error when updateAccesses fails in successful authentication\n expect(logErrorSpy).toHaveBeenCalled()\n })\n\n it('throws FORBIDDEN when password is incorrect', async () => {\n const link = { ...baseLink, requireAuth: true }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(link)\n usersManagerMock.compareUserPassword.mockResolvedValueOnce(false)\n usersManagerMock.updateAccesses.mockResolvedValueOnce(undefined)\n\n await expect(service.linkAuthentication(identity, link.uuid, { password: 'bad' } as any, req, res)).rejects.toMatchObject({ status: 403 })\n })\n\n it('throws BAD_REQUEST when link is invalid (e.g., expired)', async () => {\n const expired = { ...baseLink, expiresAt: new Date(Date.now() - 60_000) }\n linksQueriesMock.linkFromUUID.mockResolvedValueOnce(expired)\n\n await expect(service.linkAuthentication(identity, expired.uuid, { password: 'whatever' } as any, req, res)).rejects.toMatchObject({\n status: 400\n })\n })\n })\n})\n"],"names":["jest","mock","getAvatarBase64","fn","describe","LinksManager","name","service","linksQueriesMock","usersManagerMock","filesManagerMock","spacesManagerMock","authManagerMock","identity","id","login","baseLink","uuid","user","isActive","requireAuth","limitAccess","nbAccess","expiresAt","beforeAll","linkFromUUID","spaceLink","incrementLinkNbAccess","mockResolvedValue","undefined","compareUserPassword","updateAccesses","sendFileFromSpace","spaceEnv","setCookies","module","Test","createTestingModule","providers","provide","DB_TOKEN_PROVIDER","useValue","Cache","ContextManager","NotificationsManager","HttpService","FilesLockManager","ConfigService","JwtService","AuthManager","UsersManager","UsersQueries","AdminUsersManager","AdminUsersQueries","FilesQueries","FilesManager","SpacesQueries","SpacesManager","SharesQueries","SharesManager","LinksQueries","compile","useLogger","get","beforeEach","clearAllMocks","it","expect","toBeDefined","link","mockResolvedValueOnce","owner","share","isDir","alias","space","res","linkValidation","ok","toBe","error","toBeNull","toBeUndefined","toHaveBeenCalledWith","directCheck","checkLink","String","toLowerCase","toContain","req","ip","streamable","some","mockReturnValueOnce","checks","stream","logErrorSpy","spyOn","logger","mockImplementation","mockRejectedValueOnce","Error","result","linkAccess","toHaveBeenCalled","anything","loginDto","token","spaceEnvFromLink","UserModel","disabledLink","rejects","toMatchObject","status","sameUserIdentity","not","linkAuthentication","password","expired","Date","now"],"mappings":"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"}
|
|
@@ -28,6 +28,8 @@ var NOTIFICATION_APP = /*#__PURE__*/ function(NOTIFICATION_APP) {
|
|
|
28
28
|
NOTIFICATION_APP["SHARES"] = "shares";
|
|
29
29
|
NOTIFICATION_APP["LINKS"] = "links";
|
|
30
30
|
NOTIFICATION_APP["SYNC"] = "sync";
|
|
31
|
+
NOTIFICATION_APP["AUTH_LOCKED"] = "auth_locked";
|
|
32
|
+
NOTIFICATION_APP["AUTH_2FA"] = "auth_2fa";
|
|
31
33
|
return NOTIFICATION_APP;
|
|
32
34
|
}({});
|
|
33
35
|
const NOTIFICATION_APP_EVENT = {
|
|
@@ -56,6 +58,13 @@ const NOTIFICATION_APP_EVENT = {
|
|
|
56
58
|
},
|
|
57
59
|
SYNC: {
|
|
58
60
|
[_constants.ACTION.DELETE]: 'You are no longer synchronizing'
|
|
61
|
+
},
|
|
62
|
+
AUTH_2FA: {
|
|
63
|
+
[_constants.ACTION.ADD]: 'Two-factor authentication (2FA) on your account has been enabled',
|
|
64
|
+
[_constants.ACTION.DELETE]: 'Two-factor authentication (2FA) on your account has been disabled'
|
|
65
|
+
},
|
|
66
|
+
AUTH_LOCKED: {
|
|
67
|
+
[_constants.ACTION.DELETE]: 'Your account has been locked after several unsuccessful authentication attempts'
|
|
59
68
|
}
|
|
60
69
|
};
|
|
61
70
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/notifications/constants/notifications.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 { ACTION } from '../../../common/constants'\n\nexport enum NOTIFICATION_APP {\n COMMENTS = 'comments',\n SPACES = 'spaces',\n SPACE_ROOTS = 'spaces_roots',\n SHARES = 'shares',\n LINKS = 'links',\n SYNC = 'sync'\n}\n\nexport const NOTIFICATION_APP_EVENT = {\n COMMENTS: 'commented',\n SPACES: {\n [ACTION.ADD]: 'You now have access to the space',\n [ACTION.DELETE]: 'You no longer have access to the space',\n [ACTION.DELETE_PERMANENTLY]: 'This space has been permanently deleted'\n },\n SPACE_ROOTS: {\n [ACTION.ADD]: 'anchored',\n [ACTION.DELETE]: 'unanchored'\n },\n SHARES: {\n [ACTION.ADD]: 'shared with you',\n [ACTION.DELETE]: 'no longer share with you'\n },\n SHARES_WITHOUT_OWNER: {\n [ACTION.ADD]: 'You now have access to the share',\n [ACTION.DELETE]: 'You no longer have access to the share',\n [ACTION.DELETE_PERMANENTLY]: 'You are no longer a member of the parent share, your child share has been deleted'\n },\n LINKS: {\n [ACTION.ADD]: 'shared with you',\n [ACTION.UPDATE]: 'You now have access to the space'\n },\n SYNC: {\n [ACTION.DELETE]: 'You are no longer synchronizing'\n }\n}\n"],"names":["NOTIFICATION_APP","NOTIFICATION_APP_EVENT","COMMENTS","SPACES","ACTION","ADD","DELETE","DELETE_PERMANENTLY","SPACE_ROOTS","SHARES","SHARES_WITHOUT_OWNER","LINKS","UPDATE","SYNC"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAIWA;eAAAA;;
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/notifications/constants/notifications.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 { ACTION } from '../../../common/constants'\n\nexport enum NOTIFICATION_APP {\n COMMENTS = 'comments',\n SPACES = 'spaces',\n SPACE_ROOTS = 'spaces_roots',\n SHARES = 'shares',\n LINKS = 'links',\n SYNC = 'sync',\n AUTH_LOCKED = 'auth_locked',\n AUTH_2FA = 'auth_2fa'\n}\n\nexport const NOTIFICATION_APP_EVENT = {\n COMMENTS: 'commented',\n SPACES: {\n [ACTION.ADD]: 'You now have access to the space',\n [ACTION.DELETE]: 'You no longer have access to the space',\n [ACTION.DELETE_PERMANENTLY]: 'This space has been permanently deleted'\n },\n SPACE_ROOTS: {\n [ACTION.ADD]: 'anchored',\n [ACTION.DELETE]: 'unanchored'\n },\n SHARES: {\n [ACTION.ADD]: 'shared with you',\n [ACTION.DELETE]: 'no longer share with you'\n },\n SHARES_WITHOUT_OWNER: {\n [ACTION.ADD]: 'You now have access to the share',\n [ACTION.DELETE]: 'You no longer have access to the share',\n [ACTION.DELETE_PERMANENTLY]: 'You are no longer a member of the parent share, your child share has been deleted'\n },\n LINKS: {\n [ACTION.ADD]: 'shared with you',\n [ACTION.UPDATE]: 'You now have access to the space'\n },\n SYNC: {\n [ACTION.DELETE]: 'You are no longer synchronizing'\n },\n AUTH_2FA: {\n [ACTION.ADD]: 'Two-factor authentication (2FA) on your account has been enabled',\n [ACTION.DELETE]: 'Two-factor authentication (2FA) on your account has been disabled'\n },\n AUTH_LOCKED: {\n [ACTION.DELETE]: 'Your account has been locked after several unsuccessful authentication attempts'\n }\n}\n"],"names":["NOTIFICATION_APP","NOTIFICATION_APP_EVENT","COMMENTS","SPACES","ACTION","ADD","DELETE","DELETE_PERMANENTLY","SPACE_ROOTS","SHARES","SHARES_WITHOUT_OWNER","LINKS","UPDATE","SYNC","AUTH_2FA","AUTH_LOCKED"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAIWA;eAAAA;;QAWCC;eAAAA;;;2BAbU;AAEhB,IAAA,AAAKD,0CAAAA;;;;;;;;;WAAAA;;AAWL,MAAMC,yBAAyB;IACpCC,UAAU;IACVC,QAAQ;QACN,CAACC,iBAAM,CAACC,GAAG,CAAC,EAAE;QACd,CAACD,iBAAM,CAACE,MAAM,CAAC,EAAE;QACjB,CAACF,iBAAM,CAACG,kBAAkB,CAAC,EAAE;IAC/B;IACAC,aAAa;QACX,CAACJ,iBAAM,CAACC,GAAG,CAAC,EAAE;QACd,CAACD,iBAAM,CAACE,MAAM,CAAC,EAAE;IACnB;IACAG,QAAQ;QACN,CAACL,iBAAM,CAACC,GAAG,CAAC,EAAE;QACd,CAACD,iBAAM,CAACE,MAAM,CAAC,EAAE;IACnB;IACAI,sBAAsB;QACpB,CAACN,iBAAM,CAACC,GAAG,CAAC,EAAE;QACd,CAACD,iBAAM,CAACE,MAAM,CAAC,EAAE;QACjB,CAACF,iBAAM,CAACG,kBAAkB,CAAC,EAAE;IAC/B;IACAI,OAAO;QACL,CAACP,iBAAM,CAACC,GAAG,CAAC,EAAE;QACd,CAACD,iBAAM,CAACQ,MAAM,CAAC,EAAE;IACnB;IACAC,MAAM;QACJ,CAACT,iBAAM,CAACE,MAAM,CAAC,EAAE;IACnB;IACAQ,UAAU;QACR,CAACV,iBAAM,CAACC,GAAG,CAAC,EAAE;QACd,CAACD,iBAAM,CAACE,MAAM,CAAC,EAAE;IACnB;IACAS,aAAa;QACX,CAACX,iBAAM,CAACE,MAAM,CAAC,EAAE;IACnB;AACF"}
|
|
@@ -35,9 +35,18 @@ const fr = {
|
|
|
35
35
|
'You no longer have access to the share': `Vous n'avez plus accès au partage`,
|
|
36
36
|
'You are no longer a member of the parent share, your child share has been deleted': `Vous n'êtes plus membre du partage parent, votre partage enfant a été supprimé`,
|
|
37
37
|
'Access your shares from': 'Accédez à vos partages depuis',
|
|
38
|
+
'Access password': `Mot de passe d'accès`,
|
|
38
39
|
Sync: 'Synchronisation',
|
|
39
40
|
'Access your syncs from': 'Accédez à vos synchronisations depuis',
|
|
40
|
-
'You are no longer synchronizing': 'Vous ne synchronisez plus'
|
|
41
|
+
'You are no longer synchronizing': 'Vous ne synchronisez plus',
|
|
42
|
+
'Security notification': 'Notification de sécurité',
|
|
43
|
+
'Your account has been locked after several unsuccessful authentication attempts': 'Votre compte a été verrouillé après plusieurs tentatives d’authentification infructueuses',
|
|
44
|
+
'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.': `Cette notification de sécurité concerne votre compte Sync-in. Merci de contacter un administrateur afin qu’il procède à l’analyse et au déverrouillage de votre compte.`,
|
|
45
|
+
'Two-factor authentication (2FA) on your account has been disabled': `L’authentification à deux facteurs (2FA) sur votre compte a été désactivée`,
|
|
46
|
+
'Two-factor authentication (2FA) on your account has been enabled': `L’authentification à deux facteurs (2FA) sur votre compte a été activée`,
|
|
47
|
+
'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.': `Vous recevez cette notification car la sécurité de votre compte Sync-in a été modifiée. Si vous pensez qu’il s’agit d’une erreur, vérifiez vos paramètres de sécurité ou contactez votre administrateur.`,
|
|
48
|
+
'Address IP': 'Adresse IP',
|
|
49
|
+
Browser: 'Navigateur'
|
|
41
50
|
};
|
|
42
51
|
|
|
43
52
|
//# sourceMappingURL=fr.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/notifications/i18n/fr.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\nexport const fr = {\n 'If you no longer wish to receive notifications, change your preferences directly from your user space':\n 'Si vous ne souhaitez plus recevoir de notifications, modifiez vos préferences directement depuis votre espace utilisateur',\n 'Access it from': 'Accédez y depuis',\n Comment: 'Commentaire',\n commented: 'a commenté',\n 'You receive this notification if you are the owner of the file or if you have also commented on this file':\n 'Vous recevez cette notification si vous êtes le propriétaire du fichier ou si vous avez également commenté ce fichier',\n Space: 'Espace',\n 'from the space': `de l'espace`,\n 'to the space': `à l'espace`,\n 'Access your spaces from': 'Accédez à vos espaces depuis',\n 'Access this space from': 'Accédez à cet espace depuis',\n 'You now have access to the space': `Vous avez désormais accès à l'espace`,\n 'You no longer have access to the space': `Vous n'avez plus accès à l'espace`,\n 'This space has been permanently deleted': 'Cet espace a été définitivement supprimé',\n anchored: `a ancré`,\n unanchored: `a désancré`,\n Share: 'Partage',\n 'shared with you': 'a partagé avec vous',\n 'no longer share with you': 'ne partage plus avec vous',\n 'You now have access to the share': `Vous avez désormais accès au partage`,\n 'You no longer have access to the share': `Vous n'avez plus accès au partage`,\n 'You are no longer a member of the parent share, your child share has been deleted': `Vous n'êtes plus membre du partage parent, votre partage enfant a été supprimé`,\n 'Access your shares from': 'Accédez à vos partages depuis',\n Sync: 'Synchronisation',\n 'Access your syncs from': 'Accédez à vos synchronisations depuis',\n 'You are no longer synchronizing': 'Vous ne synchronisez plus'\n} as const\n"],"names":["fr","Comment","commented","Space","anchored","unanchored","Share","Sync"],"mappings":"AAAA;;;;CAIC;;;;+BAEYA;;;eAAAA;;;AAAN,MAAMA,KAAK;IAChB,yGACE;IACF,kBAAkB;IAClBC,SAAS;IACTC,WAAW;IACX,6GACE;IACFC,OAAO;IACP,kBAAkB,CAAC,WAAW,CAAC;IAC/B,gBAAgB,CAAC,UAAU,CAAC;IAC5B,2BAA2B;IAC3B,0BAA0B;IAC1B,oCAAoC,CAAC,oCAAoC,CAAC;IAC1E,0CAA0C,CAAC,iCAAiC,CAAC;IAC7E,2CAA2C;IAC3CC,UAAU,CAAC,OAAO,CAAC;IACnBC,YAAY,CAAC,UAAU,CAAC;IACxBC,OAAO;IACP,mBAAmB;IACnB,4BAA4B;IAC5B,oCAAoC,CAAC,oCAAoC,CAAC;IAC1E,0CAA0C,CAAC,iCAAiC,CAAC;IAC7E,qFAAqF,CAAC,8EAA8E,CAAC;IACrK,2BAA2B;
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/notifications/i18n/fr.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\nexport const fr = {\n 'If you no longer wish to receive notifications, change your preferences directly from your user space':\n 'Si vous ne souhaitez plus recevoir de notifications, modifiez vos préferences directement depuis votre espace utilisateur',\n 'Access it from': 'Accédez y depuis',\n Comment: 'Commentaire',\n commented: 'a commenté',\n 'You receive this notification if you are the owner of the file or if you have also commented on this file':\n 'Vous recevez cette notification si vous êtes le propriétaire du fichier ou si vous avez également commenté ce fichier',\n Space: 'Espace',\n 'from the space': `de l'espace`,\n 'to the space': `à l'espace`,\n 'Access your spaces from': 'Accédez à vos espaces depuis',\n 'Access this space from': 'Accédez à cet espace depuis',\n 'You now have access to the space': `Vous avez désormais accès à l'espace`,\n 'You no longer have access to the space': `Vous n'avez plus accès à l'espace`,\n 'This space has been permanently deleted': 'Cet espace a été définitivement supprimé',\n anchored: `a ancré`,\n unanchored: `a désancré`,\n Share: 'Partage',\n 'shared with you': 'a partagé avec vous',\n 'no longer share with you': 'ne partage plus avec vous',\n 'You now have access to the share': `Vous avez désormais accès au partage`,\n 'You no longer have access to the share': `Vous n'avez plus accès au partage`,\n 'You are no longer a member of the parent share, your child share has been deleted': `Vous n'êtes plus membre du partage parent, votre partage enfant a été supprimé`,\n 'Access your shares from': 'Accédez à vos partages depuis',\n 'Access password': `Mot de passe d'accès`,\n Sync: 'Synchronisation',\n 'Access your syncs from': 'Accédez à vos synchronisations depuis',\n 'You are no longer synchronizing': 'Vous ne synchronisez plus',\n 'Security notification': 'Notification de sécurité',\n 'Your account has been locked after several unsuccessful authentication attempts':\n 'Votre compte a été verrouillé après plusieurs tentatives d’authentification infructueuses',\n 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.': `Cette notification de sécurité concerne votre compte Sync-in. Merci de contacter un administrateur afin qu’il procède à l’analyse et au déverrouillage de votre compte.`,\n 'Two-factor authentication (2FA) on your account has been disabled': `L’authentification à deux facteurs (2FA) sur votre compte a été désactivée`,\n 'Two-factor authentication (2FA) on your account has been enabled': `L’authentification à deux facteurs (2FA) sur votre compte a été activée`,\n 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.': `Vous recevez cette notification car la sécurité de votre compte Sync-in a été modifiée. Si vous pensez qu’il s’agit d’une erreur, vérifiez vos paramètres de sécurité ou contactez votre administrateur.`,\n 'Address IP': 'Adresse IP',\n Browser: 'Navigateur'\n} as const\n"],"names":["fr","Comment","commented","Space","anchored","unanchored","Share","Sync","Browser"],"mappings":"AAAA;;;;CAIC;;;;+BAEYA;;;eAAAA;;;AAAN,MAAMA,KAAK;IAChB,yGACE;IACF,kBAAkB;IAClBC,SAAS;IACTC,WAAW;IACX,6GACE;IACFC,OAAO;IACP,kBAAkB,CAAC,WAAW,CAAC;IAC/B,gBAAgB,CAAC,UAAU,CAAC;IAC5B,2BAA2B;IAC3B,0BAA0B;IAC1B,oCAAoC,CAAC,oCAAoC,CAAC;IAC1E,0CAA0C,CAAC,iCAAiC,CAAC;IAC7E,2CAA2C;IAC3CC,UAAU,CAAC,OAAO,CAAC;IACnBC,YAAY,CAAC,UAAU,CAAC;IACxBC,OAAO;IACP,mBAAmB;IACnB,4BAA4B;IAC5B,oCAAoC,CAAC,oCAAoC,CAAC;IAC1E,0CAA0C,CAAC,iCAAiC,CAAC;IAC7E,qFAAqF,CAAC,8EAA8E,CAAC;IACrK,2BAA2B;IAC3B,mBAAmB,CAAC,oBAAoB,CAAC;IACzCC,MAAM;IACN,0BAA0B;IAC1B,mCAAmC;IACnC,yBAAyB;IACzB,mFACE;IACF,8IAA8I,CAAC,uKAAuK,CAAC;IACvT,qEAAqE,CAAC,0EAA0E,CAAC;IACjJ,oEAAoE,CAAC,uEAAuE,CAAC;IAC7I,iMAAiM,CAAC,wMAAwM,CAAC;IAC3Y,cAAc;IACdC,SAAS;AACX"}
|
package/server/applications/notifications/interfaces/notification-properties.interface.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../backend/src/applications/notifications/interfaces/notification-properties.interface.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport type { ACTION } from '../../../common/constants'\nimport type { Owner } from '../../users/interfaces/owner.interface'\nimport type { UserModel } from '../../users/models/user.model'\nimport type { NOTIFICATION_APP } from '../constants/notifications'\nimport type { Notification } from '../schemas/notification.interface'\n\nexport interface NotificationContent {\n app: NOTIFICATION_APP\n event: string\n element: string\n url: string\n}\n\nexport interface NotificationOptions {\n author?: UserModel\n currentUrl?: string\n content?: string\n action?: ACTION\n linkUUID?: string\n}\n\nexport type NotificationFromUser = Omit<Notification, 'fromUserId' | 'toUserId'> & { fromUser: Owner }\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
|
|
1
|
+
{"version":3,"sources":["../../../../../backend/src/applications/notifications/interfaces/notification-properties.interface.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport type { ACTION } from '../../../common/constants'\nimport type { Owner } from '../../users/interfaces/owner.interface'\nimport type { UserModel } from '../../users/models/user.model'\nimport type { NOTIFICATION_APP } from '../constants/notifications'\nimport type { Notification } from '../schemas/notification.interface'\n\nexport interface NotificationContent {\n app: NOTIFICATION_APP\n event: string\n element: string\n url: string\n}\n\nexport interface NotificationOptions {\n author?: UserModel\n currentUrl?: string\n content?: string\n action?: ACTION\n linkUUID?: string\n linkPassword?: string\n}\n\nexport type NotificationFromUser = Omit<Notification, 'fromUserId' | 'toUserId'> & { fromUser: Owner }\n"],"names":[],"mappings":"AAAA;;;;CAIC"}
|
|
@@ -13,6 +13,12 @@ function _export(target, all) {
|
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
_export(exports, {
|
|
16
|
+
get auth2FaMail () {
|
|
17
|
+
return auth2FaMail;
|
|
18
|
+
},
|
|
19
|
+
get authLocked () {
|
|
20
|
+
return authLocked;
|
|
21
|
+
},
|
|
16
22
|
get commentMail () {
|
|
17
23
|
return commentMail;
|
|
18
24
|
},
|
|
@@ -103,12 +109,15 @@ function shareMail(language, notification, options) {
|
|
|
103
109
|
function linkMail(language, notification, options) {
|
|
104
110
|
const tr = (0, _i18n.translateObject)(language, {
|
|
105
111
|
title: options.action === _constants.ACTION.ADD ? 'Share' : 'Space',
|
|
106
|
-
|
|
112
|
+
passwordText: 'Access password',
|
|
107
113
|
urlText: 'Access it from',
|
|
108
114
|
event: notification.event
|
|
109
115
|
});
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
let content = `${options.author ? (0, _templates.mailAuthor)(options.author) : ''}${(0, _templates.mailEventOnElement)(tr.event, notification.element)}`;
|
|
117
|
+
if (options.linkPassword) {
|
|
118
|
+
content += `<br><br>${tr.passwordText}: <div style="border:1px solid #000; padding:8px; display:inline-block;">${options.linkPassword}</div>`;
|
|
119
|
+
}
|
|
120
|
+
const footer = `<br>${tr.urlText} <a href="${(0, _urls.urlFromLink)(options.currentUrl, options.linkUUID)}">${_appconstants.SERVER_NAME}</a>`;
|
|
112
121
|
return [
|
|
113
122
|
`${tr.title}: ${(0, _shared.capitalizeString)(notification.element)}`,
|
|
114
123
|
(0, _templates.mailTemplate)(content, footer)
|
|
@@ -129,5 +138,34 @@ function syncMail(language, notification, options) {
|
|
|
129
138
|
(0, _templates.mailTemplate)(content, footer)
|
|
130
139
|
];
|
|
131
140
|
}
|
|
141
|
+
function auth2FaMail(language, notification) {
|
|
142
|
+
const tr = (0, _i18n.translateObject)(language, {
|
|
143
|
+
title: 'Security notification',
|
|
144
|
+
footer: 'You received this notification because the security of your Sync-in account has changed. If you think this was a mistake, please review your security settings or contact your administrator.',
|
|
145
|
+
event: notification.event,
|
|
146
|
+
addressIp: 'Address IP',
|
|
147
|
+
browser: 'Browser'
|
|
148
|
+
});
|
|
149
|
+
const content = `${tr.event}<br><br>${tr.addressIp}: ${notification.url}<br>${tr.browser}: ${notification.element}`;
|
|
150
|
+
const footer = `<br>${tr.footer}<br>`;
|
|
151
|
+
return [
|
|
152
|
+
tr.title,
|
|
153
|
+
(0, _templates.mailTemplate)(content, footer)
|
|
154
|
+
];
|
|
155
|
+
}
|
|
156
|
+
function authLocked(language, notification) {
|
|
157
|
+
const tr = (0, _i18n.translateObject)(language, {
|
|
158
|
+
title: 'Security notification',
|
|
159
|
+
footer: 'This security notification concerns your Sync-in account. Please contact an administrator to perform the analysis and unlock your account.',
|
|
160
|
+
event: notification.event,
|
|
161
|
+
addressIp: 'Address IP'
|
|
162
|
+
});
|
|
163
|
+
const content = `${tr.event}<br><br>${tr.addressIp}: ${notification.url}<br>`;
|
|
164
|
+
const footer = `<br>${tr.footer}<br>`;
|
|
165
|
+
return [
|
|
166
|
+
tr.title,
|
|
167
|
+
(0, _templates.mailTemplate)(content, footer)
|
|
168
|
+
];
|
|
169
|
+
}
|
|
132
170
|
|
|
133
171
|
//# sourceMappingURL=models.js.map
|