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.
- package/admin/assets/{af-RjyQ-neT.js → af-DWEYq388.js} +1 -1
- package/admin/assets/{am-PptHpglb.js → am-DgLbAgj6.js} +1 -1
- package/admin/assets/{ar-Du3syDxa.js → ar-DgEWkO74.js} +1 -1
- package/admin/assets/{ar-dz-CiziRh1x.js → ar-dz-DHq--Sr8.js} +1 -1
- package/admin/assets/{ar-iq-hCKg0CRP.js → ar-iq-D1r3nsb9.js} +1 -1
- package/admin/assets/{ar-kw-COYePt-p.js → ar-kw-C85fGHwp.js} +1 -1
- package/admin/assets/{ar-ly-CY5yETqb.js → ar-ly-Bq6pjGjs.js} +1 -1
- package/admin/assets/{ar-ma-DczXi97r.js → ar-ma-SGvmh6Mj.js} +1 -1
- package/admin/assets/{ar-sa-Bu7sTKzl.js → ar-sa-Bv8hiFi6.js} +1 -1
- package/admin/assets/{ar-tn-BrG0r6qZ.js → ar-tn-Bdvo77v3.js} +1 -1
- package/admin/assets/{az-DYRCrdk0.js → az-7fPndoov.js} +1 -1
- package/admin/assets/{be-DObSs5HX.js → be-wjXeIeAK.js} +1 -1
- package/admin/assets/{bg-BDBkMe50.js → bg-DZwBvjzH.js} +1 -1
- package/admin/assets/{bi-CApXFwc6.js → bi-qCtxvMhO.js} +1 -1
- package/admin/assets/{bm-CjxCV8Lr.js → bm-BVPWvreb.js} +1 -1
- package/admin/assets/{bn-DzWZbDi3.js → bn-CdWvye7d.js} +1 -1
- package/admin/assets/{bn-bd-ijdPRJbb.js → bn-bd-B5-3blmz.js} +1 -1
- package/admin/assets/{bo-BDDfj5XH.js → bo-BEVcgyN2.js} +1 -1
- package/admin/assets/{br-DRHEjait.js → br-DGQD6fFs.js} +1 -1
- package/admin/assets/{bs-B0Zv2Agm.js → bs-So4MoRua.js} +1 -1
- package/admin/assets/{ca-DuZAUqU_.js → ca-Bk5ytG4g.js} +1 -1
- package/admin/assets/{cs-DVkylosR.js → cs-C4NU8eW-.js} +1 -1
- package/admin/assets/{cv-8Is1Fns9.js → cv-Ct-s-zrW.js} +1 -1
- package/admin/assets/{cy-Bk30Or_y.js → cy-ojtDPj8_.js} +1 -1
- package/admin/assets/{da-C41DIdZK.js → da-CYGin6vm.js} +1 -1
- package/admin/assets/{de--qvLJgIE.js → de-BEbJ01zH.js} +1 -1
- package/admin/assets/{de-at-D5vCBlsw.js → de-at-C7UwE1rJ.js} +1 -1
- package/admin/assets/{de-ch-Oh2cO23c.js → de-ch-CsZ7YQc_.js} +1 -1
- package/admin/assets/{dv-4ZO2KNbw.js → dv-DaVliwLd.js} +1 -1
- package/admin/assets/{el-CobOUqyu.js → el-DM_KqKEP.js} +1 -1
- package/admin/assets/{en-C9afClpS.js → en-DedtOfaf.js} +1 -1
- package/admin/assets/{en-au-C_QMghEl.js → en-au-52Bzk5D9.js} +1 -1
- package/admin/assets/{en-ca-C80KILwc.js → en-ca-3pzEPK2N.js} +1 -1
- package/admin/assets/{en-gb-BwQ0asAI.js → en-gb-BrwDQS2G.js} +1 -1
- package/admin/assets/{en-ie-ConCcQkq.js → en-ie-BUXSHrkL.js} +1 -1
- package/admin/assets/{en-il-CAOzD4DD.js → en-il-a22drDCn.js} +1 -1
- package/admin/assets/{en-in-87gardaO.js → en-in-BUjecjkp.js} +1 -1
- package/admin/assets/{en-nz-uMTjgkDP.js → en-nz-Bbo7tnB_.js} +1 -1
- package/admin/assets/{en-sg-BlbiLv4L.js → en-sg-CZVDddmd.js} +1 -1
- package/admin/assets/{en-tt-BXXmBax2.js → en-tt-DmSGwRia.js} +1 -1
- package/admin/assets/{eo-BBL7o-0W.js → eo-B71nkHZU.js} +1 -1
- package/admin/assets/{es-DuNej-79.js → es-Dk6VCuuk.js} +1 -1
- package/admin/assets/{es-do-bZWKFwTE.js → es-do-DMErY8ol.js} +1 -1
- package/admin/assets/{es-mx-C2Lfb86F.js → es-mx-BMRmqa3u.js} +1 -1
- package/admin/assets/{es-pr-wU3Du8m-.js → es-pr-CtBQz48p.js} +1 -1
- package/admin/assets/{es-us-qcU-zRiw.js → es-us-CrDl5pnO.js} +1 -1
- package/admin/assets/{et-B-4PjN_n.js → et-CO9OHqio.js} +1 -1
- package/admin/assets/{eu-D0pNDZ9i.js → eu-Bip44atW.js} +1 -1
- package/admin/assets/{fa-R_zmYBGc.js → fa-CHbJ_dTM.js} +1 -1
- package/admin/assets/{fi-CWYS_0Hg.js → fi-DKfoLmaQ.js} +1 -1
- package/admin/assets/{fo-aJYpcnWS.js → fo-DG1kOEfw.js} +1 -1
- package/admin/assets/{fr-BHFrWfwB.js → fr-DV73GZR4.js} +1 -1
- package/admin/assets/{fr-ca-ihwmO47n.js → fr-ca-BK-RoZiC.js} +1 -1
- package/admin/assets/{fr-ch-Cb8XbRfE.js → fr-ch-DjqEC5E_.js} +1 -1
- package/admin/assets/{fy-DT9BUc6t.js → fy-znrRQdeC.js} +1 -1
- package/admin/assets/{ga-B8p4naXJ.js → ga-BlZeKu0N.js} +1 -1
- package/admin/assets/{gd-Dzrl6rPc.js → gd-BmrycMnC.js} +1 -1
- package/admin/assets/{gl-bN2tXl9d.js → gl-CuT8e5mi.js} +1 -1
- package/admin/assets/{gom-latn-DUK8PgIJ.js → gom-latn-BSWVd0A6.js} +1 -1
- package/admin/assets/{gu-CxAIP8fw.js → gu-BHK6LfvD.js} +1 -1
- package/admin/assets/{he-Bm9XJVAj.js → he-DPoTUevR.js} +1 -1
- package/admin/assets/{hi-CHik9Qxx.js → hi-BRuLafoW.js} +1 -1
- package/admin/assets/{hr-Dn57_dqN.js → hr-Bzge-10P.js} +1 -1
- package/admin/assets/{ht-BRS-FrJq.js → ht-Ck9BCna1.js} +1 -1
- package/admin/assets/{hu-hVaGcZ-U.js → hu-CzqqbYmU.js} +1 -1
- package/admin/assets/{hy-am-heLxXhpz.js → hy-am-C-eV4E8v.js} +1 -1
- package/admin/assets/{id-B6AkO4h8.js → id-Dv8GZQvB.js} +1 -1
- package/admin/assets/{index-Buyl8rI8.js → index-BPIX0qPj.js} +1 -1
- package/admin/assets/index-D3HviM6x.js +889 -0
- package/admin/assets/{is-BUADPoni.js → is-CK6VY3M_.js} +1 -1
- package/admin/assets/{it-Ce3gssOP.js → it-1gtki4a5.js} +1 -1
- package/admin/assets/{it-ch-CJzj2czr.js → it-ch-C0Mj3-pC.js} +1 -1
- package/admin/assets/{ja-DykMIu-9.js → ja-Dl3AfnM1.js} +1 -1
- package/admin/assets/{jv-Cum6DLwa.js → jv-CznX-tGV.js} +1 -1
- package/admin/assets/{ka-foCPVFxw.js → ka-BNjZxCug.js} +1 -1
- package/admin/assets/{kk-CMNu1ysC.js → kk-80J_xldf.js} +1 -1
- package/admin/assets/{km-BfMisGaD.js → km-CuWChDRB.js} +1 -1
- package/admin/assets/{kn-R_9S5KJz.js → kn-BZp_PBdl.js} +1 -1
- package/admin/assets/{ko-DYRND-mM.js → ko-RirpyUl_.js} +1 -1
- package/admin/assets/{ku-CNZ_weGy.js → ku-Dz8ACD5w.js} +1 -1
- package/admin/assets/{ky-BhTAWL4I.js → ky-BN3ylOhj.js} +1 -1
- package/admin/assets/{lb-CxWhQxwF.js → lb-D7h_YoEn.js} +1 -1
- package/admin/assets/{lo-DBL_XLkE.js → lo-BrlbTUPD.js} +1 -1
- package/admin/assets/{lt-BakZVm4p.js → lt-cXuHFdTa.js} +1 -1
- package/admin/assets/{lv-CCn-slXG.js → lv-CjIpv13Q.js} +1 -1
- package/admin/assets/{me-xPEA4qjE.js → me-B-jTh39Z.js} +1 -1
- package/admin/assets/{mi-6cCs2Mzx.js → mi-D06xdVmt.js} +1 -1
- package/admin/assets/{mk-CwWbHJPS.js → mk-iLbuxyOf.js} +1 -1
- package/admin/assets/{ml-Dp7Ab1SV.js → ml-2W0y6Zb2.js} +1 -1
- package/admin/assets/{mn-ClotGWAe.js → mn-6zbvKjeb.js} +1 -1
- package/admin/assets/{mr-GiM-paTF.js → mr-7-jrgLyw.js} +1 -1
- package/admin/assets/{ms-BiZ1_eVR.js → ms-CRH6rEXt.js} +1 -1
- package/admin/assets/{ms-my-oevI0fOH.js → ms-my-BIJmu2S-.js} +1 -1
- package/admin/assets/{mt-BaIHeOl1.js → mt-CbXmxK-D.js} +1 -1
- package/admin/assets/{my-Cg5Fc_1j.js → my-BvMUsxU8.js} +1 -1
- package/admin/assets/{nb-ZPODjT6R.js → nb-DvKHgF7L.js} +1 -1
- package/admin/assets/{ne-C0ti-ZX2.js → ne-DiZZ3Lm6.js} +1 -1
- package/admin/assets/{nl-be-VPC0QyaW.js → nl-be-Dy7PYRbC.js} +1 -1
- package/admin/assets/{nl-DP2PkkGx.js → nl-t_2A_VAT.js} +1 -1
- package/admin/assets/{nn-NLidKyJd.js → nn-Cw7EwosO.js} +1 -1
- package/admin/assets/{oc-lnc-Ddj9_PnD.js → oc-lnc-CuFfB75K.js} +1 -1
- package/admin/assets/{pa-in-DSAWffhb.js → pa-in-DOFyZ-Ft.js} +1 -1
- package/admin/assets/{pl-Yojex5aS.js → pl-BD7FyCJj.js} +1 -1
- package/admin/assets/{pt-BQMs2la2.js → pt-DSKLLE_u.js} +1 -1
- package/admin/assets/{pt-br-DVeeNZu8.js → pt-br-BhL4gb5Z.js} +1 -1
- package/admin/assets/{rn-CKkTrK3f.js → rn-DoHoZZPd.js} +1 -1
- package/admin/assets/{ro-BbgGULSZ.js → ro-B0v-_lH0.js} +1 -1
- package/admin/assets/{ru-mAZX3DTa.js → ru-BMVOk5eA.js} +1 -1
- package/admin/assets/{rw-CYErOxKd.js → rw-CWF0w6eL.js} +1 -1
- package/admin/assets/{sd-kfPTqkSy.js → sd-DO2rrjch.js} +1 -1
- package/admin/assets/{se-D0bN3rDS.js → se-CAolO9WQ.js} +1 -1
- package/admin/assets/{sha512-99nhg44S.js → sha512-ZlUYj4Hr.js} +1 -1
- package/admin/assets/{si-COjb_4Hy.js → si-D03dHfb5.js} +1 -1
- package/admin/assets/{sk-Co95XNOo.js → sk-_GcZGaN3.js} +1 -1
- package/admin/assets/{sl-DUXa5wTF.js → sl-Cb1lUGab.js} +1 -1
- package/admin/assets/{sq-B-KU0nWK.js → sq-Czzt23Tr.js} +1 -1
- package/admin/assets/{sr-Cb_b-zPG.js → sr-D76dVqKJ.js} +1 -1
- package/admin/assets/{sr-cyrl-csuTDIB6.js → sr-cyrl-CuoFbJjW.js} +1 -1
- package/admin/assets/{ss-BDnE-cG6.js → ss-g-fGaM29.js} +1 -1
- package/admin/assets/{sv-CzWdOHcE.js → sv-CZxc8I45.js} +1 -1
- package/admin/assets/{sv-fi-IK8oi5nB.js → sv-fi-D8REJeLz.js} +1 -1
- package/admin/assets/{sw-fPHo5hof.js → sw-B1n3PjWG.js} +1 -1
- package/admin/assets/{ta-TteN0nyU.js → ta-K5mexJNT.js} +1 -1
- package/admin/assets/{te-2gsQb1fF.js → te-DT6dj5B6.js} +1 -1
- package/admin/assets/{tet-ClTpDYJv.js → tet-DXwYNm_H.js} +1 -1
- package/admin/assets/{tg-Bel7Uc6z.js → tg-BCcZKcE2.js} +1 -1
- package/admin/assets/{th-pDQttM9V.js → th-CeeeseFX.js} +1 -1
- package/admin/assets/{tk-CxoKYZH6.js → tk-CJ6KW44d.js} +1 -1
- package/admin/assets/{tl-ph-D9htRcOQ.js → tl-ph-DzE8lDmm.js} +1 -1
- package/admin/assets/{tlh-7UqvDBxU.js → tlh-ER6KiMxG.js} +1 -1
- package/admin/assets/{tr-NjJrq1iC.js → tr-D48NGNpr.js} +1 -1
- package/admin/assets/{tzl-CzGaXn8M.js → tzl-5AsmDTYM.js} +1 -1
- package/admin/assets/{tzm-BiuscZFr.js → tzm-2AzZ1YPf.js} +1 -1
- package/admin/assets/{tzm-latn-IeWkCgWf.js → tzm-latn-Cd5hPQuT.js} +1 -1
- package/admin/assets/{ug-cn-5LK64x5v.js → ug-cn-DU-MZ9Vx.js} +1 -1
- package/admin/assets/{uk-CzacUaQe.js → uk-hn6vcOkn.js} +1 -1
- package/admin/assets/{ur-BRV7z4Gu.js → ur-jOObtqB6.js} +1 -1
- package/admin/assets/{uz-C4G77QOI.js → uz-BlftYfHF.js} +1 -1
- package/admin/assets/{uz-latn-CQFrzZ6F.js → uz-latn-BpuI0ccM.js} +1 -1
- package/admin/assets/{vi-DEFXdlJi.js → vi-DVo3LusT.js} +1 -1
- package/admin/assets/{x-pseudo-sWj5RKxR.js → x-pseudo-BuVzNhqi.js} +1 -1
- package/admin/assets/{yo-CBDjk96e.js → yo-BvWGwb4m.js} +1 -1
- package/admin/assets/{zh-CQtX_fkD.js → zh-D9-tfba1.js} +1 -1
- package/admin/assets/{zh-cn-D6dF0jKM.js → zh-cn-CFL5sbIW.js} +1 -1
- package/admin/assets/{zh-hk-DY-Jaqdg.js → zh-hk-DRP8u65r.js} +1 -1
- package/admin/assets/{zh-tw-BdmVby0R.js → zh-tw-CtVs1ihI.js} +1 -1
- package/admin/index.html +1 -1
- package/frontend/assets/index-legacy-D3BTBYs5.js +9 -0
- package/frontend/assets/{index-legacy-CQovmh_0.js → index-legacy-DcrWtKxQ.js} +1 -1
- package/frontend/assets/{sha512-legacy-CXU3efCO.js → sha512-legacy-DJvEwScE.js} +1 -1
- package/frontend/index.html +1 -1
- package/npm-shrinkwrap.json +66 -22
- package/package.json +2 -2
- package/src/api.get_file_list.js +2 -2
- package/src/basicWeb.js +1 -1
- package/src/comments.js +7 -4
- package/src/const.js +1 -1
- package/src/cross.js +12 -6
- package/src/events.js +2 -3
- package/src/expiringCache.js +8 -7
- package/src/frontEndApis.js +17 -14
- package/src/listen.js +2 -1
- package/src/nat.js +4 -1
- package/src/roots.js +1 -1
- package/src/selfCheck.js +2 -1
- package/src/serveGuiAndSharedFiles.js +17 -7
- package/src/serveGuiFiles.js +1 -1
- package/src/update.js +1 -3
- package/src/util-files.js +9 -4
- package/src/util-http.js +2 -0
- package/src/vfs.js +20 -8
- package/src/zip.js +1 -1
- package/admin/assets/index-WXxQwyJV.js +0 -889
- package/frontend/assets/index-legacy-BtoTkZho.js +0 -9
package/src/expiringCache.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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
|
}
|
package/src/frontEndApis.js
CHANGED
|
@@ -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:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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 }
|
|
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
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
|
-
|
|
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()
|
|
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
|
|
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 (
|
|
123
|
-
const found = await (0, vfs_1.
|
|
124
|
-
if (found && /\.html?/i.test(
|
|
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
|
|
164
|
-
|
|
165
|
-
|
|
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) => {
|
package/src/serveGuiFiles.js
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
|
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
|
-
|
|
272
|
-
|
|
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:
|
|
43
|
+
yield* (0, vfs_1.walkNode)(subNode, { ctx, prefixPath: (0, misc_1.pathDecodeSegments)(uri) + '/', requiredPerm: 'can_archive' });
|
|
44
44
|
}
|
|
45
45
|
continue;
|
|
46
46
|
}
|