hfs 3.2.0-alpha1.1 → 3.2.0-beta2

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 (174) hide show
  1. package/admin/assets/{af-RjyQ-neT.js → af-DWEYq388.js} +1 -1
  2. package/admin/assets/{am-PptHpglb.js → am-DgLbAgj6.js} +1 -1
  3. package/admin/assets/{ar-Du3syDxa.js → ar-DgEWkO74.js} +1 -1
  4. package/admin/assets/{ar-dz-CiziRh1x.js → ar-dz-DHq--Sr8.js} +1 -1
  5. package/admin/assets/{ar-iq-hCKg0CRP.js → ar-iq-D1r3nsb9.js} +1 -1
  6. package/admin/assets/{ar-kw-COYePt-p.js → ar-kw-C85fGHwp.js} +1 -1
  7. package/admin/assets/{ar-ly-CY5yETqb.js → ar-ly-Bq6pjGjs.js} +1 -1
  8. package/admin/assets/{ar-ma-DczXi97r.js → ar-ma-SGvmh6Mj.js} +1 -1
  9. package/admin/assets/{ar-sa-Bu7sTKzl.js → ar-sa-Bv8hiFi6.js} +1 -1
  10. package/admin/assets/{ar-tn-BrG0r6qZ.js → ar-tn-Bdvo77v3.js} +1 -1
  11. package/admin/assets/{az-DYRCrdk0.js → az-7fPndoov.js} +1 -1
  12. package/admin/assets/{be-DObSs5HX.js → be-wjXeIeAK.js} +1 -1
  13. package/admin/assets/{bg-BDBkMe50.js → bg-DZwBvjzH.js} +1 -1
  14. package/admin/assets/{bi-CApXFwc6.js → bi-qCtxvMhO.js} +1 -1
  15. package/admin/assets/{bm-CjxCV8Lr.js → bm-BVPWvreb.js} +1 -1
  16. package/admin/assets/{bn-DzWZbDi3.js → bn-CdWvye7d.js} +1 -1
  17. package/admin/assets/{bn-bd-ijdPRJbb.js → bn-bd-B5-3blmz.js} +1 -1
  18. package/admin/assets/{bo-BDDfj5XH.js → bo-BEVcgyN2.js} +1 -1
  19. package/admin/assets/{br-DRHEjait.js → br-DGQD6fFs.js} +1 -1
  20. package/admin/assets/{bs-B0Zv2Agm.js → bs-So4MoRua.js} +1 -1
  21. package/admin/assets/{ca-DuZAUqU_.js → ca-Bk5ytG4g.js} +1 -1
  22. package/admin/assets/{cs-DVkylosR.js → cs-C4NU8eW-.js} +1 -1
  23. package/admin/assets/{cv-8Is1Fns9.js → cv-Ct-s-zrW.js} +1 -1
  24. package/admin/assets/{cy-Bk30Or_y.js → cy-ojtDPj8_.js} +1 -1
  25. package/admin/assets/{da-C41DIdZK.js → da-CYGin6vm.js} +1 -1
  26. package/admin/assets/{de--qvLJgIE.js → de-BEbJ01zH.js} +1 -1
  27. package/admin/assets/{de-at-D5vCBlsw.js → de-at-C7UwE1rJ.js} +1 -1
  28. package/admin/assets/{de-ch-Oh2cO23c.js → de-ch-CsZ7YQc_.js} +1 -1
  29. package/admin/assets/{dv-4ZO2KNbw.js → dv-DaVliwLd.js} +1 -1
  30. package/admin/assets/{el-CobOUqyu.js → el-DM_KqKEP.js} +1 -1
  31. package/admin/assets/{en-C9afClpS.js → en-DedtOfaf.js} +1 -1
  32. package/admin/assets/{en-au-C_QMghEl.js → en-au-52Bzk5D9.js} +1 -1
  33. package/admin/assets/{en-ca-C80KILwc.js → en-ca-3pzEPK2N.js} +1 -1
  34. package/admin/assets/{en-gb-BwQ0asAI.js → en-gb-BrwDQS2G.js} +1 -1
  35. package/admin/assets/{en-ie-ConCcQkq.js → en-ie-BUXSHrkL.js} +1 -1
  36. package/admin/assets/{en-il-CAOzD4DD.js → en-il-a22drDCn.js} +1 -1
  37. package/admin/assets/{en-in-87gardaO.js → en-in-BUjecjkp.js} +1 -1
  38. package/admin/assets/{en-nz-uMTjgkDP.js → en-nz-Bbo7tnB_.js} +1 -1
  39. package/admin/assets/{en-sg-BlbiLv4L.js → en-sg-CZVDddmd.js} +1 -1
  40. package/admin/assets/{en-tt-BXXmBax2.js → en-tt-DmSGwRia.js} +1 -1
  41. package/admin/assets/{eo-BBL7o-0W.js → eo-B71nkHZU.js} +1 -1
  42. package/admin/assets/{es-DuNej-79.js → es-Dk6VCuuk.js} +1 -1
  43. package/admin/assets/{es-do-bZWKFwTE.js → es-do-DMErY8ol.js} +1 -1
  44. package/admin/assets/{es-mx-C2Lfb86F.js → es-mx-BMRmqa3u.js} +1 -1
  45. package/admin/assets/{es-pr-wU3Du8m-.js → es-pr-CtBQz48p.js} +1 -1
  46. package/admin/assets/{es-us-qcU-zRiw.js → es-us-CrDl5pnO.js} +1 -1
  47. package/admin/assets/{et-B-4PjN_n.js → et-CO9OHqio.js} +1 -1
  48. package/admin/assets/{eu-D0pNDZ9i.js → eu-Bip44atW.js} +1 -1
  49. package/admin/assets/{fa-R_zmYBGc.js → fa-CHbJ_dTM.js} +1 -1
  50. package/admin/assets/{fi-CWYS_0Hg.js → fi-DKfoLmaQ.js} +1 -1
  51. package/admin/assets/{fo-aJYpcnWS.js → fo-DG1kOEfw.js} +1 -1
  52. package/admin/assets/{fr-BHFrWfwB.js → fr-DV73GZR4.js} +1 -1
  53. package/admin/assets/{fr-ca-ihwmO47n.js → fr-ca-BK-RoZiC.js} +1 -1
  54. package/admin/assets/{fr-ch-Cb8XbRfE.js → fr-ch-DjqEC5E_.js} +1 -1
  55. package/admin/assets/{fy-DT9BUc6t.js → fy-znrRQdeC.js} +1 -1
  56. package/admin/assets/{ga-B8p4naXJ.js → ga-BlZeKu0N.js} +1 -1
  57. package/admin/assets/{gd-Dzrl6rPc.js → gd-BmrycMnC.js} +1 -1
  58. package/admin/assets/{gl-bN2tXl9d.js → gl-CuT8e5mi.js} +1 -1
  59. package/admin/assets/{gom-latn-DUK8PgIJ.js → gom-latn-BSWVd0A6.js} +1 -1
  60. package/admin/assets/{gu-CxAIP8fw.js → gu-BHK6LfvD.js} +1 -1
  61. package/admin/assets/{he-Bm9XJVAj.js → he-DPoTUevR.js} +1 -1
  62. package/admin/assets/{hi-CHik9Qxx.js → hi-BRuLafoW.js} +1 -1
  63. package/admin/assets/{hr-Dn57_dqN.js → hr-Bzge-10P.js} +1 -1
  64. package/admin/assets/{ht-BRS-FrJq.js → ht-Ck9BCna1.js} +1 -1
  65. package/admin/assets/{hu-hVaGcZ-U.js → hu-CzqqbYmU.js} +1 -1
  66. package/admin/assets/{hy-am-heLxXhpz.js → hy-am-C-eV4E8v.js} +1 -1
  67. package/admin/assets/{id-B6AkO4h8.js → id-Dv8GZQvB.js} +1 -1
  68. package/admin/assets/{index-Buyl8rI8.js → index-BPIX0qPj.js} +1 -1
  69. package/admin/assets/index-D3HviM6x.js +889 -0
  70. package/admin/assets/{is-BUADPoni.js → is-CK6VY3M_.js} +1 -1
  71. package/admin/assets/{it-Ce3gssOP.js → it-1gtki4a5.js} +1 -1
  72. package/admin/assets/{it-ch-CJzj2czr.js → it-ch-C0Mj3-pC.js} +1 -1
  73. package/admin/assets/{ja-DykMIu-9.js → ja-Dl3AfnM1.js} +1 -1
  74. package/admin/assets/{jv-Cum6DLwa.js → jv-CznX-tGV.js} +1 -1
  75. package/admin/assets/{ka-foCPVFxw.js → ka-BNjZxCug.js} +1 -1
  76. package/admin/assets/{kk-CMNu1ysC.js → kk-80J_xldf.js} +1 -1
  77. package/admin/assets/{km-BfMisGaD.js → km-CuWChDRB.js} +1 -1
  78. package/admin/assets/{kn-R_9S5KJz.js → kn-BZp_PBdl.js} +1 -1
  79. package/admin/assets/{ko-DYRND-mM.js → ko-RirpyUl_.js} +1 -1
  80. package/admin/assets/{ku-CNZ_weGy.js → ku-Dz8ACD5w.js} +1 -1
  81. package/admin/assets/{ky-BhTAWL4I.js → ky-BN3ylOhj.js} +1 -1
  82. package/admin/assets/{lb-CxWhQxwF.js → lb-D7h_YoEn.js} +1 -1
  83. package/admin/assets/{lo-DBL_XLkE.js → lo-BrlbTUPD.js} +1 -1
  84. package/admin/assets/{lt-BakZVm4p.js → lt-cXuHFdTa.js} +1 -1
  85. package/admin/assets/{lv-CCn-slXG.js → lv-CjIpv13Q.js} +1 -1
  86. package/admin/assets/{me-xPEA4qjE.js → me-B-jTh39Z.js} +1 -1
  87. package/admin/assets/{mi-6cCs2Mzx.js → mi-D06xdVmt.js} +1 -1
  88. package/admin/assets/{mk-CwWbHJPS.js → mk-iLbuxyOf.js} +1 -1
  89. package/admin/assets/{ml-Dp7Ab1SV.js → ml-2W0y6Zb2.js} +1 -1
  90. package/admin/assets/{mn-ClotGWAe.js → mn-6zbvKjeb.js} +1 -1
  91. package/admin/assets/{mr-GiM-paTF.js → mr-7-jrgLyw.js} +1 -1
  92. package/admin/assets/{ms-BiZ1_eVR.js → ms-CRH6rEXt.js} +1 -1
  93. package/admin/assets/{ms-my-oevI0fOH.js → ms-my-BIJmu2S-.js} +1 -1
  94. package/admin/assets/{mt-BaIHeOl1.js → mt-CbXmxK-D.js} +1 -1
  95. package/admin/assets/{my-Cg5Fc_1j.js → my-BvMUsxU8.js} +1 -1
  96. package/admin/assets/{nb-ZPODjT6R.js → nb-DvKHgF7L.js} +1 -1
  97. package/admin/assets/{ne-C0ti-ZX2.js → ne-DiZZ3Lm6.js} +1 -1
  98. package/admin/assets/{nl-be-VPC0QyaW.js → nl-be-Dy7PYRbC.js} +1 -1
  99. package/admin/assets/{nl-DP2PkkGx.js → nl-t_2A_VAT.js} +1 -1
  100. package/admin/assets/{nn-NLidKyJd.js → nn-Cw7EwosO.js} +1 -1
  101. package/admin/assets/{oc-lnc-Ddj9_PnD.js → oc-lnc-CuFfB75K.js} +1 -1
  102. package/admin/assets/{pa-in-DSAWffhb.js → pa-in-DOFyZ-Ft.js} +1 -1
  103. package/admin/assets/{pl-Yojex5aS.js → pl-BD7FyCJj.js} +1 -1
  104. package/admin/assets/{pt-BQMs2la2.js → pt-DSKLLE_u.js} +1 -1
  105. package/admin/assets/{pt-br-DVeeNZu8.js → pt-br-BhL4gb5Z.js} +1 -1
  106. package/admin/assets/{rn-CKkTrK3f.js → rn-DoHoZZPd.js} +1 -1
  107. package/admin/assets/{ro-BbgGULSZ.js → ro-B0v-_lH0.js} +1 -1
  108. package/admin/assets/{ru-mAZX3DTa.js → ru-BMVOk5eA.js} +1 -1
  109. package/admin/assets/{rw-CYErOxKd.js → rw-CWF0w6eL.js} +1 -1
  110. package/admin/assets/{sd-kfPTqkSy.js → sd-DO2rrjch.js} +1 -1
  111. package/admin/assets/{se-D0bN3rDS.js → se-CAolO9WQ.js} +1 -1
  112. package/admin/assets/{sha512-99nhg44S.js → sha512-ZlUYj4Hr.js} +1 -1
  113. package/admin/assets/{si-COjb_4Hy.js → si-D03dHfb5.js} +1 -1
  114. package/admin/assets/{sk-Co95XNOo.js → sk-_GcZGaN3.js} +1 -1
  115. package/admin/assets/{sl-DUXa5wTF.js → sl-Cb1lUGab.js} +1 -1
  116. package/admin/assets/{sq-B-KU0nWK.js → sq-Czzt23Tr.js} +1 -1
  117. package/admin/assets/{sr-Cb_b-zPG.js → sr-D76dVqKJ.js} +1 -1
  118. package/admin/assets/{sr-cyrl-csuTDIB6.js → sr-cyrl-CuoFbJjW.js} +1 -1
  119. package/admin/assets/{ss-BDnE-cG6.js → ss-g-fGaM29.js} +1 -1
  120. package/admin/assets/{sv-CzWdOHcE.js → sv-CZxc8I45.js} +1 -1
  121. package/admin/assets/{sv-fi-IK8oi5nB.js → sv-fi-D8REJeLz.js} +1 -1
  122. package/admin/assets/{sw-fPHo5hof.js → sw-B1n3PjWG.js} +1 -1
  123. package/admin/assets/{ta-TteN0nyU.js → ta-K5mexJNT.js} +1 -1
  124. package/admin/assets/{te-2gsQb1fF.js → te-DT6dj5B6.js} +1 -1
  125. package/admin/assets/{tet-ClTpDYJv.js → tet-DXwYNm_H.js} +1 -1
  126. package/admin/assets/{tg-Bel7Uc6z.js → tg-BCcZKcE2.js} +1 -1
  127. package/admin/assets/{th-pDQttM9V.js → th-CeeeseFX.js} +1 -1
  128. package/admin/assets/{tk-CxoKYZH6.js → tk-CJ6KW44d.js} +1 -1
  129. package/admin/assets/{tl-ph-D9htRcOQ.js → tl-ph-DzE8lDmm.js} +1 -1
  130. package/admin/assets/{tlh-7UqvDBxU.js → tlh-ER6KiMxG.js} +1 -1
  131. package/admin/assets/{tr-NjJrq1iC.js → tr-D48NGNpr.js} +1 -1
  132. package/admin/assets/{tzl-CzGaXn8M.js → tzl-5AsmDTYM.js} +1 -1
  133. package/admin/assets/{tzm-BiuscZFr.js → tzm-2AzZ1YPf.js} +1 -1
  134. package/admin/assets/{tzm-latn-IeWkCgWf.js → tzm-latn-Cd5hPQuT.js} +1 -1
  135. package/admin/assets/{ug-cn-5LK64x5v.js → ug-cn-DU-MZ9Vx.js} +1 -1
  136. package/admin/assets/{uk-CzacUaQe.js → uk-hn6vcOkn.js} +1 -1
  137. package/admin/assets/{ur-BRV7z4Gu.js → ur-jOObtqB6.js} +1 -1
  138. package/admin/assets/{uz-C4G77QOI.js → uz-BlftYfHF.js} +1 -1
  139. package/admin/assets/{uz-latn-CQFrzZ6F.js → uz-latn-BpuI0ccM.js} +1 -1
  140. package/admin/assets/{vi-DEFXdlJi.js → vi-DVo3LusT.js} +1 -1
  141. package/admin/assets/{x-pseudo-sWj5RKxR.js → x-pseudo-BuVzNhqi.js} +1 -1
  142. package/admin/assets/{yo-CBDjk96e.js → yo-BvWGwb4m.js} +1 -1
  143. package/admin/assets/{zh-CQtX_fkD.js → zh-D9-tfba1.js} +1 -1
  144. package/admin/assets/{zh-cn-D6dF0jKM.js → zh-cn-CFL5sbIW.js} +1 -1
  145. package/admin/assets/{zh-hk-DY-Jaqdg.js → zh-hk-DRP8u65r.js} +1 -1
  146. package/admin/assets/{zh-tw-BdmVby0R.js → zh-tw-CtVs1ihI.js} +1 -1
  147. package/admin/index.html +1 -1
  148. package/frontend/assets/index-legacy-D3BTBYs5.js +9 -0
  149. package/frontend/assets/{index-legacy-CQovmh_0.js → index-legacy-DcrWtKxQ.js} +1 -1
  150. package/frontend/assets/{sha512-legacy-CXU3efCO.js → sha512-legacy-DJvEwScE.js} +1 -1
  151. package/frontend/index.html +1 -1
  152. package/npm-shrinkwrap.json +66 -22
  153. package/package.json +2 -2
  154. package/src/api.get_file_list.js +2 -2
  155. package/src/basicWeb.js +1 -1
  156. package/src/comments.js +7 -4
  157. package/src/const.js +1 -1
  158. package/src/cross.js +12 -6
  159. package/src/events.js +2 -3
  160. package/src/expiringCache.js +8 -7
  161. package/src/frontEndApis.js +17 -14
  162. package/src/listen.js +2 -1
  163. package/src/nat.js +4 -1
  164. package/src/roots.js +1 -1
  165. package/src/selfCheck.js +2 -1
  166. package/src/serveGuiAndSharedFiles.js +17 -7
  167. package/src/serveGuiFiles.js +1 -1
  168. package/src/update.js +1 -3
  169. package/src/util-files.js +9 -4
  170. package/src/util-http.js +2 -0
  171. package/src/vfs.js +20 -8
  172. package/src/zip.js +1 -1
  173. package/admin/assets/index-WXxQwyJV.js +0 -889
  174. package/frontend/assets/index-legacy-BtoTkZho.js +0 -9
@@ -6,24 +6,25 @@ function expiringCache(ttlMs) {
6
6
  throw Error('invalid TTL');
7
7
  const o = new Map();
8
8
  return Object.assign(o, {
9
- // creator can return undefined if the value should not be cached. `invalidate` is useful in case you have some custom logic for it, other than ttl.
9
+ invalidate,
10
+ // creator can return undefined if the value should not be cached
10
11
  try(k, creator) {
11
12
  let ret = o.get(k);
12
13
  if (ret === undefined) { // undefined = missing, as we don't accept this value in our cache
13
- ret = creator(invalidate);
14
+ ret = creator(k);
14
15
  if (ret !== undefined) {
15
16
  o.set(k, ret);
16
17
  Promise.resolve(ret).then(v => {
17
18
  if (v === undefined) // even in a promise, we'll consider undefined as a request to cancel the caching
18
- invalidate();
19
+ invalidate(k);
19
20
  }, () => { }) // avoid js warning
20
- .finally(() => setTimeout(invalidate, ttlMs)); // wait for async (in case) before starting the timer
21
- }
22
- function invalidate() {
23
- o.delete(k);
21
+ .finally(() => setTimeout(() => invalidate(k), ttlMs)); // wait for async (in case) before starting the timer
24
22
  }
25
23
  }
26
24
  return ret;
27
25
  },
28
26
  });
27
+ function invalidate(k) {
28
+ o.delete(k);
29
+ }
29
30
  }
@@ -20,11 +20,13 @@ const promises_1 = require("fs/promises");
20
20
  const path_1 = require("path");
21
21
  const upload_1 = require("./upload");
22
22
  const misc_1 = require("./misc");
23
+ const config_1 = require("./config");
23
24
  const comments_1 = require("./comments");
24
25
  const SendList_1 = require("./SendList");
25
26
  const adminApis_1 = require("./adminApis");
26
27
  const lodash_1 = __importDefault(require("lodash"));
27
28
  const partialFolderSize = {};
29
+ const showUploader = (0, config_1.defineConfig)(misc_1.CFG.show_uploader, misc_1.WHO_ADMIN);
28
30
  exports.frontEndApis = {
29
31
  get_file_list: api_get_file_list_1.get_file_list,
30
32
  ...api_auth_1.authApis,
@@ -43,19 +45,20 @@ exports.frontEndApis = {
43
45
  return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'bad uris');
44
46
  const isAdmin = (0, adminApis_1.ctxAdminAccess)(ctx);
45
47
  return {
46
- details: await Promise.all(uris.map(async (uri) => {
47
- if (typeof uri !== 'string')
48
- return false; // false means error
49
- const node = await (0, vfs_1.urlToNode)(uri, ctx);
50
- if (!node || !(0, vfs_1.hasPermission)(node, 'can_see', ctx))
51
- return false;
52
- let upload = node.source && await (0, upload_1.getUploadMeta)(node.source).catch(() => undefined);
53
- if (!upload)
54
- return;
55
- if (!isAdmin)
56
- upload = lodash_1.default.omit(upload, 'ip');
57
- return { upload };
58
- }))
48
+ details: (0, vfs_1.simpleWhoToError)(showUploader.get(), ctx) ? [] // return early because at the moment we only have the uploader
49
+ : await Promise.all(uris.map(async (uri) => {
50
+ if (typeof uri !== 'string')
51
+ return false; // false means error
52
+ const node = await (0, vfs_1.urlToNode)(uri, ctx);
53
+ if (!node || !(0, vfs_1.hasPermission)(node, 'can_see', ctx))
54
+ return false;
55
+ let upload = node.source && await (0, upload_1.getUploadMeta)(node.source).catch(() => undefined);
56
+ if (!upload)
57
+ return;
58
+ if (!isAdmin)
59
+ upload = lodash_1.default.omit(upload, 'ip');
60
+ return { upload };
61
+ }))
59
62
  };
60
63
  },
61
64
  async create_folder({ uri, name }, ctx) {
@@ -126,7 +129,7 @@ exports.frontEndApis = {
126
129
  await (0, comments_1.setCommentFor)(node.source, comment);
127
130
  return {};
128
131
  },
129
- async get_folder_size_partial({ id }, ctx) {
132
+ async get_folder_size_partial({ id }) {
130
133
  (0, misc_1.apiAssertTypes)({ string: { id } });
131
134
  return partialFolderSize[id] || new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
132
135
  },
package/src/listen.js CHANGED
@@ -298,7 +298,8 @@ function stopServer(srv) {
298
298
  console.debug("Failed to stop server", String(err));
299
299
  resolve(err);
300
300
  });
301
- srv.closeAllConnections();
301
+ if (first_1.quitting)
302
+ srv.closeAllConnections();
302
303
  });
303
304
  }
304
305
  function getCurrentPort(srv) {
package/src/nat.js CHANGED
@@ -76,7 +76,10 @@ exports.getPublicIps = (0, debounceAsync_1.debounceAsync)(async () => {
76
76
  throw "no good";
77
77
  return validIps;
78
78
  }))));
79
- return exports.defaultBaseUrl.publicIps = lodash_1.default.uniq(ips.flat());
79
+ const ret = exports.defaultBaseUrl.publicIps = lodash_1.default.uniq(ips.flat());
80
+ if (!ret.length) // don't keep empty results for long
81
+ setTimeout(() => exports.getPublicIps.clearRetain(), 5_000);
82
+ return ret;
80
83
  }, { retain: 10 * cross_1.MINUTE });
81
84
  exports.getNatInfo = (0, debounceAsync_1.debounceAsync)(async () => {
82
85
  const upnp = await exports.upnpEnabled.getWhenReady() ? getUpnpClient() : null;
package/src/roots.js CHANGED
@@ -32,7 +32,7 @@ const rootsMiddleware = (ctx, next) => (() => {
32
32
  }
33
33
  if (lodash_1.default.isEmpty(exports.roots.get()))
34
34
  return;
35
- const root = ctx.state.root = exports.roots.compiled()?.(ctx.host);
35
+ const root = ctx.state.root = exports.roots.compiled()(ctx.host);
36
36
  if (!ctx.state.skipFilters && forceAddress.get()
37
37
  && root === undefined && !(0, misc_1.isLocalHost)(ctx) && ctx.host !== listen_1.baseUrl.compiled())
38
38
  return (0, connections_1.disconnect)(ctx, forceAddress.key()); // returning truthy will not call next
package/src/selfCheck.js CHANGED
@@ -38,7 +38,8 @@ async function selfCheck(url) {
38
38
  console.debug(svc);
39
39
  body = applySymbols(body);
40
40
  serviceUrl = applySymbols(serviceUrl);
41
- const res = await (0, cross_1.haveTimeout)(6_000, (0, util_http_1.httpString)(serviceUrl, { family, ...rest, body }));
41
+ const timeout = 8_000;
42
+ const res = await (0, cross_1.haveTimeout)(timeout, (0, util_http_1.httpString)(serviceUrl, { family, timeout, ...rest, body }));
42
43
  const success = new RegExp(regexpSuccess).test(res);
43
44
  const failure = new RegExp(regexpFailure).test(res);
44
45
  if (success === failure)
@@ -28,6 +28,7 @@ const comments_1 = require("./comments");
28
28
  const basicWeb_1 = require("./basicWeb");
29
29
  const icons_1 = require("./icons");
30
30
  const plugins_1 = require("./plugins");
31
+ const roots_1 = require("./roots");
31
32
  const serveFrontendFiles = (0, serveGuiFiles_1.serveGuiFiles)(process.env.FRONTEND_PROXY, cross_const_1.FRONTEND_URI);
32
33
  const serveFrontendPrefixed = (0, koa_mount_1.default)(cross_const_1.FRONTEND_URI.slice(0, -1), serveFrontendFiles);
33
34
  const serveAdminFiles = (0, serveGuiFiles_1.serveGuiFiles)(process.env.ADMIN_PROXY, cross_const_1.ADMIN_URI);
@@ -119,11 +120,10 @@ const serveSharedFiles = async (ctx, next) => {
119
120
  return ctx.status = cross_const_1.HTTP_SERVER_ERROR;
120
121
  }
121
122
  }
122
- if (node.default && path.endsWith('/') && !get) { // final/ needed on browser to make resource urls correctly with html pages
123
- const found = await (0, vfs_1.urlToNode)(node.default, ctx, node);
124
- if (found && /\.html?/i.test(node.default))
123
+ if (path.endsWith('/') && !get) { // final slash needed on browsers to make resource urls working with html pages
124
+ const found = await (0, vfs_1.getDefaultFile)(node, ctx);
125
+ if (found && /\.html?/i.test((0, vfs_1.getNodeName)(node = found)))
125
126
  ctx.state.considerAsGui = true;
126
- node = found ?? node;
127
127
  }
128
128
  if (get === 'icon')
129
129
  return (0, serveFile_1.serveFile)(ctx, node.icon || '|'); // pipe to cause not-found
@@ -160,9 +160,19 @@ async function sendFolderList(node, ctx) {
160
160
  ctx.type = 'text';
161
161
  if (prepend === undefined || prepend === '*') { // * = force auto-detection even if we have baseUrl set
162
162
  const { URL } = ctx;
163
- const base = prepend === undefined && listen_1.baseUrl.get()
164
- || URL.protocol + '//' + URL.host + ctx.state.revProxyPath;
165
- prepend = base + (0, misc_1.pathEncode)(decodeURI(ctx.path)); // redo the encoding our way, keeping unicode chars unchanged
163
+ const requestBase = URL.protocol + '//' + URL.host + ctx.state.revProxyPath;
164
+ const configuredBaseUrl = prepend === undefined && listen_1.baseUrl.get();
165
+ const configuredRoot = configuredBaseUrl && roots_1.roots.compiled()(listen_1.baseUrl.compiled() || '');
166
+ const pathInConfiguredRoot = configuredRoot && (configuredRoot === '/' ? ctx.path
167
+ : ctx.path.startsWith(configuredRoot) ? ctx.path.slice(configuredRoot.length - 1)
168
+ : ctx.path === configuredRoot.slice(0, -1) ? '/'
169
+ : false);
170
+ // base_url may expose a host-rooted home; use it only for VFS paths inside that host root
171
+ const [base, path] = !configuredBaseUrl ? [requestBase, ctx.path]
172
+ : pathInConfiguredRoot === false ? [requestBase, ctx.path]
173
+ : [configuredBaseUrl, pathInConfiguredRoot || ctx.path];
174
+ // redo the encoding our way, keeping unicode chars unchanged. decode each segment separately because decodeURI preserves reserved escapes like %3A, which pathEncode would double-encode
175
+ prepend = base + (0, misc_1.pathDecodeSegments)(path, misc_1.pathEncode);
166
176
  }
167
177
  const walker = (0, vfs_1.walkNode)(node, { ctx, depth: depth === '*' ? Infinity : Number(depth), parallelizeRecursion: false }); // parallelization produces out-of-order results, and we don't want it like that here
168
178
  ctx.body = (0, misc_1.asyncGeneratorToReadable)((0, misc_1.filterMapGenerator)(walker, async (el) => {
@@ -39,7 +39,7 @@ function serveStatic(uri) {
39
39
  return ctx.status = const_1.HTTP_METHOD_NOT_ALLOWED;
40
40
  const serveApp = shouldServeApp(ctx);
41
41
  const fullPath = (0, path_1.join)(__dirname, '..', folder, serveApp ? '/index.html' : ctx.path);
42
- const content = await (0, misc_1.parseFile)(fullPath, raw => serveApp || !raw.length ? raw : adjustBundlerLinks(ctx, uri, raw))
42
+ const content = await (0, misc_1.parseFile)(fullPath, raw => serveApp || !raw.length ? raw : adjustBundlerLinks(ctx, uri, raw), 1000)
43
43
  .catch(e => {
44
44
  if (e?.code !== 'ENOENT') // not supposed to happen, and yet a user reported a strange behavior
45
45
  console.error(`serveStatic/parseFile: ${String(e)}`);
package/src/update.js CHANGED
@@ -128,9 +128,7 @@ async function update(tagOrUrl = '') {
128
128
  throw "No update has been found";
129
129
  const plat = '-' + (0, misc_1.xlate)(process.platform, { win32: 'windows', darwin: 'mac' });
130
130
  const assetSearch = `${plat}-${process.arch}`;
131
- const legacyAssetSearch = `${plat}${(0, misc_1.prefix)('-', (0, misc_1.xlate)(process.arch, { x64: '', arm64: 'arm' }))}.zip`; // legacy pre-0.53.0-rc16
132
- const asset = update.assets.find((x) => x.name.includes(assetSearch) && x.name.endsWith('.zip'))
133
- || update.assets.find((x) => x.name.endsWith(legacyAssetSearch));
131
+ const asset = update.assets.find((x) => x.name.includes(assetSearch) && x.name.endsWith('.zip'));
134
132
  if (!asset)
135
133
  throw `Asset not found: ${assetSearch}`;
136
134
  url = asset.browser_download_url;
package/src/util-files.js CHANGED
@@ -182,19 +182,24 @@ function exists(path) {
182
182
  }
183
183
  // parse a file, caching unless timestamp has changed
184
184
  exports.parseFileCache = new Map();
185
- async function loadFileCached(path, loader) {
185
+ async function loadFileCached(path, loader, minInterval = 0) {
186
186
  const cached = exports.parseFileCache.get(path);
187
+ const now = Date.now();
188
+ if (cached && now - cached.lastCheck < minInterval)
189
+ return cached.parsed;
187
190
  const ts = await statWithTimeout(path).then(x => x.mtime, e => {
188
191
  if (e?.message !== 'timeout')
189
192
  throw e;
190
193
  return cached?.ts || new Date(0); // on timeout (e.g. thread pool saturated), serve cache if any, or attempt the loader
191
194
  });
195
+ if (cached)
196
+ cached.lastCheck = now;
192
197
  if (cached && Number(ts) === Number(cached.ts))
193
198
  return cached.parsed;
194
199
  const parsed = loader(path);
195
- exports.parseFileCache.set(path, { ts, parsed });
200
+ exports.parseFileCache.set(path, { ts, parsed, lastCheck: now });
196
201
  return parsed;
197
202
  }
198
- async function parseFile(path, parse) {
199
- return loadFileCached(path, () => (0, promises_1.readFile)(path).then(parse));
203
+ async function parseFile(path, parse, skipStatBefore = 0) {
204
+ return loadFileCached(path, () => (0, promises_1.readFile)(path).then(parse), skipStatBefore);
200
205
  }
package/src/util-http.js CHANGED
@@ -137,6 +137,8 @@ function httpStream(url, { body, proxy, jar, noRedirect, httpThrow = true, ...op
137
137
  e.cause ??= req; // enrich the error
138
138
  reject(e);
139
139
  });
140
+ if (options.timeout) // node only emits the timeout event, so destroy the request to unblock callers waiting for the body
141
+ req.setTimeout(options.timeout, () => req.destroy(Object.assign(Error('timeout'), { code: 'ETIMEDOUT' })));
140
142
  if (body && body instanceof node_stream_1.Readable)
141
143
  body.pipe(req).on('end', () => req.end());
142
144
  else
package/src/vfs.js CHANGED
@@ -15,10 +15,11 @@ exports.getNodeByName = getNodeByName;
15
15
  exports.isRoot = isRoot;
16
16
  exports.getNodeName = getNodeName;
17
17
  exports.nodeIsFolder = nodeIsFolder;
18
- exports.hasDefaultFile = hasDefaultFile;
18
+ exports.getDefaultFile = getDefaultFile;
19
19
  exports.nodeIsLink = nodeIsLink;
20
20
  exports.hasPermission = hasPermission;
21
21
  exports.statusCodeForMissingPerm = statusCodeForMissingPerm;
22
+ exports.simpleWhoToError = simpleWhoToError;
22
23
  exports.walkNode = walkNode;
23
24
  exports.masksCouldGivePermission = masksCouldGivePermission;
24
25
  exports.parentMaskApplier = parentMaskApplier;
@@ -35,6 +36,7 @@ const fswin_1 = __importDefault(require("fswin"));
35
36
  const comments_1 = require("./comments");
36
37
  const walkDir_1 = require("./walkDir");
37
38
  const node_stream_1 = require("node:stream");
39
+ const adminApis_1 = require("./adminApis");
38
40
  const showHiddenFiles = (0, config_1.defineConfig)('show_hidden_files', false);
39
41
  function permsFromParent(parent, child) {
40
42
  const ret = {};
@@ -225,7 +227,7 @@ function nodeIsFolder(node) {
225
227
  return undefined;
226
228
  }
227
229
  }
228
- async function hasDefaultFile(node, ctx) {
230
+ async function getDefaultFile(node, ctx) {
229
231
  return node.default && nodeIsFolder(node) && await urlToNode(node.default, ctx, node) || undefined;
230
232
  }
231
233
  function nodeIsLink(node) {
@@ -254,7 +256,7 @@ function statusCodeForMissingPerm(node, perm, ctx, assign = true) {
254
256
  if ((0, misc_1.isWhoObject)(who))
255
257
  who = who.this;
256
258
  who ??= misc_1.defaultPerms[cur];
257
- if (typeof who !== 'string' || who === misc_1.WHO_ANY_ACCOUNT)
259
+ if (typeof who !== 'string' || who === misc_1.WHO_ANY_ACCOUNT || who === misc_1.WHO_ADMIN)
258
260
  break;
259
261
  if (!max--) {
260
262
  console.error(`Endless loop in permission ${perm}=${node[perm] ?? misc_1.defaultPerms[perm]} for ${node.url || getNodeName(node)}`);
@@ -262,19 +264,29 @@ function statusCodeForMissingPerm(node, perm, ctx, assign = true) {
262
264
  }
263
265
  cur = who;
264
266
  } while (1);
267
+ if ((0, misc_1.isWhoObject)(who) || isWhoVfsPerms(who))
268
+ throw Error(`permission type-guard: ${JSON.stringify(who)}`);
265
269
  const eventName = 'checkVfsPermission';
266
270
  if (events_1.default.anyListener(eventName)) {
267
271
  const first = lodash_1.default.max(events_1.default.emit(eventName, { who, node, perm, ctx }));
268
272
  if (first !== undefined)
269
273
  return first;
270
274
  }
271
- if (Array.isArray(who))
272
- return (0, perm_1.ctxBelongsTo)(ctx, who) ? 0 : const_1.HTTP_UNAUTHORIZED;
273
- return typeof who === 'boolean' ? (who ? 0 : const_1.HTTP_FORBIDDEN)
274
- : who === misc_1.WHO_ANY_ACCOUNT ? ((0, auth_1.getCurrentUsername)(ctx) ? 0 : const_1.HTTP_UNAUTHORIZED)
275
- : (0, misc_1.throw_)(Error(`invalid permission: ${perm}=${(0, misc_1.try_)(() => JSON.stringify(who))}`));
275
+ return simpleWhoToError(who, ctx)
276
+ ?? (0, misc_1.throw_)(Error(`invalid permission: ${perm}=${(0, misc_1.try_)(() => JSON.stringify(who))}`));
276
277
  }
277
278
  }
279
+ function simpleWhoToError(who, ctx) {
280
+ if (Array.isArray(who))
281
+ return (0, perm_1.ctxBelongsTo)(ctx, who) ? 0 : const_1.HTTP_UNAUTHORIZED;
282
+ return typeof who === 'boolean' ? (who ? 0 : const_1.HTTP_FORBIDDEN)
283
+ : who === misc_1.WHO_ANY_ACCOUNT ? ((0, auth_1.getCurrentUsername)(ctx) ? 0 : const_1.HTTP_UNAUTHORIZED)
284
+ : who === misc_1.WHO_ADMIN ? ((0, adminApis_1.ctxAdminAccess)(ctx) ? 0 : const_1.HTTP_UNAUTHORIZED)
285
+ : undefined;
286
+ }
287
+ function isWhoVfsPerms(who) {
288
+ return typeof who === 'string' && misc_1.PERM_KEYS.includes(who);
289
+ }
278
290
  // it's the responsibility of the caller to verify you have list permission on parent, as callers have different needs.
279
291
  async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requiredPerm, onlyFolders = false, onlyFiles = false, parallelizeRecursion = true, } = {}) {
280
292
  let started = false;
package/src/zip.js CHANGED
@@ -40,7 +40,7 @@ async function zipStreamFromFolder(node, ctx) {
40
40
  if ((0, vfs_1.nodeIsFolder)(subNode)) { // a directory needs to be walked
41
41
  if ((0, vfs_1.hasPermission)(subNode, 'can_list', ctx) && (0, vfs_1.hasPermission)(subNode, 'can_archive', ctx)) {
42
42
  yield subNode; // it could be empty
43
- yield* (0, vfs_1.walkNode)(subNode, { ctx, prefixPath: decodeURI(uri) + '/', requiredPerm: 'can_archive' });
43
+ yield* (0, vfs_1.walkNode)(subNode, { ctx, prefixPath: (0, misc_1.pathDecodeSegments)(uri) + '/', requiredPerm: 'can_archive' });
44
44
  }
45
45
  continue;
46
46
  }