@sync-in/server 1.10.0 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +2 -2
  3. package/package.json +2 -3
  4. package/server/app.bootstrap.js +3 -22
  5. package/server/app.bootstrap.js.map +1 -1
  6. package/server/applications/comments/services/comments-queries.service.js +5 -9
  7. package/server/applications/comments/services/comments-queries.service.js.map +1 -1
  8. package/server/applications/users/users.e2e-spec.js +0 -1
  9. package/server/applications/users/users.e2e-spec.js.map +1 -1
  10. package/server/applications/webdav/constants/webdav.js +7 -0
  11. package/server/applications/webdav/constants/webdav.js.map +1 -1
  12. package/server/applications/webdav/utils/bootstrap.js +45 -0
  13. package/server/applications/webdav/utils/bootstrap.js.map +1 -0
  14. package/server/applications/webdav/webdav.controller.js +1 -1
  15. package/server/applications/webdav/webdav.controller.js.map +1 -1
  16. package/server/applications/webdav/webdav.e2e-spec.js +131 -2
  17. package/server/applications/webdav/webdav.e2e-spec.js.map +1 -1
  18. package/server/authentication/auth.e2e-spec.js +12 -6
  19. package/server/authentication/auth.e2e-spec.js.map +1 -1
  20. package/server/authentication/guards/auth-basic.guard.spec.js +23 -0
  21. package/server/authentication/guards/auth-basic.guard.spec.js.map +1 -1
  22. package/server/authentication/guards/auth-basic.strategy.js +3 -3
  23. package/server/authentication/guards/auth-basic.strategy.js.map +1 -1
  24. package/server/authentication/guards/auth-digest.strategy.js +32 -11
  25. package/server/authentication/guards/auth-digest.strategy.js.map +1 -1
  26. package/server/authentication/guards/implementations/http-basic.strategy.js +76 -0
  27. package/server/authentication/guards/implementations/http-basic.strategy.js.map +1 -0
  28. package/server/authentication/guards/implementations/http-digest.strategy.js +155 -0
  29. package/server/authentication/guards/implementations/http-digest.strategy.js.map +1 -0
  30. package/server/authentication/services/auth-manager.service.js +1 -2
  31. package/server/authentication/services/auth-manager.service.js.map +1 -1
  32. package/static/{chunk-XBKCQCBI.js → chunk-2GXOVGTD.js} +1 -1
  33. package/static/{chunk-QHJT5H4M.js → chunk-3MVPXC3U.js} +1 -1
  34. package/static/{chunk-I5SPA4G2.js → chunk-3VRUIWQG.js} +1 -1
  35. package/static/{chunk-L3BIP4AA.js → chunk-3ZBAQTHJ.js} +1 -1
  36. package/static/{chunk-D55YR5X7.js → chunk-76M3BMK6.js} +11 -11
  37. package/static/{chunk-GXWGB7WO.js → chunk-76REYAEA.js} +1 -1
  38. package/static/{chunk-CCZWPM7Q.js → chunk-7HJFIMNF.js} +1 -1
  39. package/static/{chunk-NIR4YE2E.js → chunk-7KAYOR3A.js} +1 -1
  40. package/static/{chunk-O3YLAEVE.js → chunk-AALPWGPB.js} +2 -2
  41. package/static/{chunk-KWFELZTM.js → chunk-CN5YVRFT.js} +1 -1
  42. package/static/{chunk-B6HQYQYG.js → chunk-CVXLHSO5.js} +1 -1
  43. package/static/{chunk-R7PLNX75.js → chunk-D2MLAO5N.js} +1 -1
  44. package/static/{chunk-HGODIZTV.js → chunk-EKWB5W72.js} +1 -1
  45. package/static/{chunk-PQZLR4P3.js → chunk-FTFEQDWH.js} +1 -1
  46. package/static/{chunk-3WZ6F3LC.js → chunk-FWQJ4ZCD.js} +1 -1
  47. package/static/{chunk-FIUF2JM4.js → chunk-IHS5LSJJ.js} +1 -1
  48. package/static/{chunk-G3PL6YX3.js → chunk-J7474P3L.js} +1 -1
  49. package/static/{chunk-LGIVVJDD.js → chunk-JAJ7VXMB.js} +1 -1
  50. package/static/{chunk-T42BV6TR.js → chunk-KEZNIIFH.js} +1 -1
  51. package/static/{chunk-OUHCDDT6.js → chunk-LWSCODLD.js} +1 -1
  52. package/static/{chunk-6WMXMIE4.js → chunk-NIKNG2FX.js} +1 -1
  53. package/static/{chunk-KPOQLDWF.js → chunk-QGHNJVJ6.js} +1 -1
  54. package/static/{chunk-GWRAGN3M.js → chunk-QJ22N76V.js} +1 -1
  55. package/static/{chunk-NJJURHX4.js → chunk-QTPIEEZW.js} +1 -1
  56. package/static/{chunk-ZHOE5VEY.js → chunk-R4VYKZVJ.js} +1 -1
  57. package/static/{chunk-7VRYTDX4.js → chunk-RBTLSPYJ.js} +1 -1
  58. package/static/{chunk-GQHXYX6Z.js → chunk-S44QIK3G.js} +1 -1
  59. package/static/{chunk-45AZ6ZML.js → chunk-S6H2ELRY.js} +1 -1
  60. package/static/{chunk-E32J777S.js → chunk-SPQH3ATC.js} +1 -1
  61. package/static/{chunk-DGCVA6BM.js → chunk-TTWMFWEC.js} +1 -1
  62. package/static/{chunk-ULSPQ3HP.js → chunk-U5E5H2DD.js} +1 -1
  63. package/static/{chunk-LNLBIJZD.js → chunk-VBTZDHZ3.js} +1 -1
  64. package/static/{chunk-I3FR3A45.js → chunk-VZFZUI6D.js} +1 -1
  65. package/static/{chunk-S3TTWPQA.js → chunk-WFMEUST4.js} +1 -1
  66. package/static/{chunk-27Z3SYRL.js → chunk-WRK2FTKU.js} +1 -1
  67. package/static/{chunk-4TPFERL6.js → chunk-WZPF4LS2.js} +1 -1
  68. package/static/{chunk-POUWUMC4.js → chunk-X7NHX5C7.js} +1 -1
  69. package/static/{chunk-XTVNHFKX.js → chunk-XSURUW7C.js} +1 -1
  70. package/static/{chunk-5O66CLTD.js → chunk-XX3JPJUM.js} +1 -1
  71. package/static/{chunk-3RPUQ22U.js → chunk-XZHWESIY.js} +1 -1
  72. package/static/{chunk-3JYMJQYT.js → chunk-ZHUBWKA2.js} +1 -1
  73. package/static/{chunk-XEWLBWFF.js → chunk-ZU5MQTFN.js} +1 -1
  74. package/static/index.html +1 -1
  75. package/static/{main-YKDNJ7LK.js → main-5O3KLGIR.js} +3 -3
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Copyright (C) 2012-2026 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "HttpBasicStrategy", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return HttpBasicStrategy;
13
+ }
14
+ });
15
+ const _passportstrategy = require("passport-strategy");
16
+ function splitFirst(str, sep) {
17
+ const i = str.indexOf(sep);
18
+ if (i < 0) return [
19
+ str
20
+ ];
21
+ return [
22
+ str.substring(0, i),
23
+ str.substring(i + 1)
24
+ ];
25
+ }
26
+ let HttpBasicStrategy = class HttpBasicStrategy extends _passportstrategy.Strategy {
27
+ authenticate(req) {
28
+ const authorization = req?.headers?.authorization;
29
+ if (!authorization) {
30
+ return this.fail(this.challenge(), 401);
31
+ }
32
+ const parts = authorization.split(' ');
33
+ if (parts.length !== 2) {
34
+ return this.fail(400);
35
+ }
36
+ if (!/^Basic$/i.test(parts[0])) {
37
+ return this.fail(this.challenge(), 401);
38
+ }
39
+ let decoded;
40
+ try {
41
+ decoded = Buffer.from(parts[1], 'base64').toString();
42
+ } catch {
43
+ return this.fail(400);
44
+ }
45
+ const [userid, password] = splitFirst(decoded, ':');
46
+ if (password === undefined) {
47
+ return this.fail(400);
48
+ }
49
+ const verified = (err, user)=>{
50
+ if (err) return this.error(err);
51
+ if (!user) return this.fail(this.challenge(), 401);
52
+ return this.success(user);
53
+ };
54
+ if (this.passReqToCallback) {
55
+ ;
56
+ this.verify(req, userid, password, verified);
57
+ } else {
58
+ ;
59
+ this.verify(userid, password, verified);
60
+ }
61
+ }
62
+ challenge() {
63
+ return `Basic realm="${this.realm}"`;
64
+ }
65
+ constructor(options = {}, verify){
66
+ super(), this.name = 'basic';
67
+ if (!verify) {
68
+ throw new TypeError('HttpBasicStrategy requires a verify callback');
69
+ }
70
+ this.verify = verify;
71
+ this.realm = options.realm ?? 'Sync-in';
72
+ this.passReqToCallback = !!options.passReqToCallback;
73
+ }
74
+ };
75
+
76
+ //# sourceMappingURL=http-basic.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/authentication/guards/implementations/http-basic.strategy.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2026 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 { Strategy as PassportStrategy } from 'passport-strategy'\n\nexport type BasicVerifyCallback = (err?: any, user?: any) => void\n\nexport type BasicVerifyFunction = (userid: string, password: string, done: BasicVerifyCallback) => void\n\nexport type BasicVerifyFunctionWithRequest = (req: any, userid: string, password: string, done: BasicVerifyCallback) => void\n\nfunction splitFirst(str: string, sep: string): [string] | [string, string] {\n const i = str.indexOf(sep)\n if (i < 0) return [str]\n return [str.substring(0, i), str.substring(i + 1)]\n}\n\nexport interface HttpBasicStrategyOptions {\n realm?: string\n passReqToCallback?: boolean\n}\n\n/**\n * Pure HTTP Basic authentication strategy\n **/\nexport class HttpBasicStrategy extends PassportStrategy {\n name = 'basic'\n\n private readonly verify: BasicVerifyFunction | BasicVerifyFunctionWithRequest\n private readonly realm: string\n private readonly passReqToCallback: boolean\n\n constructor(options: HttpBasicStrategyOptions = {}, verify: BasicVerifyFunction | BasicVerifyFunctionWithRequest) {\n super()\n\n if (!verify) {\n throw new TypeError('HttpBasicStrategy requires a verify callback')\n }\n\n this.verify = verify\n this.realm = options.realm ?? 'Sync-in'\n this.passReqToCallback = !!options.passReqToCallback\n }\n\n authenticate(req: any): void {\n const authorization: string | undefined = req?.headers?.authorization\n if (!authorization) {\n return this.fail(this.challenge(), 401)\n }\n\n const parts = authorization.split(' ')\n if (parts.length !== 2) {\n return this.fail(400)\n }\n\n if (!/^Basic$/i.test(parts[0])) {\n return this.fail(this.challenge(), 401)\n }\n\n let decoded: string\n try {\n decoded = Buffer.from(parts[1], 'base64').toString()\n } catch {\n return this.fail(400)\n }\n\n const [userid, password] = splitFirst(decoded, ':')\n if (password === undefined) {\n return this.fail(400)\n }\n\n const verified: BasicVerifyCallback = (err, user) => {\n if (err) return this.error(err)\n if (!user) return this.fail(this.challenge(), 401)\n return this.success(user)\n }\n\n if (this.passReqToCallback) {\n ;(this.verify as BasicVerifyFunctionWithRequest)(req, userid, password, verified)\n } else {\n ;(this.verify as BasicVerifyFunction)(userid, password, verified)\n }\n }\n\n private challenge(): string {\n return `Basic realm=\"${this.realm}\"`\n }\n}\n"],"names":["HttpBasicStrategy","splitFirst","str","sep","i","indexOf","substring","PassportStrategy","authenticate","req","authorization","headers","fail","challenge","parts","split","length","test","decoded","Buffer","from","toString","userid","password","undefined","verified","err","user","error","success","passReqToCallback","verify","realm","options","name","TypeError"],"mappings":"AAAA;;;;CAIC;;;;+BAwBYA;;;eAAAA;;;kCAtBgC;AAQ7C,SAASC,WAAWC,GAAW,EAAEC,GAAW;IAC1C,MAAMC,IAAIF,IAAIG,OAAO,CAACF;IACtB,IAAIC,IAAI,GAAG,OAAO;QAACF;KAAI;IACvB,OAAO;QAACA,IAAII,SAAS,CAAC,GAAGF;QAAIF,IAAII,SAAS,CAACF,IAAI;KAAG;AACpD;AAUO,IAAA,AAAMJ,oBAAN,MAAMA,0BAA0BO,0BAAgB;IAmBrDC,aAAaC,GAAQ,EAAQ;QAC3B,MAAMC,gBAAoCD,KAAKE,SAASD;QACxD,IAAI,CAACA,eAAe;YAClB,OAAO,IAAI,CAACE,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI;QACrC;QAEA,MAAMC,QAAQJ,cAAcK,KAAK,CAAC;QAClC,IAAID,MAAME,MAAM,KAAK,GAAG;YACtB,OAAO,IAAI,CAACJ,IAAI,CAAC;QACnB;QAEA,IAAI,CAAC,WAAWK,IAAI,CAACH,KAAK,CAAC,EAAE,GAAG;YAC9B,OAAO,IAAI,CAACF,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI;QACrC;QAEA,IAAIK;QACJ,IAAI;YACFA,UAAUC,OAAOC,IAAI,CAACN,KAAK,CAAC,EAAE,EAAE,UAAUO,QAAQ;QACpD,EAAE,OAAM;YACN,OAAO,IAAI,CAACT,IAAI,CAAC;QACnB;QAEA,MAAM,CAACU,QAAQC,SAAS,GAAGtB,WAAWiB,SAAS;QAC/C,IAAIK,aAAaC,WAAW;YAC1B,OAAO,IAAI,CAACZ,IAAI,CAAC;QACnB;QAEA,MAAMa,WAAgC,CAACC,KAAKC;YAC1C,IAAID,KAAK,OAAO,IAAI,CAACE,KAAK,CAACF;YAC3B,IAAI,CAACC,MAAM,OAAO,IAAI,CAACf,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI;YAC9C,OAAO,IAAI,CAACgB,OAAO,CAACF;QACtB;QAEA,IAAI,IAAI,CAACG,iBAAiB,EAAE;;YACxB,IAAI,CAACC,MAAM,CAAoCtB,KAAKa,QAAQC,UAAUE;QAC1E,OAAO;;YACH,IAAI,CAACM,MAAM,CAAyBT,QAAQC,UAAUE;QAC1D;IACF;IAEQZ,YAAoB;QAC1B,OAAO,CAAC,aAAa,EAAE,IAAI,CAACmB,KAAK,CAAC,CAAC,CAAC;IACtC;IAtDA,YAAYC,UAAoC,CAAC,CAAC,EAAEF,MAA4D,CAAE;QAChH,KAAK,SAPPG,OAAO;QASL,IAAI,CAACH,QAAQ;YACX,MAAM,IAAII,UAAU;QACtB;QAEA,IAAI,CAACJ,MAAM,GAAGA;QACd,IAAI,CAACC,KAAK,GAAGC,QAAQD,KAAK,IAAI;QAC9B,IAAI,CAACF,iBAAiB,GAAG,CAAC,CAACG,QAAQH,iBAAiB;IACtD;AA6CF"}
@@ -0,0 +1,155 @@
1
+ /*
2
+ * Copyright (C) 2012-2026 Johan Legrand <johan.legrand@sync-in.com>
3
+ * This file is part of Sync-in | The open source file sync and share solution
4
+ * See the LICENSE file for licensing details
5
+ */ "use strict";
6
+ Object.defineProperty(exports, "__esModule", {
7
+ value: true
8
+ });
9
+ Object.defineProperty(exports, "HttpDigestStrategy", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return HttpDigestStrategy;
13
+ }
14
+ });
15
+ const _nodecrypto = /*#__PURE__*/ _interop_require_default(require("node:crypto"));
16
+ const _passportstrategy = require("passport-strategy");
17
+ function _interop_require_default(obj) {
18
+ return obj && obj.__esModule ? obj : {
19
+ default: obj
20
+ };
21
+ }
22
+ function md5(str, encoding = 'hex') {
23
+ return _nodecrypto.default.createHash('md5').update(str).digest(encoding);
24
+ }
25
+ function nonce(len) {
26
+ const buf = [];
27
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
28
+ const charlen = chars.length;
29
+ for(let i = 0; i < len; ++i){
30
+ buf.push(chars[Math.random() * charlen | 0]);
31
+ }
32
+ return buf.join('');
33
+ }
34
+ // parsing identique à digest.js
35
+ function parse(params) {
36
+ const opts = {};
37
+ const tokens = params.split(/,(?=(?:[^"]|"[^"]*")*$)/);
38
+ for (const token of tokens){
39
+ const m = /(\w+)=["]?([^"]+)["]?$/.exec(token);
40
+ if (m) opts[m[1]] = m[2];
41
+ }
42
+ return opts;
43
+ }
44
+ let HttpDigestStrategy = class HttpDigestStrategy extends _passportstrategy.Strategy {
45
+ authenticate(req) {
46
+ const authorization = req?.headers?.authorization;
47
+ if (!authorization) {
48
+ return this.fail(this.challenge(), 401);
49
+ }
50
+ const parts = authorization.split(' ');
51
+ if (parts.length < 2) return this.fail(400);
52
+ const scheme = parts[0];
53
+ const params = parts.slice(1).join(' ');
54
+ if (!/Digest/i.test(scheme)) {
55
+ return this.fail(this.challenge(), 401);
56
+ }
57
+ const creds = parse(params);
58
+ if (Object.keys(creds).length === 0) return this.fail(400);
59
+ if (!creds.username) return this.fail(this.challenge(), 401);
60
+ // Même check que digest.js : req.url doit matcher creds.uri
61
+ // (en Fastify, req.url inclut la querystring, ce qui est généralement OK)
62
+ if (req.url !== creds.uri) return this.fail(400);
63
+ const verified = (err, result)=>{
64
+ if (err) return this.error(err);
65
+ if (!result || !result.user) return this.fail(this.challenge(), 401);
66
+ const { user, secret } = result;
67
+ if (!secret) return this.fail(400);
68
+ // compute HA1
69
+ let ha1;
70
+ const algo = creds.algorithm || 'MD5';
71
+ if (algo === 'MD5') {
72
+ if (typeof secret === 'object' && secret.ha1) {
73
+ ha1 = secret.ha1;
74
+ } else {
75
+ // password en clair (peu probable)
76
+ ha1 = md5(`${creds.username}:${creds.realm}:${String(secret)}`);
77
+ }
78
+ } else if (algo === 'MD5-sess') {
79
+ // idem digest.js (note: nonce/cnonce init non gérés)
80
+ const base = typeof secret === 'object' && secret.ha1 ? secret.ha1 : md5(`${creds.username}:${creds.realm}:${String(secret)}`);
81
+ ha1 = md5(`${base}:${creds.nonce}:${creds.cnonce}`);
82
+ } else {
83
+ return this.fail(400);
84
+ }
85
+ // compute HA2
86
+ let ha2;
87
+ if (!creds.qop || creds.qop === 'auth') {
88
+ ha2 = md5(`${req.method}:${creds.uri}`);
89
+ } else if (creds.qop === 'auth-int') {
90
+ return this.error(new Error('auth-int not implemented'));
91
+ } else {
92
+ return this.fail(400);
93
+ }
94
+ // compute expected digest
95
+ let digest;
96
+ if (!creds.qop) {
97
+ digest = md5(`${ha1}:${creds.nonce}:${ha2}`);
98
+ } else if (creds.qop === 'auth' || creds.qop === 'auth-int') {
99
+ digest = md5(`${ha1}:${creds.nonce}:${creds.nc}:${creds.cnonce}:${creds.qop}:${ha2}`);
100
+ } else {
101
+ return this.fail(400);
102
+ }
103
+ if (creds.response !== digest) {
104
+ return this.fail(this.challenge(), 401);
105
+ }
106
+ if (this.validateCb) {
107
+ return this.validateCb({
108
+ nonce: creds.nonce,
109
+ cnonce: creds.cnonce,
110
+ nc: creds.nc,
111
+ opaque: creds.opaque
112
+ }, (e, ok)=>{
113
+ if (e) return this.error(e);
114
+ if (!ok) return this.fail(this.challenge(), 401);
115
+ return this.success(user);
116
+ });
117
+ }
118
+ return this.success(user);
119
+ };
120
+ if (this.passReqToCallback) {
121
+ ;
122
+ this.verify(req, creds.username, verified);
123
+ } else {
124
+ ;
125
+ this.verify(creds.username, verified);
126
+ }
127
+ }
128
+ challenge() {
129
+ let challenge = `Digest realm="${this.realm}"`;
130
+ if (this.domain) challenge += `, domain="${this.domain.join(' ')}"`;
131
+ challenge += `, nonce="${nonce(32)}"`;
132
+ if (this.opaque) challenge += `, opaque="${this.opaque}"`;
133
+ if (this.algorithm) challenge += `, algorithm=${this.algorithm}`;
134
+ if (this.qop) challenge += `, qop="${this.qop.join(',')}"`;
135
+ return challenge;
136
+ }
137
+ constructor(options = {}, verify){
138
+ super(), this.name = 'digest';
139
+ if (!verify) throw new Error('HTTP Digest authentication strategy requires a secret function');
140
+ this.verify = verify;
141
+ this.realm = options.realm ?? 'Users';
142
+ if (options.domain) this.domain = Array.isArray(options.domain) ? options.domain : [
143
+ options.domain
144
+ ];
145
+ this.opaque = options.opaque;
146
+ this.algorithm = options.algorithm;
147
+ this.qop = options.qop ? Array.isArray(options.qop) ? options.qop : [
148
+ options.qop
149
+ ] : undefined;
150
+ this.validateCb = options.validate;
151
+ this.passReqToCallback = options.passReqToCallback === true;
152
+ }
153
+ };
154
+
155
+ //# sourceMappingURL=http-digest.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../backend/src/authentication/guards/implementations/http-digest.strategy.ts"],"sourcesContent":["/*\n * Copyright (C) 2012-2026 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 crypto from 'node:crypto'\nimport { Strategy as PassportStrategy } from 'passport-strategy'\n\nexport interface DigestValidateParams {\n nonce?: string\n cnonce?: string\n nc?: string\n opaque?: string\n}\n\nexport type DigestValidateCallback = (err?: any, valid?: boolean) => void\n\n// ⚠️ verify (secret callback) : on attend un \"user container\" qui contient aussi le secret\nexport type DigestVerifyCallback = (err?: any, result?: any) => void\n\nexport type DigestVerifyFunction = (username: string, done: DigestVerifyCallback) => void\nexport type DigestVerifyFunctionWithRequest = (req: any, username: string, done: DigestVerifyCallback) => void\n\nexport type DigestSecret =\n | string // password en clair (rare)\n | { ha1: string } // recommandé : HA1 = MD5(username:realm:password)\n\nexport interface DigestVerifyResult {\n user: any\n secret: DigestSecret\n}\n\nexport interface HttpDigestStrategyOptionsBase {\n realm?: string\n domain?: string | string[]\n opaque?: string\n algorithm?: 'MD5' | 'MD5-sess'\n qop?: ('auth' | 'auth-int')[] | 'auth' | 'auth-int'\n // optionnel : anti-replay\n validate?: (params: DigestValidateParams, done: DigestValidateCallback) => void\n}\n\nexport type HttpDigestStrategyOptionsWithReq = HttpDigestStrategyOptionsBase & {\n passReqToCallback: true\n}\n\nexport type HttpDigestStrategyOptionsNoReq = HttpDigestStrategyOptionsBase & {\n passReqToCallback?: false | undefined\n}\n\nfunction md5(str: string, encoding: crypto.BinaryToTextEncoding = 'hex'): string {\n return crypto.createHash('md5').update(str).digest(encoding)\n}\n\nfunction nonce(len: number): string {\n const buf: string[] = []\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n const charlen = chars.length\n for (let i = 0; i < len; ++i) {\n buf.push(chars[(Math.random() * charlen) | 0])\n }\n return buf.join('')\n}\n\n// parsing identique à digest.js\nfunction parse(params: string): Record<string, string> {\n const opts: Record<string, string> = {}\n const tokens = params.split(/,(?=(?:[^\"]|\"[^\"]*\")*$)/)\n for (const token of tokens) {\n const m = /(\\w+)=[\"]?([^\"]+)[\"]?$/.exec(token)\n if (m) opts[m[1]] = m[2]\n }\n return opts\n}\n\nexport class HttpDigestStrategy extends PassportStrategy {\n name = 'digest'\n\n private readonly realm: string\n private readonly domain?: string[]\n private readonly opaque?: string\n private readonly algorithm?: 'MD5' | 'MD5-sess'\n private readonly qop?: ('auth' | 'auth-int')[]\n private readonly passReqToCallback: boolean\n private readonly validateCb?: (params: DigestValidateParams, done: DigestValidateCallback) => void\n\n private readonly verify: DigestVerifyFunction | DigestVerifyFunctionWithRequest\n\n // overloads typés selon passReqToCallback\n constructor(options: HttpDigestStrategyOptionsWithReq, verify: DigestVerifyFunctionWithRequest)\n constructor(options?: HttpDigestStrategyOptionsNoReq, verify?: DigestVerifyFunction)\n constructor(\n options: HttpDigestStrategyOptionsWithReq | HttpDigestStrategyOptionsNoReq = {},\n verify?: DigestVerifyFunction | DigestVerifyFunctionWithRequest\n ) {\n super()\n if (!verify) throw new Error('HTTP Digest authentication strategy requires a secret function')\n\n this.verify = verify\n this.realm = options.realm ?? 'Users'\n\n if (options.domain) this.domain = Array.isArray(options.domain) ? options.domain : [options.domain]\n this.opaque = options.opaque\n this.algorithm = options.algorithm\n this.qop = options.qop ? (Array.isArray(options.qop) ? options.qop : [options.qop]) : undefined\n\n this.validateCb = options.validate\n this.passReqToCallback = (options as HttpDigestStrategyOptionsWithReq).passReqToCallback === true\n }\n\n authenticate(req: any): void {\n const authorization: string | undefined = req?.headers?.authorization\n if (!authorization) {\n return this.fail(this.challenge(), 401)\n }\n\n const parts = authorization.split(' ')\n if (parts.length < 2) return this.fail(400 as any)\n\n const scheme = parts[0]\n const params = parts.slice(1).join(' ')\n if (!/Digest/i.test(scheme)) {\n return this.fail(this.challenge(), 401)\n }\n\n const creds = parse(params)\n if (Object.keys(creds).length === 0) return this.fail(400 as any)\n if (!creds.username) return this.fail(this.challenge(), 401)\n\n // Même check que digest.js : req.url doit matcher creds.uri\n // (en Fastify, req.url inclut la querystring, ce qui est généralement OK)\n if (req.url !== creds.uri) return this.fail(400 as any)\n\n const verified: DigestVerifyCallback = (err, result) => {\n if (err) return this.error(err)\n if (!result || !result.user) return this.fail(this.challenge(), 401)\n\n const { user, secret } = result as DigestVerifyResult\n if (!secret) return this.fail(400 as any)\n\n // compute HA1\n let ha1: string\n const algo = creds.algorithm || 'MD5'\n if (algo === 'MD5') {\n if (typeof secret === 'object' && (secret as any).ha1) {\n ha1 = (secret as any).ha1\n } else {\n // password en clair (peu probable)\n ha1 = md5(`${creds.username}:${creds.realm}:${String(secret)}`)\n }\n } else if (algo === 'MD5-sess') {\n // idem digest.js (note: nonce/cnonce init non gérés)\n const base =\n typeof secret === 'object' && (secret as any).ha1 ? (secret as any).ha1 : md5(`${creds.username}:${creds.realm}:${String(secret)}`)\n ha1 = md5(`${base}:${creds.nonce}:${creds.cnonce}`)\n } else {\n return this.fail(400 as any)\n }\n\n // compute HA2\n let ha2: string\n if (!creds.qop || creds.qop === 'auth') {\n ha2 = md5(`${req.method}:${creds.uri}`)\n } else if (creds.qop === 'auth-int') {\n return this.error(new Error('auth-int not implemented'))\n } else {\n return this.fail(400 as any)\n }\n\n // compute expected digest\n let digest: string\n if (!creds.qop) {\n digest = md5(`${ha1}:${creds.nonce}:${ha2}`)\n } else if (creds.qop === 'auth' || creds.qop === 'auth-int') {\n digest = md5(`${ha1}:${creds.nonce}:${creds.nc}:${creds.cnonce}:${creds.qop}:${ha2}`)\n } else {\n return this.fail(400 as any)\n }\n\n if (creds.response !== digest) {\n return this.fail(this.challenge(), 401)\n }\n\n if (this.validateCb) {\n return this.validateCb({ nonce: creds.nonce, cnonce: creds.cnonce, nc: creds.nc, opaque: creds.opaque }, (e, ok) => {\n if (e) return this.error(e)\n if (!ok) return this.fail(this.challenge(), 401)\n return this.success(user)\n })\n }\n\n return this.success(user)\n }\n\n if (this.passReqToCallback) {\n ;(this.verify as DigestVerifyFunctionWithRequest)(req, creds.username, verified)\n } else {\n ;(this.verify as DigestVerifyFunction)(creds.username, verified)\n }\n }\n\n private challenge(): string {\n let challenge = `Digest realm=\"${this.realm}\"`\n if (this.domain) challenge += `, domain=\"${this.domain.join(' ')}\"`\n challenge += `, nonce=\"${nonce(32)}\"`\n if (this.opaque) challenge += `, opaque=\"${this.opaque}\"`\n if (this.algorithm) challenge += `, algorithm=${this.algorithm}`\n if (this.qop) challenge += `, qop=\"${this.qop.join(',')}\"`\n return challenge\n }\n}\n"],"names":["HttpDigestStrategy","md5","str","encoding","crypto","createHash","update","digest","nonce","len","buf","chars","charlen","length","i","push","Math","random","join","parse","params","opts","tokens","split","token","m","exec","PassportStrategy","authenticate","req","authorization","headers","fail","challenge","parts","scheme","slice","test","creds","Object","keys","username","url","uri","verified","err","result","error","user","secret","ha1","algo","algorithm","realm","String","base","cnonce","ha2","qop","method","Error","nc","response","validateCb","opaque","e","ok","success","passReqToCallback","verify","domain","options","name","Array","isArray","undefined","validate"],"mappings":"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"}
@@ -114,8 +114,7 @@ let AuthManager = class AuthManager {
114
114
  async clearCookies(res) {
115
115
  for (const [type, path] of Object.entries(_auth.TOKEN_PATHS)){
116
116
  res.clearCookie(_configenvironment.configuration.auth.token[type].name, {
117
- path: path,
118
- httpOnly: type !== _tokeninterface.TOKEN_TYPE.CSRF
117
+ path: path
119
118
  });
120
119
  }
121
120
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../backend/src/authentication/services/auth-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 */\nimport { unsign, UnsignResult } from '@fastify/cookie'\nimport { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { JwtService } from '@nestjs/jwt'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport crypto from 'node:crypto'\nimport { HTTP_CSRF_IGNORED_METHODS } from '../../applications/applications.constants'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { convertHumanTimeToSeconds } from '../../common/functions'\nimport { currentTimeStamp } from '../../common/shared'\nimport { configuration, serverConfig } from '../../configuration/config.environment'\nimport { CSRF_ERROR, CSRF_KEY, TOKEN_2FA_TYPES, TOKEN_PATHS, TOKEN_TYPES } from '../constants/auth'\nimport { LoginResponseDto, LoginVerify2FaDto } from '../dto/login-response.dto'\nimport { TokenResponseDto } from '../dto/token-response.dto'\nimport { JwtIdentity2FaPayload, JwtIdentityPayload, JwtPayload } from '../interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from '../interfaces/token.interface'\n\n@Injectable()\nexport class AuthManager {\n private readonly logger = new Logger(AuthManager.name)\n\n constructor(private readonly jwt: JwtService) {}\n\n async getTokens(user: UserModel, refresh = false): Promise<TokenResponseDto> {\n const currentTime = currentTimeStamp()\n if (refresh && user.exp < currentTime) {\n this.logger.error(`${this.getTokens.name} - token refresh has incorrect expiration : *${user.login}*`)\n throw new HttpException('Token has expired', HttpStatus.FORBIDDEN)\n }\n const accessExpiration = convertHumanTimeToSeconds(configuration.auth.token.access.expiration)\n const refreshExpiration = refresh ? user.exp - currentTime : convertHumanTimeToSeconds(configuration.auth.token.refresh.expiration)\n return {\n [TOKEN_TYPE.ACCESS]: await this.jwtSign(user, TOKEN_TYPE.ACCESS, accessExpiration),\n [TOKEN_TYPE.REFRESH]: await this.jwtSign(user, TOKEN_TYPE.REFRESH, refreshExpiration),\n [`${TOKEN_TYPE.ACCESS}_expiration`]: accessExpiration + currentTime,\n [`${TOKEN_TYPE.REFRESH}_expiration`]: refreshExpiration + currentTime\n }\n }\n\n async setCookies(user: UserModel, res: FastifyReply, init2FaVerify: true): Promise<LoginVerify2FaDto>\n async setCookies(user: UserModel, res: FastifyReply, init2FaVerify?: false): Promise<LoginResponseDto>\n async setCookies(user: UserModel, res: FastifyReply, init2FaVerify = false): Promise<LoginResponseDto | LoginVerify2FaDto> {\n // If `verify2Fa` is true, it sets the cookies and response required for valid 2FA authentication.\n const verify2Fa = init2FaVerify && configuration.auth.mfa.totp.enabled && user.twoFaEnabled\n const response = verify2Fa ? new LoginVerify2FaDto(serverConfig) : new LoginResponseDto(user, serverConfig)\n const currentTime = currentTimeStamp()\n const csrfToken: string = crypto.randomUUID()\n const tokenTypes: TOKEN_TYPE[] = verify2Fa ? TOKEN_2FA_TYPES : TOKEN_TYPES\n for (const type of tokenTypes) {\n const isCSRFToken = type === TOKEN_TYPE.CSRF || type === TOKEN_TYPE.CSRF_2FA\n const tokenExpiration = convertHumanTimeToSeconds(configuration.auth.token[type].expiration)\n let cookieValue: string\n if (isCSRFToken) {\n cookieValue = csrfToken\n } else if (verify2Fa) {\n cookieValue = await this.jwtSign2Fa(user, type, tokenExpiration, csrfToken)\n } else {\n cookieValue = await this.jwtSign(user, type, tokenExpiration, csrfToken)\n }\n res.setCookie(configuration.auth.token[type].name, cookieValue, {\n signed: isCSRFToken,\n path: TOKEN_PATHS[type],\n maxAge: tokenExpiration,\n httpOnly: !isCSRFToken\n })\n if (type === TOKEN_TYPE.ACCESS || type === TOKEN_TYPE.REFRESH || type === TOKEN_TYPE.ACCESS_2FA) {\n response.token[`${type}_expiration`] = tokenExpiration + currentTime\n }\n }\n return response\n }\n\n async refreshCookies(user: UserModel, res: FastifyReply): Promise<TokenResponseDto> {\n const response = {} as TokenResponseDto\n const currentTime = currentTimeStamp()\n let refreshTokenExpiration: number\n // refresh cookie must have the `exp` attribute\n // reuse token expiration to make it final\n if (user.exp && user.exp > currentTime) {\n refreshTokenExpiration = user.exp - currentTime\n } else {\n this.logger.error(`${this.refreshCookies.name} - token ${TOKEN_TYPE.REFRESH} has incorrect expiration : *${user.login}*`)\n throw new HttpException('Token has expired', HttpStatus.FORBIDDEN)\n }\n const csrfToken: string = crypto.randomUUID()\n for (const type of TOKEN_TYPES) {\n const tokenExpiration =\n type === TOKEN_TYPE.ACCESS ? convertHumanTimeToSeconds(configuration.auth.token[TOKEN_TYPE.ACCESS].expiration) : refreshTokenExpiration\n const cookieValue: string = type === TOKEN_TYPE.CSRF ? csrfToken : await this.jwtSign(user, type, tokenExpiration, csrfToken)\n res.setCookie(configuration.auth.token[type].name, cookieValue, {\n signed: type === TOKEN_TYPE.CSRF,\n path: TOKEN_PATHS[type],\n maxAge: tokenExpiration,\n httpOnly: type !== TOKEN_TYPE.CSRF\n })\n if (type === TOKEN_TYPE.ACCESS || type === TOKEN_TYPE.REFRESH) {\n response[`${type}_expiration`] = tokenExpiration + currentTime\n }\n }\n return response\n }\n\n async clearCookies(res: FastifyReply) {\n for (const [type, path] of Object.entries(TOKEN_PATHS)) {\n res.clearCookie(configuration.auth.token[type].name, { path: path, httpOnly: type !== TOKEN_TYPE.CSRF })\n }\n }\n\n csrfValidation(req: FastifyRequest, jwtPayload: JwtPayload, type: TOKEN_TYPE.ACCESS | TOKEN_TYPE.REFRESH): void {\n // ignore safe methods\n if (HTTP_CSRF_IGNORED_METHODS.has(req.method)) {\n return\n }\n\n // check csrf only for access and refresh cookies\n if (typeof req.cookies !== 'object' || req.cookies[configuration.auth.token[type].name] === undefined) {\n return\n }\n\n if (!jwtPayload.csrf) {\n this.logger.warn(`${this.csrfValidation.name} - ${CSRF_ERROR.MISSING_JWT}`)\n throw new HttpException(CSRF_ERROR.MISSING_JWT, HttpStatus.FORBIDDEN)\n }\n\n if (!req.headers[CSRF_KEY]) {\n this.logger.warn(`${this.csrfValidation.name} - ${CSRF_ERROR.MISSING_HEADERS}`)\n throw new HttpException(CSRF_ERROR.MISSING_HEADERS, HttpStatus.FORBIDDEN)\n }\n\n const csrfHeader: UnsignResult = unsign(req.headers[CSRF_KEY] as string, configuration.auth.token.csrf.secret)\n if (jwtPayload.csrf !== csrfHeader.value) {\n this.logger.warn(`${this.csrfValidation.name} - ${CSRF_ERROR.MISMATCH}`)\n throw new HttpException(CSRF_ERROR.MISMATCH, HttpStatus.FORBIDDEN)\n }\n }\n\n private jwtSign(user: UserModel, type: TOKEN_TYPE, expiration: number, csrfToken?: string): Promise<string> {\n return this.jwt.signAsync(\n {\n identity: {\n id: user.id,\n login: user.login,\n email: user.email,\n fullName: user.fullName,\n language: user.language,\n role: user.role,\n applications: user.applications,\n impersonatedFromId: user.impersonatedFromId || undefined,\n impersonatedClientId: user.impersonatedClientId || undefined,\n clientId: user.clientId || undefined,\n twoFaEnabled: user.twoFaEnabled || undefined\n } satisfies JwtIdentityPayload,\n ...((type === TOKEN_TYPE.ACCESS || type === TOKEN_TYPE.REFRESH) && { csrf: csrfToken })\n },\n {\n secret: configuration.auth.token[type].secret,\n expiresIn: expiration\n }\n )\n }\n\n private jwtSign2Fa(user: UserModel, type: TOKEN_TYPE, expiration: number, csrfToken: string): Promise<string> {\n // Restrict the temporary token to the minimum required information\n return this.jwt.signAsync(\n {\n identity: {\n id: user.id,\n login: user.login,\n language: user.language,\n role: user.role,\n twoFaEnabled: true\n } satisfies JwtIdentity2FaPayload,\n csrf: csrfToken\n },\n {\n secret: configuration.auth.token[type].secret,\n expiresIn: expiration\n }\n )\n }\n}\n"],"names":["AuthManager","getTokens","user","refresh","currentTime","currentTimeStamp","exp","logger","error","name","login","HttpException","HttpStatus","FORBIDDEN","accessExpiration","convertHumanTimeToSeconds","configuration","auth","token","access","expiration","refreshExpiration","TOKEN_TYPE","ACCESS","jwtSign","REFRESH","setCookies","res","init2FaVerify","verify2Fa","mfa","totp","enabled","twoFaEnabled","response","LoginVerify2FaDto","serverConfig","LoginResponseDto","csrfToken","crypto","randomUUID","tokenTypes","TOKEN_2FA_TYPES","TOKEN_TYPES","type","isCSRFToken","CSRF","CSRF_2FA","tokenExpiration","cookieValue","jwtSign2Fa","setCookie","signed","path","TOKEN_PATHS","maxAge","httpOnly","ACCESS_2FA","refreshCookies","refreshTokenExpiration","clearCookies","Object","entries","clearCookie","csrfValidation","req","jwtPayload","HTTP_CSRF_IGNORED_METHODS","has","method","cookies","undefined","csrf","warn","CSRF_ERROR","MISSING_JWT","headers","CSRF_KEY","MISSING_HEADERS","csrfHeader","unsign","secret","value","MISMATCH","jwt","signAsync","identity","id","email","fullName","language","role","applications","impersonatedFromId","impersonatedClientId","clientId","expiresIn","Logger"],"mappings":"AAAA;;;;CAIC;;;;+BAkBYA;;;eAAAA;;;wBAjBwB;wBACyB;qBACnC;mEAER;uCACuB;2BAEA;wBACT;mCACW;sBACoC;kCAC5B;gCAGzB;;;;;;;;;;;;;;;AAGpB,IAAA,AAAMA,cAAN,MAAMA;IAKX,MAAMC,UAAUC,IAAe,EAAEC,UAAU,KAAK,EAA6B;QAC3E,MAAMC,cAAcC,IAAAA,wBAAgB;QACpC,IAAIF,WAAWD,KAAKI,GAAG,GAAGF,aAAa;YACrC,IAAI,CAACG,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACP,SAAS,CAACQ,IAAI,CAAC,6CAA6C,EAAEP,KAAKQ,KAAK,CAAC,CAAC,CAAC;YACrG,MAAM,IAAIC,qBAAa,CAAC,qBAAqBC,kBAAU,CAACC,SAAS;QACnE;QACA,MAAMC,mBAAmBC,IAAAA,oCAAyB,EAACC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAACC,MAAM,CAACC,UAAU;QAC7F,MAAMC,oBAAoBlB,UAAUD,KAAKI,GAAG,GAAGF,cAAcW,IAAAA,oCAAyB,EAACC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAACf,OAAO,CAACiB,UAAU;QAClI,OAAO;YACL,CAACE,0BAAU,CAACC,MAAM,CAAC,EAAE,MAAM,IAAI,CAACC,OAAO,CAACtB,MAAMoB,0BAAU,CAACC,MAAM,EAAET;YACjE,CAACQ,0BAAU,CAACG,OAAO,CAAC,EAAE,MAAM,IAAI,CAACD,OAAO,CAACtB,MAAMoB,0BAAU,CAACG,OAAO,EAAEJ;YACnE,CAAC,GAAGC,0BAAU,CAACC,MAAM,CAAC,WAAW,CAAC,CAAC,EAAET,mBAAmBV;YACxD,CAAC,GAAGkB,0BAAU,CAACG,OAAO,CAAC,WAAW,CAAC,CAAC,EAAEJ,oBAAoBjB;QAC5D;IACF;IAIA,MAAMsB,WAAWxB,IAAe,EAAEyB,GAAiB,EAAEC,gBAAgB,KAAK,EAAiD;QACzH,kGAAkG;QAClG,MAAMC,YAAYD,iBAAiBZ,gCAAa,CAACC,IAAI,CAACa,GAAG,CAACC,IAAI,CAACC,OAAO,IAAI9B,KAAK+B,YAAY;QAC3F,MAAMC,WAAWL,YAAY,IAAIM,mCAAiB,CAACC,+BAAY,IAAI,IAAIC,kCAAgB,CAACnC,MAAMkC,+BAAY;QAC1G,MAAMhC,cAAcC,IAAAA,wBAAgB;QACpC,MAAMiC,YAAoBC,mBAAM,CAACC,UAAU;QAC3C,MAAMC,aAA2BZ,YAAYa,qBAAe,GAAGC,iBAAW;QAC1E,KAAK,MAAMC,QAAQH,WAAY;YAC7B,MAAMI,cAAcD,SAAStB,0BAAU,CAACwB,IAAI,IAAIF,SAAStB,0BAAU,CAACyB,QAAQ;YAC5E,MAAMC,kBAAkBjC,IAAAA,oCAAyB,EAACC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACxB,UAAU;YAC3F,IAAI6B;YACJ,IAAIJ,aAAa;gBACfI,cAAcX;YAChB,OAAO,IAAIT,WAAW;gBACpBoB,cAAc,MAAM,IAAI,CAACC,UAAU,CAAChD,MAAM0C,MAAMI,iBAAiBV;YACnE,OAAO;gBACLW,cAAc,MAAM,IAAI,CAACzB,OAAO,CAACtB,MAAM0C,MAAMI,iBAAiBV;YAChE;YACAX,IAAIwB,SAAS,CAACnC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACnC,IAAI,EAAEwC,aAAa;gBAC9DG,QAAQP;gBACRQ,MAAMC,iBAAW,CAACV,KAAK;gBACvBW,QAAQP;gBACRQ,UAAU,CAACX;YACb;YACA,IAAID,SAAStB,0BAAU,CAACC,MAAM,IAAIqB,SAAStB,0BAAU,CAACG,OAAO,IAAImB,SAAStB,0BAAU,CAACmC,UAAU,EAAE;gBAC/FvB,SAAShB,KAAK,CAAC,GAAG0B,KAAK,WAAW,CAAC,CAAC,GAAGI,kBAAkB5C;YAC3D;QACF;QACA,OAAO8B;IACT;IAEA,MAAMwB,eAAexD,IAAe,EAAEyB,GAAiB,EAA6B;QAClF,MAAMO,WAAW,CAAC;QAClB,MAAM9B,cAAcC,IAAAA,wBAAgB;QACpC,IAAIsD;QACJ,+CAA+C;QAC/C,0CAA0C;QAC1C,IAAIzD,KAAKI,GAAG,IAAIJ,KAAKI,GAAG,GAAGF,aAAa;YACtCuD,yBAAyBzD,KAAKI,GAAG,GAAGF;QACtC,OAAO;YACL,IAAI,CAACG,MAAM,CAACC,KAAK,CAAC,GAAG,IAAI,CAACkD,cAAc,CAACjD,IAAI,CAAC,SAAS,EAAEa,0BAAU,CAACG,OAAO,CAAC,6BAA6B,EAAEvB,KAAKQ,KAAK,CAAC,CAAC,CAAC;YACxH,MAAM,IAAIC,qBAAa,CAAC,qBAAqBC,kBAAU,CAACC,SAAS;QACnE;QACA,MAAMyB,YAAoBC,mBAAM,CAACC,UAAU;QAC3C,KAAK,MAAMI,QAAQD,iBAAW,CAAE;YAC9B,MAAMK,kBACJJ,SAAStB,0BAAU,CAACC,MAAM,GAAGR,IAAAA,oCAAyB,EAACC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAACI,0BAAU,CAACC,MAAM,CAAC,CAACH,UAAU,IAAIuC;YACnH,MAAMV,cAAsBL,SAAStB,0BAAU,CAACwB,IAAI,GAAGR,YAAY,MAAM,IAAI,CAACd,OAAO,CAACtB,MAAM0C,MAAMI,iBAAiBV;YACnHX,IAAIwB,SAAS,CAACnC,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACnC,IAAI,EAAEwC,aAAa;gBAC9DG,QAAQR,SAAStB,0BAAU,CAACwB,IAAI;gBAChCO,MAAMC,iBAAW,CAACV,KAAK;gBACvBW,QAAQP;gBACRQ,UAAUZ,SAAStB,0BAAU,CAACwB,IAAI;YACpC;YACA,IAAIF,SAAStB,0BAAU,CAACC,MAAM,IAAIqB,SAAStB,0BAAU,CAACG,OAAO,EAAE;gBAC7DS,QAAQ,CAAC,GAAGU,KAAK,WAAW,CAAC,CAAC,GAAGI,kBAAkB5C;YACrD;QACF;QACA,OAAO8B;IACT;IAEA,MAAM0B,aAAajC,GAAiB,EAAE;QACpC,KAAK,MAAM,CAACiB,MAAMS,KAAK,IAAIQ,OAAOC,OAAO,CAACR,iBAAW,EAAG;YACtD3B,IAAIoC,WAAW,CAAC/C,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACnC,IAAI,EAAE;gBAAE4C,MAAMA;gBAAMG,UAAUZ,SAAStB,0BAAU,CAACwB,IAAI;YAAC;QACxG;IACF;IAEAkB,eAAeC,GAAmB,EAAEC,UAAsB,EAAEtB,IAA4C,EAAQ;QAC9G,sBAAsB;QACtB,IAAIuB,gDAAyB,CAACC,GAAG,CAACH,IAAII,MAAM,GAAG;YAC7C;QACF;QAEA,iDAAiD;QACjD,IAAI,OAAOJ,IAAIK,OAAO,KAAK,YAAYL,IAAIK,OAAO,CAACtD,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACnC,IAAI,CAAC,KAAK8D,WAAW;YACrG;QACF;QAEA,IAAI,CAACL,WAAWM,IAAI,EAAE;YACpB,IAAI,CAACjE,MAAM,CAACkE,IAAI,CAAC,GAAG,IAAI,CAACT,cAAc,CAACvD,IAAI,CAAC,GAAG,EAAEiE,gBAAU,CAACC,WAAW,EAAE;YAC1E,MAAM,IAAIhE,qBAAa,CAAC+D,gBAAU,CAACC,WAAW,EAAE/D,kBAAU,CAACC,SAAS;QACtE;QAEA,IAAI,CAACoD,IAAIW,OAAO,CAACC,cAAQ,CAAC,EAAE;YAC1B,IAAI,CAACtE,MAAM,CAACkE,IAAI,CAAC,GAAG,IAAI,CAACT,cAAc,CAACvD,IAAI,CAAC,GAAG,EAAEiE,gBAAU,CAACI,eAAe,EAAE;YAC9E,MAAM,IAAInE,qBAAa,CAAC+D,gBAAU,CAACI,eAAe,EAAElE,kBAAU,CAACC,SAAS;QAC1E;QAEA,MAAMkE,aAA2BC,IAAAA,cAAM,EAACf,IAAIW,OAAO,CAACC,cAAQ,CAAC,EAAY7D,gCAAa,CAACC,IAAI,CAACC,KAAK,CAACsD,IAAI,CAACS,MAAM;QAC7G,IAAIf,WAAWM,IAAI,KAAKO,WAAWG,KAAK,EAAE;YACxC,IAAI,CAAC3E,MAAM,CAACkE,IAAI,CAAC,GAAG,IAAI,CAACT,cAAc,CAACvD,IAAI,CAAC,GAAG,EAAEiE,gBAAU,CAACS,QAAQ,EAAE;YACvE,MAAM,IAAIxE,qBAAa,CAAC+D,gBAAU,CAACS,QAAQ,EAAEvE,kBAAU,CAACC,SAAS;QACnE;IACF;IAEQW,QAAQtB,IAAe,EAAE0C,IAAgB,EAAExB,UAAkB,EAAEkB,SAAkB,EAAmB;QAC1G,OAAO,IAAI,CAAC8C,GAAG,CAACC,SAAS,CACvB;YACEC,UAAU;gBACRC,IAAIrF,KAAKqF,EAAE;gBACX7E,OAAOR,KAAKQ,KAAK;gBACjB8E,OAAOtF,KAAKsF,KAAK;gBACjBC,UAAUvF,KAAKuF,QAAQ;gBACvBC,UAAUxF,KAAKwF,QAAQ;gBACvBC,MAAMzF,KAAKyF,IAAI;gBACfC,cAAc1F,KAAK0F,YAAY;gBAC/BC,oBAAoB3F,KAAK2F,kBAAkB,IAAItB;gBAC/CuB,sBAAsB5F,KAAK4F,oBAAoB,IAAIvB;gBACnDwB,UAAU7F,KAAK6F,QAAQ,IAAIxB;gBAC3BtC,cAAc/B,KAAK+B,YAAY,IAAIsC;YACrC;YACA,GAAI,AAAC3B,CAAAA,SAAStB,0BAAU,CAACC,MAAM,IAAIqB,SAAStB,0BAAU,CAACG,OAAO,AAAD,KAAM;gBAAE+C,MAAMlC;YAAU,CAAC;QACxF,GACA;YACE2C,QAAQjE,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACqC,MAAM;YAC7Ce,WAAW5E;QACb;IAEJ;IAEQ8B,WAAWhD,IAAe,EAAE0C,IAAgB,EAAExB,UAAkB,EAAEkB,SAAiB,EAAmB;QAC5G,mEAAmE;QACnE,OAAO,IAAI,CAAC8C,GAAG,CAACC,SAAS,CACvB;YACEC,UAAU;gBACRC,IAAIrF,KAAKqF,EAAE;gBACX7E,OAAOR,KAAKQ,KAAK;gBACjBgF,UAAUxF,KAAKwF,QAAQ;gBACvBC,MAAMzF,KAAKyF,IAAI;gBACf1D,cAAc;YAChB;YACAuC,MAAMlC;QACR,GACA;YACE2C,QAAQjE,gCAAa,CAACC,IAAI,CAACC,KAAK,CAAC0B,KAAK,CAACqC,MAAM;YAC7Ce,WAAW5E;QACb;IAEJ;IA9JA,YAAY,AAAiBgE,GAAe,CAAE;aAAjBA,MAAAA;aAFZ7E,SAAS,IAAI0F,cAAM,CAACjG,YAAYS,IAAI;IAEN;AA+JjD"}
1
+ {"version":3,"sources":["../../../../backend/src/authentication/services/auth-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 */\nimport { unsign, UnsignResult } from '@fastify/cookie'\nimport { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'\nimport { JwtService } from '@nestjs/jwt'\nimport { FastifyReply, FastifyRequest } from 'fastify'\nimport crypto from 'node:crypto'\nimport { HTTP_CSRF_IGNORED_METHODS } from '../../applications/applications.constants'\nimport { UserModel } from '../../applications/users/models/user.model'\nimport { convertHumanTimeToSeconds } from '../../common/functions'\nimport { currentTimeStamp } from '../../common/shared'\nimport { configuration, serverConfig } from '../../configuration/config.environment'\nimport { CSRF_ERROR, CSRF_KEY, TOKEN_2FA_TYPES, TOKEN_PATHS, TOKEN_TYPES } from '../constants/auth'\nimport { LoginResponseDto, LoginVerify2FaDto } from '../dto/login-response.dto'\nimport { TokenResponseDto } from '../dto/token-response.dto'\nimport { JwtIdentity2FaPayload, JwtIdentityPayload, JwtPayload } from '../interfaces/jwt-payload.interface'\nimport { TOKEN_TYPE } from '../interfaces/token.interface'\n\n@Injectable()\nexport class AuthManager {\n private readonly logger = new Logger(AuthManager.name)\n\n constructor(private readonly jwt: JwtService) {}\n\n async getTokens(user: UserModel, refresh = false): Promise<TokenResponseDto> {\n const currentTime = currentTimeStamp()\n if (refresh && user.exp < currentTime) {\n this.logger.error(`${this.getTokens.name} - token refresh has incorrect expiration : *${user.login}*`)\n throw new HttpException('Token has expired', HttpStatus.FORBIDDEN)\n }\n const accessExpiration = convertHumanTimeToSeconds(configuration.auth.token.access.expiration)\n const refreshExpiration = refresh ? user.exp - currentTime : convertHumanTimeToSeconds(configuration.auth.token.refresh.expiration)\n return {\n [TOKEN_TYPE.ACCESS]: await this.jwtSign(user, TOKEN_TYPE.ACCESS, accessExpiration),\n [TOKEN_TYPE.REFRESH]: await this.jwtSign(user, TOKEN_TYPE.REFRESH, refreshExpiration),\n [`${TOKEN_TYPE.ACCESS}_expiration`]: accessExpiration + currentTime,\n [`${TOKEN_TYPE.REFRESH}_expiration`]: refreshExpiration + currentTime\n }\n }\n\n async setCookies(user: UserModel, res: FastifyReply, init2FaVerify: true): Promise<LoginVerify2FaDto>\n async setCookies(user: UserModel, res: FastifyReply, init2FaVerify?: false): Promise<LoginResponseDto>\n async setCookies(user: UserModel, res: FastifyReply, init2FaVerify = false): Promise<LoginResponseDto | LoginVerify2FaDto> {\n // If `verify2Fa` is true, it sets the cookies and response required for valid 2FA authentication.\n const verify2Fa = init2FaVerify && configuration.auth.mfa.totp.enabled && user.twoFaEnabled\n const response = verify2Fa ? new LoginVerify2FaDto(serverConfig) : new LoginResponseDto(user, serverConfig)\n const currentTime = currentTimeStamp()\n const csrfToken: string = crypto.randomUUID()\n const tokenTypes: TOKEN_TYPE[] = verify2Fa ? TOKEN_2FA_TYPES : TOKEN_TYPES\n for (const type of tokenTypes) {\n const isCSRFToken = type === TOKEN_TYPE.CSRF || type === TOKEN_TYPE.CSRF_2FA\n const tokenExpiration = convertHumanTimeToSeconds(configuration.auth.token[type].expiration)\n let cookieValue: string\n if (isCSRFToken) {\n cookieValue = csrfToken\n } else if (verify2Fa) {\n cookieValue = await this.jwtSign2Fa(user, type, tokenExpiration, csrfToken)\n } else {\n cookieValue = await this.jwtSign(user, type, tokenExpiration, csrfToken)\n }\n res.setCookie(configuration.auth.token[type].name, cookieValue, {\n signed: isCSRFToken,\n path: TOKEN_PATHS[type],\n maxAge: tokenExpiration,\n httpOnly: !isCSRFToken\n })\n if (type === TOKEN_TYPE.ACCESS || type === TOKEN_TYPE.REFRESH || type === TOKEN_TYPE.ACCESS_2FA) {\n response.token[`${type}_expiration`] = tokenExpiration + currentTime\n }\n }\n return response\n }\n\n async refreshCookies(user: UserModel, res: FastifyReply): Promise<TokenResponseDto> {\n const response = {} as TokenResponseDto\n const currentTime = currentTimeStamp()\n let refreshTokenExpiration: number\n // refresh cookie must have the `exp` attribute\n // reuse token expiration to make it final\n if (user.exp && user.exp > currentTime) {\n refreshTokenExpiration = user.exp - currentTime\n } else {\n this.logger.error(`${this.refreshCookies.name} - token ${TOKEN_TYPE.REFRESH} has incorrect expiration : *${user.login}*`)\n throw new HttpException('Token has expired', HttpStatus.FORBIDDEN)\n }\n const csrfToken: string = crypto.randomUUID()\n for (const type of TOKEN_TYPES) {\n const tokenExpiration =\n type === TOKEN_TYPE.ACCESS ? convertHumanTimeToSeconds(configuration.auth.token[TOKEN_TYPE.ACCESS].expiration) : refreshTokenExpiration\n const cookieValue: string = type === TOKEN_TYPE.CSRF ? csrfToken : await this.jwtSign(user, type, tokenExpiration, csrfToken)\n res.setCookie(configuration.auth.token[type].name, cookieValue, {\n signed: type === TOKEN_TYPE.CSRF,\n path: TOKEN_PATHS[type],\n maxAge: tokenExpiration,\n httpOnly: type !== TOKEN_TYPE.CSRF\n })\n if (type === TOKEN_TYPE.ACCESS || type === TOKEN_TYPE.REFRESH) {\n response[`${type}_expiration`] = tokenExpiration + currentTime\n }\n }\n return response\n }\n\n async clearCookies(res: FastifyReply) {\n for (const [type, path] of Object.entries(TOKEN_PATHS)) {\n res.clearCookie(configuration.auth.token[type].name, { path: path })\n }\n }\n\n csrfValidation(req: FastifyRequest, jwtPayload: JwtPayload, type: TOKEN_TYPE.ACCESS | TOKEN_TYPE.REFRESH): void {\n // ignore safe methods\n if (HTTP_CSRF_IGNORED_METHODS.has(req.method)) {\n return\n }\n\n // check csrf only for access and refresh cookies\n if (typeof req.cookies !== 'object' || req.cookies[configuration.auth.token[type].name] === undefined) {\n return\n }\n\n if (!jwtPayload.csrf) {\n this.logger.warn(`${this.csrfValidation.name} - ${CSRF_ERROR.MISSING_JWT}`)\n throw new HttpException(CSRF_ERROR.MISSING_JWT, HttpStatus.FORBIDDEN)\n }\n\n if (!req.headers[CSRF_KEY]) {\n this.logger.warn(`${this.csrfValidation.name} - ${CSRF_ERROR.MISSING_HEADERS}`)\n throw new HttpException(CSRF_ERROR.MISSING_HEADERS, HttpStatus.FORBIDDEN)\n }\n\n const csrfHeader: UnsignResult = unsign(req.headers[CSRF_KEY] as string, configuration.auth.token.csrf.secret)\n if (jwtPayload.csrf !== csrfHeader.value) {\n this.logger.warn(`${this.csrfValidation.name} - ${CSRF_ERROR.MISMATCH}`)\n throw new HttpException(CSRF_ERROR.MISMATCH, HttpStatus.FORBIDDEN)\n }\n }\n\n private jwtSign(user: UserModel, type: TOKEN_TYPE, expiration: number, csrfToken?: string): Promise<string> {\n return this.jwt.signAsync(\n {\n identity: {\n id: user.id,\n login: user.login,\n email: user.email,\n fullName: user.fullName,\n language: user.language,\n role: user.role,\n applications: user.applications,\n impersonatedFromId: user.impersonatedFromId || undefined,\n impersonatedClientId: user.impersonatedClientId || undefined,\n clientId: user.clientId || undefined,\n twoFaEnabled: user.twoFaEnabled || undefined\n } satisfies JwtIdentityPayload,\n ...((type === TOKEN_TYPE.ACCESS || type === TOKEN_TYPE.REFRESH) && { csrf: csrfToken })\n },\n {\n secret: configuration.auth.token[type].secret,\n expiresIn: expiration\n }\n )\n }\n\n private jwtSign2Fa(user: UserModel, type: TOKEN_TYPE, expiration: number, csrfToken: string): Promise<string> {\n // Restrict the temporary token to the minimum required information\n return this.jwt.signAsync(\n {\n identity: {\n id: user.id,\n login: user.login,\n language: user.language,\n role: user.role,\n twoFaEnabled: true\n } satisfies JwtIdentity2FaPayload,\n csrf: csrfToken\n },\n {\n secret: configuration.auth.token[type].secret,\n expiresIn: expiration\n }\n )\n }\n}\n"],"names":["AuthManager","getTokens","user","refresh","currentTime","currentTimeStamp","exp","logger","error","name","login","HttpException","HttpStatus","FORBIDDEN","accessExpiration","convertHumanTimeToSeconds","configuration","auth","token","access","expiration","refreshExpiration","TOKEN_TYPE","ACCESS","jwtSign","REFRESH","setCookies","res","init2FaVerify","verify2Fa","mfa","totp","enabled","twoFaEnabled","response","LoginVerify2FaDto","serverConfig","LoginResponseDto","csrfToken","crypto","randomUUID","tokenTypes","TOKEN_2FA_TYPES","TOKEN_TYPES","type","isCSRFToken","CSRF","CSRF_2FA","tokenExpiration","cookieValue","jwtSign2Fa","setCookie","signed","path","TOKEN_PATHS","maxAge","httpOnly","ACCESS_2FA","refreshCookies","refreshTokenExpiration","clearCookies","Object","entries","clearCookie","csrfValidation","req","jwtPayload","HTTP_CSRF_IGNORED_METHODS","has","method","cookies","undefined","csrf","warn","CSRF_ERROR","MISSING_JWT","headers","CSRF_KEY","MISSING_HEADERS","csrfHeader","unsign","secret","value","MISMATCH","jwt","signAsync","identity","id","email","fullName","language","role","applications","impersonatedFromId","impersonatedClientId","clientId","expiresIn","Logger"],"mappings":"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"}
@@ -1 +1 @@
1
- import{a as ie,b as ne,c as ae}from"./chunk-L3BIP4AA.js";import{Ab as te,qb as I,s as q,xb as D,yb as $,zb as ee}from"./chunk-O3YLAEVE.js";import{$f as N,Be as T,Cd as B,Ed as j,Gb as _,Jd as k,Kd as G,Ld as x,Lf as Z,Oa as t,Rb as P,Sb as s,Tb as r,Ub as M,Vb as R,Wd as J,Xb as g,Yb as y,Zb as h,Ze as X,ab as u,cc as d,fd as H,ja as O,jd as w,kc as L,lb as C,mb as f,mc as Y,od as F,qd as z,qe as K,qg as v,rb as a,sb as i,se as Q,tb as l,ub as m,ud as b,vd as W,wd as U,xd as V}from"./chunk-D55YR5X7.js";function se(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltDown)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function ce(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.LOCAL]),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.LOCAL])}}function re(o,p){if(o&1&&C(0,se,1,2,"fa-icon",1)(1,ce,1,3,"fa-icon",2),o&2){let n=_();f(n.small?0:1)}}function de(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltUp)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function pe(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.REMOTE]),P("ms-1",n.syncPath.settings.mode===n.SYNC_PATH_MODE.BOTH),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.REMOTE])}}function me(o,p){if(o&1&&C(0,de,1,2,"fa-icon",1)(1,pe,1,5,"fa-icon",4),o&2){let n=_();f(n.small?0:1)}}var oe=(()=>{let p=class p{constructor(){this.small=!1,this.SYNC_PATH_MODE=D,this.SYNC_TRANSFER_SIDE_ICON=ae,this.icons={faLongArrowAltDown:N,faLongArrowAltUp:T},this.SYNC_TRANSFER_SIDE=ie,this.SYNC_TRANSFER_SIDE_CLASS=ne}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-direction-icon"]],inputs:{syncPath:"syncPath",small:"small"},decls:3,vars:2,consts:[[1,"d-flex","justify-content-center"],[3,"icon","fixedWidth"],[3,"icon","class"],[3,"icon"],[3,"icon","ms-1","class"]],template:function(S,e){S&1&&(i(0,"span",0),C(1,re,2,1),C(2,me,2,1),l()),S&2&&(t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.DOWNLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?1:-1),t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.UPLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?2:-1))},dependencies:[v],encapsulation:2});let o=p;return o})();function _e(o,p){if(o&1&&(i(0,"div")(1,"div"),m(2,"fa-icon",0),i(3,"span",1),r(4,"Client"),l()(),i(5,"div",10)(6,"span",11),r(7),l()()(),i(8,"div")(9,"div"),m(10,"fa-icon",0),i(11,"span",1),r(12,"Server"),l()(),i(13,"div",10)(14,"span",11)(15,"div",12),m(16,"fa-icon",13),r(17),l()()()()),o&2){let n=_();s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.CLIENT),t(5),M(n.syncPath.settings.localPath),t(),s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.SERVER),t(6),a("icon",n.syncPath.icon),t(),R(" ",n.syncPath.showedPath," ")}}function Se(o,p){if(o&1&&(i(0,"span",4),m(1,"fa-icon",14),L(2,"translate"),l()),o&2){let n=_();t(),a("icon",n.icons.faExclamationCircle)("tooltip",Y(2,2,"You must have permission to modify the server folder to choose a different sync mode",n.locale.language))}}var Le=(()=>{let p=class p{constructor(){this.direction="center",this.showPaths=!1,this.size="small",this.locale=O(j),this.icons={CLIENT:I.CLIENT,SERVER:I.SERVER,faExclamationCircle:X,faLongArrowAltDown:N,faLongArrowAltUp:T,faGauge:J,faClock:Q,faRotate:x,faEdit:K,faBug:Z},this.colSize={small:[2,5],large:[3,6]},this.SYNC_PATH_CONFLICT_MODE=ee,this.SYNC_PATH_MODE=D,this.SYNC_PATH_DIFF_MODE=$,this.SYNC_PATH_SCHEDULER_UNIT=te}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-settings"]],inputs:{syncPath:"syncPath",direction:"direction",showPaths:"showPaths",size:"size"},decls:74,vars:98,consts:[[3,"icon"],["l10nTranslate","",1,"ms-2"],["type","text",3,"ngModelChange","ngModel"],[3,"syncPath","small"],[1,"ms-2","fs-lg","cursor-pointer"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel"],["l10nTranslate","",3,"disabled","ngValue"],["l10nTranslate","",3,"ngValue"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel","disabled"],["min","1","type","number",1,"form-control","form-select-sm","pe-1","me-2",2,"width","70px",3,"ngModelChange","ngModel","disabled"],[1,"col-8"],[1,"form-control-sm","form-control-plaintext"],[1,"d-flex","align-items-center"],[1,"me-1",3,"icon"],[1,"text-warning",3,"icon","tooltip"]],template:function(S,e){S&1&&(i(0,"div"),C(1,_e,18,17),i(2,"div")(3,"div"),m(4,"fa-icon",0),i(5,"span",1),r(6,"Name"),l()(),i(7,"div")(8,"input",2),h("ngModelChange",function(c){return y(e.syncPath.settings.name,c)||(e.syncPath.settings.name=c),c}),l()()(),i(9,"div")(10,"div"),m(11,"app-sync-path-direction-icon",3),i(12,"span",1),r(13,"Direction"),l(),C(14,Se,3,5,"span",4),l(),i(15,"div")(16,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.mode,c)||(e.syncPath.settings.mode=c),c}),i(17,"option",6),r(18,"upload only"),l(),i(19,"option",7),r(20,"download only"),l(),i(21,"option",6),r(22,"both"),l()()()(),i(23,"div")(24,"div"),m(25,"fa-icon",0),i(26,"span",1),r(27,"Conflict"),l()(),i(28,"div")(29,"select",8),h("ngModelChange",function(c){return y(e.syncPath.settings.conflictMode,c)||(e.syncPath.settings.conflictMode=c),c}),i(30,"option",7),r(31,"the client\u2019s files take precedence"),l(),i(32,"option",7),r(33,"the server\u2019s files take precedence"),l(),i(34,"option",7),r(35,"the most recent files will be kept"),l()()()(),i(36,"div")(37,"div"),m(38,"fa-icon",0),i(39,"span",1),r(40,"Mode"),l()(),i(41,"div")(42,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.diffMode,c)||(e.syncPath.settings.diffMode=c),c}),i(43,"option",7),r(44),l(),i(45,"option",7),r(46),l()()()(),i(47,"div")(48,"div"),m(49,"fa-icon",0),i(50,"span",1),r(51,"Scheduler"),l()(),i(52,"div")(53,"input",9),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.value,c)||(e.syncPath.settings.scheduler.value=c),c}),l(),i(54,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.unit,c)||(e.syncPath.settings.scheduler.unit=c),c}),i(55,"option",7),r(56,"disabled"),l(),i(57,"option",7),r(58,"scheduler_unit_minute"),l(),i(59,"option",7),r(60,"scheduler_unit_hour"),l(),i(61,"option",7),r(62,"scheduler_unit_day"),l()()()(),i(63,"div")(64,"div"),m(65,"fa-icon",0),i(66,"span",1),r(67,"Status"),l()(),i(68,"div")(69,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.enabled,c)||(e.syncPath.settings.enabled=c),c}),i(70,"option",7),r(71,"enabled"),l(),i(72,"option",7),r(73,"disabled"),l()()()()()),S&2&&(s(d("d-flex flex-column justify-content-",e.direction)),t(),f(e.showPaths?1:-1),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faEdit),t(3),s(d("col-",e.colSize[e.size][1])),t(),s(d("form-control form-select-sm ",e.syncPath.settings.name?"":"is-invalid")),g("ngModel",e.syncPath.settings.name),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("d-flex align-items-center col-",e.colSize[e.size][0])),t(),a("syncPath",e.syncPath)("small",!0),t(3),f(e.syncPath.isWriteable?-1:14),t(),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.mode),t(),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.UPLOAD),t(2),a("ngValue",e.SYNC_PATH_MODE.DOWNLOAD),t(2),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.BOTH),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faBug),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.conflictMode),a("disabled",e.syncPath.settings.mode!=="both"),t(),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.LOCAL),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.REMOTE),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.RECENT),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faGauge),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.diffMode),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.FAST),t(),M(e.SYNC_PATH_DIFF_MODE.FAST),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.SECURE),t(),M(e.SYNC_PATH_DIFF_MODE.SECURE),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faClock),t(3),s(d("d-flex flex-row col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.scheduler.value),a("disabled",e.syncPath.settings.scheduler.unit===e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(),g("ngModel",e.syncPath.settings.scheduler.unit),t(),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.MINUTE),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.HOUR),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DAY),t(2),s(d("d-flex justify-content-",e.direction," align-items-center")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faRotate),t(3),s(d("col-",e.colSize[e.size][1])),t(),P("text-danger",!e.syncPath.settings.enabled),g("ngModel",e.syncPath.settings.enabled),t(),a("ngValue",!0),t(2),a("ngValue",!1))},dependencies:[G,v,B,W,U,H,z,b,w,V,F,q,oe,k],encapsulation:2});let o=p;return o})();export{oe as a,Le as b};
1
+ import{a as ie,b as ne,c as ae}from"./chunk-3ZBAQTHJ.js";import{Ab as te,qb as I,s as q,xb as D,yb as $,zb as ee}from"./chunk-AALPWGPB.js";import{$f as N,Be as T,Cd as B,Ed as j,Gb as _,Jd as k,Kd as G,Ld as x,Lf as Z,Oa as t,Rb as P,Sb as s,Tb as r,Ub as M,Vb as R,Wd as J,Xb as g,Yb as y,Zb as h,Ze as X,ab as u,cc as d,fd as H,ja as O,jd as w,kc as L,lb as C,mb as f,mc as Y,od as F,qd as z,qe as K,qg as v,rb as a,sb as i,se as Q,tb as l,ub as m,ud as b,vd as W,wd as U,xd as V}from"./chunk-76M3BMK6.js";function se(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltDown)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function ce(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.LOCAL]),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.LOCAL])}}function re(o,p){if(o&1&&C(0,se,1,2,"fa-icon",1)(1,ce,1,3,"fa-icon",2),o&2){let n=_();f(n.small?0:1)}}function de(o,p){if(o&1&&m(0,"fa-icon",1),o&2){let n=_(2);a("icon",n.icons.faLongArrowAltUp)("fixedWidth",n.syncPath.settings.mode!==n.SYNC_PATH_MODE.BOTH)}}function pe(o,p){if(o&1&&m(0,"fa-icon",3),o&2){let n=_(2);s(n.SYNC_TRANSFER_SIDE_CLASS[n.SYNC_TRANSFER_SIDE.REMOTE]),P("ms-1",n.syncPath.settings.mode===n.SYNC_PATH_MODE.BOTH),a("icon",n.SYNC_TRANSFER_SIDE_ICON[n.SYNC_TRANSFER_SIDE.REMOTE])}}function me(o,p){if(o&1&&C(0,de,1,2,"fa-icon",1)(1,pe,1,5,"fa-icon",4),o&2){let n=_();f(n.small?0:1)}}var oe=(()=>{let p=class p{constructor(){this.small=!1,this.SYNC_PATH_MODE=D,this.SYNC_TRANSFER_SIDE_ICON=ae,this.icons={faLongArrowAltDown:N,faLongArrowAltUp:T},this.SYNC_TRANSFER_SIDE=ie,this.SYNC_TRANSFER_SIDE_CLASS=ne}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-direction-icon"]],inputs:{syncPath:"syncPath",small:"small"},decls:3,vars:2,consts:[[1,"d-flex","justify-content-center"],[3,"icon","fixedWidth"],[3,"icon","class"],[3,"icon"],[3,"icon","ms-1","class"]],template:function(S,e){S&1&&(i(0,"span",0),C(1,re,2,1),C(2,me,2,1),l()),S&2&&(t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.DOWNLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?1:-1),t(),f(e.syncPath.settings.mode===e.SYNC_PATH_MODE.UPLOAD||e.syncPath.settings.mode===e.SYNC_PATH_MODE.BOTH?2:-1))},dependencies:[v],encapsulation:2});let o=p;return o})();function _e(o,p){if(o&1&&(i(0,"div")(1,"div"),m(2,"fa-icon",0),i(3,"span",1),r(4,"Client"),l()(),i(5,"div",10)(6,"span",11),r(7),l()()(),i(8,"div")(9,"div"),m(10,"fa-icon",0),i(11,"span",1),r(12,"Server"),l()(),i(13,"div",10)(14,"span",11)(15,"div",12),m(16,"fa-icon",13),r(17),l()()()()),o&2){let n=_();s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.CLIENT),t(5),M(n.syncPath.settings.localPath),t(),s(d("d-flex justify-content-",n.direction," align-items-center mb-2")),t(),s(d("col-",n.colSize[n.size][0])),t(),a("icon",n.icons.SERVER),t(6),a("icon",n.syncPath.icon),t(),R(" ",n.syncPath.showedPath," ")}}function Se(o,p){if(o&1&&(i(0,"span",4),m(1,"fa-icon",14),L(2,"translate"),l()),o&2){let n=_();t(),a("icon",n.icons.faExclamationCircle)("tooltip",Y(2,2,"You must have permission to modify the server folder to choose a different sync mode",n.locale.language))}}var Le=(()=>{let p=class p{constructor(){this.direction="center",this.showPaths=!1,this.size="small",this.locale=O(j),this.icons={CLIENT:I.CLIENT,SERVER:I.SERVER,faExclamationCircle:X,faLongArrowAltDown:N,faLongArrowAltUp:T,faGauge:J,faClock:Q,faRotate:x,faEdit:K,faBug:Z},this.colSize={small:[2,5],large:[3,6]},this.SYNC_PATH_CONFLICT_MODE=ee,this.SYNC_PATH_MODE=D,this.SYNC_PATH_DIFF_MODE=$,this.SYNC_PATH_SCHEDULER_UNIT=te}};p.\u0275fac=function(S){return new(S||p)},p.\u0275cmp=u({type:p,selectors:[["app-sync-path-settings"]],inputs:{syncPath:"syncPath",direction:"direction",showPaths:"showPaths",size:"size"},decls:74,vars:98,consts:[[3,"icon"],["l10nTranslate","",1,"ms-2"],["type","text",3,"ngModelChange","ngModel"],[3,"syncPath","small"],[1,"ms-2","fs-lg","cursor-pointer"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel"],["l10nTranslate","",3,"disabled","ngValue"],["l10nTranslate","",3,"ngValue"],[1,"form-select","form-select-sm",3,"ngModelChange","ngModel","disabled"],["min","1","type","number",1,"form-control","form-select-sm","pe-1","me-2",2,"width","70px",3,"ngModelChange","ngModel","disabled"],[1,"col-8"],[1,"form-control-sm","form-control-plaintext"],[1,"d-flex","align-items-center"],[1,"me-1",3,"icon"],[1,"text-warning",3,"icon","tooltip"]],template:function(S,e){S&1&&(i(0,"div"),C(1,_e,18,17),i(2,"div")(3,"div"),m(4,"fa-icon",0),i(5,"span",1),r(6,"Name"),l()(),i(7,"div")(8,"input",2),h("ngModelChange",function(c){return y(e.syncPath.settings.name,c)||(e.syncPath.settings.name=c),c}),l()()(),i(9,"div")(10,"div"),m(11,"app-sync-path-direction-icon",3),i(12,"span",1),r(13,"Direction"),l(),C(14,Se,3,5,"span",4),l(),i(15,"div")(16,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.mode,c)||(e.syncPath.settings.mode=c),c}),i(17,"option",6),r(18,"upload only"),l(),i(19,"option",7),r(20,"download only"),l(),i(21,"option",6),r(22,"both"),l()()()(),i(23,"div")(24,"div"),m(25,"fa-icon",0),i(26,"span",1),r(27,"Conflict"),l()(),i(28,"div")(29,"select",8),h("ngModelChange",function(c){return y(e.syncPath.settings.conflictMode,c)||(e.syncPath.settings.conflictMode=c),c}),i(30,"option",7),r(31,"the client\u2019s files take precedence"),l(),i(32,"option",7),r(33,"the server\u2019s files take precedence"),l(),i(34,"option",7),r(35,"the most recent files will be kept"),l()()()(),i(36,"div")(37,"div"),m(38,"fa-icon",0),i(39,"span",1),r(40,"Mode"),l()(),i(41,"div")(42,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.diffMode,c)||(e.syncPath.settings.diffMode=c),c}),i(43,"option",7),r(44),l(),i(45,"option",7),r(46),l()()()(),i(47,"div")(48,"div"),m(49,"fa-icon",0),i(50,"span",1),r(51,"Scheduler"),l()(),i(52,"div")(53,"input",9),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.value,c)||(e.syncPath.settings.scheduler.value=c),c}),l(),i(54,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.scheduler.unit,c)||(e.syncPath.settings.scheduler.unit=c),c}),i(55,"option",7),r(56,"disabled"),l(),i(57,"option",7),r(58,"scheduler_unit_minute"),l(),i(59,"option",7),r(60,"scheduler_unit_hour"),l(),i(61,"option",7),r(62,"scheduler_unit_day"),l()()()(),i(63,"div")(64,"div"),m(65,"fa-icon",0),i(66,"span",1),r(67,"Status"),l()(),i(68,"div")(69,"select",5),h("ngModelChange",function(c){return y(e.syncPath.settings.enabled,c)||(e.syncPath.settings.enabled=c),c}),i(70,"option",7),r(71,"enabled"),l(),i(72,"option",7),r(73,"disabled"),l()()()()()),S&2&&(s(d("d-flex flex-column justify-content-",e.direction)),t(),f(e.showPaths?1:-1),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faEdit),t(3),s(d("col-",e.colSize[e.size][1])),t(),s(d("form-control form-select-sm ",e.syncPath.settings.name?"":"is-invalid")),g("ngModel",e.syncPath.settings.name),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("d-flex align-items-center col-",e.colSize[e.size][0])),t(),a("syncPath",e.syncPath)("small",!0),t(3),f(e.syncPath.isWriteable?-1:14),t(),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.mode),t(),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.UPLOAD),t(2),a("ngValue",e.SYNC_PATH_MODE.DOWNLOAD),t(2),a("disabled",!e.syncPath.isWriteable)("ngValue",e.SYNC_PATH_MODE.BOTH),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faBug),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.conflictMode),a("disabled",e.syncPath.settings.mode!=="both"),t(),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.LOCAL),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.REMOTE),t(2),a("ngValue",e.SYNC_PATH_CONFLICT_MODE.RECENT),t(2),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faGauge),t(3),s(d("col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.diffMode),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.FAST),t(),M(e.SYNC_PATH_DIFF_MODE.FAST),t(),a("ngValue",e.SYNC_PATH_DIFF_MODE.SECURE),t(),M(e.SYNC_PATH_DIFF_MODE.SECURE),t(),s(d("d-flex justify-content-",e.direction," align-items-center mb-2")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faClock),t(3),s(d("d-flex flex-row col-",e.colSize[e.size][1])),t(),g("ngModel",e.syncPath.settings.scheduler.value),a("disabled",e.syncPath.settings.scheduler.unit===e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(),g("ngModel",e.syncPath.settings.scheduler.unit),t(),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DISABLED),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.MINUTE),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.HOUR),t(2),a("ngValue",e.SYNC_PATH_SCHEDULER_UNIT.DAY),t(2),s(d("d-flex justify-content-",e.direction," align-items-center")),t(),s(d("col-",e.colSize[e.size][0])),t(),a("icon",e.icons.faRotate),t(3),s(d("col-",e.colSize[e.size][1])),t(),P("text-danger",!e.syncPath.settings.enabled),g("ngModel",e.syncPath.settings.enabled),t(),a("ngValue",!0),t(2),a("ngValue",!1))},dependencies:[G,v,B,W,U,H,z,b,w,V,F,q,oe,k],encapsulation:2});let o=p;return o})();export{oe as a,Le as b};