@sync-in/server 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/CHANGELOG.md +12 -8
  2. package/package.json +7 -7
  3. package/server/applications/files/services/files-manager.service.js +2 -2
  4. package/server/applications/files/services/files-manager.service.js.map +1 -1
  5. package/server/applications/files/services/files-tasks-manager.service.js +1 -1
  6. package/server/applications/files/services/files-tasks-manager.service.js.map +1 -1
  7. package/server/applications/files/utils/send-file.js +18 -9
  8. package/server/applications/files/utils/send-file.js.map +1 -1
  9. package/server/applications/files/utils/url-file.js +6 -6
  10. package/server/applications/files/utils/url-file.js.map +1 -1
  11. package/server/applications/links/services/links-manager.service.js +1 -1
  12. package/server/applications/links/services/links-manager.service.js.map +1 -1
  13. package/server/applications/shares/interfaces/share-props.interface.js.map +1 -1
  14. package/server/applications/shares/services/shares-manager.service.js +6 -4
  15. package/server/applications/shares/services/shares-manager.service.js.map +1 -1
  16. package/server/applications/spaces/services/spaces-manager.service.js +15 -12
  17. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  18. package/server/applications/users/services/admin-users-manager.service.js +4 -0
  19. package/server/applications/users/services/admin-users-manager.service.js.map +1 -1
  20. package/server/applications/users/users.controller.js +4 -1
  21. package/server/applications/users/users.controller.js.map +1 -1
  22. package/static/assets/pdfjs/build/pdf.mjs +35 -20
  23. package/static/assets/pdfjs/build/pdf.mjs.map +1 -1
  24. package/static/assets/pdfjs/build/pdf.sandbox.mjs +2 -2
  25. package/static/assets/pdfjs/build/pdf.worker.mjs +1488 -52
  26. package/static/assets/pdfjs/build/pdf.worker.mjs.map +1 -1
  27. package/static/assets/pdfjs/version +1 -1
  28. package/static/assets/pdfjs/web/locale/be/viewer.ftl +2 -12
  29. package/static/assets/pdfjs/web/locale/bg/viewer.ftl +4 -0
  30. package/static/assets/pdfjs/web/locale/bs/viewer.ftl +0 -15
  31. package/static/assets/pdfjs/web/locale/ca/viewer.ftl +0 -4
  32. package/static/assets/pdfjs/web/locale/cs/viewer.ftl +4 -14
  33. package/static/assets/pdfjs/web/locale/cy/viewer.ftl +2 -12
  34. package/static/assets/pdfjs/web/locale/da/viewer.ftl +2 -12
  35. package/static/assets/pdfjs/web/locale/de/viewer.ftl +0 -12
  36. package/static/assets/pdfjs/web/locale/dsb/viewer.ftl +0 -12
  37. package/static/assets/pdfjs/web/locale/el/viewer.ftl +2 -12
  38. package/static/assets/pdfjs/web/locale/en-CA/viewer.ftl +0 -12
  39. package/static/assets/pdfjs/web/locale/en-GB/viewer.ftl +0 -12
  40. package/static/assets/pdfjs/web/locale/eo/viewer.ftl +2 -12
  41. package/static/assets/pdfjs/web/locale/es-AR/viewer.ftl +0 -12
  42. package/static/assets/pdfjs/web/locale/es-CL/viewer.ftl +2 -12
  43. package/static/assets/pdfjs/web/locale/es-ES/viewer.ftl +2 -12
  44. package/static/assets/pdfjs/web/locale/es-MX/viewer.ftl +0 -12
  45. package/static/assets/pdfjs/web/locale/eu/viewer.ftl +0 -12
  46. package/static/assets/pdfjs/web/locale/fi/viewer.ftl +0 -12
  47. package/static/assets/pdfjs/web/locale/fr/viewer.ftl +0 -12
  48. package/static/assets/pdfjs/web/locale/fur/viewer.ftl +0 -12
  49. package/static/assets/pdfjs/web/locale/fy-NL/viewer.ftl +0 -12
  50. package/static/assets/pdfjs/web/locale/gn/viewer.ftl +2 -12
  51. package/static/assets/pdfjs/web/locale/he/viewer.ftl +0 -12
  52. package/static/assets/pdfjs/web/locale/hsb/viewer.ftl +0 -12
  53. package/static/assets/pdfjs/web/locale/hu/viewer.ftl +0 -12
  54. package/static/assets/pdfjs/web/locale/hy-AM/viewer.ftl +0 -15
  55. package/static/assets/pdfjs/web/locale/ia/viewer.ftl +0 -12
  56. package/static/assets/pdfjs/web/locale/id/viewer.ftl +0 -15
  57. package/static/assets/pdfjs/web/locale/is/viewer.ftl +0 -15
  58. package/static/assets/pdfjs/web/locale/it/viewer.ftl +2 -14
  59. package/static/assets/pdfjs/web/locale/ja/viewer.ftl +7 -2
  60. package/static/assets/pdfjs/web/locale/ka/viewer.ftl +0 -12
  61. package/static/assets/pdfjs/web/locale/kab/viewer.ftl +0 -12
  62. package/static/assets/pdfjs/web/locale/kk/viewer.ftl +3 -12
  63. package/static/assets/pdfjs/web/locale/ko/viewer.ftl +0 -12
  64. package/static/assets/pdfjs/web/locale/nb-NO/viewer.ftl +2 -12
  65. package/static/assets/pdfjs/web/locale/nl/viewer.ftl +0 -12
  66. package/static/assets/pdfjs/web/locale/nn-NO/viewer.ftl +0 -12
  67. package/static/assets/pdfjs/web/locale/pa-IN/viewer.ftl +4 -12
  68. package/static/assets/pdfjs/web/locale/pl/viewer.ftl +2 -12
  69. package/static/assets/pdfjs/web/locale/pt-BR/viewer.ftl +2 -12
  70. package/static/assets/pdfjs/web/locale/rm/viewer.ftl +0 -12
  71. package/static/assets/pdfjs/web/locale/ro/viewer.ftl +2 -14
  72. package/static/assets/pdfjs/web/locale/ru/viewer.ftl +0 -12
  73. package/static/assets/pdfjs/web/locale/sc/viewer.ftl +0 -1
  74. package/static/assets/pdfjs/web/locale/sk/viewer.ftl +0 -12
  75. package/static/assets/pdfjs/web/locale/sl/viewer.ftl +2 -12
  76. package/static/assets/pdfjs/web/locale/sq/viewer.ftl +2 -12
  77. package/static/assets/pdfjs/web/locale/sv-SE/viewer.ftl +0 -12
  78. package/static/assets/pdfjs/web/locale/tg/viewer.ftl +2 -12
  79. package/static/assets/pdfjs/web/locale/th/viewer.ftl +0 -12
  80. package/static/assets/pdfjs/web/locale/tr/viewer.ftl +2 -12
  81. package/static/assets/pdfjs/web/locale/vi/viewer.ftl +0 -12
  82. package/static/assets/pdfjs/web/locale/zh-CN/viewer.ftl +2 -12
  83. package/static/assets/pdfjs/web/locale/zh-TW/viewer.ftl +0 -12
  84. package/static/assets/pdfjs/web/viewer.css +53 -41
  85. package/static/assets/pdfjs/web/viewer.html +493 -132
  86. package/static/assets/pdfjs/web/viewer.mjs +225 -150
  87. package/static/assets/pdfjs/web/viewer.mjs.map +1 -1
  88. package/static/{chunk-LYZGJZNP.js → chunk-25PWAXTJ.js} +1 -1
  89. package/static/{chunk-HCSWO7BO.js → chunk-27XEAHMV.js} +1 -1
  90. package/static/{chunk-YMAN4LIU.js → chunk-2CAAJBRO.js} +1 -1
  91. package/static/{chunk-RK2ONYTL.js → chunk-2LHHXDD5.js} +1 -1
  92. package/static/{chunk-YCTCESL4.js → chunk-2XY4PMI5.js} +1 -1
  93. package/static/{chunk-ERDZ7IVF.js → chunk-33WFRCUP.js} +1 -1
  94. package/static/chunk-3LVFDMTN.js +1 -0
  95. package/static/{chunk-V6FA5QY4.js → chunk-4DF2SQD4.js} +1 -1
  96. package/static/{chunk-Q556XB3S.js → chunk-4EUHBTWV.js} +1 -1
  97. package/static/{chunk-AADK5D2H.js → chunk-4KXJ6C4N.js} +1 -1
  98. package/static/{chunk-BHZEPHRI.js → chunk-4OV3SAUS.js} +1 -1
  99. package/static/{chunk-5S6KPQRA.js → chunk-5HCVWZMA.js} +1 -1
  100. package/static/{chunk-ZCOWBVOT.js → chunk-5HYSNQR4.js} +1 -1
  101. package/static/{chunk-4PZPHJ7L.js → chunk-5NHB7SV3.js} +1 -1
  102. package/static/chunk-6VJI4X2A.js +1 -0
  103. package/static/{chunk-XCLK7NJL.js → chunk-7H5O4BLV.js} +1 -1
  104. package/static/{chunk-ACUF7IKP.js → chunk-7NI353LS.js} +1 -1
  105. package/static/{chunk-TGLJFALR.js → chunk-A6J6SOM6.js} +1 -1
  106. package/static/{chunk-XOF4UW3S.js → chunk-A7DSX7VP.js} +1 -1
  107. package/static/chunk-A7R246NW.js +1 -0
  108. package/static/{chunk-EL6QL4TP.js → chunk-ASBPYTLT.js} +1 -1
  109. package/static/chunk-BJARRIS6.js +562 -0
  110. package/static/{chunk-VQJYCYWI.js → chunk-CAZSNVMS.js} +1 -1
  111. package/static/{chunk-EIYRBM4J.js → chunk-CURVLK7L.js} +1 -1
  112. package/static/{chunk-5E3TYOL3.js → chunk-DDRGLHOP.js} +1 -1
  113. package/static/{chunk-ZXXHFBGL.js → chunk-FLPZB3OX.js} +1 -1
  114. package/static/{chunk-23UUFZSR.js → chunk-FRBTL2ER.js} +1 -1
  115. package/static/{chunk-JY2I3HGL.js → chunk-FXM7XXWA.js} +1 -1
  116. package/static/{chunk-7CKHC72R.js → chunk-GDPJRUVU.js} +1 -1
  117. package/static/{chunk-QMHUIHSR.js → chunk-GENTF6JM.js} +1 -1
  118. package/static/{chunk-VK7XMFVE.js → chunk-H4RLHI3Y.js} +1 -1
  119. package/static/{chunk-3WLBVJ2S.js → chunk-HE6EDXWI.js} +1 -1
  120. package/static/{chunk-U4RW6XG5.js → chunk-IUJ4IK26.js} +1 -1
  121. package/static/{chunk-XQGPSNQB.js → chunk-JEVBUJQ4.js} +1 -1
  122. package/static/{chunk-K657XPXA.js → chunk-K3MOXDU5.js} +1 -1
  123. package/static/{chunk-6B3GGAV3.js → chunk-KBWK65KM.js} +1 -1
  124. package/static/{chunk-I2S3XPC5.js → chunk-L3PDWJZ3.js} +2 -2
  125. package/static/{chunk-KDEEERWZ.js → chunk-LBXOAKBD.js} +1 -1
  126. package/static/{chunk-Y5RLD72B.js → chunk-LFAQLJZK.js} +1 -1
  127. package/static/{chunk-M4XL3JN5.js → chunk-MBFMTBVJ.js} +1 -1
  128. package/static/{chunk-HMOB6XC5.js → chunk-MZBO5PAR.js} +1 -1
  129. package/static/{chunk-DJDRX53V.js → chunk-NFIES7BC.js} +1 -1
  130. package/static/{chunk-3YDYZLF7.js → chunk-NK2NMAJI.js} +1 -1
  131. package/static/{chunk-FNOTGWRW.js → chunk-O7UXVNR2.js} +1 -1
  132. package/static/{chunk-RDNTK4YH.js → chunk-PKU4IIIR.js} +1 -1
  133. package/static/{chunk-NN4ONTOT.js → chunk-QUSS6SUC.js} +1 -1
  134. package/static/{chunk-BU4ZICZR.js → chunk-R6VB3INJ.js} +1 -1
  135. package/static/{chunk-2TB2INBF.js → chunk-RJOHDAPM.js} +1 -1
  136. package/static/{chunk-BODMMLVB.js → chunk-S6YKBWJE.js} +1 -1
  137. package/static/{chunk-AZ5TF5Y3.js → chunk-SDR3UG2F.js} +1 -1
  138. package/static/{chunk-C3AAEQKW.js → chunk-TGHBDJZA.js} +1 -1
  139. package/static/{chunk-HNMGPG72.js → chunk-TVJQXN73.js} +1 -1
  140. package/static/{chunk-6NEBGCAZ.js → chunk-U75PLYIJ.js} +1 -1
  141. package/static/chunk-UUX3M6DC.js +1 -0
  142. package/static/{chunk-JWPXQOS3.js → chunk-VJ2HWQRJ.js} +2 -2
  143. package/static/{chunk-S2VBGI6Q.js → chunk-VO4WVT6K.js} +1 -1
  144. package/static/{chunk-5XUIPWOH.js → chunk-W72JYHOH.js} +1 -1
  145. package/static/{chunk-PXRT4L57.js → chunk-WJYVS27M.js} +1 -1
  146. package/static/{chunk-HKRGIRKB.js → chunk-XAIOGRBO.js} +1 -1
  147. package/static/{chunk-NKGKBQBX.js → chunk-XHQEF2IX.js} +1 -1
  148. package/static/{chunk-DQ3GEMPM.js → chunk-XXYMVRSH.js} +1 -1
  149. package/static/{chunk-HHWXIK2M.js → chunk-YTBSB2GE.js} +1 -1
  150. package/static/{chunk-GRLHFXGB.js → chunk-YXWF2DGF.js} +1 -1
  151. package/static/{chunk-JMYAD7E2.js → chunk-Z6RJZIDG.js} +1 -1
  152. package/static/{chunk-GNZPP2VO.js → chunk-ZC5ZDCDC.js} +1 -1
  153. package/static/{chunk-EDJAISWO.js → chunk-ZERBTNFW.js} +8 -8
  154. package/static/{chunk-MIA5YBOI.js → chunk-ZPI7RQ2S.js} +1 -1
  155. package/static/{chunk-NOPACN4F.js → chunk-ZRBLCAOK.js} +1 -1
  156. package/static/index.html +2 -2
  157. package/static/{main-56PZQ6TJ.js → main-FE6GWZXU.js} +4 -4
  158. package/static/{styles-Q4OZOSSK.css → styles-S5HVK4H5.css} +1 -1
  159. package/static/chunk-H6WOTGQ5.js +0 -1
  160. package/static/chunk-HC7F57NA.js +0 -1
  161. package/static/chunk-IOIBQGHN.js +0 -562
  162. package/static/chunk-J6YSFHLZ.js +0 -1
  163. package/static/chunk-QVFPHTOH.js +0 -1
package/CHANGELOG.md CHANGED
@@ -1,16 +1,20 @@
1
1
 
2
- ## [1.9.1](https://github.com/Sync-in/server/compare/v1.8.1...v1.9.1) (2025-11-25)
2
+ ## [1.9.3](https://github.com/Sync-in/server/compare/v1.9.1...v1.9.3) (2025-12-07)
3
+
4
+ ### Security Fixes
5
+ * **backend:security:** prevent stored XSS by serving files with `Content-Disposition: attachment` to avoid arbitrary JavaScript execution in the browser ([a6276d0](https://github.com/Sync-in/server/commit/a6276d067725637310e4e83a3eee337aae81f439))
3
6
 
4
- ### Highlights 1.9
7
+ ### Bug Fixes
8
+ * **ci:** update Dockerfile to use alpine3.22 to avoid errors with busybox-1.37.0-r29 ([ede1bec](https://github.com/Sync-in/server/commit/ede1bec4b3c33f17c3b94c32d68c4b642ee710c0))
9
+ * **backend:users:** clear whitelist caches when group visibility changes ([071c3ae](https://github.com/Sync-in/server/commit/071c3aed68d3bdacead571d39a1f4006b2380915))
10
+ * **frontend:files:** fix DataTransfer usage after async operations and delay overwrite until analysis completes to restore overwrite on dropped files ([d9935e5](https://github.com/Sync-in/server/commit/d9935e5a3887448635c30fd49f22657461177610))
11
+ * **frontend:styles:** add min-width on app-auth background class ([dffd5e5](https://github.com/Sync-in/server/commit/dffd5e5c7a1a65994970bedf33a95dd00827aa94))
5
12
 
6
- * 🎨 **Visual identity updated** — refreshed branding.
7
- * 🖼️ **Enhanced image viewer** — browse all images in a directory, start slideshows, use fullscreen mode, and view detailed properties.
8
- * ✏️ **Native text editor** — search, syntax highlighting, undo/redo, and lock/unlock capabilities built directly into the UI.
9
- * 🔐 **Improved file lock management** — users can request unlocks from lock owners, and file owners can now remove locks themselves.
10
- * ⚠️ **Overwrite confirmation dialogs** — added confirmation prompts for uploads, renaming, copying, and moving files to prevent accidental overwrites.
13
+ ### Community Highlights ❤️
11
14
 
12
- ➡️ [More details](https://sync-in.com/news/sync-in-server-1-9)
15
+ We would like to thank @x0root for reporting this vulnerability and helping improve the security of the project.
13
16
 
17
+ ## [1.9.1](https://github.com/Sync-in/server/compare/v1.8.1...v1.9.1) (2025-11-25)
14
18
 
15
19
  ### Features
16
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sync-in/server",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
4
4
  "description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
5
5
  "author": {
6
6
  "name": "Johan Legrand",
@@ -95,7 +95,7 @@
95
95
  "archiver": "7.0.1",
96
96
  "bcryptjs": "3.0.3",
97
97
  "class-transformer": "0.5.1",
98
- "class-validator": "0.14.2",
98
+ "class-validator": "0.14.3",
99
99
  "deepmerge": "4.3.1",
100
100
  "drizzle-kit": "0.31.7",
101
101
  "drizzle-orm": "0.44.7",
@@ -103,16 +103,16 @@
103
103
  "fs-extra": "11.3.2",
104
104
  "html-to-text": "9.0.5",
105
105
  "js-yaml": "4.1.1",
106
- "ldapts": "8.0.9",
107
- "mime-types": "3.0.1",
106
+ "ldapts": "8.0.11",
107
+ "mime-types": "3.0.2",
108
108
  "mysql2": "3.15.3",
109
- "nestjs-pino": "4.4.1",
110
- "nodemailer": "7.0.10",
109
+ "nestjs-pino": "4.5.0",
110
+ "nodemailer": "7.0.11",
111
111
  "passport-http": "0.3.0",
112
112
  "passport-jwt": "4.0.1",
113
113
  "passport-local": "1.0.0",
114
114
  "passport": "0.7.0",
115
- "pino-pretty": "13.1.2",
115
+ "pino-pretty": "13.1.3",
116
116
  "qrcode-generator": "2.0.4",
117
117
  "redis": "5.10.0",
118
118
  "sax": "1.4.3",
@@ -57,8 +57,8 @@ function _ts_metadata(k, v) {
57
57
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
58
58
  }
59
59
  let FilesManager = class FilesManager {
60
- sendFileFromSpace(space, asAttachment = false, downloadName = '') {
61
- return new _sendfile.SendFile(space.realPath, asAttachment, downloadName);
60
+ sendFileFromSpace(space, downloadName = '') {
61
+ return new _sendfile.SendFile(space.realPath, downloadName);
62
62
  }
63
63
  async saveStream(user, space, req, options) {
64
64
  // if tmpPath is used, we lock the final destination during the transfer
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-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 { HttpService } from '@nestjs/axios'\nimport { HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport archiver, { Archiver, ArchiverError } from 'archiver'\nimport { AxiosResponse } from 'axios'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { Readable } from 'node:stream'\nimport { extract as extractTar } from 'tar'\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\nimport { generateThumbnail } from '../../../common/image'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { NOTIFICATION_APP, NOTIFICATION_APP_EVENT } from '../../notifications/constants/notifications'\nimport { NotificationContent } from '../../notifications/interfaces/notification-properties.interface'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SPACE_OPERATION } from '../../spaces/constants/spaces'\nimport { FastifySpaceRequest } from '../../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { realTrashPathFromSpace } from '../../spaces/utils/paths'\nimport { canAccessToSpace, haveSpaceEnvPermissions } from '../../spaces/utils/permissions'\nimport { UserModel } from '../../users/models/user.model'\nimport { DEPTH, LOCK_DEPTH } from '../../webdav/constants/webdav'\nimport { CACHE_LOCK_FILE_TTL } from '../constants/cache'\nimport { tarGzExtension } from '../constants/compress'\nimport { COMPRESSION_EXTENSION, DEFAULT_HIGH_WATER_MARK } from '../constants/files'\nimport { FILE_OPERATION } from '../constants/operations'\nimport { DOCUMENT_TYPE, SAMPLE_PATH_WITHOUT_EXT } from '../constants/samples'\nimport { CompressFileDto } from '../dto/file-operations.dto'\nimport { FileTaskEvent } from '../events/file-task-event'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock } from '../interfaces/file-lock.interface'\nimport { FileLockProps } from '../interfaces/file-props.interface'\nimport { FileError } from '../models/file-error'\nimport { LockConflict } from '../models/file-lock-error'\nimport {\n checkFileName,\n copyFileContent,\n copyFiles,\n createEmptyFile,\n dirName,\n dirSize,\n fileName,\n fileSize,\n getMimeType,\n isPathExists,\n isPathIsDir,\n makeDir,\n moveFiles,\n removeFiles,\n touchFile,\n uniqueDatedFilePath,\n uniqueFilePathFromDir,\n writeFromStream,\n writeFromStreamAndChecksum\n} from '../utils/files'\nimport { SendFile } from '../utils/send-file'\nimport { extractZip } from '../utils/unzip-file'\nimport { regExpPrivateIP } from '../utils/url-file'\nimport { FilesLockManager } from './files-lock-manager.service'\nimport { FilesQueries } from './files-queries.service'\n\n@Injectable()\nexport class FilesManager {\n /* Spaces permissions are checked in the space guard, except for the copy/move destination */\n private logger = new Logger(FilesManager.name)\n\n constructor(\n private readonly http: HttpService,\n private readonly filesQueries: FilesQueries,\n private readonly spacesManager: SpacesManager,\n private readonly contextManager: ContextManager,\n private readonly notificationsManager: NotificationsManager,\n public readonly filesLockManager: FilesLockManager\n ) {}\n\n sendFileFromSpace(space: SpaceEnv, asAttachment = false, downloadName = ''): SendFile {\n return new SendFile(space.realPath, asAttachment, downloadName)\n }\n\n async saveStream(\n user: UserModel,\n space: SpaceEnv,\n req: FastifyAuthenticatedRequest,\n options: {\n checksumAlg: string\n tmpPath?: string\n }\n ): Promise<string>\n async saveStream(user: UserModel, space: SpaceEnv, req: FastifyAuthenticatedRequest, options?: any): Promise<boolean>\n async saveStream(\n user: UserModel,\n space: SpaceEnv,\n req: FastifyAuthenticatedRequest,\n options?: { dav?: { depth: LOCK_DEPTH; lockTokens: string[] }; checksumAlg?: string; tmpPath?: string }\n ): Promise<boolean | string> {\n // if tmpPath is used, we lock the final destination during the transfer\n // space.realPath is replaced by tmpPath (if allowed), if the move operation failed we remove the tmp file\n const fExists = await isPathExists(space.realPath)\n const fTmpExists = options?.tmpPath ? await isPathExists(options.tmpPath) : false\n if (fExists && req.method === HTTP_METHOD.POST) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'Resource already exists')\n }\n if (fExists && (await isPathIsDir(space.realPath))) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'The location is a directory')\n }\n if (options?.tmpPath) {\n // ensure tmpPath parent dir exists\n await makeDir(dirName(options.tmpPath), true)\n } else if (!(await isPathExists(dirName(space.realPath)))) {\n throw new FileError(HttpStatus.CONFLICT, 'Parent must exists')\n }\n /* File Lock */\n let fileLock: FileLock | undefined\n if (options?.dav) {\n // check locks\n await this.filesLockManager.checkConflicts(space.dbFile, options?.dav?.depth || DEPTH.RESOURCE, {\n userId: user.id,\n lockTokens: options.dav?.lockTokens\n })\n } else {\n // create lock if there is no webdav context\n const [ok, lock] = await this.filesLockManager.create(user, space.dbFile, DEPTH.RESOURCE)\n if (!ok) {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n fileLock = lock\n }\n try {\n // check range\n let startRange = 0\n if ((fExists || fTmpExists) && req.headers['content-range']) {\n // with PUT method, some webdav clients use the `content-range` header,\n // which is normally reserved for a response to a request containing the `range` header.\n // However, for more compatibility let's accept it\n const match = /\\d+/.exec(req.headers['content-range'])\n if (!match.length) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Content-range : header is malformed')\n }\n startRange = parseInt(match[0], 10)\n const size = await fileSize(options?.tmpPath || space.realPath)\n if (startRange !== size) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Content-range : start offset does not match the current file size')\n }\n }\n // todo: check file in db to update\n // todo : versioning here\n let checksum: string\n if (options?.checksumAlg) {\n checksum = await writeFromStreamAndChecksum(options?.tmpPath || space.realPath, req.raw, startRange, options.checksumAlg)\n } else {\n await writeFromStream(options?.tmpPath || space.realPath, req.raw, startRange)\n }\n if (options?.tmpPath) {\n try {\n // ensure parent path exists\n await makeDir(path.dirname(space.realPath), true)\n // move the uploaded file to destination\n await moveFiles(options.tmpPath, space.realPath, true)\n } catch (e) {\n // cleanup tmp file\n await removeFiles(options.tmpPath)\n this.logger.error(`${this.saveStream.name} - unable to move ${options.tmpPath} -> ${space.realPath} : ${e}`)\n throw new FileError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to move tmp file to dst file')\n }\n }\n if (options?.checksumAlg) {\n return checksum\n }\n return fExists\n } finally {\n if (fileLock) {\n try {\n await this.filesLockManager.removeLock(fileLock.key)\n } catch (e) {\n this.logger.warn(`Failed to remove lock ${fileLock.key}: ${e}`)\n }\n }\n }\n }\n\n async saveMultipart(user: UserModel, space: SpaceEnv, req: FastifySpaceRequest) {\n /* Accepted methods:\n POST: Creates new resource\n PUT: Creates or fully replaces a resource at the given URI (even if intermediate paths do not exist)\n PATCH: Updates the content of an existing resource without creating a new one.\n In this text-editing scenario, locking and refreshing occur automatically, but unlocking must be handled explicitly via\n the `unlock` method.\n */\n const overwrite = req.method === HTTP_METHOD.PUT\n const patch = req.method === HTTP_METHOD.PATCH\n const realParentPath = dirName(space.realPath)\n\n if (!overwrite) {\n if (!patch && (await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Resource already exists')\n }\n if (!(await isPathExists(realParentPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Parent must exists')\n }\n if (!(await isPathIsDir(realParentPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Parent must be a directory')\n }\n }\n\n const basePath = realParentPath + path.sep\n\n for await (const part of req.files()) {\n // If the request uses the PATCH method, the file name corresponds to the space\n const partFileName = patch ? fileName(space.realPath) : part.filename\n // `part.filename` may contain a path like foo/bar.txt\n const dstFile = path.resolve(basePath, partFileName)\n // Prevent path traversal\n if (!dstFile.startsWith(basePath)) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Location is not allowed')\n }\n\n const dstDir = dirName(dstFile)\n\n if (overwrite) {\n // Prevent errors when an uploaded file would replace a directory with the same name\n // Only applies in `overwrite` cases\n if ((await isPathExists(dstFile)) && (await isPathIsDir(dstFile))) {\n // If a directory already exists at the destination path, delete it to allow overwriting with the uploaded file\n const dstUrl = path.join(path.dirname(space.url), partFileName)\n const dstSpace = await this.spacesManager.spaceEnv(user, dstUrl.split('/'))\n await this.delete(user, dstSpace)\n } else if ((await isPathExists(dstDir)) && !(await isPathIsDir(dstDir))) {\n // If the destination's parent exists but is a file, remove it so we can create the directory\n const dstUrl = path.join(path.dirname(space.url), path.dirname(partFileName))\n const dstSpace = await this.spacesManager.spaceEnv(user, dstUrl.split('/'))\n await this.delete(user, dstSpace)\n }\n }\n // Create the directory in the space\n if (!(await isPathExists(dstDir))) {\n await makeDir(dstDir, true)\n }\n // Create or refresh lock\n const dbFile = { ...space.dbFile, path: path.join(dirName(space.dbFile.path), partFileName) }\n // Use a short TTL for the PATCH method (which is also used for refreshing)\n const ttl = patch ? CACHE_LOCK_FILE_TTL : undefined\n const [created, fileLock] = await this.filesLockManager.createOrRefresh(user, dbFile, DEPTH.RESOURCE, ttl)\n // Do\n try {\n await writeFromStream(dstFile, part.file)\n } finally {\n if (!patch && created) {\n // Remove the file lock only if it has not been refreshed\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n if (patch) {\n // Only one resource can be updated with the PATCH method.\n break\n }\n }\n }\n\n async touch(user: UserModel, space: SpaceEnv, mtime: number, checkLocks = true): Promise<void> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (checkLocks) {\n await this.filesLockManager.checkConflicts(space.dbFile, DEPTH.RESOURCE, { userId: user.id })\n }\n // todo: update mtime in last files ( & in db file ?)\n await touchFile(space.realPath, mtime)\n }\n\n async mkFile(user: UserModel, space: SpaceEnv, overwrite = false, checkLocks = true, checkDocument = false): Promise<void> {\n checkFileName(space.realPath)\n if (!overwrite && (await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Resource already exists')\n }\n if (checkLocks) {\n await this.filesLockManager.checkConflicts(space.dbFile, DEPTH.RESOURCE, { userId: user.id })\n }\n // use sample documents when possible\n const fileExtension = path.extname(space.realPath)\n if (checkDocument && fileExtension !== '.txt' && Object.values(DOCUMENT_TYPE).indexOf(fileExtension) > -1) {\n const srcSample = path.join(__dirname, `${SAMPLE_PATH_WITHOUT_EXT}${fileExtension}`)\n return copyFileContent(srcSample, space.realPath)\n } else {\n return createEmptyFile(space.realPath)\n }\n }\n\n async mkDir(user: UserModel, space: SpaceEnv, recursive = false, dav?: { depth: LOCK_DEPTH; lockTokens: string[] }): Promise<void> {\n checkFileName(space.realPath)\n if (!recursive) {\n if (await isPathExists(space.realPath)) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'Resource already exists')\n } else if (!(await isPathExists(dirName(space.realPath)))) {\n throw new FileError(HttpStatus.CONFLICT, 'Parent must exists')\n }\n }\n await this.filesLockManager.checkConflicts(space.dbFile, dav?.depth || DEPTH.RESOURCE, { userId: user.id, lockTokens: dav?.lockTokens })\n await makeDir(space.realPath, recursive)\n }\n\n async copyMove(\n user: UserModel,\n srcSpace: SpaceEnv,\n dstSpace: SpaceEnv,\n isMove: boolean,\n overwrite = false,\n mkdirDstParentPath = false,\n dav?: { depth: LOCK_DEPTH; lockTokens: string[] }\n ): Promise<void> {\n // checks\n if (!canAccessToSpace(user, dstSpace)) {\n this.logger.warn(`${this.copyMove.name} - is not allowed to access to this space repository : ${dstSpace.repository}`)\n throw new FileError(HttpStatus.FORBIDDEN, 'You are not allowed to access to this repository')\n }\n if (!haveSpaceEnvPermissions(dstSpace, SPACE_OPERATION.ADD)) {\n this.logger.warn(`${this.copyMove.name} - is not allowed to copy/move on this space : *${dstSpace.alias}* (${dstSpace.id}) : ${dstSpace.url}`)\n throw new FileError(HttpStatus.FORBIDDEN, 'You are not allowed to copy/move on the destination')\n }\n if (dstSpace.quotaIsExceeded) {\n this.logger.warn(`${this.copyMove.name} - quota is exceeded for *${dstSpace.alias}* (${dstSpace.id})`)\n throw new FileError(HttpStatus.INSUFFICIENT_STORAGE, 'Quota is exceeded')\n }\n if (!(await isPathExists(srcSpace.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (!(await isPathExists(dirName(dstSpace.realPath)))) {\n if (mkdirDstParentPath) {\n try {\n await makeDir(dirName(dstSpace.realPath), true)\n } catch (e) {\n this.logger.error(`${this.copyMove.name} - Cannot create parent directory for destination ${dstSpace.realPath} : ${e}`)\n throw new FileError(HttpStatus.INTERNAL_SERVER_ERROR, 'Cannot create parent directory for destination')\n }\n } else {\n throw new FileError(HttpStatus.CONFLICT, 'Parent must exists')\n }\n }\n if (srcSpace.realPath === dstSpace.realPath) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Cannot copy/move source onto itself')\n }\n if (`${dstSpace.realPath}/`.startsWith(`${srcSpace.realPath}/`)) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Cannot copy/move source below itself')\n }\n if (dirName(srcSpace.url) === dirName(dstSpace.url) && dirName(srcSpace.realPath) !== dirName(dstSpace.realPath)) {\n /* Handle renaming a space file with the same name as a space root :\n srcSpace.url = '/space/sync-in/code2.ts' (a space file)\n srcSpace.realPath = '/home/sync-in/spaces/sync-in/code2.ts\n dstSpace.url = '/space/sync-in/code.ts' (a space root)\n dstSpace.realPath = '/home/sync-in/users/jo/files/code2.ts !!\n */\n throw new FileError(HttpStatus.BAD_REQUEST, 'An anchored file already has this name')\n }\n if (!overwrite && (await isPathExists(dstSpace.realPath))) {\n /* Handle case-sensitive (in renaming context):\n srcSpace.url = '/space/sync-in/code.ts'\n dstSpace.url = '/space/sync-in/code.TS'\n The destination exists because it's the same file, bypass this\n */\n if (!(isMove && srcSpace.realPath.toLowerCase() === dstSpace.realPath.toLowerCase())) {\n throw new FileError(dav ? HttpStatus.PRECONDITION_FAILED : HttpStatus.BAD_REQUEST, 'The destination already exists')\n }\n }\n\n const isDir = await isPathIsDir(srcSpace.realPath)\n\n if (dstSpace.storageQuota) {\n /* Skip validation when moving to the same space; for copy operations, run all checks. */\n if (!isMove || (isMove && srcSpace.id !== dstSpace.id)) {\n const size = isDir ? (await dirSize(srcSpace.realPath))[0] : await fileSize(srcSpace.realPath)\n if (dstSpace.willExceedQuota(size)) {\n this.logger.warn(`${this.copyMove.name} - storage quota will be exceeded for *${dstSpace.alias}* (${dstSpace.id})`)\n throw new FileError(HttpStatus.INSUFFICIENT_STORAGE, 'Storage quota will be exceeded')\n }\n }\n }\n\n // check lock conflicts on source and destination\n let recursive: boolean\n let depth: LOCK_DEPTH\n if (dav?.depth) {\n recursive = dav.depth === DEPTH.INFINITY\n depth = dav.depth\n } else {\n recursive = isDir\n depth = recursive ? DEPTH.INFINITY : DEPTH.RESOURCE\n }\n if (isMove) {\n // check source\n await this.filesLockManager.checkConflicts(srcSpace.dbFile, depth, { userId: user.id, lockTokens: dav?.lockTokens })\n }\n // check destination\n await this.filesLockManager.checkConflicts(dstSpace.dbFile, depth, { userId: user.id, lockTokens: dav?.lockTokens })\n\n // overwrite\n if (overwrite && (await isPathExists(dstSpace.realPath))) {\n // todo : versioning here\n await this.delete(user, dstSpace)\n }\n\n // send it to task watcher\n if (srcSpace.task?.cacheKey) {\n if (!isDir) srcSpace.task.props.totalSize = await fileSize(srcSpace.realPath)\n FileTaskEvent.emit('startWatch', srcSpace, isMove ? FILE_OPERATION.MOVE : FILE_OPERATION.COPY, dstSpace.realPath)\n }\n\n // do\n if (isMove) {\n await moveFiles(srcSpace.realPath, dstSpace.realPath, overwrite)\n return this.filesQueries.moveFiles(srcSpace.dbFile, dstSpace.dbFile, isDir)\n }\n return copyFiles(srcSpace.realPath, dstSpace.realPath, overwrite, recursive)\n }\n\n async delete(user: UserModel, space: SpaceEnv, dav?: { lockTokens: string[] }): Promise<void> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n // check lock conflicts\n const isDir = await isPathIsDir(space.realPath)\n await this.filesLockManager.checkConflicts(space.dbFile, isDir ? DEPTH.INFINITY : DEPTH.RESOURCE, {\n userId: user.id,\n lockTokens: dav?.lockTokens\n })\n // file system deletion\n let forceDeleteInDB = false\n if (space.inTrashRepository) {\n await removeFiles(space.realPath)\n } else {\n const baseTrashPath = realTrashPathFromSpace(user, space)\n if (baseTrashPath) {\n const name = fileName(space.realPath)\n const trashDir = path.join(baseTrashPath, dirName(space.dbFile.path))\n const trashFile = path.join(trashDir, name)\n if (!(await isPathExists(trashDir))) {\n await makeDir(trashDir, true)\n }\n if (await isPathExists(trashFile)) {\n // if a resource already exists in the trash, rename it with the date\n const dstTrash = await uniqueDatedFilePath(trashFile)\n // move the resource on fs\n await moveFiles(trashFile, dstTrash.path)\n // move the resource in db\n const trashFileDB: FileDBProps = { ...space.dbFile, inTrash: true }\n const dstTrashFileDB: FileDBProps = { ...trashFileDB, path: path.join(dirName(trashFileDB.path), fileName(dstTrash.path)) }\n await this.filesQueries.moveFiles(trashFileDB, dstTrashFileDB, dstTrash.isDir)\n }\n await moveFiles(space.realPath, trashFile, true)\n } else {\n // unsupported case: delete the file (this shouldn't happen)\n this.logger.error(`Unable to find trash path for space - *${space.alias}* (${space.id}) : delete permanently : ${space.realPath}`)\n forceDeleteInDB = true\n await removeFiles(space.realPath)\n }\n }\n // remove locks, these locks have already been checked in the `checkConflicts` function\n if (isDir) {\n this.filesLockManager.removeChildLocks(user, space.dbFile).catch((e: Error) => this.logger.error(`${this.delete.name} - ${e}`))\n }\n for (const lock of await this.filesLockManager.getLocksByPath(space.dbFile)) {\n this.filesLockManager.removeLock(lock.key).catch((e: Error) => this.logger.error(`${this.delete.name} - ${e}`))\n }\n // delete or move to trash the files in db\n return this.filesQueries.deleteFiles(space.dbFile, isDir, forceDeleteInDB)\n }\n\n async downloadFromUrl(user: UserModel, space: SpaceEnv, url: string): Promise<void> {\n this.logger.log(`${this.downloadFromUrl.name} : ${url}`)\n // create lock\n const rPath = await uniqueFilePathFromDir(space.realPath)\n const dbFile = space.dbFile\n dbFile.path = path.join(dirName(dbFile.path), fileName(space.realPath))\n const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, DEPTH.RESOURCE)\n if (!ok) {\n throw new LockConflict(fileLock, 'Conflicting lock')\n }\n // tasking\n if (space.task.cacheKey) {\n let headRes: AxiosResponse\n\n try {\n headRes = await this.http.axiosRef({ method: HTTP_METHOD.HEAD, url: url, maxRedirects: 1 })\n } catch (e) {\n // release lock\n await this.filesLockManager.removeLock(fileLock.key)\n this.logger.error(`${this.downloadFromUrl.name} - ${url} : ${e}`)\n throw new FileError(HttpStatus.BAD_REQUEST, 'Unable to download file')\n }\n\n if (regExpPrivateIP.test(headRes.request.socket.remoteAddress)) {\n // release lock\n await this.filesLockManager.removeLock(fileLock.key)\n // prevent SSRF attack\n throw new FileError(HttpStatus.FORBIDDEN, 'Access to internal IP addresses is forbidden')\n }\n\n // attempt to retrieve the Content-Length header\n try {\n if ('content-length' in headRes.headers) {\n space.task.props.totalSize = parseInt(headRes.headers['content-length'], 10) || null\n }\n } catch (e) {\n this.logger.debug(`${this.downloadFromUrl.name} - content-length : ${e}`)\n }\n FileTaskEvent.emit('startWatch', space, FILE_OPERATION.DOWNLOAD, rPath)\n }\n // do\n try {\n const getRes = await this.http.axiosRef({ method: HTTP_METHOD.GET, url: url, responseType: 'stream', maxRedirects: 1 })\n if (regExpPrivateIP.test(getRes.request.socket.remoteAddress)) {\n // Prevent SSRF attacks and perform a DNS-rebinding check if a HEAD request has already been made\n throw new FileError(HttpStatus.FORBIDDEN, 'Access to internal IP addresses is forbidden')\n }\n await writeFromStream(rPath, getRes.data)\n } finally {\n // release lock\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n\n async compress(user: UserModel, space: SpaceEnv, dto: CompressFileDto): Promise<void> {\n // This method is currently used only by files-methods.service, which handles input sanitization.\n // If it is used in other services in the future, make sure to refactor accordingly to sanitize inputs properly.\n const srcPath = dirName(space.realPath)\n // todo: a guest link tasksPath should be in specific directory (guest link has no home)\n const archiveExt = dto.name.endsWith(dto.extension) ? '' : `.${dto.extension}`\n const dstPath = await uniqueFilePathFromDir(path.join(dto.compressInDirectory ? srcPath : user.tasksPath, `${dto.name}${archiveExt}`))\n const archive: Archiver = archiver('tar', {\n gzip: dto.extension === tarGzExtension,\n gzipOptions: {\n level: 9\n }\n })\n // create lock\n let fileLock: FileLock\n if (dto.compressInDirectory) {\n const dbFile = space.dbFile\n dbFile.path = path.join(dirName(dbFile.path), fileName(dstPath))\n const [ok, lock] = await this.filesLockManager.create(user, dbFile, DEPTH.RESOURCE)\n if (!ok) {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n fileLock = lock\n }\n if (space.task?.cacheKey) {\n space.task.props.compressInDirectory = dto.compressInDirectory\n FileTaskEvent.emit('startWatch', space, FILE_OPERATION.COMPRESS, dstPath)\n }\n // do\n try {\n archive.on('error', (error: ArchiverError) => {\n throw error\n })\n const dstStream = fs.createWriteStream(dstPath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n archive.pipe(dstStream)\n for (const f of dto.files) {\n if (await isPathIsDir(f.path)) {\n archive.directory(f.path, dto.files.length > 1 ? fileName(f.path) : false)\n } else {\n archive.file(f.path, {\n name: f.rootAlias ? f.name : fileName(f.path)\n })\n }\n }\n await archive.finalize()\n } finally {\n if (fileLock) {\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n }\n\n async decompress(user: UserModel, space: SpaceEnv): Promise<void> {\n // checks\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n const extension = path.extname(space.realPath)\n if (!COMPRESSION_EXTENSION.has(extension)) {\n throw new FileError(HttpStatus.BAD_REQUEST, `${extension} is not supported`)\n }\n // make destination folder\n const dstPath = await uniqueFilePathFromDir(path.join(dirName(space.realPath), path.basename(space.realPath, extension)))\n await makeDir(dstPath)\n // create lock\n const dbFile = space.dbFile\n dbFile.path = path.join(dirName(dbFile.path), fileName(dstPath))\n const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, DEPTH.INFINITY)\n if (!ok) {\n throw new LockConflict(fileLock, 'Conflicting lock')\n }\n // tasking\n if (space.task?.cacheKey) FileTaskEvent.emit('startWatch', space, FILE_OPERATION.DECOMPRESS, dstPath)\n // do\n try {\n if (extension === '.zip') {\n await extractZip(space.realPath, dstPath)\n } else {\n await extractTar({\n file: space.realPath,\n cwd: dstPath,\n gzip: COMPRESSION_EXTENSION.get(extension) === tarGzExtension,\n preserveOwner: false\n })\n }\n } finally {\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n\n async generateThumbnail(space: SpaceEnv, size: number): Promise<Readable> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (getMimeType(space.realPath, false).indexOf('image') === -1) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'File is not an image')\n }\n try {\n return generateThumbnail(space.realPath, size)\n } catch (e) {\n this.logger.warn(e)\n throw new FileError(HttpStatus.BAD_REQUEST, 'File is not an image')\n }\n }\n\n async lock(user: UserModel, space: SpaceEnv): Promise<FileLockProps> {\n const rExists = await isPathExists(space.realPath)\n if (!rExists) {\n this.logger.warn('Lock refresh must specify an existing resource')\n throw new FileError(HttpStatus.BAD_REQUEST, 'Lock refresh must specify an existing resource')\n }\n const [_created, lock] = await this.filesLockManager.createOrRefresh(user, space.dbFile, DEPTH.RESOURCE, CACHE_LOCK_FILE_TTL)\n return this.filesLockManager.convertLockToFileLockProps(lock)\n }\n\n async unlock(user: UserModel, space: SpaceEnv, forceAsOwner = false): Promise<void> {\n if (!(await isPathExists(space.realPath))) {\n this.logger.warn(`Unable to unlock: ${space.url} - resource does not exist`)\n throw new FileError(HttpStatus.BAD_REQUEST, 'Unlock must specify an existing resource')\n }\n const fileLocks = await this.filesLockManager.getLocksByPath(space.dbFile)\n if (fileLocks.length === 0) {\n this.logger.warn(`Unable to find lock: ${space.url} - resource does not exist`)\n return\n }\n for (const lock of fileLocks) {\n if ((forceAsOwner && space.dbFile?.ownerId === user.id) || lock.owner.id === user.id) {\n // Refresh if more than half of the TTL has passed\n await this.filesLockManager.removeLock(lock.key)\n } else {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n }\n }\n\n async unlockRequest(user: UserModel, space: SpaceEnv): Promise<void> {\n const fileLocks = await this.filesLockManager.getLocksByPath(space.dbFile)\n if (fileLocks.length === 0) {\n this.logger.warn(`Unable to find lock: ${space.url} - resource does not exist`)\n throw new FileError(HttpStatus.NOT_FOUND, 'Lock not found')\n }\n for (const lock of fileLocks) {\n if (lock.owner.id !== user.id) {\n const notification: NotificationContent = {\n app: NOTIFICATION_APP.UNLOCK_REQUEST,\n event: NOTIFICATION_APP_EVENT.UNLOCK_REQUEST,\n element: fileName(space.url),\n url: dirName(space.url)\n }\n this.notificationsManager\n .create([lock.owner.id], notification, {\n author: user,\n currentUrl: this.contextManager.headerOriginUrl()\n })\n .catch((e: Error) => this.logger.error(`${this.unlockRequest.name} - ${e}`))\n }\n }\n }\n\n async getSize(space: SpaceEnv): Promise<number> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (await isPathIsDir(space.realPath)) {\n return (await dirSize(space.realPath))[0]\n } else {\n return await fileSize(space.realPath)\n }\n }\n}\n"],"names":["FilesManager","sendFileFromSpace","space","asAttachment","downloadName","SendFile","realPath","saveStream","user","req","options","fExists","isPathExists","fTmpExists","tmpPath","method","HTTP_METHOD","POST","FileError","HttpStatus","METHOD_NOT_ALLOWED","isPathIsDir","makeDir","dirName","CONFLICT","fileLock","dav","filesLockManager","checkConflicts","dbFile","depth","DEPTH","RESOURCE","userId","id","lockTokens","ok","lock","create","LockConflict","startRange","headers","match","exec","length","BAD_REQUEST","parseInt","size","fileSize","checksum","checksumAlg","writeFromStreamAndChecksum","raw","writeFromStream","path","dirname","moveFiles","e","removeFiles","logger","error","name","INTERNAL_SERVER_ERROR","removeLock","key","warn","saveMultipart","overwrite","PUT","patch","PATCH","realParentPath","basePath","sep","part","files","partFileName","fileName","filename","dstFile","resolve","startsWith","FORBIDDEN","dstDir","dstUrl","join","url","dstSpace","spacesManager","spaceEnv","split","delete","ttl","CACHE_LOCK_FILE_TTL","undefined","created","createOrRefresh","file","touch","mtime","checkLocks","NOT_FOUND","touchFile","mkFile","checkDocument","checkFileName","fileExtension","extname","Object","values","DOCUMENT_TYPE","indexOf","srcSample","__dirname","SAMPLE_PATH_WITHOUT_EXT","copyFileContent","createEmptyFile","mkDir","recursive","copyMove","srcSpace","isMove","mkdirDstParentPath","canAccessToSpace","repository","haveSpaceEnvPermissions","SPACE_OPERATION","ADD","alias","quotaIsExceeded","INSUFFICIENT_STORAGE","toLowerCase","PRECONDITION_FAILED","isDir","storageQuota","dirSize","willExceedQuota","INFINITY","task","cacheKey","props","totalSize","FileTaskEvent","emit","FILE_OPERATION","MOVE","COPY","filesQueries","copyFiles","forceDeleteInDB","inTrashRepository","baseTrashPath","realTrashPathFromSpace","trashDir","trashFile","dstTrash","uniqueDatedFilePath","trashFileDB","inTrash","dstTrashFileDB","removeChildLocks","catch","getLocksByPath","deleteFiles","downloadFromUrl","log","rPath","uniqueFilePathFromDir","headRes","http","axiosRef","HEAD","maxRedirects","regExpPrivateIP","test","request","socket","remoteAddress","debug","DOWNLOAD","getRes","GET","responseType","data","compress","dto","srcPath","archiveExt","endsWith","extension","dstPath","compressInDirectory","tasksPath","archive","archiver","gzip","tarGzExtension","gzipOptions","level","COMPRESS","on","dstStream","fs","createWriteStream","highWaterMark","DEFAULT_HIGH_WATER_MARK","pipe","f","directory","rootAlias","finalize","decompress","COMPRESSION_EXTENSION","has","basename","DECOMPRESS","extractZip","extractTar","cwd","get","preserveOwner","generateThumbnail","getMimeType","rExists","_created","convertLockToFileLockProps","unlock","forceAsOwner","fileLocks","ownerId","owner","unlockRequest","notification","app","NOTIFICATION_APP","UNLOCK_REQUEST","event","NOTIFICATION_APP_EVENT","element","notificationsManager","author","currentUrl","contextManager","headerOriginUrl","getSize","Logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-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 { HttpService } from '@nestjs/axios'\nimport { HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport archiver, { Archiver, ArchiverError } from 'archiver'\nimport { AxiosResponse } from 'axios'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport { Readable } from 'node:stream'\nimport { extract as extractTar } from 'tar'\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\nimport { generateThumbnail } from '../../../common/image'\nimport { ContextManager } from '../../../infrastructure/context/services/context-manager.service'\nimport { HTTP_METHOD } from '../../applications.constants'\nimport { NOTIFICATION_APP, NOTIFICATION_APP_EVENT } from '../../notifications/constants/notifications'\nimport { NotificationContent } from '../../notifications/interfaces/notification-properties.interface'\nimport { NotificationsManager } from '../../notifications/services/notifications-manager.service'\nimport { SPACE_OPERATION } from '../../spaces/constants/spaces'\nimport { FastifySpaceRequest } from '../../spaces/interfaces/space-request.interface'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { SpacesManager } from '../../spaces/services/spaces-manager.service'\nimport { realTrashPathFromSpace } from '../../spaces/utils/paths'\nimport { canAccessToSpace, haveSpaceEnvPermissions } from '../../spaces/utils/permissions'\nimport { UserModel } from '../../users/models/user.model'\nimport { DEPTH, LOCK_DEPTH } from '../../webdav/constants/webdav'\nimport { CACHE_LOCK_FILE_TTL } from '../constants/cache'\nimport { tarGzExtension } from '../constants/compress'\nimport { COMPRESSION_EXTENSION, DEFAULT_HIGH_WATER_MARK } from '../constants/files'\nimport { FILE_OPERATION } from '../constants/operations'\nimport { DOCUMENT_TYPE, SAMPLE_PATH_WITHOUT_EXT } from '../constants/samples'\nimport { CompressFileDto } from '../dto/file-operations.dto'\nimport { FileTaskEvent } from '../events/file-task-event'\nimport { FileDBProps } from '../interfaces/file-db-props.interface'\nimport { FileLock } from '../interfaces/file-lock.interface'\nimport { FileLockProps } from '../interfaces/file-props.interface'\nimport { FileError } from '../models/file-error'\nimport { LockConflict } from '../models/file-lock-error'\nimport {\n checkFileName,\n copyFileContent,\n copyFiles,\n createEmptyFile,\n dirName,\n dirSize,\n fileName,\n fileSize,\n getMimeType,\n isPathExists,\n isPathIsDir,\n makeDir,\n moveFiles,\n removeFiles,\n touchFile,\n uniqueDatedFilePath,\n uniqueFilePathFromDir,\n writeFromStream,\n writeFromStreamAndChecksum\n} from '../utils/files'\nimport { SendFile } from '../utils/send-file'\nimport { extractZip } from '../utils/unzip-file'\nimport { regExpPrivateIP } from '../utils/url-file'\nimport { FilesLockManager } from './files-lock-manager.service'\nimport { FilesQueries } from './files-queries.service'\n\n@Injectable()\nexport class FilesManager {\n /* Spaces permissions are checked in the space guard, except for the copy/move destination */\n private logger = new Logger(FilesManager.name)\n\n constructor(\n private readonly http: HttpService,\n private readonly filesQueries: FilesQueries,\n private readonly spacesManager: SpacesManager,\n private readonly contextManager: ContextManager,\n private readonly notificationsManager: NotificationsManager,\n public readonly filesLockManager: FilesLockManager\n ) {}\n\n sendFileFromSpace(space: SpaceEnv, downloadName = ''): SendFile {\n return new SendFile(space.realPath, downloadName)\n }\n\n async saveStream(\n user: UserModel,\n space: SpaceEnv,\n req: FastifyAuthenticatedRequest,\n options: {\n checksumAlg: string\n tmpPath?: string\n }\n ): Promise<string>\n async saveStream(user: UserModel, space: SpaceEnv, req: FastifyAuthenticatedRequest, options?: any): Promise<boolean>\n async saveStream(\n user: UserModel,\n space: SpaceEnv,\n req: FastifyAuthenticatedRequest,\n options?: { dav?: { depth: LOCK_DEPTH; lockTokens: string[] }; checksumAlg?: string; tmpPath?: string }\n ): Promise<boolean | string> {\n // if tmpPath is used, we lock the final destination during the transfer\n // space.realPath is replaced by tmpPath (if allowed), if the move operation failed we remove the tmp file\n const fExists = await isPathExists(space.realPath)\n const fTmpExists = options?.tmpPath ? await isPathExists(options.tmpPath) : false\n if (fExists && req.method === HTTP_METHOD.POST) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'Resource already exists')\n }\n if (fExists && (await isPathIsDir(space.realPath))) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'The location is a directory')\n }\n if (options?.tmpPath) {\n // ensure tmpPath parent dir exists\n await makeDir(dirName(options.tmpPath), true)\n } else if (!(await isPathExists(dirName(space.realPath)))) {\n throw new FileError(HttpStatus.CONFLICT, 'Parent must exists')\n }\n /* File Lock */\n let fileLock: FileLock | undefined\n if (options?.dav) {\n // check locks\n await this.filesLockManager.checkConflicts(space.dbFile, options?.dav?.depth || DEPTH.RESOURCE, {\n userId: user.id,\n lockTokens: options.dav?.lockTokens\n })\n } else {\n // create lock if there is no webdav context\n const [ok, lock] = await this.filesLockManager.create(user, space.dbFile, DEPTH.RESOURCE)\n if (!ok) {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n fileLock = lock\n }\n try {\n // check range\n let startRange = 0\n if ((fExists || fTmpExists) && req.headers['content-range']) {\n // with PUT method, some webdav clients use the `content-range` header,\n // which is normally reserved for a response to a request containing the `range` header.\n // However, for more compatibility let's accept it\n const match = /\\d+/.exec(req.headers['content-range'])\n if (!match.length) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Content-range : header is malformed')\n }\n startRange = parseInt(match[0], 10)\n const size = await fileSize(options?.tmpPath || space.realPath)\n if (startRange !== size) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Content-range : start offset does not match the current file size')\n }\n }\n // todo: check file in db to update\n // todo : versioning here\n let checksum: string\n if (options?.checksumAlg) {\n checksum = await writeFromStreamAndChecksum(options?.tmpPath || space.realPath, req.raw, startRange, options.checksumAlg)\n } else {\n await writeFromStream(options?.tmpPath || space.realPath, req.raw, startRange)\n }\n if (options?.tmpPath) {\n try {\n // ensure parent path exists\n await makeDir(path.dirname(space.realPath), true)\n // move the uploaded file to destination\n await moveFiles(options.tmpPath, space.realPath, true)\n } catch (e) {\n // cleanup tmp file\n await removeFiles(options.tmpPath)\n this.logger.error(`${this.saveStream.name} - unable to move ${options.tmpPath} -> ${space.realPath} : ${e}`)\n throw new FileError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to move tmp file to dst file')\n }\n }\n if (options?.checksumAlg) {\n return checksum\n }\n return fExists\n } finally {\n if (fileLock) {\n try {\n await this.filesLockManager.removeLock(fileLock.key)\n } catch (e) {\n this.logger.warn(`Failed to remove lock ${fileLock.key}: ${e}`)\n }\n }\n }\n }\n\n async saveMultipart(user: UserModel, space: SpaceEnv, req: FastifySpaceRequest) {\n /* Accepted methods:\n POST: Creates new resource\n PUT: Creates or fully replaces a resource at the given URI (even if intermediate paths do not exist)\n PATCH: Updates the content of an existing resource without creating a new one.\n In this text-editing scenario, locking and refreshing occur automatically, but unlocking must be handled explicitly via\n the `unlock` method.\n */\n const overwrite = req.method === HTTP_METHOD.PUT\n const patch = req.method === HTTP_METHOD.PATCH\n const realParentPath = dirName(space.realPath)\n\n if (!overwrite) {\n if (!patch && (await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Resource already exists')\n }\n if (!(await isPathExists(realParentPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Parent must exists')\n }\n if (!(await isPathIsDir(realParentPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Parent must be a directory')\n }\n }\n\n const basePath = realParentPath + path.sep\n\n for await (const part of req.files()) {\n // If the request uses the PATCH method, the file name corresponds to the space\n const partFileName = patch ? fileName(space.realPath) : part.filename\n // `part.filename` may contain a path like foo/bar.txt\n const dstFile = path.resolve(basePath, partFileName)\n // Prevent path traversal\n if (!dstFile.startsWith(basePath)) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Location is not allowed')\n }\n\n const dstDir = dirName(dstFile)\n\n if (overwrite) {\n // Prevent errors when an uploaded file would replace a directory with the same name\n // Only applies in `overwrite` cases\n if ((await isPathExists(dstFile)) && (await isPathIsDir(dstFile))) {\n // If a directory already exists at the destination path, delete it to allow overwriting with the uploaded file\n const dstUrl = path.join(path.dirname(space.url), partFileName)\n const dstSpace = await this.spacesManager.spaceEnv(user, dstUrl.split('/'))\n await this.delete(user, dstSpace)\n } else if ((await isPathExists(dstDir)) && !(await isPathIsDir(dstDir))) {\n // If the destination's parent exists but is a file, remove it so we can create the directory\n const dstUrl = path.join(path.dirname(space.url), path.dirname(partFileName))\n const dstSpace = await this.spacesManager.spaceEnv(user, dstUrl.split('/'))\n await this.delete(user, dstSpace)\n }\n }\n // Create the directory in the space\n if (!(await isPathExists(dstDir))) {\n await makeDir(dstDir, true)\n }\n // Create or refresh lock\n const dbFile = { ...space.dbFile, path: path.join(dirName(space.dbFile.path), partFileName) }\n // Use a short TTL for the PATCH method (which is also used for refreshing)\n const ttl = patch ? CACHE_LOCK_FILE_TTL : undefined\n const [created, fileLock] = await this.filesLockManager.createOrRefresh(user, dbFile, DEPTH.RESOURCE, ttl)\n // Do\n try {\n await writeFromStream(dstFile, part.file)\n } finally {\n if (!patch && created) {\n // Remove the file lock only if it has not been refreshed\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n if (patch) {\n // Only one resource can be updated with the PATCH method.\n break\n }\n }\n }\n\n async touch(user: UserModel, space: SpaceEnv, mtime: number, checkLocks = true): Promise<void> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (checkLocks) {\n await this.filesLockManager.checkConflicts(space.dbFile, DEPTH.RESOURCE, { userId: user.id })\n }\n // todo: update mtime in last files ( & in db file ?)\n await touchFile(space.realPath, mtime)\n }\n\n async mkFile(user: UserModel, space: SpaceEnv, overwrite = false, checkLocks = true, checkDocument = false): Promise<void> {\n checkFileName(space.realPath)\n if (!overwrite && (await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Resource already exists')\n }\n if (checkLocks) {\n await this.filesLockManager.checkConflicts(space.dbFile, DEPTH.RESOURCE, { userId: user.id })\n }\n // use sample documents when possible\n const fileExtension = path.extname(space.realPath)\n if (checkDocument && fileExtension !== '.txt' && Object.values(DOCUMENT_TYPE).indexOf(fileExtension) > -1) {\n const srcSample = path.join(__dirname, `${SAMPLE_PATH_WITHOUT_EXT}${fileExtension}`)\n return copyFileContent(srcSample, space.realPath)\n } else {\n return createEmptyFile(space.realPath)\n }\n }\n\n async mkDir(user: UserModel, space: SpaceEnv, recursive = false, dav?: { depth: LOCK_DEPTH; lockTokens: string[] }): Promise<void> {\n checkFileName(space.realPath)\n if (!recursive) {\n if (await isPathExists(space.realPath)) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'Resource already exists')\n } else if (!(await isPathExists(dirName(space.realPath)))) {\n throw new FileError(HttpStatus.CONFLICT, 'Parent must exists')\n }\n }\n await this.filesLockManager.checkConflicts(space.dbFile, dav?.depth || DEPTH.RESOURCE, { userId: user.id, lockTokens: dav?.lockTokens })\n await makeDir(space.realPath, recursive)\n }\n\n async copyMove(\n user: UserModel,\n srcSpace: SpaceEnv,\n dstSpace: SpaceEnv,\n isMove: boolean,\n overwrite = false,\n mkdirDstParentPath = false,\n dav?: { depth: LOCK_DEPTH; lockTokens: string[] }\n ): Promise<void> {\n // checks\n if (!canAccessToSpace(user, dstSpace)) {\n this.logger.warn(`${this.copyMove.name} - is not allowed to access to this space repository : ${dstSpace.repository}`)\n throw new FileError(HttpStatus.FORBIDDEN, 'You are not allowed to access to this repository')\n }\n if (!haveSpaceEnvPermissions(dstSpace, SPACE_OPERATION.ADD)) {\n this.logger.warn(`${this.copyMove.name} - is not allowed to copy/move on this space : *${dstSpace.alias}* (${dstSpace.id}) : ${dstSpace.url}`)\n throw new FileError(HttpStatus.FORBIDDEN, 'You are not allowed to copy/move on the destination')\n }\n if (dstSpace.quotaIsExceeded) {\n this.logger.warn(`${this.copyMove.name} - quota is exceeded for *${dstSpace.alias}* (${dstSpace.id})`)\n throw new FileError(HttpStatus.INSUFFICIENT_STORAGE, 'Quota is exceeded')\n }\n if (!(await isPathExists(srcSpace.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (!(await isPathExists(dirName(dstSpace.realPath)))) {\n if (mkdirDstParentPath) {\n try {\n await makeDir(dirName(dstSpace.realPath), true)\n } catch (e) {\n this.logger.error(`${this.copyMove.name} - Cannot create parent directory for destination ${dstSpace.realPath} : ${e}`)\n throw new FileError(HttpStatus.INTERNAL_SERVER_ERROR, 'Cannot create parent directory for destination')\n }\n } else {\n throw new FileError(HttpStatus.CONFLICT, 'Parent must exists')\n }\n }\n if (srcSpace.realPath === dstSpace.realPath) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Cannot copy/move source onto itself')\n }\n if (`${dstSpace.realPath}/`.startsWith(`${srcSpace.realPath}/`)) {\n throw new FileError(HttpStatus.FORBIDDEN, 'Cannot copy/move source below itself')\n }\n if (dirName(srcSpace.url) === dirName(dstSpace.url) && dirName(srcSpace.realPath) !== dirName(dstSpace.realPath)) {\n /* Handle renaming a space file with the same name as a space root :\n srcSpace.url = '/space/sync-in/code2.ts' (a space file)\n srcSpace.realPath = '/home/sync-in/spaces/sync-in/code2.ts\n dstSpace.url = '/space/sync-in/code.ts' (a space root)\n dstSpace.realPath = '/home/sync-in/users/jo/files/code2.ts !!\n */\n throw new FileError(HttpStatus.BAD_REQUEST, 'An anchored file already has this name')\n }\n if (!overwrite && (await isPathExists(dstSpace.realPath))) {\n /* Handle case-sensitive (in renaming context):\n srcSpace.url = '/space/sync-in/code.ts'\n dstSpace.url = '/space/sync-in/code.TS'\n The destination exists because it's the same file, bypass this\n */\n if (!(isMove && srcSpace.realPath.toLowerCase() === dstSpace.realPath.toLowerCase())) {\n throw new FileError(dav ? HttpStatus.PRECONDITION_FAILED : HttpStatus.BAD_REQUEST, 'The destination already exists')\n }\n }\n\n const isDir = await isPathIsDir(srcSpace.realPath)\n\n if (dstSpace.storageQuota) {\n /* Skip validation when moving to the same space; for copy operations, run all checks. */\n if (!isMove || (isMove && srcSpace.id !== dstSpace.id)) {\n const size = isDir ? (await dirSize(srcSpace.realPath))[0] : await fileSize(srcSpace.realPath)\n if (dstSpace.willExceedQuota(size)) {\n this.logger.warn(`${this.copyMove.name} - storage quota will be exceeded for *${dstSpace.alias}* (${dstSpace.id})`)\n throw new FileError(HttpStatus.INSUFFICIENT_STORAGE, 'Storage quota will be exceeded')\n }\n }\n }\n\n // check lock conflicts on source and destination\n let recursive: boolean\n let depth: LOCK_DEPTH\n if (dav?.depth) {\n recursive = dav.depth === DEPTH.INFINITY\n depth = dav.depth\n } else {\n recursive = isDir\n depth = recursive ? DEPTH.INFINITY : DEPTH.RESOURCE\n }\n if (isMove) {\n // check source\n await this.filesLockManager.checkConflicts(srcSpace.dbFile, depth, { userId: user.id, lockTokens: dav?.lockTokens })\n }\n // check destination\n await this.filesLockManager.checkConflicts(dstSpace.dbFile, depth, { userId: user.id, lockTokens: dav?.lockTokens })\n\n // overwrite\n if (overwrite && (await isPathExists(dstSpace.realPath))) {\n // todo : versioning here\n await this.delete(user, dstSpace)\n }\n\n // send it to task watcher\n if (srcSpace.task?.cacheKey) {\n if (!isDir) srcSpace.task.props.totalSize = await fileSize(srcSpace.realPath)\n FileTaskEvent.emit('startWatch', srcSpace, isMove ? FILE_OPERATION.MOVE : FILE_OPERATION.COPY, dstSpace.realPath)\n }\n\n // do\n if (isMove) {\n await moveFiles(srcSpace.realPath, dstSpace.realPath, overwrite)\n return this.filesQueries.moveFiles(srcSpace.dbFile, dstSpace.dbFile, isDir)\n }\n return copyFiles(srcSpace.realPath, dstSpace.realPath, overwrite, recursive)\n }\n\n async delete(user: UserModel, space: SpaceEnv, dav?: { lockTokens: string[] }): Promise<void> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n // check lock conflicts\n const isDir = await isPathIsDir(space.realPath)\n await this.filesLockManager.checkConflicts(space.dbFile, isDir ? DEPTH.INFINITY : DEPTH.RESOURCE, {\n userId: user.id,\n lockTokens: dav?.lockTokens\n })\n // file system deletion\n let forceDeleteInDB = false\n if (space.inTrashRepository) {\n await removeFiles(space.realPath)\n } else {\n const baseTrashPath = realTrashPathFromSpace(user, space)\n if (baseTrashPath) {\n const name = fileName(space.realPath)\n const trashDir = path.join(baseTrashPath, dirName(space.dbFile.path))\n const trashFile = path.join(trashDir, name)\n if (!(await isPathExists(trashDir))) {\n await makeDir(trashDir, true)\n }\n if (await isPathExists(trashFile)) {\n // if a resource already exists in the trash, rename it with the date\n const dstTrash = await uniqueDatedFilePath(trashFile)\n // move the resource on fs\n await moveFiles(trashFile, dstTrash.path)\n // move the resource in db\n const trashFileDB: FileDBProps = { ...space.dbFile, inTrash: true }\n const dstTrashFileDB: FileDBProps = { ...trashFileDB, path: path.join(dirName(trashFileDB.path), fileName(dstTrash.path)) }\n await this.filesQueries.moveFiles(trashFileDB, dstTrashFileDB, dstTrash.isDir)\n }\n await moveFiles(space.realPath, trashFile, true)\n } else {\n // unsupported case: delete the file (this shouldn't happen)\n this.logger.error(`Unable to find trash path for space - *${space.alias}* (${space.id}) : delete permanently : ${space.realPath}`)\n forceDeleteInDB = true\n await removeFiles(space.realPath)\n }\n }\n // remove locks, these locks have already been checked in the `checkConflicts` function\n if (isDir) {\n this.filesLockManager.removeChildLocks(user, space.dbFile).catch((e: Error) => this.logger.error(`${this.delete.name} - ${e}`))\n }\n for (const lock of await this.filesLockManager.getLocksByPath(space.dbFile)) {\n this.filesLockManager.removeLock(lock.key).catch((e: Error) => this.logger.error(`${this.delete.name} - ${e}`))\n }\n // delete or move to trash the files in db\n return this.filesQueries.deleteFiles(space.dbFile, isDir, forceDeleteInDB)\n }\n\n async downloadFromUrl(user: UserModel, space: SpaceEnv, url: string): Promise<void> {\n this.logger.log(`${this.downloadFromUrl.name} : ${url}`)\n // create lock\n const rPath = await uniqueFilePathFromDir(space.realPath)\n const dbFile = space.dbFile\n dbFile.path = path.join(dirName(dbFile.path), fileName(space.realPath))\n const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, DEPTH.RESOURCE)\n if (!ok) {\n throw new LockConflict(fileLock, 'Conflicting lock')\n }\n // tasking\n if (space.task.cacheKey) {\n let headRes: AxiosResponse\n\n try {\n headRes = await this.http.axiosRef({ method: HTTP_METHOD.HEAD, url: url, maxRedirects: 1 })\n } catch (e) {\n // release lock\n await this.filesLockManager.removeLock(fileLock.key)\n this.logger.error(`${this.downloadFromUrl.name} - ${url} : ${e}`)\n throw new FileError(HttpStatus.BAD_REQUEST, 'Unable to download file')\n }\n\n if (regExpPrivateIP.test(headRes.request.socket.remoteAddress)) {\n // release lock\n await this.filesLockManager.removeLock(fileLock.key)\n // prevent SSRF attack\n throw new FileError(HttpStatus.FORBIDDEN, 'Access to internal IP addresses is forbidden')\n }\n\n // attempt to retrieve the Content-Length header\n try {\n if ('content-length' in headRes.headers) {\n space.task.props.totalSize = parseInt(headRes.headers['content-length'], 10) || null\n }\n } catch (e) {\n this.logger.debug(`${this.downloadFromUrl.name} - content-length : ${e}`)\n }\n FileTaskEvent.emit('startWatch', space, FILE_OPERATION.DOWNLOAD, rPath)\n }\n // do\n try {\n const getRes = await this.http.axiosRef({ method: HTTP_METHOD.GET, url: url, responseType: 'stream', maxRedirects: 1 })\n if (regExpPrivateIP.test(getRes.request.socket.remoteAddress)) {\n // Prevent SSRF attacks and perform a DNS-rebinding check if a HEAD request has already been made\n throw new FileError(HttpStatus.FORBIDDEN, 'Access to internal IP addresses is forbidden')\n }\n await writeFromStream(rPath, getRes.data)\n } finally {\n // release lock\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n\n async compress(user: UserModel, space: SpaceEnv, dto: CompressFileDto): Promise<void> {\n // This method is currently used only by files-methods.service, which handles input sanitization.\n // If it is used in other services in the future, make sure to refactor accordingly to sanitize inputs properly.\n const srcPath = dirName(space.realPath)\n // todo: a guest link tasksPath should be in specific directory (guest link has no home)\n const archiveExt = dto.name.endsWith(dto.extension) ? '' : `.${dto.extension}`\n const dstPath = await uniqueFilePathFromDir(path.join(dto.compressInDirectory ? srcPath : user.tasksPath, `${dto.name}${archiveExt}`))\n const archive: Archiver = archiver('tar', {\n gzip: dto.extension === tarGzExtension,\n gzipOptions: {\n level: 9\n }\n })\n // create lock\n let fileLock: FileLock\n if (dto.compressInDirectory) {\n const dbFile = space.dbFile\n dbFile.path = path.join(dirName(dbFile.path), fileName(dstPath))\n const [ok, lock] = await this.filesLockManager.create(user, dbFile, DEPTH.RESOURCE)\n if (!ok) {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n fileLock = lock\n }\n if (space.task?.cacheKey) {\n space.task.props.compressInDirectory = dto.compressInDirectory\n FileTaskEvent.emit('startWatch', space, FILE_OPERATION.COMPRESS, dstPath)\n }\n // do\n try {\n archive.on('error', (error: ArchiverError) => {\n throw error\n })\n const dstStream = fs.createWriteStream(dstPath, { highWaterMark: DEFAULT_HIGH_WATER_MARK })\n archive.pipe(dstStream)\n for (const f of dto.files) {\n if (await isPathIsDir(f.path)) {\n archive.directory(f.path, dto.files.length > 1 ? fileName(f.path) : false)\n } else {\n archive.file(f.path, {\n name: f.rootAlias ? f.name : fileName(f.path)\n })\n }\n }\n await archive.finalize()\n } finally {\n if (fileLock) {\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n }\n\n async decompress(user: UserModel, space: SpaceEnv): Promise<void> {\n // checks\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n const extension = path.extname(space.realPath)\n if (!COMPRESSION_EXTENSION.has(extension)) {\n throw new FileError(HttpStatus.BAD_REQUEST, `${extension} is not supported`)\n }\n // make destination folder\n const dstPath = await uniqueFilePathFromDir(path.join(dirName(space.realPath), path.basename(space.realPath, extension)))\n await makeDir(dstPath)\n // create lock\n const dbFile = space.dbFile\n dbFile.path = path.join(dirName(dbFile.path), fileName(dstPath))\n const [ok, fileLock] = await this.filesLockManager.create(user, dbFile, DEPTH.INFINITY)\n if (!ok) {\n throw new LockConflict(fileLock, 'Conflicting lock')\n }\n // tasking\n if (space.task?.cacheKey) FileTaskEvent.emit('startWatch', space, FILE_OPERATION.DECOMPRESS, dstPath)\n // do\n try {\n if (extension === '.zip') {\n await extractZip(space.realPath, dstPath)\n } else {\n await extractTar({\n file: space.realPath,\n cwd: dstPath,\n gzip: COMPRESSION_EXTENSION.get(extension) === tarGzExtension,\n preserveOwner: false\n })\n }\n } finally {\n await this.filesLockManager.removeLock(fileLock.key)\n }\n }\n\n async generateThumbnail(space: SpaceEnv, size: number): Promise<Readable> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (getMimeType(space.realPath, false).indexOf('image') === -1) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'File is not an image')\n }\n try {\n return generateThumbnail(space.realPath, size)\n } catch (e) {\n this.logger.warn(e)\n throw new FileError(HttpStatus.BAD_REQUEST, 'File is not an image')\n }\n }\n\n async lock(user: UserModel, space: SpaceEnv): Promise<FileLockProps> {\n const rExists = await isPathExists(space.realPath)\n if (!rExists) {\n this.logger.warn('Lock refresh must specify an existing resource')\n throw new FileError(HttpStatus.BAD_REQUEST, 'Lock refresh must specify an existing resource')\n }\n const [_created, lock] = await this.filesLockManager.createOrRefresh(user, space.dbFile, DEPTH.RESOURCE, CACHE_LOCK_FILE_TTL)\n return this.filesLockManager.convertLockToFileLockProps(lock)\n }\n\n async unlock(user: UserModel, space: SpaceEnv, forceAsOwner = false): Promise<void> {\n if (!(await isPathExists(space.realPath))) {\n this.logger.warn(`Unable to unlock: ${space.url} - resource does not exist`)\n throw new FileError(HttpStatus.BAD_REQUEST, 'Unlock must specify an existing resource')\n }\n const fileLocks = await this.filesLockManager.getLocksByPath(space.dbFile)\n if (fileLocks.length === 0) {\n this.logger.warn(`Unable to find lock: ${space.url} - resource does not exist`)\n return\n }\n for (const lock of fileLocks) {\n if ((forceAsOwner && space.dbFile?.ownerId === user.id) || lock.owner.id === user.id) {\n // Refresh if more than half of the TTL has passed\n await this.filesLockManager.removeLock(lock.key)\n } else {\n throw new LockConflict(lock, 'Conflicting lock')\n }\n }\n }\n\n async unlockRequest(user: UserModel, space: SpaceEnv): Promise<void> {\n const fileLocks = await this.filesLockManager.getLocksByPath(space.dbFile)\n if (fileLocks.length === 0) {\n this.logger.warn(`Unable to find lock: ${space.url} - resource does not exist`)\n throw new FileError(HttpStatus.NOT_FOUND, 'Lock not found')\n }\n for (const lock of fileLocks) {\n if (lock.owner.id !== user.id) {\n const notification: NotificationContent = {\n app: NOTIFICATION_APP.UNLOCK_REQUEST,\n event: NOTIFICATION_APP_EVENT.UNLOCK_REQUEST,\n element: fileName(space.url),\n url: dirName(space.url)\n }\n this.notificationsManager\n .create([lock.owner.id], notification, {\n author: user,\n currentUrl: this.contextManager.headerOriginUrl()\n })\n .catch((e: Error) => this.logger.error(`${this.unlockRequest.name} - ${e}`))\n }\n }\n }\n\n async getSize(space: SpaceEnv): Promise<number> {\n if (!(await isPathExists(space.realPath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (await isPathIsDir(space.realPath)) {\n return (await dirSize(space.realPath))[0]\n } else {\n return await fileSize(space.realPath)\n }\n }\n}\n"],"names":["FilesManager","sendFileFromSpace","space","downloadName","SendFile","realPath","saveStream","user","req","options","fExists","isPathExists","fTmpExists","tmpPath","method","HTTP_METHOD","POST","FileError","HttpStatus","METHOD_NOT_ALLOWED","isPathIsDir","makeDir","dirName","CONFLICT","fileLock","dav","filesLockManager","checkConflicts","dbFile","depth","DEPTH","RESOURCE","userId","id","lockTokens","ok","lock","create","LockConflict","startRange","headers","match","exec","length","BAD_REQUEST","parseInt","size","fileSize","checksum","checksumAlg","writeFromStreamAndChecksum","raw","writeFromStream","path","dirname","moveFiles","e","removeFiles","logger","error","name","INTERNAL_SERVER_ERROR","removeLock","key","warn","saveMultipart","overwrite","PUT","patch","PATCH","realParentPath","basePath","sep","part","files","partFileName","fileName","filename","dstFile","resolve","startsWith","FORBIDDEN","dstDir","dstUrl","join","url","dstSpace","spacesManager","spaceEnv","split","delete","ttl","CACHE_LOCK_FILE_TTL","undefined","created","createOrRefresh","file","touch","mtime","checkLocks","NOT_FOUND","touchFile","mkFile","checkDocument","checkFileName","fileExtension","extname","Object","values","DOCUMENT_TYPE","indexOf","srcSample","__dirname","SAMPLE_PATH_WITHOUT_EXT","copyFileContent","createEmptyFile","mkDir","recursive","copyMove","srcSpace","isMove","mkdirDstParentPath","canAccessToSpace","repository","haveSpaceEnvPermissions","SPACE_OPERATION","ADD","alias","quotaIsExceeded","INSUFFICIENT_STORAGE","toLowerCase","PRECONDITION_FAILED","isDir","storageQuota","dirSize","willExceedQuota","INFINITY","task","cacheKey","props","totalSize","FileTaskEvent","emit","FILE_OPERATION","MOVE","COPY","filesQueries","copyFiles","forceDeleteInDB","inTrashRepository","baseTrashPath","realTrashPathFromSpace","trashDir","trashFile","dstTrash","uniqueDatedFilePath","trashFileDB","inTrash","dstTrashFileDB","removeChildLocks","catch","getLocksByPath","deleteFiles","downloadFromUrl","log","rPath","uniqueFilePathFromDir","headRes","http","axiosRef","HEAD","maxRedirects","regExpPrivateIP","test","request","socket","remoteAddress","debug","DOWNLOAD","getRes","GET","responseType","data","compress","dto","srcPath","archiveExt","endsWith","extension","dstPath","compressInDirectory","tasksPath","archive","archiver","gzip","tarGzExtension","gzipOptions","level","COMPRESS","on","dstStream","fs","createWriteStream","highWaterMark","DEFAULT_HIGH_WATER_MARK","pipe","f","directory","rootAlias","finalize","decompress","COMPRESSION_EXTENSION","has","basename","DECOMPRESS","extractZip","extractTar","cwd","get","preserveOwner","generateThumbnail","getMimeType","rExists","_created","convertLockToFileLockProps","unlock","forceAsOwner","fileLocks","ownerId","owner","unlockRequest","notification","app","NOTIFICATION_APP","UNLOCK_REQUEST","event","NOTIFICATION_APP_EVENT","element","notificationsManager","author","currentUrl","contextManager","headerOriginUrl","getSize","Logger"],"mappings":"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"}
@@ -104,7 +104,7 @@ let FilesTasksManager = class FilesTasksManager {
104
104
  throw new _common.HttpException('Not applicable', _common.HttpStatus.BAD_REQUEST);
105
105
  }
106
106
  const rPath = _nodepath.default.join(user.tasksPath, task.name);
107
- const sendFile = new _sendfile.SendFile(rPath, true);
107
+ const sendFile = new _sendfile.SendFile(rPath);
108
108
  try {
109
109
  await sendFile.checks();
110
110
  } catch (e) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-tasks-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 } from 'fastify'\nimport crypto from 'node:crypto'\nimport path from 'node:path'\nimport { setTimeout } from 'node:timers/promises'\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { UserModel } from '../../users/models/user.model'\nimport { CACHE_TASK_PREFIX, CACHE_TASK_TTL } from '../constants/cache'\nimport { FILE_OPERATION } from '../constants/operations'\nimport { FileTaskEvent } from '../events/file-task-event'\nimport { FileTask, FileTaskProps, FileTaskStatus } from '../models/file-task'\nimport { countDirEntries, dirName, fileName, fileSize, isPathIsDir, removeFiles } from '../utils/files'\nimport { SendFile } from '../utils/send-file'\nimport { FilesMethods } from './files-methods.service'\n\n@Injectable()\nexport class FilesTasksManager {\n // task cache key = `ftask-$(userId}-${taskId}` => FileTask\n private readonly logger = new Logger(FilesTasksManager.name)\n private readonly watchInterval = 1000\n private tasksWatcher: Record<string, any> = {}\n\n constructor(\n private readonly cache: Cache,\n private readonly filesMethods: FilesMethods\n ) {\n FileTaskEvent.on('startWatch', async (space: SpaceEnv, taskType: FILE_OPERATION, rPath: string) =>\n this.startWatch(space, taskType, rPath, dirName(space.url))\n )\n }\n\n static getCacheKey(userId: number, taskId?: string): string {\n return `${CACHE_TASK_PREFIX}-${userId}-${taskId || '*'}`\n }\n\n async createTask(type: FILE_OPERATION, user: UserModel, space: SpaceEnv, dto: any, method: string): Promise<FileTask> {\n const taskId: string = crypto.randomUUID()\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const newTask = new FileTask(taskId, type, dirName(space.url), fileName(space.url))\n await this.storeTask(cacheKey, newTask)\n space.task = { cacheKey: cacheKey, props: {} }\n this.filesMethods[method](user, space, dto)\n .then((data: any) => {\n this.logger.debug(`${this.createTask.name} - ${newTask.name} : ${method} done`)\n this.setTaskDone(cacheKey, FileTaskStatus.SUCCESS, data).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n .catch((e: HttpException | any) => {\n this.logger.error(`${this.createTask.name} - ${newTask.name} : ${method} : ${e}`)\n this.setTaskDone(cacheKey, FileTaskStatus.ERROR, e.message).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n return newTask\n }\n\n async getTasks(userId: number, taskId?: string): Promise<FileTask | FileTask[]> {\n const cacheKey = FilesTasksManager.getCacheKey(userId, taskId)\n if (taskId) {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) return task\n throw new HttpException('Task not found', HttpStatus.NOT_FOUND)\n } else {\n const keys = await this.cache.keys(cacheKey)\n return keys.length ? await this.cache.mget(keys) : []\n }\n }\n\n async deleteTasks(user: UserModel, taskId?: string): Promise<void> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n let keys: string[]\n if (taskId) {\n keys = [cacheKey]\n } else {\n keys = await this.cache.keys(cacheKey)\n }\n if (!keys.length) return\n for (const key of keys) {\n const task: FileTask = await this.cache.get(key)\n if (!task || task.status === FileTaskStatus.PENDING) continue\n if (task.props.compressInDirectory === false) {\n // delete task file\n const rPath = path.join(user.tasksPath, task.name)\n removeFiles(rPath).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n // clear watcher\n this.stopWatch(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n // remove from cache\n this.cache.del(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n }\n\n async downloadArchive(user: UserModel, taskId: string, req: FastifyAuthenticatedRequest, res: FastifyReply): Promise<StreamableFile> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const task: FileTask = await this.cache.get(cacheKey)\n if (!task || task.status !== FileTaskStatus.SUCCESS || task.props.compressInDirectory !== false) {\n throw new HttpException('Not applicable', HttpStatus.BAD_REQUEST)\n }\n const rPath = path.join(user.tasksPath, task.name)\n const sendFile = new SendFile(rPath, true)\n try {\n await sendFile.checks()\n } catch (e) {\n throw new HttpException(e.message, e.httpCode)\n }\n return await sendFile.stream(req, res)\n }\n\n private async storeTask(cacheKey: string, task: FileTask) {\n task.startedAt = currentTimeStamp(null, true)\n task.status = FileTaskStatus.PENDING\n try {\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n } catch (e) {\n this.logger.error(`${this.storeTask.name} - ${e}`)\n }\n }\n\n private async setTaskDone(cacheKey: string, status: FileTaskStatus, result: any): Promise<void> {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) {\n task.status = status\n task.endedAt = currentTimeStamp(null, true)\n if (result) {\n if (typeof result === 'string') {\n task.result = result\n } else {\n Object.assign(task, result)\n }\n }\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n }\n await this.stopWatch(cacheKey)\n }\n\n private async updateTask(cacheKey: string, props?: FileTaskProps, task?: Partial<FileTask>): Promise<void> {\n let ftask: FileTask = await this.cache.get(cacheKey)\n if (ftask) {\n if (task) ftask = { ...ftask, ...task }\n if (props) ftask.props = { ...ftask.props, ...props }\n await this.cache.set(cacheKey, ftask, CACHE_TASK_TTL)\n } else {\n await this.stopWatch(cacheKey)\n }\n }\n\n private async startWatch(space: SpaceEnv, taskType: FILE_OPERATION, rPath: string, taskPath?: string): Promise<void> {\n if (!space.task?.cacheKey || space.task.cacheKey in this.tasksWatcher) return\n this.logger.verbose(`${this.startWatch.name} - ${space.task.cacheKey}`)\n this.updateTask(space.task.cacheKey, space.task?.props, {\n name: fileName(rPath),\n path: taskPath\n }).catch((e: Error) => this.logger.error(`${this.startWatch.name} - ${e}`))\n switch (taskType) {\n case FILE_OPERATION.COMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DECOMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDecompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DOWNLOAD:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDownloadTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.COPY:\n case FILE_OPERATION.MOVE:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCopyMoveTask(space, rPath), this.watchInterval)\n return\n default:\n this.logger.warn(`${this.startWatch.name} - unknown task type ${taskType}`)\n return\n }\n }\n\n private async stopWatch(cacheKey: string): Promise<void> {\n if (!(cacheKey in this.tasksWatcher)) return\n await setTimeout(this.watchInterval)\n clearInterval(this.tasksWatcher[cacheKey])\n delete this.tasksWatcher[cacheKey]\n }\n\n private async updateCompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props.size = await fileSize(rPath)\n await this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDecompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props = await countDirEntries(rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDecompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDecompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDownloadTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n await this.calcSizeAndProgressTask(space, rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDownloadTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDownloadTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateCopyMoveTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n if (await isPathIsDir(rPath)) {\n space.task.props = await countDirEntries(rPath)\n } else {\n await this.calcSizeAndProgressTask(space, rPath)\n }\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async calcSizeAndProgressTask(space: SpaceEnv, rPath: string) {\n space.task.props.size = await fileSize(rPath)\n if (space.task.props.totalSize) {\n space.task.props.progress = (100 * space.task.props.size) / space.task.props.totalSize\n }\n }\n}\n"],"names":["FilesTasksManager","getCacheKey","userId","taskId","CACHE_TASK_PREFIX","createTask","type","user","space","dto","method","crypto","randomUUID","cacheKey","id","newTask","FileTask","dirName","url","fileName","storeTask","task","props","filesMethods","then","data","logger","debug","name","setTaskDone","FileTaskStatus","SUCCESS","catch","e","error","ERROR","message","getTasks","cache","get","HttpException","HttpStatus","NOT_FOUND","keys","length","mget","deleteTasks","key","status","PENDING","compressInDirectory","rPath","path","join","tasksPath","removeFiles","stopWatch","del","downloadArchive","req","res","BAD_REQUEST","sendFile","SendFile","checks","httpCode","stream","startedAt","currentTimeStamp","set","CACHE_TASK_TTL","result","endedAt","Object","assign","updateTask","ftask","startWatch","taskType","taskPath","tasksWatcher","verbose","FILE_OPERATION","COMPRESS","setInterval","updateCompressTask","watchInterval","DECOMPRESS","updateDecompressTask","DOWNLOAD","updateDownloadTask","COPY","MOVE","updateCopyMoveTask","warn","setTimeout","clearInterval","size","fileSize","countDirEntries","calcSizeAndProgressTask","isPathIsDir","totalSize","progress","Logger","FileTaskEvent","on"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/services/files-tasks-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 } from 'fastify'\nimport crypto from 'node:crypto'\nimport path from 'node:path'\nimport { setTimeout } from 'node:timers/promises'\nimport { FastifyAuthenticatedRequest } from '../../../authentication/interfaces/auth-request.interface'\n\nimport { currentTimeStamp } from '../../../common/shared'\nimport { Cache } from '../../../infrastructure/cache/services/cache.service'\nimport { SpaceEnv } from '../../spaces/models/space-env.model'\nimport { UserModel } from '../../users/models/user.model'\nimport { CACHE_TASK_PREFIX, CACHE_TASK_TTL } from '../constants/cache'\nimport { FILE_OPERATION } from '../constants/operations'\nimport { FileTaskEvent } from '../events/file-task-event'\nimport { FileTask, FileTaskProps, FileTaskStatus } from '../models/file-task'\nimport { countDirEntries, dirName, fileName, fileSize, isPathIsDir, removeFiles } from '../utils/files'\nimport { SendFile } from '../utils/send-file'\nimport { FilesMethods } from './files-methods.service'\n\n@Injectable()\nexport class FilesTasksManager {\n // task cache key = `ftask-$(userId}-${taskId}` => FileTask\n private readonly logger = new Logger(FilesTasksManager.name)\n private readonly watchInterval = 1000\n private tasksWatcher: Record<string, any> = {}\n\n constructor(\n private readonly cache: Cache,\n private readonly filesMethods: FilesMethods\n ) {\n FileTaskEvent.on('startWatch', async (space: SpaceEnv, taskType: FILE_OPERATION, rPath: string) =>\n this.startWatch(space, taskType, rPath, dirName(space.url))\n )\n }\n\n static getCacheKey(userId: number, taskId?: string): string {\n return `${CACHE_TASK_PREFIX}-${userId}-${taskId || '*'}`\n }\n\n async createTask(type: FILE_OPERATION, user: UserModel, space: SpaceEnv, dto: any, method: string): Promise<FileTask> {\n const taskId: string = crypto.randomUUID()\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const newTask = new FileTask(taskId, type, dirName(space.url), fileName(space.url))\n await this.storeTask(cacheKey, newTask)\n space.task = { cacheKey: cacheKey, props: {} }\n this.filesMethods[method](user, space, dto)\n .then((data: any) => {\n this.logger.debug(`${this.createTask.name} - ${newTask.name} : ${method} done`)\n this.setTaskDone(cacheKey, FileTaskStatus.SUCCESS, data).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n .catch((e: HttpException | any) => {\n this.logger.error(`${this.createTask.name} - ${newTask.name} : ${method} : ${e}`)\n this.setTaskDone(cacheKey, FileTaskStatus.ERROR, e.message).catch((e: Error) => this.logger.error(`${this.createTask.name} - ${e}`))\n })\n return newTask\n }\n\n async getTasks(userId: number, taskId?: string): Promise<FileTask | FileTask[]> {\n const cacheKey = FilesTasksManager.getCacheKey(userId, taskId)\n if (taskId) {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) return task\n throw new HttpException('Task not found', HttpStatus.NOT_FOUND)\n } else {\n const keys = await this.cache.keys(cacheKey)\n return keys.length ? await this.cache.mget(keys) : []\n }\n }\n\n async deleteTasks(user: UserModel, taskId?: string): Promise<void> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n let keys: string[]\n if (taskId) {\n keys = [cacheKey]\n } else {\n keys = await this.cache.keys(cacheKey)\n }\n if (!keys.length) return\n for (const key of keys) {\n const task: FileTask = await this.cache.get(key)\n if (!task || task.status === FileTaskStatus.PENDING) continue\n if (task.props.compressInDirectory === false) {\n // delete task file\n const rPath = path.join(user.tasksPath, task.name)\n removeFiles(rPath).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n // clear watcher\n this.stopWatch(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n // remove from cache\n this.cache.del(key).catch((e: Error) => this.logger.error(`${this.deleteTasks.name} - ${e}`))\n }\n }\n\n async downloadArchive(user: UserModel, taskId: string, req: FastifyAuthenticatedRequest, res: FastifyReply): Promise<StreamableFile> {\n const cacheKey = FilesTasksManager.getCacheKey(user.id, taskId)\n const task: FileTask = await this.cache.get(cacheKey)\n if (!task || task.status !== FileTaskStatus.SUCCESS || task.props.compressInDirectory !== false) {\n throw new HttpException('Not applicable', HttpStatus.BAD_REQUEST)\n }\n const rPath = path.join(user.tasksPath, task.name)\n const sendFile = new SendFile(rPath)\n try {\n await sendFile.checks()\n } catch (e) {\n throw new HttpException(e.message, e.httpCode)\n }\n return await sendFile.stream(req, res)\n }\n\n private async storeTask(cacheKey: string, task: FileTask) {\n task.startedAt = currentTimeStamp(null, true)\n task.status = FileTaskStatus.PENDING\n try {\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n } catch (e) {\n this.logger.error(`${this.storeTask.name} - ${e}`)\n }\n }\n\n private async setTaskDone(cacheKey: string, status: FileTaskStatus, result: any): Promise<void> {\n const task: FileTask = await this.cache.get(cacheKey)\n if (task) {\n task.status = status\n task.endedAt = currentTimeStamp(null, true)\n if (result) {\n if (typeof result === 'string') {\n task.result = result\n } else {\n Object.assign(task, result)\n }\n }\n await this.cache.set(cacheKey, task, CACHE_TASK_TTL)\n }\n await this.stopWatch(cacheKey)\n }\n\n private async updateTask(cacheKey: string, props?: FileTaskProps, task?: Partial<FileTask>): Promise<void> {\n let ftask: FileTask = await this.cache.get(cacheKey)\n if (ftask) {\n if (task) ftask = { ...ftask, ...task }\n if (props) ftask.props = { ...ftask.props, ...props }\n await this.cache.set(cacheKey, ftask, CACHE_TASK_TTL)\n } else {\n await this.stopWatch(cacheKey)\n }\n }\n\n private async startWatch(space: SpaceEnv, taskType: FILE_OPERATION, rPath: string, taskPath?: string): Promise<void> {\n if (!space.task?.cacheKey || space.task.cacheKey in this.tasksWatcher) return\n this.logger.verbose(`${this.startWatch.name} - ${space.task.cacheKey}`)\n this.updateTask(space.task.cacheKey, space.task?.props, {\n name: fileName(rPath),\n path: taskPath\n }).catch((e: Error) => this.logger.error(`${this.startWatch.name} - ${e}`))\n switch (taskType) {\n case FILE_OPERATION.COMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DECOMPRESS:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDecompressTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.DOWNLOAD:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateDownloadTask(space, rPath), this.watchInterval)\n return\n case FILE_OPERATION.COPY:\n case FILE_OPERATION.MOVE:\n this.tasksWatcher[space.task.cacheKey] = setInterval(async () => this.updateCopyMoveTask(space, rPath), this.watchInterval)\n return\n default:\n this.logger.warn(`${this.startWatch.name} - unknown task type ${taskType}`)\n return\n }\n }\n\n private async stopWatch(cacheKey: string): Promise<void> {\n if (!(cacheKey in this.tasksWatcher)) return\n await setTimeout(this.watchInterval)\n clearInterval(this.tasksWatcher[cacheKey])\n delete this.tasksWatcher[cacheKey]\n }\n\n private async updateCompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props.size = await fileSize(rPath)\n await this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDecompressTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n space.task.props = await countDirEntries(rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDecompressTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDecompressTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateDownloadTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n await this.calcSizeAndProgressTask(space, rPath)\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateDownloadTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateDownloadTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async updateCopyMoveTask(space: SpaceEnv, rPath: string): Promise<void> {\n try {\n if (await isPathIsDir(rPath)) {\n space.task.props = await countDirEntries(rPath)\n } else {\n await this.calcSizeAndProgressTask(space, rPath)\n }\n this.updateTask(space.task.cacheKey, space.task.props).catch((e: Error) => this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`))\n } catch (e) {\n this.logger.error(`${this.updateCopyMoveTask.name} - ${e}`)\n await this.stopWatch(space.task.cacheKey)\n }\n }\n\n private async calcSizeAndProgressTask(space: SpaceEnv, rPath: string) {\n space.task.props.size = await fileSize(rPath)\n if (space.task.props.totalSize) {\n space.task.props.progress = (100 * space.task.props.size) / space.task.props.totalSize\n }\n }\n}\n"],"names":["FilesTasksManager","getCacheKey","userId","taskId","CACHE_TASK_PREFIX","createTask","type","user","space","dto","method","crypto","randomUUID","cacheKey","id","newTask","FileTask","dirName","url","fileName","storeTask","task","props","filesMethods","then","data","logger","debug","name","setTaskDone","FileTaskStatus","SUCCESS","catch","e","error","ERROR","message","getTasks","cache","get","HttpException","HttpStatus","NOT_FOUND","keys","length","mget","deleteTasks","key","status","PENDING","compressInDirectory","rPath","path","join","tasksPath","removeFiles","stopWatch","del","downloadArchive","req","res","BAD_REQUEST","sendFile","SendFile","checks","httpCode","stream","startedAt","currentTimeStamp","set","CACHE_TASK_TTL","result","endedAt","Object","assign","updateTask","ftask","startWatch","taskType","taskPath","tasksWatcher","verbose","FILE_OPERATION","COMPRESS","setInterval","updateCompressTask","watchInterval","DECOMPRESS","updateDecompressTask","DOWNLOAD","updateDownloadTask","COPY","MOVE","updateCopyMoveTask","warn","setTimeout","clearInterval","size","fileSize","countDirEntries","calcSizeAndProgressTask","isPathIsDir","totalSize","progress","Logger","FileTaskEvent","on"],"mappings":"AAAA;;;;CAIC;;;;+BAsBYA;;;eAAAA;;;wBApBiE;mEAE3D;iEACF;0BACU;wBAGM;8BACX;uBAG4B;4BACnB;+BACD;0BAC0B;uBAC+B;0BAC9D;qCACI;;;;;;;;;;;;;;;AAGtB,IAAA,AAAMA,oBAAN,MAAMA;IAeX,OAAOC,YAAYC,MAAc,EAAEC,MAAe,EAAU;QAC1D,OAAO,GAAGC,wBAAiB,CAAC,CAAC,EAAEF,OAAO,CAAC,EAAEC,UAAU,KAAK;IAC1D;IAEA,MAAME,WAAWC,IAAoB,EAAEC,IAAe,EAAEC,KAAe,EAAEC,GAAQ,EAAEC,MAAc,EAAqB;QACpH,MAAMP,SAAiBQ,mBAAM,CAACC,UAAU;QACxC,MAAMC,WAAWb,kBAAkBC,WAAW,CAACM,KAAKO,EAAE,EAAEX;QACxD,MAAMY,UAAU,IAAIC,kBAAQ,CAACb,QAAQG,MAAMW,IAAAA,cAAO,EAACT,MAAMU,GAAG,GAAGC,IAAAA,eAAQ,EAACX,MAAMU,GAAG;QACjF,MAAM,IAAI,CAACE,SAAS,CAACP,UAAUE;QAC/BP,MAAMa,IAAI,GAAG;YAAER,UAAUA;YAAUS,OAAO,CAAC;QAAE;QAC7C,IAAI,CAACC,YAAY,CAACb,OAAO,CAACH,MAAMC,OAAOC,KACpCe,IAAI,CAAC,CAACC;YACL,IAAI,CAACC,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACtB,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEb,QAAQa,IAAI,CAAC,GAAG,EAAElB,OAAO,KAAK,CAAC;YAC9E,IAAI,CAACmB,WAAW,CAAChB,UAAUiB,wBAAc,CAACC,OAAO,EAAEN,MAAMO,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC7B,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEK,GAAG;QACjI,GACCD,KAAK,CAAC,CAACC;YACN,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC7B,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEb,QAAQa,IAAI,CAAC,GAAG,EAAElB,OAAO,GAAG,EAAEuB,GAAG;YAChF,IAAI,CAACJ,WAAW,CAAChB,UAAUiB,wBAAc,CAACK,KAAK,EAAEF,EAAEG,OAAO,EAAEJ,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC7B,UAAU,CAACuB,IAAI,CAAC,GAAG,EAAEK,GAAG;QACpI;QACF,OAAOlB;IACT;IAEA,MAAMsB,SAASnC,MAAc,EAAEC,MAAe,EAAkC;QAC9E,MAAMU,WAAWb,kBAAkBC,WAAW,CAACC,QAAQC;QACvD,IAAIA,QAAQ;YACV,MAAMkB,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAAC1B;YAC5C,IAAIQ,MAAM,OAAOA;YACjB,MAAM,IAAImB,qBAAa,CAAC,kBAAkBC,kBAAU,CAACC,SAAS;QAChE,OAAO;YACL,MAAMC,OAAO,MAAM,IAAI,CAACL,KAAK,CAACK,IAAI,CAAC9B;YACnC,OAAO8B,KAAKC,MAAM,GAAG,MAAM,IAAI,CAACN,KAAK,CAACO,IAAI,CAACF,QAAQ,EAAE;QACvD;IACF;IAEA,MAAMG,YAAYvC,IAAe,EAAEJ,MAAe,EAAiB;QACjE,MAAMU,WAAWb,kBAAkBC,WAAW,CAACM,KAAKO,EAAE,EAAEX;QACxD,IAAIwC;QACJ,IAAIxC,QAAQ;YACVwC,OAAO;gBAAC9B;aAAS;QACnB,OAAO;YACL8B,OAAO,MAAM,IAAI,CAACL,KAAK,CAACK,IAAI,CAAC9B;QAC/B;QACA,IAAI,CAAC8B,KAAKC,MAAM,EAAE;QAClB,KAAK,MAAMG,OAAOJ,KAAM;YACtB,MAAMtB,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAACQ;YAC5C,IAAI,CAAC1B,QAAQA,KAAK2B,MAAM,KAAKlB,wBAAc,CAACmB,OAAO,EAAE;YACrD,IAAI5B,KAAKC,KAAK,CAAC4B,mBAAmB,KAAK,OAAO;gBAC5C,mBAAmB;gBACnB,MAAMC,QAAQC,iBAAI,CAACC,IAAI,CAAC9C,KAAK+C,SAAS,EAAEjC,KAAKO,IAAI;gBACjD2B,IAAAA,kBAAW,EAACJ,OAAOnB,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACY,WAAW,CAAClB,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC5F;YACA,gBAAgB;YAChB,IAAI,CAACuB,SAAS,CAACT,KAAKf,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACY,WAAW,CAAClB,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC3F,oBAAoB;YACpB,IAAI,CAACK,KAAK,CAACmB,GAAG,CAACV,KAAKf,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACY,WAAW,CAAClB,IAAI,CAAC,GAAG,EAAEK,GAAG;QAC7F;IACF;IAEA,MAAMyB,gBAAgBnD,IAAe,EAAEJ,MAAc,EAAEwD,GAAgC,EAAEC,GAAiB,EAA2B;QACnI,MAAM/C,WAAWb,kBAAkBC,WAAW,CAACM,KAAKO,EAAE,EAAEX;QACxD,MAAMkB,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAAC1B;QAC5C,IAAI,CAACQ,QAAQA,KAAK2B,MAAM,KAAKlB,wBAAc,CAACC,OAAO,IAAIV,KAAKC,KAAK,CAAC4B,mBAAmB,KAAK,OAAO;YAC/F,MAAM,IAAIV,qBAAa,CAAC,kBAAkBC,kBAAU,CAACoB,WAAW;QAClE;QACA,MAAMV,QAAQC,iBAAI,CAACC,IAAI,CAAC9C,KAAK+C,SAAS,EAAEjC,KAAKO,IAAI;QACjD,MAAMkC,WAAW,IAAIC,kBAAQ,CAACZ;QAC9B,IAAI;YACF,MAAMW,SAASE,MAAM;QACvB,EAAE,OAAO/B,GAAG;YACV,MAAM,IAAIO,qBAAa,CAACP,EAAEG,OAAO,EAAEH,EAAEgC,QAAQ;QAC/C;QACA,OAAO,MAAMH,SAASI,MAAM,CAACP,KAAKC;IACpC;IAEA,MAAcxC,UAAUP,QAAgB,EAAEQ,IAAc,EAAE;QACxDA,KAAK8C,SAAS,GAAGC,IAAAA,wBAAgB,EAAC,MAAM;QACxC/C,KAAK2B,MAAM,GAAGlB,wBAAc,CAACmB,OAAO;QACpC,IAAI;YACF,MAAM,IAAI,CAACX,KAAK,CAAC+B,GAAG,CAACxD,UAAUQ,MAAMiD,qBAAc;QACrD,EAAE,OAAOrC,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACd,SAAS,CAACQ,IAAI,CAAC,GAAG,EAAEK,GAAG;QACnD;IACF;IAEA,MAAcJ,YAAYhB,QAAgB,EAAEmC,MAAsB,EAAEuB,MAAW,EAAiB;QAC9F,MAAMlD,OAAiB,MAAM,IAAI,CAACiB,KAAK,CAACC,GAAG,CAAC1B;QAC5C,IAAIQ,MAAM;YACRA,KAAK2B,MAAM,GAAGA;YACd3B,KAAKmD,OAAO,GAAGJ,IAAAA,wBAAgB,EAAC,MAAM;YACtC,IAAIG,QAAQ;gBACV,IAAI,OAAOA,WAAW,UAAU;oBAC9BlD,KAAKkD,MAAM,GAAGA;gBAChB,OAAO;oBACLE,OAAOC,MAAM,CAACrD,MAAMkD;gBACtB;YACF;YACA,MAAM,IAAI,CAACjC,KAAK,CAAC+B,GAAG,CAACxD,UAAUQ,MAAMiD,qBAAc;QACrD;QACA,MAAM,IAAI,CAACd,SAAS,CAAC3C;IACvB;IAEA,MAAc8D,WAAW9D,QAAgB,EAAES,KAAqB,EAAED,IAAwB,EAAiB;QACzG,IAAIuD,QAAkB,MAAM,IAAI,CAACtC,KAAK,CAACC,GAAG,CAAC1B;QAC3C,IAAI+D,OAAO;YACT,IAAIvD,MAAMuD,QAAQ;gBAAE,GAAGA,KAAK;gBAAE,GAAGvD,IAAI;YAAC;YACtC,IAAIC,OAAOsD,MAAMtD,KAAK,GAAG;gBAAE,GAAGsD,MAAMtD,KAAK;gBAAE,GAAGA,KAAK;YAAC;YACpD,MAAM,IAAI,CAACgB,KAAK,CAAC+B,GAAG,CAACxD,UAAU+D,OAAON,qBAAc;QACtD,OAAO;YACL,MAAM,IAAI,CAACd,SAAS,CAAC3C;QACvB;IACF;IAEA,MAAcgE,WAAWrE,KAAe,EAAEsE,QAAwB,EAAE3B,KAAa,EAAE4B,QAAiB,EAAiB;QACnH,IAAI,CAACvE,MAAMa,IAAI,EAAER,YAAYL,MAAMa,IAAI,CAACR,QAAQ,IAAI,IAAI,CAACmE,YAAY,EAAE;QACvE,IAAI,CAACtD,MAAM,CAACuD,OAAO,CAAC,GAAG,IAAI,CAACJ,UAAU,CAACjD,IAAI,CAAC,GAAG,EAAEpB,MAAMa,IAAI,CAACR,QAAQ,EAAE;QACtE,IAAI,CAAC8D,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,EAAEC,OAAO;YACtDM,MAAMT,IAAAA,eAAQ,EAACgC;YACfC,MAAM2B;QACR,GAAG/C,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC2C,UAAU,CAACjD,IAAI,CAAC,GAAG,EAAEK,GAAG;QACzE,OAAQ6C;YACN,KAAKI,0BAAc,CAACC,QAAQ;gBAC1B,IAAI,CAACH,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACC,kBAAkB,CAAC7E,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC1H;YACF,KAAKJ,0BAAc,CAACK,UAAU;gBAC5B,IAAI,CAACP,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACI,oBAAoB,CAAChF,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC5H;YACF,KAAKJ,0BAAc,CAACO,QAAQ;gBAC1B,IAAI,CAACT,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACM,kBAAkB,CAAClF,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC1H;YACF,KAAKJ,0BAAc,CAACS,IAAI;YACxB,KAAKT,0BAAc,CAACU,IAAI;gBACtB,IAAI,CAACZ,YAAY,CAACxE,MAAMa,IAAI,CAACR,QAAQ,CAAC,GAAGuE,YAAY,UAAY,IAAI,CAACS,kBAAkB,CAACrF,OAAO2C,QAAQ,IAAI,CAACmC,aAAa;gBAC1H;YACF;gBACE,IAAI,CAAC5D,MAAM,CAACoE,IAAI,CAAC,GAAG,IAAI,CAACjB,UAAU,CAACjD,IAAI,CAAC,qBAAqB,EAAEkD,UAAU;gBAC1E;QACJ;IACF;IAEA,MAActB,UAAU3C,QAAgB,EAAiB;QACvD,IAAI,CAAEA,CAAAA,YAAY,IAAI,CAACmE,YAAY,AAAD,GAAI;QACtC,MAAMe,IAAAA,oBAAU,EAAC,IAAI,CAACT,aAAa;QACnCU,cAAc,IAAI,CAAChB,YAAY,CAACnE,SAAS;QACzC,OAAO,IAAI,CAACmE,YAAY,CAACnE,SAAS;IACpC;IAEA,MAAcwE,mBAAmB7E,KAAe,EAAE2C,KAAa,EAAiB;QAC9E,IAAI;YACF3C,MAAMa,IAAI,CAACC,KAAK,CAAC2E,IAAI,GAAG,MAAMC,IAAAA,eAAQ,EAAC/C;YACvC,MAAM,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACmD,kBAAkB,CAACzD,IAAI,CAAC,GAAG,EAAEK,GAAG;QAC7I,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACmD,kBAAkB,CAACzD,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC1D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAc2E,qBAAqBhF,KAAe,EAAE2C,KAAa,EAAiB;QAChF,IAAI;YACF3C,MAAMa,IAAI,CAACC,KAAK,GAAG,MAAM6E,IAAAA,sBAAe,EAAChD;YACzC,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACsD,oBAAoB,CAAC5D,IAAI,CAAC,GAAG,EAAEK,GAAG;QACzI,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACsD,oBAAoB,CAAC5D,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC5D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAc6E,mBAAmBlF,KAAe,EAAE2C,KAAa,EAAiB;QAC9E,IAAI;YACF,MAAM,IAAI,CAACiD,uBAAuB,CAAC5F,OAAO2C;YAC1C,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACwD,kBAAkB,CAAC9D,IAAI,CAAC,GAAG,EAAEK,GAAG;QACvI,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAACwD,kBAAkB,CAAC9D,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC1D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAcgF,mBAAmBrF,KAAe,EAAE2C,KAAa,EAAiB;QAC9E,IAAI;YACF,IAAI,MAAMkD,IAAAA,kBAAW,EAAClD,QAAQ;gBAC5B3C,MAAMa,IAAI,CAACC,KAAK,GAAG,MAAM6E,IAAAA,sBAAe,EAAChD;YAC3C,OAAO;gBACL,MAAM,IAAI,CAACiD,uBAAuB,CAAC5F,OAAO2C;YAC5C;YACA,IAAI,CAACwB,UAAU,CAACnE,MAAMa,IAAI,CAACR,QAAQ,EAAEL,MAAMa,IAAI,CAACC,KAAK,EAAEU,KAAK,CAAC,CAACC,IAAa,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC2D,kBAAkB,CAACjE,IAAI,CAAC,GAAG,EAAEK,GAAG;QACvI,EAAE,OAAOA,GAAG;YACV,IAAI,CAACP,MAAM,CAACQ,KAAK,CAAC,GAAG,IAAI,CAAC2D,kBAAkB,CAACjE,IAAI,CAAC,GAAG,EAAEK,GAAG;YAC1D,MAAM,IAAI,CAACuB,SAAS,CAAChD,MAAMa,IAAI,CAACR,QAAQ;QAC1C;IACF;IAEA,MAAcuF,wBAAwB5F,KAAe,EAAE2C,KAAa,EAAE;QACpE3C,MAAMa,IAAI,CAACC,KAAK,CAAC2E,IAAI,GAAG,MAAMC,IAAAA,eAAQ,EAAC/C;QACvC,IAAI3C,MAAMa,IAAI,CAACC,KAAK,CAACgF,SAAS,EAAE;YAC9B9F,MAAMa,IAAI,CAACC,KAAK,CAACiF,QAAQ,GAAG,AAAC,MAAM/F,MAAMa,IAAI,CAACC,KAAK,CAAC2E,IAAI,GAAIzF,MAAMa,IAAI,CAACC,KAAK,CAACgF,SAAS;QACxF;IACF;IA5MA,YACE,AAAiBhE,KAAY,EAC7B,AAAiBf,YAA0B,CAC3C;aAFiBe,QAAAA;aACAf,eAAAA;QAPnB,2DAA2D;aAC1CG,SAAS,IAAI8E,cAAM,CAACxG,kBAAkB4B,IAAI;aAC1C0D,gBAAgB;aACzBN,eAAoC,CAAC;QAM3CyB,4BAAa,CAACC,EAAE,CAAC,cAAc,OAAOlG,OAAiBsE,UAA0B3B,QAC/E,IAAI,CAAC0B,UAAU,CAACrE,OAAOsE,UAAU3B,OAAOlC,IAAAA,cAAO,EAACT,MAAMU,GAAG;IAE7D;AAsMF"}
@@ -6,10 +6,18 @@
6
6
  Object.defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
- Object.defineProperty(exports, "SendFile", {
10
- enumerable: true,
11
- get: function() {
9
+ function _export(target, all) {
10
+ for(var name in all)Object.defineProperty(target, name, {
11
+ enumerable: true,
12
+ get: Object.getOwnPropertyDescriptor(all, name).get
13
+ });
14
+ }
15
+ _export(exports, {
16
+ get SendFile () {
12
17
  return SendFile;
18
+ },
19
+ get makeContentDispositionAttachment () {
20
+ return makeContentDispositionAttachment;
13
21
  }
14
22
  });
15
23
  const _send = require("@fastify/send");
@@ -17,6 +25,10 @@ const _common = require("@nestjs/common");
17
25
  const _files = require("../constants/files");
18
26
  const _fileerror = require("../models/file-error");
19
27
  const _files1 = require("./files");
28
+ function makeContentDispositionAttachment(fileName) {
29
+ const downloadName = fileName.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
30
+ return `attachment; filename="${downloadName}";filename*=UTF-8''${fileName}`;
31
+ }
20
32
  let SendFile = class SendFile {
21
33
  async checks() {
22
34
  if (!await (0, _files1.isPathExists)(this.filePath)) {
@@ -40,10 +52,8 @@ let SendFile = class SendFile {
40
52
  if (sendResult.metadata['path'] === undefined) {
41
53
  throw new _fileerror.FileError(_common.HttpStatus.BAD_REQUEST, 'Location not found');
42
54
  }
43
- if (this.asAttachment) {
44
- const downloadName = this.fileName.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
45
- sendResult.headers['content-disposition'] = `attachment; filename="${downloadName}";filename*=UTF-8''${this.fileName}`;
46
- }
55
+ // Force file to be downloaded as an attachment
56
+ sendResult.headers['content-disposition'] = makeContentDispositionAttachment(this.fileName);
47
57
  res.headers(sendResult.headers);
48
58
  res.status(sendResult.statusCode);
49
59
  // sendStream.once('stream', () => console.log(`Sending: ${this.fileName}`))
@@ -51,7 +61,7 @@ let SendFile = class SendFile {
51
61
  // sendStream.once('error', (e: Error) => console.error(`Transfer error : ${this.fileName} - ${e}`))
52
62
  return new _common.StreamableFile(sendResult.stream);
53
63
  }
54
- constructor(filePath, asAttachment = true, downloadName = '', sendOptions = {
64
+ constructor(filePath, downloadName = '', sendOptions = {
55
65
  acceptRanges: true,
56
66
  etag: true,
57
67
  dotfiles: 'allow',
@@ -62,7 +72,6 @@ let SendFile = class SendFile {
62
72
  highWaterMark: _files.DEFAULT_HIGH_WATER_MARK
63
73
  }){
64
74
  this.filePath = filePath;
65
- this.asAttachment = asAttachment;
66
75
  this.downloadName = downloadName;
67
76
  this.sendOptions = sendOptions;
68
77
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/utils/send-file.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 { send, SendOptions, SendResult } from '@fastify/send'\nimport { HttpStatus, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { DEFAULT_HIGH_WATER_MARK } from '../constants/files'\nimport { FileError } from '../models/file-error'\nimport { fileName, isPathExists, isPathIsDir, isPathIsReadable } from './files'\n\nexport class SendFile {\n private fileName: string\n\n constructor(\n private readonly filePath: string,\n private readonly asAttachment = true,\n private readonly downloadName = '',\n private readonly sendOptions: SendOptions = {\n acceptRanges: true,\n etag: true,\n dotfiles: 'allow',\n lastModified: true,\n cacheControl: true,\n maxAge: 0,\n index: false,\n highWaterMark: DEFAULT_HIGH_WATER_MARK\n }\n ) {}\n\n async checks() {\n if (!(await isPathExists(this.filePath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (await isPathIsDir(this.filePath)) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'The location is a directory')\n }\n if (!(await isPathIsReadable(this.filePath))) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'The location is not readable')\n }\n }\n\n async stream(req: FastifyRequest, res: FastifyReply): Promise<StreamableFile> {\n // SendStream manages HEAD (no including body in response) & GET request (with body)\n // Ranges, LastModified, Etag are also handled\n // Send function uses decodeURIComponent, but filePath is already decoded: we need to encode it again before passing it.\n const encodedFilePath = encodeURIComponent(this.filePath)\n this.fileName = encodeURIComponent(this.downloadName ? this.downloadName : fileName(this.filePath))\n const sendResult: SendResult = await send(req.raw, encodedFilePath, this.sendOptions)\n // Check if the path was correctly validated\n if (sendResult.metadata['path'] === undefined) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Location not found')\n }\n if (this.asAttachment) {\n const downloadName = this.fileName.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n sendResult.headers['content-disposition'] = `attachment; filename=\"${downloadName}\";filename*=UTF-8''${this.fileName}`\n }\n res.headers(sendResult.headers)\n res.status(sendResult.statusCode)\n // sendStream.once('stream', () => console.log(`Sending: ${this.fileName}`))\n // sendStream.once('end', () => console.log(`Received: ${this.fileName}`))\n // sendStream.once('error', (e: Error) => console.error(`Transfer error : ${this.fileName} - ${e}`))\n return new StreamableFile(sendResult.stream)\n }\n}\n"],"names":["SendFile","checks","isPathExists","filePath","FileError","HttpStatus","NOT_FOUND","isPathIsDir","BAD_REQUEST","isPathIsReadable","METHOD_NOT_ALLOWED","stream","req","res","encodedFilePath","encodeURIComponent","fileName","downloadName","sendResult","send","raw","sendOptions","metadata","undefined","asAttachment","normalize","replace","headers","status","statusCode","StreamableFile","acceptRanges","etag","dotfiles","lastModified","cacheControl","maxAge","index","highWaterMark","DEFAULT_HIGH_WATER_MARK"],"mappings":"AAAA;;;;CAIC;;;;+BASYA;;;eAAAA;;;sBAPiC;wBACH;uBAEH;2BACd;wBAC4C;AAE/D,IAAA,AAAMA,WAAN,MAAMA;IAmBX,MAAMC,SAAS;QACb,IAAI,CAAE,MAAMC,IAAAA,oBAAY,EAAC,IAAI,CAACC,QAAQ,GAAI;YACxC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACC,SAAS,EAAE;QAC5C;QACA,IAAI,MAAMC,IAAAA,mBAAW,EAAC,IAAI,CAACJ,QAAQ,GAAG;YACpC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,IAAI,CAAE,MAAMC,IAAAA,wBAAgB,EAAC,IAAI,CAACN,QAAQ,GAAI;YAC5C,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACK,kBAAkB,EAAE;QACrD;IACF;IAEA,MAAMC,OAAOC,GAAmB,EAAEC,GAAiB,EAA2B;QAC5E,oFAAoF;QACpF,8CAA8C;QAC9C,wHAAwH;QACxH,MAAMC,kBAAkBC,mBAAmB,IAAI,CAACZ,QAAQ;QACxD,IAAI,CAACa,QAAQ,GAAGD,mBAAmB,IAAI,CAACE,YAAY,GAAG,IAAI,CAACA,YAAY,GAAGD,IAAAA,gBAAQ,EAAC,IAAI,CAACb,QAAQ;QACjG,MAAMe,aAAyB,MAAMC,IAAAA,UAAI,EAACP,IAAIQ,GAAG,EAAEN,iBAAiB,IAAI,CAACO,WAAW;QACpF,4CAA4C;QAC5C,IAAIH,WAAWI,QAAQ,CAAC,OAAO,KAAKC,WAAW;YAC7C,MAAM,IAAInB,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,IAAI,IAAI,CAACgB,YAAY,EAAE;YACrB,MAAMP,eAAe,IAAI,CAACD,QAAQ,CAACS,SAAS,CAAC,OAAOC,OAAO,CAAC,oBAAoB;YAChFR,WAAWS,OAAO,CAAC,sBAAsB,GAAG,CAAC,sBAAsB,EAAEV,aAAa,mBAAmB,EAAE,IAAI,CAACD,QAAQ,EAAE;QACxH;QACAH,IAAIc,OAAO,CAACT,WAAWS,OAAO;QAC9Bd,IAAIe,MAAM,CAACV,WAAWW,UAAU;QAChC,4EAA4E;QAC5E,0EAA0E;QAC1E,oGAAoG;QACpG,OAAO,IAAIC,sBAAc,CAACZ,WAAWP,MAAM;IAC7C;IAjDA,YACE,AAAiBR,QAAgB,EACjC,AAAiBqB,eAAe,IAAI,EACpC,AAAiBP,eAAe,EAAE,EAClC,AAAiBI,cAA2B;QAC1CU,cAAc;QACdC,MAAM;QACNC,UAAU;QACVC,cAAc;QACdC,cAAc;QACdC,QAAQ;QACRC,OAAO;QACPC,eAAeC,8BAAuB;IACxC,CAAC,CACD;aAbiBpC,WAAAA;aACAqB,eAAAA;aACAP,eAAAA;aACAI,cAAAA;IAUhB;AAoCL"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/utils/send-file.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 { send, SendOptions, SendResult } from '@fastify/send'\nimport { HttpStatus, StreamableFile } from '@nestjs/common'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport { DEFAULT_HIGH_WATER_MARK } from '../constants/files'\nimport { FileError } from '../models/file-error'\nimport { fileName, isPathExists, isPathIsDir, isPathIsReadable } from './files'\n\nexport function makeContentDispositionAttachment(fileName: string) {\n const downloadName = fileName.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n return `attachment; filename=\"${downloadName}\";filename*=UTF-8''${fileName}`\n}\n\nexport class SendFile {\n private fileName: string\n\n constructor(\n private readonly filePath: string,\n private readonly downloadName = '',\n private readonly sendOptions: SendOptions = {\n acceptRanges: true,\n etag: true,\n dotfiles: 'allow',\n lastModified: true,\n cacheControl: true,\n maxAge: 0,\n index: false,\n highWaterMark: DEFAULT_HIGH_WATER_MARK\n }\n ) {}\n\n async checks() {\n if (!(await isPathExists(this.filePath))) {\n throw new FileError(HttpStatus.NOT_FOUND, 'Location not found')\n }\n if (await isPathIsDir(this.filePath)) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'The location is a directory')\n }\n if (!(await isPathIsReadable(this.filePath))) {\n throw new FileError(HttpStatus.METHOD_NOT_ALLOWED, 'The location is not readable')\n }\n }\n\n async stream(req: FastifyRequest, res: FastifyReply): Promise<StreamableFile> {\n // SendStream manages HEAD (no including body in response) & GET request (with body)\n // Ranges, LastModified, Etag are also handled\n // Send function uses decodeURIComponent, but filePath is already decoded: we need to encode it again before passing it.\n const encodedFilePath = encodeURIComponent(this.filePath)\n this.fileName = encodeURIComponent(this.downloadName ? this.downloadName : fileName(this.filePath))\n const sendResult: SendResult = await send(req.raw, encodedFilePath, this.sendOptions)\n // Check if the path was correctly validated\n if (sendResult.metadata['path'] === undefined) {\n throw new FileError(HttpStatus.BAD_REQUEST, 'Location not found')\n }\n // Force file to be downloaded as an attachment\n sendResult.headers['content-disposition'] = makeContentDispositionAttachment(this.fileName)\n res.headers(sendResult.headers)\n res.status(sendResult.statusCode)\n // sendStream.once('stream', () => console.log(`Sending: ${this.fileName}`))\n // sendStream.once('end', () => console.log(`Received: ${this.fileName}`))\n // sendStream.once('error', (e: Error) => console.error(`Transfer error : ${this.fileName} - ${e}`))\n return new StreamableFile(sendResult.stream)\n }\n}\n"],"names":["SendFile","makeContentDispositionAttachment","fileName","downloadName","normalize","replace","checks","isPathExists","filePath","FileError","HttpStatus","NOT_FOUND","isPathIsDir","BAD_REQUEST","isPathIsReadable","METHOD_NOT_ALLOWED","stream","req","res","encodedFilePath","encodeURIComponent","sendResult","send","raw","sendOptions","metadata","undefined","headers","status","statusCode","StreamableFile","acceptRanges","etag","dotfiles","lastModified","cacheControl","maxAge","index","highWaterMark","DEFAULT_HIGH_WATER_MARK"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAcYA;eAAAA;;QALGC;eAAAA;;;sBAP8B;wBACH;uBAEH;2BACd;wBAC4C;AAE/D,SAASA,iCAAiCC,QAAgB;IAC/D,MAAMC,eAAeD,SAASE,SAAS,CAAC,OAAOC,OAAO,CAAC,oBAAoB;IAC3E,OAAO,CAAC,sBAAsB,EAAEF,aAAa,mBAAmB,EAAED,UAAU;AAC9E;AAEO,IAAA,AAAMF,WAAN,MAAMA;IAkBX,MAAMM,SAAS;QACb,IAAI,CAAE,MAAMC,IAAAA,oBAAY,EAAC,IAAI,CAACC,QAAQ,GAAI;YACxC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACC,SAAS,EAAE;QAC5C;QACA,IAAI,MAAMC,IAAAA,mBAAW,EAAC,IAAI,CAACJ,QAAQ,GAAG;YACpC,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,IAAI,CAAE,MAAMC,IAAAA,wBAAgB,EAAC,IAAI,CAACN,QAAQ,GAAI;YAC5C,MAAM,IAAIC,oBAAS,CAACC,kBAAU,CAACK,kBAAkB,EAAE;QACrD;IACF;IAEA,MAAMC,OAAOC,GAAmB,EAAEC,GAAiB,EAA2B;QAC5E,oFAAoF;QACpF,8CAA8C;QAC9C,wHAAwH;QACxH,MAAMC,kBAAkBC,mBAAmB,IAAI,CAACZ,QAAQ;QACxD,IAAI,CAACN,QAAQ,GAAGkB,mBAAmB,IAAI,CAACjB,YAAY,GAAG,IAAI,CAACA,YAAY,GAAGD,IAAAA,gBAAQ,EAAC,IAAI,CAACM,QAAQ;QACjG,MAAMa,aAAyB,MAAMC,IAAAA,UAAI,EAACL,IAAIM,GAAG,EAAEJ,iBAAiB,IAAI,CAACK,WAAW;QACpF,4CAA4C;QAC5C,IAAIH,WAAWI,QAAQ,CAAC,OAAO,KAAKC,WAAW;YAC7C,MAAM,IAAIjB,oBAAS,CAACC,kBAAU,CAACG,WAAW,EAAE;QAC9C;QACA,+CAA+C;QAC/CQ,WAAWM,OAAO,CAAC,sBAAsB,GAAG1B,iCAAiC,IAAI,CAACC,QAAQ;QAC1FgB,IAAIS,OAAO,CAACN,WAAWM,OAAO;QAC9BT,IAAIU,MAAM,CAACP,WAAWQ,UAAU;QAChC,4EAA4E;QAC5E,0EAA0E;QAC1E,oGAAoG;QACpG,OAAO,IAAIC,sBAAc,CAACT,WAAWL,MAAM;IAC7C;IA9CA,YACE,AAAiBR,QAAgB,EACjC,AAAiBL,eAAe,EAAE,EAClC,AAAiBqB,cAA2B;QAC1CO,cAAc;QACdC,MAAM;QACNC,UAAU;QACVC,cAAc;QACdC,cAAc;QACdC,QAAQ;QACRC,OAAO;QACPC,eAAeC,8BAAuB;IACxC,CAAC,CACD;aAZiB/B,WAAAA;aACAL,eAAAA;aACAqB,cAAAA;IAUhB;AAkCL"}
@@ -1,8 +1,4 @@
1
- /*
2
- * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
3
- * This file is part of Sync-in | The open source file sync and share solution
4
- * See the LICENSE file for licensing details
5
- */ "use strict";
1
+ "use strict";
6
2
  Object.defineProperty(exports, "__esModule", {
7
3
  value: true
8
4
  });
@@ -12,7 +8,11 @@ Object.defineProperty(exports, "regExpPrivateIP", {
12
8
  return regExpPrivateIP;
13
9
  }
14
10
  });
15
- const parts = [
11
+ /*
12
+ * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>
13
+ * This file is part of Sync-in | The open source file sync and share solution
14
+ * See the LICENSE file for licensing details
15
+ */ const parts = [
16
16
  // IPv4 loopback (127.0.0.0/8)
17
17
  '127\\.(?:\\d{1,3}\\.){2}\\d{1,3}',
18
18
  // IPv4 link-local (169.254.0.0/16)