@sync-in/server 1.3.9 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +3 -2
  3. package/environment/environment.dist.yaml +2 -0
  4. package/package.json +2 -2
  5. package/server/app.bootstrap.js +9 -0
  6. package/server/app.bootstrap.js.map +1 -1
  7. package/server/app.service.spec.js +44 -19
  8. package/server/app.service.spec.js.map +1 -1
  9. package/server/applications/files/constants/files.js +0 -23
  10. package/server/applications/files/constants/files.js.map +1 -1
  11. package/server/applications/files/constants/only-office.js +8 -0
  12. package/server/applications/files/constants/only-office.js.map +1 -1
  13. package/server/applications/files/files.config.js +5 -0
  14. package/server/applications/files/files.config.js.map +1 -1
  15. package/server/applications/files/guards/files-only-office.strategy.js +0 -1
  16. package/server/applications/files/guards/files-only-office.strategy.js.map +1 -1
  17. package/server/applications/spaces/guards/space.guard.spec.js +153 -18
  18. package/server/applications/spaces/guards/space.guard.spec.js.map +1 -1
  19. package/server/applications/spaces/services/spaces-browser.service.js +7 -7
  20. package/server/applications/spaces/services/spaces-browser.service.js.map +1 -1
  21. package/server/applications/spaces/services/spaces-manager.service.js +17 -17
  22. package/server/applications/spaces/services/spaces-manager.service.js.map +1 -1
  23. package/server/applications/sync/utils/routes.js +1 -1
  24. package/server/applications/sync/utils/routes.js.map +1 -1
  25. package/server/applications/users/guards/permissions.guard.js +4 -4
  26. package/server/applications/users/guards/permissions.guard.js.map +1 -1
  27. package/server/applications/users/guards/permissions.guard.spec.js +6 -6
  28. package/server/applications/users/guards/permissions.guard.spec.js.map +1 -1
  29. package/server/applications/users/guards/roles.guard.js +1 -1
  30. package/server/applications/users/guards/roles.guard.js.map +1 -1
  31. package/server/applications/users/models/user.model.js +1 -1
  32. package/server/applications/users/models/user.model.js.map +1 -1
  33. package/server/authentication/guards/auth-basic.guard.spec.js +38 -2
  34. package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
  35. package/server/authentication/guards/auth-basic.strategy.js +0 -1
  36. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  37. package/server/authentication/guards/auth-local.guard.spec.js +7 -5
  38. package/server/authentication/guards/auth-local.guard.spec.js.map +1 -1
  39. package/server/authentication/guards/auth-local.strategy.js +0 -1
  40. package/server/authentication/guards/auth-local.strategy.js.map +1 -1
  41. package/server/authentication/guards/auth-token-access.guard.spec.js +30 -0
  42. package/server/authentication/guards/auth-token-access.guard.spec.js.map +1 -1
  43. package/server/authentication/guards/auth-token-access.strategy.js +0 -1
  44. package/server/authentication/guards/auth-token-access.strategy.js.map +1 -1
  45. package/server/authentication/guards/auth-token-refresh.strategy.js +0 -1
  46. package/server/authentication/guards/auth-token-refresh.strategy.js.map +1 -1
  47. package/server/authentication/services/auth-methods/auth-method-database.service.js +1 -1
  48. package/server/authentication/services/auth-methods/auth-method-database.service.js.map +1 -1
  49. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js +8 -6
  50. package/server/authentication/services/auth-methods/auth-method-database.service.spec.js.map +1 -1
  51. package/server/authentication/services/auth-methods/auth-method-ldap.service.js +2 -2
  52. package/server/authentication/services/auth-methods/auth-method-ldap.service.js.map +1 -1
  53. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js +500 -5
  54. package/server/authentication/services/auth-methods/auth-method-ldap.service.spec.js.map +1 -1
  55. package/server/configuration/config.loader.js +0 -3
  56. package/server/configuration/config.loader.js.map +1 -1
  57. package/server/infrastructure/context/services/context-manager.service.spec.js +98 -0
  58. package/server/infrastructure/context/services/context-manager.service.spec.js.map +1 -0
  59. package/server/infrastructure/database/constants.js +0 -1
  60. package/server/infrastructure/database/constants.js.map +1 -1
  61. package/server/infrastructure/database/scripts/seed/usersgroups.js +3 -3
  62. package/server/infrastructure/database/scripts/seed/usersgroups.js.map +1 -1
  63. package/server/infrastructure/mailer/mailer.service.js +20 -19
  64. package/server/infrastructure/mailer/mailer.service.js.map +1 -1
  65. package/server/infrastructure/mailer/mailer.service.spec.js +176 -0
  66. package/server/infrastructure/mailer/mailer.service.spec.js.map +1 -0
  67. package/static/{chunk-KFM544CA.js → chunk-3GC2BQZD.js} +1 -1
  68. package/static/{chunk-MWFRZBJD.js → chunk-5YKWZT33.js} +1 -1
  69. package/static/{chunk-XUZSYWRF.js → chunk-6F55D74O.js} +1 -1
  70. package/static/{chunk-ZFKCGL6X.js → chunk-B2Y2RNFP.js} +1 -1
  71. package/static/{chunk-PYSFXLMV.js → chunk-C23BPTJZ.js} +1 -1
  72. package/static/{chunk-FJFNDK67.js → chunk-DGVNNICG.js} +1 -1
  73. package/static/{chunk-SRLMFJ7C.js → chunk-FQ4AFNGE.js} +1 -1
  74. package/static/{chunk-Z5X7LVMZ.js → chunk-GBCYYDCI.js} +1 -1
  75. package/static/{chunk-MK7WZG3F.js → chunk-HZA7R43P.js} +1 -1
  76. package/static/{chunk-HUWQHCUX.js → chunk-KZQCFEPT.js} +1 -1
  77. package/static/{chunk-S5WXHO6D.js → chunk-LJIGRUEF.js} +1 -1
  78. package/static/{chunk-4KESSWTF.js → chunk-MOVWEZ7J.js} +1 -1
  79. package/static/{chunk-LYTD6AJE.js → chunk-N2LYWNTC.js} +1 -1
  80. package/static/{chunk-NV2MEIWP.js → chunk-PF4K7MVG.js} +1 -1
  81. package/static/{chunk-SKDQM65G.js → chunk-PY3BGNJN.js} +1 -1
  82. package/static/{chunk-QTW62OKJ.js → chunk-T55FAU2O.js} +1 -1
  83. package/static/{chunk-N3T57OCA.js → chunk-TCFKH6K6.js} +1 -1
  84. package/static/{chunk-3FX6ISDY.js → chunk-TDQAEVZN.js} +1 -1
  85. package/static/{chunk-O4AQBQBF.js → chunk-TNW2CGK6.js} +1 -1
  86. package/static/{chunk-3S4WNZ2T.js → chunk-TXPODW5Q.js} +1 -1
  87. package/static/{chunk-BW5PQAKK.js → chunk-VHYIXL7R.js} +1 -1
  88. package/static/{chunk-CLSVDV7J.js → chunk-VMQMD36Z.js} +1 -1
  89. package/static/{chunk-O67RFAWU.js → chunk-VMUOUCEI.js} +1 -1
  90. package/static/{chunk-WLPYIJFI.js → chunk-W3QXNDI5.js} +1 -1
  91. package/static/{chunk-AY2GOSJ2.js → chunk-WHMS3PJ3.js} +1 -1
  92. package/static/{chunk-4TEHM3AS.js → chunk-WWIC7UW3.js} +1 -1
  93. package/static/{chunk-LB7B5RIV.js → chunk-X43VWRFP.js} +1 -1
  94. package/static/{chunk-WL65GYD5.js → chunk-Y2CDUS4J.js} +2 -2
  95. package/static/{chunk-ZTXJC5IC.js → chunk-YCINY2YI.js} +1 -1
  96. package/static/index.html +2 -2
  97. package/static/{main-RREKR34B.js → main-7LDKYVXO.js} +3 -3
  98. package/static/styles-FYUSO6OJ.css +1 -0
  99. package/static/styles-3DONJ2Z4.css +0 -1
package/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
1
 
2
+ ## [1.4.0](https://github.com/Sync-in/server/compare/v1.3.9...v1.4.0) (2025-08-26)
3
+
4
+
5
+ ### Features
6
+
7
+ * **backend:webdav:** add temporary hook for Joplin sync compatibility (laurent22/joplin[#12249](https://github.com/Sync-in/server/issues/12249)) ([fc22a7d](https://github.com/Sync-in/server/commit/fc22a7d828f99abe65423d03418fe397ab45d7b0))
8
+ * **backend:files:** add showHiddenFiles option to toggle visibility of dotfiles ([ed47fbf](https://github.com/Sync-in/server/commit/ed47fbf3fe7fe5b66868489c319d3c438fde0dbf))
9
+ * **backend:files:** allow markdown files to be edited with onlyOffice ([c3d9d85](https://github.com/Sync-in/server/commit/c3d9d85d3f1dc90f4afae8db8ce9d128c8ecadf2))
10
+ * **frontend:spaces:** open documents in edit mode on double-click ([d6ef175](https://github.com/Sync-in/server/commit/d6ef175d951b4e11ce78d280e4982e3ed8a4bb3f))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **backend:users:** ensure permission guards correctly evaluate array permissions ([c27dc7b](https://github.com/Sync-in/server/commit/c27dc7b7ac20293febca17d18ae8608d61eb1b44))
16
+
2
17
  ## [1.3.9](https://github.com/Sync-in/server/compare/v1.3.8...v1.3.9) (2025-08-22)
3
18
 
4
19
 
package/README.md CHANGED
@@ -14,9 +14,10 @@ _Welcome to the official Sync-in server repository!_
14
14
  - 📦 [Deploy with NPM](https://sync-in.com/docs/setup-guide/npm)
15
15
 
16
16
  <a href="#-license"><img src="https://img.shields.io/badge/Licence-AGPL%20v3.0-green.svg" alt="License"/></a>
17
- <a href="https://discord.gg/qhJyzwaymT" target="_blank"><img src="https://img.shields.io/discord/1391081837849346088?logo=discord&label=Discord" alt="Discord"/></a>
18
- <a href="https://www.npmjs.com/package/@sync-in/server" target="_blank"><img src="https://img.shields.io/npm/d18m/@sync-in/server.svg?logo=npm&label=NPM%20Downloads&color=cb3837" alt="NPM"/></a>
17
+ <a href="https://github.com/Sync-in/server/releases" target="_blank"><img src="https://img.shields.io/github/v/release/Sync-in/server?sort=semver&display_name=tag&style=flat&logo=github&label=Release" alt="GitHub Release"/></a>
19
18
  <a href="https://hub.docker.com/r/syncin/server" target="_blank"><img src="https://img.shields.io/docker/pulls/syncin/server?logo=docker&label=Docker%20Hub%20Pulls" alt="Docker pulls"/></a>
19
+ <a href="https://www.npmjs.com/package/@sync-in/server" target="_blank"><img src="https://img.shields.io/npm/d18m/@sync-in/server.svg?logo=npm&label=NPM%20Downloads&color=cb3837" alt="NPM"/></a>
20
+ <a href="https://discord.gg/qhJyzwaymT" target="_blank"><img src="https://img.shields.io/discord/1391081837849346088?logo=discord&label=Discord" alt="Discord"/></a>
20
21
 
21
22
  The **Sync-in Server** is designed to run on your own infrastructure, it gives you **full control over your data** while offering a modern,
22
23
  intuitive interface for both internal and external users.
@@ -81,6 +81,8 @@ applications:
81
81
  dataPath: /home/sync-in
82
82
  # Default to 5 GB if not specified
83
83
  maxUploadSize: 5368709120
84
+ # Show files starting with a dot in the file explorer (default: false)
85
+ showHiddenFiles: false
84
86
  onlyoffice:
85
87
  enabled: false
86
88
  # for an external server (e.g: https://onlyoffice.domain.com), remember the url must be accessible from browser !
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sync-in/server",
3
- "version": "1.3.9",
3
+ "version": "1.4.0",
4
4
  "description": "The secure, open-source platform for file storage, sharing, collaboration, and sync",
5
5
  "author": {
6
6
  "name": "Johan Legrand",
@@ -98,7 +98,7 @@
98
98
  "class-validator": "0.14.2",
99
99
  "deepmerge": "4.3.1",
100
100
  "drizzle-kit": "0.31.4",
101
- "drizzle-orm": "0.44.4",
101
+ "drizzle-orm": "0.44.5",
102
102
  "fast-xml-parser": "5.2.5",
103
103
  "fs-extra": "11.3.1",
104
104
  "html-to-text": "9.0.5",
@@ -22,6 +22,7 @@ const _nestjspino = require("nestjs-pino");
22
22
  const _appconstants = require("./app.constants");
23
23
  const _appmodule = require("./app.module");
24
24
  const _applicationsconstants = require("./applications/applications.constants");
25
+ const _routes = require("./applications/webdav/constants/routes");
25
26
  const _configconstants = require("./configuration/config.constants");
26
27
  const _configenvironment = require("./configuration/config.environment");
27
28
  const _websocketadapter = require("./infrastructure/websocket/adapters/web-socket.adapter");
@@ -60,6 +61,14 @@ async function appBootstrap() {
60
61
  fastifyInstance.addContentTypeParser('*', {
61
62
  bodyLimit: 0
62
63
  }, (_req, _payload, done)=>done(null));
64
+ // Joplin clients send incorrect `Content-Type` headers when syncing over WebDAV (issue: https://github.com/laurent22/joplin/issues/122499)
65
+ // This hook intercepts matching requests and sets `application/octet-stream` to ensure compatibility and successful sync.
66
+ // todo: remove it when fixed on Joplin side
67
+ fastifyInstance.addHook('onRequest', async (req, _reply)=>{
68
+ if ((req.headers['user-agent'] || '').indexOf('Joplin') !== -1 && req.originalUrl.startsWith(_routes.WEBDAV_SPACES[_routes.WEBDAV_NS.WEBDAV].route)) {
69
+ req.headers['content-type'] = 'application/octet-stream';
70
+ }
71
+ });
63
72
  /* INTERCEPTORS */ app.useGlobalInterceptors(new _nestjspino.LoggerErrorInterceptor(), new _common.ClassSerializerInterceptor(app.get(_core.Reflector), {
64
73
  excludePrefixes: [
65
74
  '_'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../backend/src/app.bootstrap.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 fastifyCookie from '@fastify/cookie'\nimport fastifyHelmet from '@fastify/helmet'\nimport multipart from '@fastify/multipart'\nimport { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'\nimport { NestFactory, Reflector } from '@nestjs/core'\nimport { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { HTTP_WEBDAV_METHOD } from './applications/applications.constants'\nimport { IS_TEST_ENV, STATIC_PATH } from './configuration/config.constants'\nimport { configuration } from './configuration/config.environment'\nimport { WebSocketAdapter } from './infrastructure/websocket/adapters/web-socket.adapter'\n\nexport async function appBootstrap(): Promise<NestFastifyApplication> {\n /* APP */\n const fastifyAdapter = new FastifyAdapter({\n logger: false,\n trustProxy: configuration.server.trustProxy,\n ignoreTrailingSlash: true,\n maxParamLength: 256,\n bodyLimit: 26214400 /* 25 MB */\n })\n const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter, {\n bufferLogs: true\n })\n\n /* Fastify instance */\n const fastifyInstance = fastifyAdapter.getInstance()\n\n /* LOGGER */\n app.useLogger(IS_TEST_ENV ? ['fatal'] : app.get(Logger))\n\n /* PARSER */\n // xml body parser is used for webdav methods\n app.useBodyParser(['application/xml', 'text/xml'])\n // add webdav methods\n for (const method of Object.values(HTTP_WEBDAV_METHOD)) {\n fastifyInstance.addHttpMethod(method, { hasBody: true })\n }\n // '*' body parser allow binary data as stream (unlimited body size)\n fastifyInstance.addContentTypeParser('*', { bodyLimit: 0 }, (_req: FastifyRequest, _payload: FastifyRequest['raw'], done) => done(null))\n\n /* INTERCEPTORS */\n app.useGlobalInterceptors(\n new LoggerErrorInterceptor(),\n new ClassSerializerInterceptor(app.get(Reflector), {\n excludePrefixes: ['_']\n })\n )\n /* VALIDATION */\n app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))\n\n /* STATIC */\n app.useStaticAssets({ root: STATIC_PATH, prefixAvoidTrailingSlash: true })\n\n /* SECURITY */\n await app.register(fastifyHelmet, { contentSecurityPolicy: CONTENT_SECURITY_POLICY(configuration.applications.files.onlyoffice.externalServer) })\n\n /* COOKIES */\n // we use csrf secret to unsign csrf cookie\n await app.register(fastifyCookie, {\n secret: configuration.auth.token.csrf.secret,\n parseOptions: {\n secure: 'auto',\n sameSite: configuration.auth.sameSite,\n httpOnly: true\n }\n })\n\n /* UPLOAD */\n await app.register(multipart, {\n preservePath: true,\n limits: { parts: Infinity, fileSize: configuration.applications.files.maxUploadSize }\n })\n\n /* WEBSOCKET */\n if (!IS_TEST_ENV) {\n const webSocketAdapter = new WebSocketAdapter(app)\n await webSocketAdapter.initAdapter()\n app.useWebSocketAdapter(webSocketAdapter)\n }\n\n return app\n}\n"],"names":["appBootstrap","fastifyAdapter","FastifyAdapter","logger","trustProxy","configuration","server","ignoreTrailingSlash","maxParamLength","bodyLimit","app","NestFactory","create","AppModule","bufferLogs","fastifyInstance","getInstance","useLogger","IS_TEST_ENV","get","Logger","useBodyParser","method","Object","values","HTTP_WEBDAV_METHOD","addHttpMethod","hasBody","addContentTypeParser","_req","_payload","done","useGlobalInterceptors","LoggerErrorInterceptor","ClassSerializerInterceptor","Reflector","excludePrefixes","useGlobalPipes","ValidationPipe","transform","whitelist","useStaticAssets","root","STATIC_PATH","prefixAvoidTrailingSlash","register","fastifyHelmet","contentSecurityPolicy","CONTENT_SECURITY_POLICY","applications","files","onlyoffice","externalServer","fastifyCookie","secret","auth","token","csrf","parseOptions","secure","sameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"AAAA;;;;CAIC;;;;+BAiBqBA;;;eAAAA;;;+DAfI;+DACA;kEACJ;wBACqC;sBACpB;iCACgB;4BAER;8BACP;2BACd;uCACS;iCACM;mCACX;kCACG;;;;;;AAE1B,eAAeA;IACpB,OAAO,GACP,MAAMC,iBAAiB,IAAIC,+BAAc,CAAC;QACxCC,QAAQ;QACRC,YAAYC,gCAAa,CAACC,MAAM,CAACF,UAAU;QAC3CG,qBAAqB;QACrBC,gBAAgB;QAChBC,WAAW,SAAS,SAAS;IAC/B;IACA,MAAMC,MAA8B,MAAMC,iBAAW,CAACC,MAAM,CAAyBC,oBAAS,EAAEZ,gBAAgB;QAC9Ga,YAAY;IACd;IAEA,oBAAoB,GACpB,MAAMC,kBAAkBd,eAAee,WAAW;IAElD,UAAU,GACVN,IAAIO,SAAS,CAACC,4BAAW,GAAG;QAAC;KAAQ,GAAGR,IAAIS,GAAG,CAACC,kBAAM;IAEtD,UAAU,GACV,6CAA6C;IAC7CV,IAAIW,aAAa,CAAC;QAAC;QAAmB;KAAW;IACjD,qBAAqB;IACrB,KAAK,MAAMC,UAAUC,OAAOC,MAAM,CAACC,yCAAkB,EAAG;QACtDV,gBAAgBW,aAAa,CAACJ,QAAQ;YAAEK,SAAS;QAAK;IACxD;IACA,oEAAoE;IACpEZ,gBAAgBa,oBAAoB,CAAC,KAAK;QAAEnB,WAAW;IAAE,GAAG,CAACoB,MAAsBC,UAAiCC,OAASA,KAAK;IAElI,gBAAgB,GAChBrB,IAAIsB,qBAAqB,CACvB,IAAIC,kCAAsB,IAC1B,IAAIC,kCAA0B,CAACxB,IAAIS,GAAG,CAACgB,eAAS,GAAG;QACjDC,iBAAiB;YAAC;SAAI;IACxB;IAEF,cAAc,GACd1B,IAAI2B,cAAc,CAAC,IAAIC,sBAAc,CAAC;QAAEC,WAAW;QAAMC,WAAW;IAAK;IAEzE,UAAU,GACV9B,IAAI+B,eAAe,CAAC;QAAEC,MAAMC,4BAAW;QAAEC,0BAA0B;IAAK;IAExE,YAAY,GACZ,MAAMlC,IAAImC,QAAQ,CAACC,eAAa,EAAE;QAAEC,uBAAuBC,IAAAA,qCAAuB,EAAC3C,gCAAa,CAAC4C,YAAY,CAACC,KAAK,CAACC,UAAU,CAACC,cAAc;IAAE;IAE/I,WAAW,GACX,2CAA2C;IAC3C,MAAM1C,IAAImC,QAAQ,CAACQ,eAAa,EAAE;QAChCC,QAAQjD,gCAAa,CAACkD,IAAI,CAACC,KAAK,CAACC,IAAI,CAACH,MAAM;QAC5CI,cAAc;YACZC,QAAQ;YACRC,UAAUvD,gCAAa,CAACkD,IAAI,CAACK,QAAQ;YACrCC,UAAU;QACZ;IACF;IAEA,UAAU,GACV,MAAMnD,IAAImC,QAAQ,CAACiB,kBAAS,EAAE;QAC5BC,cAAc;QACdC,QAAQ;YAAEC,OAAOC;YAAUC,UAAU9D,gCAAa,CAAC4C,YAAY,CAACC,KAAK,CAACkB,aAAa;QAAC;IACtF;IAEA,aAAa,GACb,IAAI,CAAClD,4BAAW,EAAE;QAChB,MAAMmD,mBAAmB,IAAIC,kCAAgB,CAAC5D;QAC9C,MAAM2D,iBAAiBE,WAAW;QAClC7D,IAAI8D,mBAAmB,CAACH;IAC1B;IAEA,OAAO3D;AACT"}
1
+ {"version":3,"sources":["../../backend/src/app.bootstrap.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 fastifyCookie from '@fastify/cookie'\nimport fastifyHelmet from '@fastify/helmet'\nimport multipart from '@fastify/multipart'\nimport { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'\nimport { NestFactory, Reflector } from '@nestjs/core'\nimport { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'\nimport { FastifyRequest } from 'fastify'\nimport { Logger, LoggerErrorInterceptor } from 'nestjs-pino'\nimport { CONTENT_SECURITY_POLICY } from './app.constants'\nimport { AppModule } from './app.module'\nimport { HTTP_WEBDAV_METHOD } from './applications/applications.constants'\nimport { WEBDAV_NS, WEBDAV_SPACES } from './applications/webdav/constants/routes'\nimport { IS_TEST_ENV, STATIC_PATH } from './configuration/config.constants'\nimport { configuration } from './configuration/config.environment'\nimport { WebSocketAdapter } from './infrastructure/websocket/adapters/web-socket.adapter'\n\nexport async function appBootstrap(): Promise<NestFastifyApplication> {\n /* APP */\n const fastifyAdapter = new FastifyAdapter({\n logger: false,\n trustProxy: configuration.server.trustProxy,\n ignoreTrailingSlash: true,\n maxParamLength: 256,\n bodyLimit: 26214400 /* 25 MB */\n })\n const app: NestFastifyApplication = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter, {\n bufferLogs: true\n })\n\n /* Fastify instance */\n const fastifyInstance = fastifyAdapter.getInstance()\n\n /* LOGGER */\n app.useLogger(IS_TEST_ENV ? ['fatal'] : app.get(Logger))\n\n /* PARSER */\n // xml body parser is used for webdav methods\n app.useBodyParser(['application/xml', 'text/xml'])\n // add webdav methods\n for (const method of Object.values(HTTP_WEBDAV_METHOD)) {\n fastifyInstance.addHttpMethod(method, { hasBody: true })\n }\n // '*' body parser allow binary data as stream (unlimited body size)\n fastifyInstance.addContentTypeParser('*', { bodyLimit: 0 }, (_req: FastifyRequest, _payload: FastifyRequest['raw'], done) => done(null))\n\n // Joplin clients send incorrect `Content-Type` headers when syncing over WebDAV (issue: https://github.com/laurent22/joplin/issues/122499)\n // This hook intercepts matching requests and sets `application/octet-stream` to ensure compatibility and successful sync.\n // todo: remove it when fixed on Joplin side\n fastifyInstance.addHook('onRequest', async (req, _reply) => {\n if ((req.headers['user-agent'] || '').indexOf('Joplin') !== -1 && req.originalUrl.startsWith(WEBDAV_SPACES[WEBDAV_NS.WEBDAV].route)) {\n req.headers['content-type'] = 'application/octet-stream'\n }\n })\n\n /* INTERCEPTORS */\n app.useGlobalInterceptors(\n new LoggerErrorInterceptor(),\n new ClassSerializerInterceptor(app.get(Reflector), {\n excludePrefixes: ['_']\n })\n )\n /* VALIDATION */\n app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))\n\n /* STATIC */\n app.useStaticAssets({ root: STATIC_PATH, prefixAvoidTrailingSlash: true })\n\n /* SECURITY */\n await app.register(fastifyHelmet, { contentSecurityPolicy: CONTENT_SECURITY_POLICY(configuration.applications.files.onlyoffice.externalServer) })\n\n /* COOKIES */\n // we use csrf secret to unsign csrf cookie\n await app.register(fastifyCookie, {\n secret: configuration.auth.token.csrf.secret,\n parseOptions: {\n secure: 'auto',\n sameSite: configuration.auth.sameSite,\n httpOnly: true\n }\n })\n\n /* UPLOAD */\n await app.register(multipart, {\n preservePath: true,\n limits: { parts: Infinity, fileSize: configuration.applications.files.maxUploadSize }\n })\n\n /* WEBSOCKET */\n if (!IS_TEST_ENV) {\n const webSocketAdapter = new WebSocketAdapter(app)\n await webSocketAdapter.initAdapter()\n app.useWebSocketAdapter(webSocketAdapter)\n }\n\n return app\n}\n"],"names":["appBootstrap","fastifyAdapter","FastifyAdapter","logger","trustProxy","configuration","server","ignoreTrailingSlash","maxParamLength","bodyLimit","app","NestFactory","create","AppModule","bufferLogs","fastifyInstance","getInstance","useLogger","IS_TEST_ENV","get","Logger","useBodyParser","method","Object","values","HTTP_WEBDAV_METHOD","addHttpMethod","hasBody","addContentTypeParser","_req","_payload","done","addHook","req","_reply","headers","indexOf","originalUrl","startsWith","WEBDAV_SPACES","WEBDAV_NS","WEBDAV","route","useGlobalInterceptors","LoggerErrorInterceptor","ClassSerializerInterceptor","Reflector","excludePrefixes","useGlobalPipes","ValidationPipe","transform","whitelist","useStaticAssets","root","STATIC_PATH","prefixAvoidTrailingSlash","register","fastifyHelmet","contentSecurityPolicy","CONTENT_SECURITY_POLICY","applications","files","onlyoffice","externalServer","fastifyCookie","secret","auth","token","csrf","parseOptions","secure","sameSite","httpOnly","multipart","preservePath","limits","parts","Infinity","fileSize","maxUploadSize","webSocketAdapter","WebSocketAdapter","initAdapter","useWebSocketAdapter"],"mappings":"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"}
@@ -15,11 +15,15 @@ const _nodeprocess = /*#__PURE__*/ _interop_require_default(require("node:proces
15
15
  const _appservice = require("./app.service");
16
16
  const _configconstants = require("./configuration/config.constants");
17
17
  const _configenvironment = require("./configuration/config.environment");
18
+ const _clusteradapter = require("@socket.io/cluster-adapter");
18
19
  function _interop_require_default(obj) {
19
20
  return obj && obj.__esModule ? obj : {
20
21
  default: obj
21
22
  };
22
23
  }
24
+ jest.mock('@socket.io/cluster-adapter', ()=>({
25
+ setupPrimary: jest.fn()
26
+ }));
23
27
  describe(_appservice.AppService.name, ()=>{
24
28
  let appService;
25
29
  beforeAll(async ()=>{
@@ -32,36 +36,59 @@ describe(_appservice.AppService.name, ()=>{
32
36
  expect(appService).toBeDefined();
33
37
  });
34
38
  it('should clusterize', ()=>{
39
+ // --- MASTER, adapter='cluster' -> covers setupPrimary()
40
+ _configenvironment.configuration.websocket.adapter = 'cluster';
35
41
  _configenvironment.configuration.server.restartOnFailure = true;
36
- const callBack = jest.fn().mockReturnValue({
42
+ const bootstrap = jest.fn();
43
+ // IMPORTANT: do NOT call bootstrap() from fork mock
44
+ const fakeWorker = {
37
45
  process: {
38
46
  pid: 1
39
47
  }
40
- });
41
- _nodecluster.default.fork = jest.fn(()=>callBack());
48
+ };
49
+ _nodecluster.default.fork = jest.fn(()=>fakeWorker);
42
50
  const spyExit = jest.spyOn(_nodecluster.default, 'on');
43
- expect(()=>_appservice.AppService.clusterize(callBack)).not.toThrow();
44
- expect(callBack).toHaveBeenCalledTimes(_configenvironment.configuration.server.workers);
45
- expect(_nodecluster.default.fork).toHaveBeenCalledTimes(_configenvironment.configuration.server.workers);
46
- callBack.mockClear();
51
+ // 1) master path (cluster.isPrimary true by default)
52
+ expect(()=>_appservice.AppService.clusterize(bootstrap)).not.toThrow();
53
+ // setupPrimary() must have run once (covers the “line 21” site)
54
+ expect(_clusteradapter.setupPrimary).toHaveBeenCalledTimes(1);
55
+ // fork called exactly workers times
56
+ expect(_nodecluster.default.fork.mock.calls.length).toBe(_configenvironment.configuration.server.workers);
57
+ // --- Test exit handler with ONLY ONE registered handler
58
+ // TRUE branch: restart twice -> fork called +2
59
+ const forkCallsAfterMaster = _nodecluster.default.fork.mock.calls.length;
47
60
  _appservice.AppService.schedulerPID = 1;
48
61
  _nodecluster.default.emit('exit', {
49
62
  process: {
50
63
  pid: 1
51
64
  }
52
- }, 1, 1);
65
+ }, 1, 'SIGKILL');
53
66
  _appservice.AppService.schedulerPID = 0;
54
67
  _nodecluster.default.emit('exit', {
55
68
  process: {
56
- pid: 1
69
+ pid: 2
70
+ }
71
+ }, 1, 'SIGKILL');
72
+ expect(_nodecluster.default.fork.mock.calls.length).toBe(forkCallsAfterMaster + 2);
73
+ // FALSE branch: no restart -> fork unchanged
74
+ _configenvironment.configuration.server.restartOnFailure = false;
75
+ const forkCallsAfterTrue = _nodecluster.default.fork.mock.calls.length;
76
+ _nodecluster.default.emit('exit', {
77
+ process: {
78
+ pid: 3
57
79
  }
58
- }, 1, 1);
59
- expect(spyExit).toHaveBeenCalled();
60
- expect(callBack).toHaveBeenCalledTimes(2);
80
+ }, 1, 'SIGKILL');
81
+ expect(_nodecluster.default.fork.mock.calls.length).toBe(forkCallsAfterTrue);
82
+ // --- MASTER again, adapter != 'cluster' -> covers the FALSE side of the adapter check
83
+ _configenvironment.configuration.websocket.adapter = null;
84
+ expect(()=>_appservice.AppService.clusterize(bootstrap)).not.toThrow();
85
+ // setupPrimary should NOT be called again
86
+ expect(_clusteradapter.setupPrimary).toHaveBeenCalledTimes(1);
87
+ // --- WORKER path (else branch): bootstrap should be called exactly once here
61
88
  jest.replaceProperty(_nodecluster.default, 'isPrimary', false);
62
- callBack.mockClear();
63
- expect(()=>_appservice.AppService.clusterize(callBack)).not.toThrow();
64
- expect(callBack).toHaveBeenCalledTimes(1);
89
+ bootstrap.mockClear(); // isolate bootstrap count for a worker branch
90
+ expect(()=>_appservice.AppService.clusterize(bootstrap)).not.toThrow();
91
+ expect(bootstrap).toHaveBeenCalledTimes(1);
65
92
  spyExit.mockClear();
66
93
  });
67
94
  it(`should use ${_configconstants.ENVIRONMENT_PREFIX} environment variables to override the configuration`, ()=>{
@@ -82,12 +109,10 @@ describe(_appservice.AppService.name, ()=>{
82
109
  expect(conf.logger.colorize).toBe(false);
83
110
  expect(conf.applications.files.maxUploadSize).toBe(8888);
84
111
  expect(conf.auth.token.access.secret).toBe('fooBAR8888');
85
- // cleanup secret file
112
+ // clean up secret file
86
113
  _nodefs.default.promises.rm(tmpSecretFile, {
87
114
  force: true
88
- }).catch((e)=>{
89
- console.error(e);
90
- });
115
+ }).catch(console.error);
91
116
  });
92
117
  });
93
118
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../backend/src/app.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Logger } from '@nestjs/common'\nimport cluster from 'node:cluster'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { AppService } from './app.service'\nimport { ENVIRONMENT_PREFIX } from './configuration/config.constants'\nimport { configuration, exportConfiguration } from './configuration/config.environment'\n\ndescribe(AppService.name, () => {\n let appService: AppService\n\n beforeAll(async () => {\n appService = new AppService()\n Logger.overrideLogger(['fatal'])\n })\n\n it('should be defined', () => {\n expect(appService).toBeDefined()\n })\n\n it('should clusterize', () => {\n configuration.server.restartOnFailure = true\n const callBack = jest.fn().mockReturnValue({ process: { pid: 1 } })\n cluster.fork = jest.fn(() => callBack())\n const spyExit = jest.spyOn(cluster, 'on')\n expect(() => AppService.clusterize(callBack)).not.toThrow()\n expect(callBack).toHaveBeenCalledTimes(configuration.server.workers)\n expect(cluster.fork).toHaveBeenCalledTimes(configuration.server.workers)\n callBack.mockClear()\n AppService.schedulerPID = 1\n cluster.emit('exit', { process: { pid: 1 } }, 1, 1)\n AppService.schedulerPID = 0\n cluster.emit('exit', { process: { pid: 1 } }, 1, 1)\n expect(spyExit).toHaveBeenCalled()\n expect(callBack).toHaveBeenCalledTimes(2)\n jest.replaceProperty(cluster, 'isPrimary', false)\n callBack.mockClear()\n expect(() => AppService.clusterize(callBack)).not.toThrow()\n expect(callBack).toHaveBeenCalledTimes(1)\n spyExit.mockClear()\n })\n\n it(`should use ${ENVIRONMENT_PREFIX} environment variables to override the configuration`, () => {\n let conf = exportConfiguration()\n expect(conf.logger.stdout).toBe(true)\n expect(conf.logger.colorize).toBe(true)\n const tmpSecretFile = path.join(os.tmpdir(), 'secret')\n fs.writeFileSync(tmpSecretFile, 'fooBAR8888')\n process.env[`${ENVIRONMENT_PREFIX}APPLICATIONS_FILES_ONLYOFFICE_SECRET`] = 'fooBAR'\n process.env[`${ENVIRONMENT_PREFIX}LOGGER_STDOUT`] = 'false'\n process.env[`${ENVIRONMENT_PREFIX}LOGGER_COLORIZE`] = '\"false\"'\n process.env[`${ENVIRONMENT_PREFIX}APPLICATIONS_FILES_MAXUPLOADSIZE`] = '8888'\n // docker compose secret file\n process.env[`${ENVIRONMENT_PREFIX}AUTH_TOKEN_ACCESS_SECRET_FILE`] = tmpSecretFile\n conf = exportConfiguration(true)\n expect(conf.applications.files.onlyoffice.secret).toBe('fooBAR')\n expect(conf.logger.stdout).toBe(false)\n expect(conf.logger.colorize).toBe(false)\n expect(conf.applications.files.maxUploadSize).toBe(8888)\n expect(conf.auth.token.access.secret).toBe('fooBAR8888')\n // cleanup secret file\n fs.promises.rm(tmpSecretFile, { force: true }).catch((e) => {\n console.error(e)\n })\n })\n})\n"],"names":["describe","AppService","name","appService","beforeAll","Logger","overrideLogger","it","expect","toBeDefined","configuration","server","restartOnFailure","callBack","jest","fn","mockReturnValue","process","pid","cluster","fork","spyExit","spyOn","clusterize","not","toThrow","toHaveBeenCalledTimes","workers","mockClear","schedulerPID","emit","toHaveBeenCalled","replaceProperty","ENVIRONMENT_PREFIX","conf","exportConfiguration","logger","stdout","toBe","colorize","tmpSecretFile","path","join","os","tmpdir","fs","writeFileSync","env","applications","files","onlyoffice","secret","maxUploadSize","auth","token","access","promises","rm","force","catch","e","console","error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../backend/src/app.service.spec.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Logger } from '@nestjs/common'\nimport cluster from 'node:cluster'\nimport fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { AppService } from './app.service'\nimport { ENVIRONMENT_PREFIX } from './configuration/config.constants'\nimport { configuration, exportConfiguration } from './configuration/config.environment'\njest.mock('@socket.io/cluster-adapter', () => ({\n setupPrimary: jest.fn()\n}))\nimport { setupPrimary } from '@socket.io/cluster-adapter'\n\ndescribe(AppService.name, () => {\n let appService: AppService\n\n beforeAll(async () => {\n appService = new AppService()\n Logger.overrideLogger(['fatal'])\n })\n\n it('should be defined', () => {\n expect(appService).toBeDefined()\n })\n\n it('should clusterize', () => {\n // --- MASTER, adapter='cluster' -> covers setupPrimary()\n configuration.websocket.adapter = 'cluster'\n configuration.server.restartOnFailure = true\n\n const bootstrap = jest.fn()\n\n // IMPORTANT: do NOT call bootstrap() from fork mock\n const fakeWorker = { process: { pid: 1 } } as any\n cluster.fork = jest.fn(() => fakeWorker)\n\n const spyExit = jest.spyOn(cluster, 'on')\n\n // 1) master path (cluster.isPrimary true by default)\n expect(() => AppService.clusterize(bootstrap)).not.toThrow()\n\n // setupPrimary() must have run once (covers the “line 21” site)\n expect(setupPrimary).toHaveBeenCalledTimes(1)\n\n // fork called exactly workers times\n expect((cluster.fork as jest.Mock).mock.calls.length).toBe(configuration.server.workers)\n\n // --- Test exit handler with ONLY ONE registered handler\n // TRUE branch: restart twice -> fork called +2\n const forkCallsAfterMaster = (cluster.fork as jest.Mock).mock.calls.length\n AppService.schedulerPID = 1\n cluster.emit('exit', { process: { pid: 1 } } as any, 1 as any, 'SIGKILL' as any)\n AppService.schedulerPID = 0\n cluster.emit('exit', { process: { pid: 2 } } as any, 1 as any, 'SIGKILL' as any)\n expect((cluster.fork as jest.Mock).mock.calls.length).toBe(forkCallsAfterMaster + 2)\n\n // FALSE branch: no restart -> fork unchanged\n configuration.server.restartOnFailure = false\n const forkCallsAfterTrue = (cluster.fork as jest.Mock).mock.calls.length\n cluster.emit('exit', { process: { pid: 3 } } as any, 1 as any, 'SIGKILL' as any)\n expect((cluster.fork as jest.Mock).mock.calls.length).toBe(forkCallsAfterTrue)\n\n // --- MASTER again, adapter != 'cluster' -> covers the FALSE side of the adapter check\n configuration.websocket.adapter = null\n expect(() => AppService.clusterize(bootstrap)).not.toThrow()\n // setupPrimary should NOT be called again\n expect(setupPrimary).toHaveBeenCalledTimes(1)\n\n // --- WORKER path (else branch): bootstrap should be called exactly once here\n jest.replaceProperty(cluster, 'isPrimary', false)\n bootstrap.mockClear() // isolate bootstrap count for a worker branch\n expect(() => AppService.clusterize(bootstrap)).not.toThrow()\n expect(bootstrap).toHaveBeenCalledTimes(1)\n\n spyExit.mockClear()\n })\n\n it(`should use ${ENVIRONMENT_PREFIX} environment variables to override the configuration`, () => {\n let conf = exportConfiguration()\n expect(conf.logger.stdout).toBe(true)\n expect(conf.logger.colorize).toBe(true)\n const tmpSecretFile = path.join(os.tmpdir(), 'secret')\n fs.writeFileSync(tmpSecretFile, 'fooBAR8888')\n process.env[`${ENVIRONMENT_PREFIX}APPLICATIONS_FILES_ONLYOFFICE_SECRET`] = 'fooBAR'\n process.env[`${ENVIRONMENT_PREFIX}LOGGER_STDOUT`] = 'false'\n process.env[`${ENVIRONMENT_PREFIX}LOGGER_COLORIZE`] = '\"false\"'\n process.env[`${ENVIRONMENT_PREFIX}APPLICATIONS_FILES_MAXUPLOADSIZE`] = '8888'\n // docker compose secret file\n process.env[`${ENVIRONMENT_PREFIX}AUTH_TOKEN_ACCESS_SECRET_FILE`] = tmpSecretFile\n conf = exportConfiguration(true)\n expect(conf.applications.files.onlyoffice.secret).toBe('fooBAR')\n expect(conf.logger.stdout).toBe(false)\n expect(conf.logger.colorize).toBe(false)\n expect(conf.applications.files.maxUploadSize).toBe(8888)\n expect(conf.auth.token.access.secret).toBe('fooBAR8888')\n // clean up secret file\n fs.promises.rm(tmpSecretFile, { force: true }).catch(console.error)\n })\n})\n"],"names":["jest","mock","setupPrimary","fn","describe","AppService","name","appService","beforeAll","Logger","overrideLogger","it","expect","toBeDefined","configuration","websocket","adapter","server","restartOnFailure","bootstrap","fakeWorker","process","pid","cluster","fork","spyExit","spyOn","clusterize","not","toThrow","toHaveBeenCalledTimes","calls","length","toBe","workers","forkCallsAfterMaster","schedulerPID","emit","forkCallsAfterTrue","replaceProperty","mockClear","ENVIRONMENT_PREFIX","conf","exportConfiguration","logger","stdout","colorize","tmpSecretFile","path","join","os","tmpdir","fs","writeFileSync","env","applications","files","onlyoffice","secret","maxUploadSize","auth","token","access","promises","rm","force","catch","console","error"],"mappings":"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"}
@@ -16,9 +16,6 @@ _export(exports, {
16
16
  get COMPRESSION_EXTENSION () {
17
17
  return COMPRESSION_EXTENSION;
18
18
  },
19
- get DEFAULT_FILTERS () {
20
- return DEFAULT_FILTERS;
21
- },
22
19
  get DEFAULT_HIGH_WATER_MARK () {
23
20
  return DEFAULT_HIGH_WATER_MARK;
24
21
  },
@@ -31,26 +28,6 @@ _export(exports, {
31
28
  });
32
29
  const DEFAULT_HIGH_WATER_MARK = 1024 * 1024;
33
30
  const DEFAULT_MIME_TYPE = 'application/octet-stream';
34
- const DEFAULT_FILTERS = new Set([
35
- '.DS_Store',
36
- '.swp',
37
- '.AppleDouble',
38
- '.AppleDesktop',
39
- 'Thumbs.db',
40
- '.Spotlight-V100',
41
- '.DocumentRevisions-V100',
42
- '.fseventsd',
43
- '.MobileBackups',
44
- 'Icon?',
45
- '__MACOSX',
46
- '.thumbnails',
47
- '.DAV',
48
- '.desktop',
49
- 'desktop.ini',
50
- '.TemporaryItems',
51
- '.localized',
52
- '__pycache__'
53
- ]);
54
31
  const EXTRA_MIMES_TYPE = new Map([
55
32
  [
56
33
  '.ts',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/constants/files.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const DEFAULT_HIGH_WATER_MARK = 1024 * 1024\nexport const DEFAULT_MIME_TYPE = 'application/octet-stream'\nexport const DEFAULT_FILTERS = new Set([\n '.DS_Store',\n '.swp',\n '.AppleDouble',\n '.AppleDesktop',\n 'Thumbs.db',\n '.Spotlight-V100',\n '.DocumentRevisions-V100',\n '.fseventsd',\n '.MobileBackups',\n 'Icon?',\n '__MACOSX',\n '.thumbnails',\n '.DAV',\n '.desktop',\n 'desktop.ini',\n '.TemporaryItems',\n '.localized',\n '__pycache__'\n])\nexport const EXTRA_MIMES_TYPE = new Map([\n ['.ts', 'text-typescript'],\n ['.py', 'text-x-python'],\n ['.tgz', 'application-gzip'],\n ['.gz', 'application-gzip'],\n ['.gzip', 'application-gzip']\n])\nexport const COMPRESSION_EXTENSION = new Map([\n ['.zip', 'zip'],\n ['.gzip', 'gzip'],\n ['.tgz', 'tgz'],\n ['.gz', 'tgz'],\n ['.tar.gz', 'tgz'],\n ['.tar', 'tar']\n])\n"],"names":["COMPRESSION_EXTENSION","DEFAULT_FILTERS","DEFAULT_HIGH_WATER_MARK","DEFAULT_MIME_TYPE","EXTRA_MIMES_TYPE","Set","Map"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QA+BYA;eAAAA;;QA3BAC;eAAAA;;QAFAC;eAAAA;;QACAC;eAAAA;;QAqBAC;eAAAA;;;AAtBN,MAAMF,0BAA0B,OAAO;AACvC,MAAMC,oBAAoB;AAC1B,MAAMF,kBAAkB,IAAII,IAAI;IACrC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AACM,MAAMD,mBAAmB,IAAIE,IAAI;IACtC;QAAC;QAAO;KAAkB;IAC1B;QAAC;QAAO;KAAgB;IACxB;QAAC;QAAQ;KAAmB;IAC5B;QAAC;QAAO;KAAmB;IAC3B;QAAC;QAAS;KAAmB;CAC9B;AACM,MAAMN,wBAAwB,IAAIM,IAAI;IAC3C;QAAC;QAAQ;KAAM;IACf;QAAC;QAAS;KAAO;IACjB;QAAC;QAAQ;KAAM;IACf;QAAC;QAAO;KAAM;IACd;QAAC;QAAW;KAAM;IAClB;QAAC;QAAQ;KAAM;CAChB"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/constants/files.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const DEFAULT_HIGH_WATER_MARK = 1024 * 1024\nexport const DEFAULT_MIME_TYPE = 'application/octet-stream'\nexport const EXTRA_MIMES_TYPE = new Map([\n ['.ts', 'text-typescript'],\n ['.py', 'text-x-python'],\n ['.tgz', 'application-gzip'],\n ['.gz', 'application-gzip'],\n ['.gzip', 'application-gzip']\n])\nexport const COMPRESSION_EXTENSION = new Map([\n ['.zip', 'zip'],\n ['.gzip', 'gzip'],\n ['.tgz', 'tgz'],\n ['.gz', 'tgz'],\n ['.tar.gz', 'tgz'],\n ['.tar', 'tar']\n])\n"],"names":["COMPRESSION_EXTENSION","DEFAULT_HIGH_WATER_MARK","DEFAULT_MIME_TYPE","EXTRA_MIMES_TYPE","Map"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAWYA;eAAAA;;QATAC;eAAAA;;QACAC;eAAAA;;QACAC;eAAAA;;;AAFN,MAAMF,0BAA0B,OAAO;AACvC,MAAMC,oBAAoB;AAC1B,MAAMC,mBAAmB,IAAIC,IAAI;IACtC;QAAC;QAAO;KAAkB;IAC1B;QAAC;QAAO;KAAgB;IACxB;QAAC;QAAQ;KAAmB;IAC5B;QAAC;QAAO;KAAmB;IAC3B;QAAC;QAAS;KAAmB;CAC9B;AACM,MAAMJ,wBAAwB,IAAII,IAAI;IAC3C;QAAC;QAAQ;KAAM;IACf;QAAC;QAAS;KAAO;IACjB;QAAC;QAAQ;KAAM;IACf;QAAC;QAAO;KAAM;IACd;QAAC;QAAW;KAAM;IAClB;QAAC;QAAQ;KAAM;CAChB"}
@@ -147,6 +147,10 @@ const ONLY_OFFICE_EXTENSIONS = {
147
147
  'xml',
148
148
  'word'
149
149
  ],
150
+ [
151
+ 'md',
152
+ 'word'
153
+ ],
150
154
  // CELL
151
155
  [
152
156
  'csv',
@@ -378,6 +382,10 @@ const ONLY_OFFICE_EXTENSIONS = {
378
382
  'txt',
379
383
  'word'
380
384
  ],
385
+ [
386
+ 'md',
387
+ 'word'
388
+ ],
381
389
  // CELL
382
390
  [
383
391
  'xlsb',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/constants/only-office.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const ONLY_OFFICE_INTERNAL_URI = '/onlyoffice' // used by nginx as proxy\nexport const ONLY_OFFICE_CONTEXT = 'OnlyOfficeEnvironment'\nexport const ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME = 'token' as const\n\nexport const ONLY_OFFICE_EXTENSIONS = {\n VIEWABLE: new Map([\n // WORD\n ['doc', 'word'],\n ['docm', 'word'],\n ['docx', 'word'],\n ['dot', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['fodt', 'word'],\n ['gdoc', 'word'],\n ['htm', 'word'],\n ['html', 'word'],\n ['hwp', 'word'],\n ['hwpx', 'word'],\n ['md', 'word'],\n ['mht', 'word'],\n ['mhtml', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['pages', 'word'],\n ['rtf', 'word'],\n ['stw', 'word'],\n ['sxw', 'word'],\n ['txt', 'word'],\n ['wps', 'word'],\n ['wpt', 'word'],\n ['xml', 'word'],\n\n // CELL\n ['csv', 'cell'],\n ['et', 'cell'],\n ['ett', 'cell'],\n ['fods', 'cell'],\n ['gsheet', 'cell'],\n ['numbers', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n ['sxc', 'cell'],\n ['xls', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xlt', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n\n // SLIDE\n ['dps', 'slide'],\n ['dpt', 'slide'],\n ['fodp', 'slide'],\n ['gslide', 'slide'],\n ['key', 'slide'],\n ['odg', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n ['pot', 'slide'],\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['pps', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['ppt', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['sxi', 'slide'],\n\n // PDF\n ['djvu', 'pdf'],\n ['docxf', 'pdf'],\n ['oform', 'pdf'],\n ['oxps', 'pdf'],\n ['pdf', 'pdf'],\n ['xps', 'pdf'],\n\n // DIAGRAM\n ['vsdm', 'diagram'],\n ['vsdx', 'diagram'],\n ['vssm', 'diagram'],\n ['vssx', 'diagram'],\n ['vstm', 'diagram'],\n ['vstx', 'diagram']\n ]),\n\n EDITABLE: new Map([\n // WORD\n ['docm', 'word'],\n ['docx', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['html', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['rtf', 'word'],\n ['txt', 'word'],\n\n // CELL\n ['xlsb', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n ['csv', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n\n // SLIDE\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n\n // PDF\n ['pdf', 'pdf']\n ])\n}\n\nexport const ONLY_OFFICE_CONVERT_EXTENSIONS = {\n ALLOW_AUTO: new Set(['doc', 'xls', 'ppt']),\n FROM: new Set([\n 'doc',\n 'docm',\n 'docx',\n 'docxf',\n 'dotx',\n 'epub',\n 'fb2',\n 'html',\n 'mhtml',\n 'odt',\n 'ott',\n 'pdf',\n 'rtf',\n 'stw',\n 'sxw',\n 'txt',\n 'wps',\n 'wpt',\n 'xps'\n ]),\n TO: new Set(['docx', 'docxf', 'dotx', 'epub', 'fb2', 'html', 'jpg', 'odt', 'ott', 'pdf', 'png', 'rtf', 'txt'])\n}\n\nexport const ONLY_OFFICE_CONVERT_ERROR = new Map([\n [-9, 'error conversion output format'],\n [-8, 'error document VKey'],\n [-7, 'error document request'],\n [-6, 'error database'],\n [-5, 'incorrect password'],\n [-4, 'download error'],\n [-3, 'convert error'],\n [-2, 'convert error timeout'],\n [-1, 'convert unknown']\n])\n"],"names":["ONLY_OFFICE_CONTEXT","ONLY_OFFICE_CONVERT_ERROR","ONLY_OFFICE_CONVERT_EXTENSIONS","ONLY_OFFICE_EXTENSIONS","ONLY_OFFICE_INTERNAL_URI","ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME","VIEWABLE","Map","EDITABLE","ALLOW_AUTO","Set","FROM","TO"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/constants/only-office.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nexport const ONLY_OFFICE_INTERNAL_URI = '/onlyoffice' // used by nginx as proxy\nexport const ONLY_OFFICE_CONTEXT = 'OnlyOfficeEnvironment'\nexport const ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME = 'token' as const\n\nexport const ONLY_OFFICE_EXTENSIONS = {\n VIEWABLE: new Map([\n // WORD\n ['doc', 'word'],\n ['docm', 'word'],\n ['docx', 'word'],\n ['dot', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['fodt', 'word'],\n ['gdoc', 'word'],\n ['htm', 'word'],\n ['html', 'word'],\n ['hwp', 'word'],\n ['hwpx', 'word'],\n ['md', 'word'],\n ['mht', 'word'],\n ['mhtml', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['pages', 'word'],\n ['rtf', 'word'],\n ['stw', 'word'],\n ['sxw', 'word'],\n ['txt', 'word'],\n ['wps', 'word'],\n ['wpt', 'word'],\n ['xml', 'word'],\n ['md', 'word'],\n\n // CELL\n ['csv', 'cell'],\n ['et', 'cell'],\n ['ett', 'cell'],\n ['fods', 'cell'],\n ['gsheet', 'cell'],\n ['numbers', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n ['sxc', 'cell'],\n ['xls', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xlt', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n\n // SLIDE\n ['dps', 'slide'],\n ['dpt', 'slide'],\n ['fodp', 'slide'],\n ['gslide', 'slide'],\n ['key', 'slide'],\n ['odg', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n ['pot', 'slide'],\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['pps', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['ppt', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['sxi', 'slide'],\n\n // PDF\n ['djvu', 'pdf'],\n ['docxf', 'pdf'],\n ['oform', 'pdf'],\n ['oxps', 'pdf'],\n ['pdf', 'pdf'],\n ['xps', 'pdf'],\n\n // DIAGRAM\n ['vsdm', 'diagram'],\n ['vsdx', 'diagram'],\n ['vssm', 'diagram'],\n ['vssx', 'diagram'],\n ['vstm', 'diagram'],\n ['vstx', 'diagram']\n ]),\n\n EDITABLE: new Map([\n // WORD\n ['docm', 'word'],\n ['docx', 'word'],\n ['dotm', 'word'],\n ['dotx', 'word'],\n ['epub', 'word'],\n ['fb2', 'word'],\n ['html', 'word'],\n ['odt', 'word'],\n ['ott', 'word'],\n ['rtf', 'word'],\n ['txt', 'word'],\n ['md', 'word'],\n\n // CELL\n ['xlsb', 'cell'],\n ['xlsm', 'cell'],\n ['xlsx', 'cell'],\n ['xltm', 'cell'],\n ['xltx', 'cell'],\n ['csv', 'cell'],\n ['ods', 'cell'],\n ['ots', 'cell'],\n\n // SLIDE\n ['potm', 'slide'],\n ['potx', 'slide'],\n ['ppsm', 'slide'],\n ['ppsx', 'slide'],\n ['pptm', 'slide'],\n ['pptx', 'slide'],\n ['odp', 'slide'],\n ['otp', 'slide'],\n\n // PDF\n ['pdf', 'pdf']\n ])\n}\n\nexport const ONLY_OFFICE_CONVERT_EXTENSIONS = {\n ALLOW_AUTO: new Set(['doc', 'xls', 'ppt']),\n FROM: new Set([\n 'doc',\n 'docm',\n 'docx',\n 'docxf',\n 'dotx',\n 'epub',\n 'fb2',\n 'html',\n 'mhtml',\n 'odt',\n 'ott',\n 'pdf',\n 'rtf',\n 'stw',\n 'sxw',\n 'txt',\n 'wps',\n 'wpt',\n 'xps'\n ]),\n TO: new Set(['docx', 'docxf', 'dotx', 'epub', 'fb2', 'html', 'jpg', 'odt', 'ott', 'pdf', 'png', 'rtf', 'txt'])\n}\n\nexport const ONLY_OFFICE_CONVERT_ERROR = new Map([\n [-9, 'error conversion output format'],\n [-8, 'error document VKey'],\n [-7, 'error document request'],\n [-6, 'error database'],\n [-5, 'incorrect password'],\n [-4, 'download error'],\n [-3, 'convert error'],\n [-2, 'convert error timeout'],\n [-1, 'convert unknown']\n])\n"],"names":["ONLY_OFFICE_CONTEXT","ONLY_OFFICE_CONVERT_ERROR","ONLY_OFFICE_CONVERT_EXTENSIONS","ONLY_OFFICE_EXTENSIONS","ONLY_OFFICE_INTERNAL_URI","ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME","VIEWABLE","Map","EDITABLE","ALLOW_AUTO","Set","FROM","TO"],"mappings":"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"}
@@ -59,6 +59,7 @@ _ts_decorate([
59
59
  let FilesConfig = class FilesConfig {
60
60
  constructor(){
61
61
  this.maxUploadSize = 5368709120; // 5 GB
62
+ this.showHiddenFiles = false;
62
63
  this.onlyoffice = new FilesOnlyOfficeConfig();
63
64
  }
64
65
  };
@@ -86,6 +87,10 @@ _ts_decorate([
86
87
  (0, _classvalidator.IsInt)(),
87
88
  _ts_metadata("design:type", Number)
88
89
  ], FilesConfig.prototype, "maxUploadSize", void 0);
90
+ _ts_decorate([
91
+ (0, _classvalidator.IsBoolean)(),
92
+ _ts_metadata("design:type", Boolean)
93
+ ], FilesConfig.prototype, "showHiddenFiles", void 0);
89
94
  _ts_decorate([
90
95
  (0, _classvalidator.IsNotEmptyObject)(),
91
96
  (0, _classvalidator.ValidateNested)(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/applications/files/files.config.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Type } from 'class-transformer'\nimport { IsBoolean, IsInt, IsNotEmpty, IsNotEmptyObject, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator'\n\nexport class FilesOnlyOfficeConfig {\n @IsBoolean()\n enabled = false\n\n @IsOptional()\n @IsString()\n externalServer: string = null\n\n @ValidateIf((o: FilesOnlyOfficeConfig) => o.enabled)\n @IsString()\n @IsNotEmpty()\n secret: string\n\n @IsBoolean()\n verifySSL: boolean = false\n}\n\nexport class FilesConfig {\n @IsNotEmpty()\n @IsString()\n dataPath: string\n\n @IsNotEmpty()\n @IsString()\n usersPath: string\n\n @IsNotEmpty()\n @IsString()\n spacesPath: string\n\n @IsNotEmpty()\n @IsString()\n tmpPath: string\n\n @IsInt()\n maxUploadSize: number = 5368709120 // 5 GB\n\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => FilesOnlyOfficeConfig)\n onlyoffice: FilesOnlyOfficeConfig = new FilesOnlyOfficeConfig()\n}\n"],"names":["FilesConfig","FilesOnlyOfficeConfig","enabled","externalServer","verifySSL","o","maxUploadSize","onlyoffice"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAsBYA;eAAAA;;QAjBAC;eAAAA;;;kCAHQ;gCAC4F;;;;;;;;;;AAE1G,IAAA,AAAMA,wBAAN,MAAMA;;aAEXC,UAAU;aAIVC,iBAAyB;aAQzBC,YAAqB;;AACvB;;;;;;;;;;qCAPeC,IAA6BA,EAAEH,OAAO;;;;;;;;;AAS9C,IAAA,AAAMF,cAAN,MAAMA;;aAkBXM,gBAAwB,YAAW,OAAO;aAK1CC,aAAoC,IAAIN;;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAFcA"}
1
+ {"version":3,"sources":["../../../../backend/src/applications/files/files.config.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com>\n * This file is part of Sync-in | The open source file sync and share solution\n * See the LICENSE file for licensing details\n */\n\nimport { Type } from 'class-transformer'\nimport { IsBoolean, IsInt, IsNotEmpty, IsNotEmptyObject, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator'\n\nexport class FilesOnlyOfficeConfig {\n @IsBoolean()\n enabled = false\n\n @IsOptional()\n @IsString()\n externalServer: string = null\n\n @ValidateIf((o: FilesOnlyOfficeConfig) => o.enabled)\n @IsString()\n @IsNotEmpty()\n secret: string\n\n @IsBoolean()\n verifySSL: boolean = false\n}\n\nexport class FilesConfig {\n @IsNotEmpty()\n @IsString()\n dataPath: string\n\n @IsNotEmpty()\n @IsString()\n usersPath: string\n\n @IsNotEmpty()\n @IsString()\n spacesPath: string\n\n @IsNotEmpty()\n @IsString()\n tmpPath: string\n\n @IsInt()\n maxUploadSize: number = 5368709120 // 5 GB\n\n @IsBoolean()\n showHiddenFiles: boolean = false\n\n @IsNotEmptyObject()\n @ValidateNested()\n @Type(() => FilesOnlyOfficeConfig)\n onlyoffice: FilesOnlyOfficeConfig = new FilesOnlyOfficeConfig()\n}\n"],"names":["FilesConfig","FilesOnlyOfficeConfig","enabled","externalServer","verifySSL","o","maxUploadSize","showHiddenFiles","onlyoffice"],"mappings":"AAAA;;;;CAIC;;;;;;;;;;;QAsBYA;eAAAA;;QAjBAC;eAAAA;;;kCAHQ;gCAC4F;;;;;;;;;;AAE1G,IAAA,AAAMA,wBAAN,MAAMA;;aAEXC,UAAU;aAIVC,iBAAyB;aAQzBC,YAAqB;;AACvB;;;;;;;;;;qCAPeC,IAA6BA,EAAEH,OAAO;;;;;;;;;AAS9C,IAAA,AAAMF,cAAN,MAAMA;;aAkBXM,gBAAwB,YAAW,OAAO;aAG1CC,kBAA2B;aAK3BC,aAAoC,IAAIP;;AAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAFcA"}
@@ -30,7 +30,6 @@ function _ts_metadata(k, v) {
30
30
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
31
31
  }
32
32
  let FilesOnlyOfficeStrategy = class FilesOnlyOfficeStrategy extends (0, _passport.PassportStrategy)(_passportjwt.Strategy, 'filesOnlyOfficeToken') {
33
- // not declared properly: https://github.com/nestjs/passport/issues/929
34
33
  validate(jwtPayload) {
35
34
  this.logger.assign({
36
35
  user: jwtPayload.identity.login
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../backend/src/applications/files/guards/files-only-office.strategy.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 { Injectable } from '@nestjs/common'\nimport { PassportStrategy } from '@nestjs/passport'\nimport { PinoLogger } from 'nestjs-pino'\nimport { ExtractJwt, Strategy } from 'passport-jwt'\nimport { AuthTokenAccessStrategy } from '../../../authentication/guards/auth-token-access.strategy'\nimport { JwtPayload } from '../../../authentication/interfaces/jwt-payload.interface'\nimport { configuration } from '../../../configuration/config.environment'\nimport { UserModel } from '../../users/models/user.model'\nimport { ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME } from '../constants/only-office'\n\n@Injectable()\nexport class FilesOnlyOfficeStrategy extends PassportStrategy(Strategy, 'filesOnlyOfficeToken') {\n constructor(private readonly logger: PinoLogger) {\n super({\n jwtFromRequest: ExtractJwt.fromExtractors([\n AuthTokenAccessStrategy.extractJWTFromCookie,\n ExtractJwt.fromUrlQueryParameter(ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME)\n ]),\n secretOrKey: configuration.auth.token.access.secret,\n ignoreExpiration: false,\n passReqToCallback: false\n })\n }\n\n // not declared properly: https://github.com/nestjs/passport/issues/929\n validate(jwtPayload: JwtPayload): UserModel {\n this.logger.assign({ user: jwtPayload.identity.login })\n return new UserModel(jwtPayload.identity)\n }\n}\n"],"names":["FilesOnlyOfficeStrategy","PassportStrategy","Strategy","validate","jwtPayload","logger","assign","user","identity","login","UserModel","jwtFromRequest","ExtractJwt","fromExtractors","AuthTokenAccessStrategy","extractJWTFromCookie","fromUrlQueryParameter","ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME","secretOrKey","configuration","auth","token","access","secret","ignoreExpiration","passReqToCallback"],"mappings":"AAAA;;;;CAIC;;;;+BAaYA;;;eAAAA;;;wBAXc;0BACM;4BACN;6BACU;yCACG;mCAEV;2BACJ;4BACyB;;;;;;;;;;AAG5C,IAAA,AAAMA,0BAAN,MAAMA,gCAAgCC,IAAAA,0BAAgB,EAACC,qBAAQ,EAAE;IAatE,wEAAwE;IACxEC,SAASC,UAAsB,EAAa;QAC1C,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMH,WAAWI,QAAQ,CAACC,KAAK;QAAC;QACrD,OAAO,IAAIC,oBAAS,CAACN,WAAWI,QAAQ;IAC1C;IAhBA,YAAY,AAAiBH,MAAkB,CAAE;QAC/C,KAAK,CAAC;YACJM,gBAAgBC,uBAAU,CAACC,cAAc,CAAC;gBACxCC,gDAAuB,CAACC,oBAAoB;gBAC5CH,uBAAU,CAACI,qBAAqB,CAACC,8CAAkC;aACpE;YACDC,aAAaC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAACC,MAAM,CAACC,MAAM;YACnDC,kBAAkB;YAClBC,mBAAmB;QACrB,SAT2BpB,SAAAA;IAU7B;AAOF"}
1
+ {"version":3,"sources":["../../../../../backend/src/applications/files/guards/files-only-office.strategy.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 { Injectable } from '@nestjs/common'\nimport { AbstractStrategy, PassportStrategy } from '@nestjs/passport'\nimport { PinoLogger } from 'nestjs-pino'\nimport { ExtractJwt, Strategy } from 'passport-jwt'\nimport { AuthTokenAccessStrategy } from '../../../authentication/guards/auth-token-access.strategy'\nimport { JwtPayload } from '../../../authentication/interfaces/jwt-payload.interface'\nimport { configuration } from '../../../configuration/config.environment'\nimport { UserModel } from '../../users/models/user.model'\nimport { ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME } from '../constants/only-office'\n\n@Injectable()\nexport class FilesOnlyOfficeStrategy extends PassportStrategy(Strategy, 'filesOnlyOfficeToken') implements AbstractStrategy {\n constructor(private readonly logger: PinoLogger) {\n super({\n jwtFromRequest: ExtractJwt.fromExtractors([\n AuthTokenAccessStrategy.extractJWTFromCookie,\n ExtractJwt.fromUrlQueryParameter(ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME)\n ]),\n secretOrKey: configuration.auth.token.access.secret,\n ignoreExpiration: false,\n passReqToCallback: false\n })\n }\n\n validate(jwtPayload: JwtPayload): UserModel {\n this.logger.assign({ user: jwtPayload.identity.login })\n return new UserModel(jwtPayload.identity)\n }\n}\n"],"names":["FilesOnlyOfficeStrategy","PassportStrategy","Strategy","validate","jwtPayload","logger","assign","user","identity","login","UserModel","jwtFromRequest","ExtractJwt","fromExtractors","AuthTokenAccessStrategy","extractJWTFromCookie","fromUrlQueryParameter","ONLY_OFFICE_TOKEN_QUERY_PARAM_NAME","secretOrKey","configuration","auth","token","access","secret","ignoreExpiration","passReqToCallback"],"mappings":"AAAA;;;;CAIC;;;;+BAaYA;;;eAAAA;;;wBAXc;0BACwB;4BACxB;6BACU;yCACG;mCAEV;2BACJ;4BACyB;;;;;;;;;;AAG5C,IAAA,AAAMA,0BAAN,MAAMA,gCAAgCC,IAAAA,0BAAgB,EAACC,qBAAQ,EAAE;IAatEC,SAASC,UAAsB,EAAa;QAC1C,IAAI,CAACC,MAAM,CAACC,MAAM,CAAC;YAAEC,MAAMH,WAAWI,QAAQ,CAACC,KAAK;QAAC;QACrD,OAAO,IAAIC,oBAAS,CAACN,WAAWI,QAAQ;IAC1C;IAfA,YAAY,AAAiBH,MAAkB,CAAE;QAC/C,KAAK,CAAC;YACJM,gBAAgBC,uBAAU,CAACC,cAAc,CAAC;gBACxCC,gDAAuB,CAACC,oBAAoB;gBAC5CH,uBAAU,CAACI,qBAAqB,CAACC,8CAAkC;aACpE;YACDC,aAAaC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAACC,MAAM,CAACC,MAAM;YACnDC,kBAAkB;YAClBC,mBAAmB;QACrB,SAT2BpB,SAAAA;IAU7B;AAMF"}