hfs 3.2.2 → 3.3.0-alpha1
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-BDoqNBMg.js → af-CevhRske.js} +1 -1
- package/admin/assets/{am-DXBvKJ3X.js → am-4ouVTwuo.js} +1 -1
- package/admin/assets/{ar-BJIoxKTh.js → ar-71cK8dbb.js} +1 -1
- package/admin/assets/{ar-dz-C9l3uc_3.js → ar-dz-CO7oh1gG.js} +1 -1
- package/admin/assets/{ar-iq-DKH8u2lX.js → ar-iq-CjG6db8J.js} +1 -1
- package/admin/assets/{ar-kw-D3gJalQp.js → ar-kw-DMsdR225.js} +1 -1
- package/admin/assets/{ar-ly-BZJzWFeR.js → ar-ly-ZhxIwUOA.js} +1 -1
- package/admin/assets/{ar-ma-DabiOCr0.js → ar-ma-Bo3Z1RyK.js} +1 -1
- package/admin/assets/{ar-sa-C7suzSCY.js → ar-sa-Db44biae.js} +1 -1
- package/admin/assets/{ar-tn-BvBucEx0.js → ar-tn-DNWRixE0.js} +1 -1
- package/admin/assets/{az-CPUppH2M.js → az-B6LcmVzB.js} +1 -1
- package/admin/assets/{be-vzvhX2dl.js → be-Dp0KhO5x.js} +1 -1
- package/admin/assets/{bg-09Xbj_Y3.js → bg-TsOJJvBm.js} +1 -1
- package/admin/assets/{bi-CvhiuiE9.js → bi-DstczOGo.js} +1 -1
- package/admin/assets/{bm-DtJAZAkZ.js → bm-Bf09NN15.js} +1 -1
- package/admin/assets/{bn-Dnzh2x6I.js → bn-Da3tHLgx.js} +1 -1
- package/admin/assets/{bn-bd-xEy4797g.js → bn-bd-CeSalisC.js} +1 -1
- package/admin/assets/{bo-vuPmptG3.js → bo-Ctxe0IKQ.js} +1 -1
- package/admin/assets/{br-C9xH4OD3.js → br-Y3dPq3Tj.js} +1 -1
- package/admin/assets/{bs-BB_uCUp1.js → bs-BbAlSeZx.js} +1 -1
- package/admin/assets/{ca-D7LKaf98.js → ca-8-Nn97gi.js} +1 -1
- package/admin/assets/{cs-DMFTNdNC.js → cs-BD5ArFNW.js} +1 -1
- package/admin/assets/{cv-DNUjJwnO.js → cv-CdMFVXGr.js} +1 -1
- package/admin/assets/{cy-qmAOTPwC.js → cy-B3QEYlIT.js} +1 -1
- package/admin/assets/{da-DDX54iM9.js → da-Bju2YQ9G.js} +1 -1
- package/admin/assets/{de-BBmlsfbM.js → de-DdzCTquR.js} +1 -1
- package/admin/assets/{de-at-CuMZqYfu.js → de-at-DgyKCkPl.js} +1 -1
- package/admin/assets/{de-ch-s8OXKb-5.js → de-ch-Dk9qkzvn.js} +1 -1
- package/admin/assets/{dist-CHP3cW_n.js → dist-KY_8edrw.js} +1 -1
- package/admin/assets/{dv-Cjs3QDBN.js → dv-C5KWK8o4.js} +1 -1
- package/admin/assets/{el-BsAOrUDP.js → el-BDL_lPlM.js} +1 -1
- package/admin/assets/{en-DQ460ET7.js → en-Ds3H1Wec.js} +1 -1
- package/admin/assets/{en-au-8tMHM2OT.js → en-au-CgltfNUb.js} +1 -1
- package/admin/assets/{en-ca-c9jM4M_8.js → en-ca-DEsKzbWO.js} +1 -1
- package/admin/assets/{en-in-D2ULzXMp.js → en-gb-21AYC3Ik.js} +1 -1
- package/admin/assets/{en-ie-D4_e3kV6.js → en-ie-aN3g-yqK.js} +1 -1
- package/admin/assets/{en-il-BoaZOven.js → en-il-CZl2d7NK.js} +1 -1
- package/admin/assets/{en-tt-Cn72OR4N.js → en-in-C7Kv4c3w.js} +1 -1
- package/admin/assets/{en-nz-grrmB3dg.js → en-nz-DA_sIaGR.js} +1 -1
- package/admin/assets/{en-sg-Cmqxpoir.js → en-sg-CP5PJpZf.js} +1 -1
- package/admin/assets/{en-gb-unFIXx9f.js → en-tt-B5vDLhL7.js} +1 -1
- package/admin/assets/{eo-Cqxmc0TT.js → eo-VE1KDD1u.js} +1 -1
- package/admin/assets/{es-CkjKdFZ3.js → es-SUzi5oTU.js} +1 -1
- package/admin/assets/{es-do-CTcTshup.js → es-do-Iri0eWm8.js} +1 -1
- package/admin/assets/{es-mx-DMXgMMxs.js → es-mx-DwneKeOc.js} +1 -1
- package/admin/assets/{es-pr-DNCV91L3.js → es-pr-C4zPUdA1.js} +1 -1
- package/admin/assets/{es-us-C7o2mlIH.js → es-us-BPS67etc.js} +1 -1
- package/admin/assets/{esm-DvUbRuYx.js → esm-CyNQ7bBW.js} +1 -1
- package/admin/assets/{et-DaPpH-gK.js → et-Ciqbfae0.js} +1 -1
- package/admin/assets/{eu-DfKyFruu.js → eu-CGhOwQpe.js} +1 -1
- package/admin/assets/{fa-xWrBjePb.js → fa-BWZiAv_E.js} +1 -1
- package/admin/assets/{fi-BOWDMsDS.js → fi-DJmgkVsJ.js} +1 -1
- package/admin/assets/{fo-B3FupW8R.js → fo-DVez5N-g.js} +1 -1
- package/admin/assets/{fr-DZBDBkwp.js → fr-D206itJo.js} +1 -1
- package/admin/assets/{fr-ca-CRePPJJ5.js → fr-ca-C6JiEHfi.js} +1 -1
- package/admin/assets/{fr-ch-pFKvYU8D.js → fr-ch-DUTEuSU_.js} +1 -1
- package/admin/assets/{fy-0k7RzHUH.js → fy-C_r06zH-.js} +1 -1
- package/admin/assets/{ga-D31rB2ys.js → ga-CrdQqAN5.js} +1 -1
- package/admin/assets/{gd-CbgY-FFE.js → gd-iWHfhKAH.js} +1 -1
- package/admin/assets/{gl-DrtvS9gt.js → gl-zgfy-pQ0.js} +1 -1
- package/admin/assets/{gom-latn-Dkke3GyE.js → gom-latn-CMZ7Vj7V.js} +1 -1
- package/admin/assets/{gu-BlEipYhR.js → gu-DNqIMjZc.js} +1 -1
- package/admin/assets/{he-BrHT6OLB.js → he-OJBbYFzL.js} +1 -1
- package/admin/assets/{hi-Bx0zlAgr.js → hi-ByrMhKpX.js} +1 -1
- package/admin/assets/{hr-CoFYGbr6.js → hr-CfRZXzCu.js} +1 -1
- package/admin/assets/{ht-Df5xKo4a.js → ht-DDrMtLzJ.js} +1 -1
- package/admin/assets/{hu-BFTN3q6-.js → hu-Ckeq3R6_.js} +1 -1
- package/admin/assets/{hy-am-DuZTJQed.js → hy-am-OpZy7Nvg.js} +1 -1
- package/admin/assets/{id-DBZ5nPkf.js → id-BE8-Ys79.js} +1 -1
- package/admin/assets/{index-BGIe1xaR.js → index-34fRsXFH.js} +128 -123
- package/admin/assets/{is-CmeHm47B.js → is-BOxJcH5N.js} +1 -1
- package/admin/assets/{it-Cv3fjOA9.js → it-BFlrIXvP.js} +1 -1
- package/admin/assets/{it-ch-DCTyHA3T.js → it-ch-ILAp-lZZ.js} +1 -1
- package/admin/assets/{ja-DHNVXAM5.js → ja-CbbYAYyn.js} +1 -1
- package/admin/assets/{jv-BdNIxhWv.js → jv-CuLkRQCH.js} +1 -1
- package/admin/assets/{ka-D-joD0QB.js → ka-BFeRDN-I.js} +1 -1
- package/admin/assets/{kk-8wRNNjxz.js → kk-CMvQxaPk.js} +1 -1
- package/admin/assets/{km-dUWOg1uK.js → km-BdQbDUNF.js} +1 -1
- package/admin/assets/{kn-CwQbzel0.js → kn-CE5AS6Nx.js} +1 -1
- package/admin/assets/{ko-D_gn9Sfw.js → ko-Ctl1mHOt.js} +1 -1
- package/admin/assets/{ku-Dh3MRML3.js → ku-Blbo7opr.js} +1 -1
- package/admin/assets/{ky-CWYuRvil.js → ky-iCha_cZX.js} +1 -1
- package/admin/assets/{lb-Cc2xsSIx.js → lb-BaP0S6h1.js} +1 -1
- package/admin/assets/{lo-CkwNFDBz.js → lo-B_Q4zUMa.js} +1 -1
- package/admin/assets/{lt-HWyFDLXu.js → lt-BOaP1KGX.js} +1 -1
- package/admin/assets/{lv-C7Zx3OLO.js → lv-S1XMSUX1.js} +1 -1
- package/admin/assets/{me-DH3AqnfF.js → me-ChOLVJHC.js} +1 -1
- package/admin/assets/{mi-DMmUry6m.js → mi-CnoIUOGl.js} +1 -1
- package/admin/assets/{mk-D6MNZrzX.js → mk-BoEaxVXE.js} +1 -1
- package/admin/assets/{ml-B_ur8Zqf.js → ml-BuvmVn6P.js} +1 -1
- package/admin/assets/{mn-DeL8Ry7x.js → mn-2bvGd1HI.js} +1 -1
- package/admin/assets/{mr-C01qRXFL.js → mr-BAoAWQmy.js} +1 -1
- package/admin/assets/{ms-DFUZJzOm.js → ms-C2eT9r-f.js} +1 -1
- package/admin/assets/{ms-my-CUYHkebs.js → ms-my-D2ZXdcAf.js} +1 -1
- package/admin/assets/{mt-CE8t5jSj.js → mt-BL5JZC4T.js} +1 -1
- package/admin/assets/{my-Df96A8jZ.js → my-CuJ4L0Ji.js} +1 -1
- package/admin/assets/{nb-D0837ewu.js → nb-CjE6cT80.js} +1 -1
- package/admin/assets/{ne-BdK5TR0R.js → ne-BL9I0cb1.js} +1 -1
- package/admin/assets/{nl-oYKmSma6.js → nl-Dt3mtMln.js} +1 -1
- package/admin/assets/{nl-be-BfVC0cur.js → nl-be-Am1mjZK9.js} +1 -1
- package/admin/assets/{nn-IEUPnyc8.js → nn-ChSewyYy.js} +1 -1
- package/admin/assets/{oc-lnc-g_wSIROr.js → oc-lnc-x6_ChCE9.js} +1 -1
- package/admin/assets/{pa-in-gWhcLmZE.js → pa-in-DVyN8o2P.js} +1 -1
- package/admin/assets/{pl-H3-LoxVn.js → pl-CqcuAUGV.js} +1 -1
- package/admin/assets/{pt-hiX8RqVw.js → pt-B2BPpD7K.js} +1 -1
- package/admin/assets/{pt-br-B8UcNR6_.js → pt-br-oBVRyUzP.js} +1 -1
- package/admin/assets/{rn-BKupViLr.js → rn-B3e3nkfp.js} +1 -1
- package/admin/assets/{ro-DmhgIvml.js → ro-C2tWFx0Q.js} +1 -1
- package/admin/assets/{ru-CcpO-b8g.js → ru-CCsEUnFL.js} +1 -1
- package/admin/assets/{rw-DWX_5ZK0.js → rw-CaCkWlGA.js} +1 -1
- package/admin/assets/{sd-Dat8YgLw.js → sd-90Zixcez.js} +1 -1
- package/admin/assets/{se-nTBYCwx3.js → se-DaZXpLsK.js} +1 -1
- package/admin/assets/{sha512-CZz40GwW.js → sha512-DlGRFb_l.js} +1 -1
- package/admin/assets/{si-DG88w5El.js → si-CSoBAkgi.js} +1 -1
- package/admin/assets/{sk-s5FxW36J.js → sk-pgQaqa2z.js} +1 -1
- package/admin/assets/{sl-B-HyGrpA.js → sl-Cr5kSdA7.js} +1 -1
- package/admin/assets/{sq-DPFtfEC8.js → sq-Pxi2MZOP.js} +1 -1
- package/admin/assets/{sr-bBPg1zz4.js → sr-Fdc9-lC-.js} +1 -1
- package/admin/assets/{sr-cyrl-cXkYHMcP.js → sr-cyrl-06jNWqpg.js} +1 -1
- package/admin/assets/{ss-7nSqXJN7.js → ss-BjEzSMit.js} +1 -1
- package/admin/assets/{sv-B8mG1QK4.js → sv-CqWqUpcA.js} +1 -1
- package/admin/assets/{sv-fi-CotGRXSH.js → sv-fi-CsO2xQHd.js} +1 -1
- package/admin/assets/{sw-fAxU-Uck.js → sw-xQUdgYhn.js} +1 -1
- package/admin/assets/{ta-Dl0Z1pan.js → ta-epbFrZ1M.js} +1 -1
- package/admin/assets/{te-DmcKasFF.js → te-DusTwU6q.js} +1 -1
- package/admin/assets/{tet-D6mmvYpQ.js → tet-ylc9v4gl.js} +1 -1
- package/admin/assets/{tg-39Hf2-oO.js → tg-2QfVTAJf.js} +1 -1
- package/admin/assets/{th-BSmTJSFN.js → th-QIm0Mh7I.js} +1 -1
- package/admin/assets/{tk-m85E5igC.js → tk-140KMZeW.js} +1 -1
- package/admin/assets/{tl-ph-BlYxVvNt.js → tl-ph-S7IZkbx3.js} +1 -1
- package/admin/assets/{tlh-D1POnIeE.js → tlh-C2fYb34-.js} +1 -1
- package/admin/assets/{tr-BurtfrLy.js → tr-Be-IM6i4.js} +1 -1
- package/admin/assets/{tzl-BvyD0lOf.js → tzl-DMy30zde.js} +1 -1
- package/admin/assets/{tzm-DZHS0dK6.js → tzm-Cu882cHO.js} +1 -1
- package/admin/assets/{tzm-latn-yNW7CNCH.js → tzm-latn-BYxpYHet.js} +1 -1
- package/admin/assets/{ug-cn-rxs2pf5Y.js → ug-cn-Cl8Jqk2E.js} +1 -1
- package/admin/assets/{uk-CgZM-NnA.js → uk-B-8XymtC.js} +1 -1
- package/admin/assets/{ur-YxIR8yYD.js → ur-ChGuAlvQ.js} +1 -1
- package/admin/assets/{uz-CE9QsQMG.js → uz-QbfaW7fT.js} +1 -1
- package/admin/assets/{uz-latn-DiVdSW6G.js → uz-latn-DIQivLCy.js} +1 -1
- package/admin/assets/{vi-DKARV6qf.js → vi-C2CmYlDu.js} +1 -1
- package/admin/assets/{x-pseudo-BuAdOrXQ.js → x-pseudo-BWgm1XlP.js} +1 -1
- package/admin/assets/{yo-BcB85DhC.js → yo-8bNbPP6u.js} +1 -1
- package/admin/assets/{zh-DLmxfxzl.js → zh-CeNSRZ4r.js} +1 -1
- package/admin/assets/{zh-cn-ILRADZJi.js → zh-cn-BlbF5C_X.js} +1 -1
- package/admin/assets/{zh-hk-fT7fQk9_.js → zh-hk-kg1c_VSK.js} +1 -1
- package/admin/assets/{zh-tw-NqRXGP6v.js → zh-tw-BCl4UsPA.js} +1 -1
- package/admin/index.html +1 -1
- package/frontend/assets/{dist-legacy-BPToXNXu.js → dist-legacy-DYE1EOcc.js} +1 -1
- package/frontend/assets/index-legacy-Br-Lpsst.js +1 -0
- package/frontend/assets/{lib-legacy-CBk-_G90.js → lib-legacy-C4Gw_0kX.js} +1 -1
- package/frontend/assets/{sha512-legacy-CWrR2rkQ.js → sha512-legacy-D3RbPSpl.js} +1 -1
- package/frontend/index.html +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/AsapStream.js +18 -14
- package/src/SendList.js +42 -16
- package/src/ThrottledStream.js +3 -3
- package/src/acme.js +23 -10
- package/src/adminApis.js +7 -6
- package/src/api.accounts.js +11 -7
- package/src/api.auth.js +8 -5
- package/src/api.cert.js +1 -1
- package/src/api.get_file_list.js +4 -3
- package/src/api.lang.js +3 -2
- package/src/api.monitor.js +1 -1
- package/src/api.net.js +3 -1
- package/src/api.plugins.js +2 -0
- package/src/api.vfs.js +5 -4
- package/src/apiMiddleware.js +5 -1
- package/src/basicWeb.js +1 -1
- package/src/block.js +1 -1
- package/src/commands.js +6 -5
- package/src/comments.js +29 -13
- package/src/config.js +7 -4
- package/src/consoleLog.js +5 -1
- package/src/cross-const.js +27 -1
- package/src/cross.js +32 -33
- package/src/ddns.js +1 -4
- package/src/events.js +1 -4
- package/src/fileAttr.js +1 -1
- package/src/frontEndApis.js +7 -3
- package/src/geo.js +8 -2
- package/src/github.js +10 -9
- package/src/index.js +1 -1
- package/src/ips.js +24 -3
- package/src/langs/hfs-lang-ar.json +1 -0
- package/src/langs/hfs-lang-bg.json +1 -0
- package/src/langs/hfs-lang-de.json +1 -0
- package/src/langs/hfs-lang-el.json +1 -0
- package/src/langs/hfs-lang-es.json +1 -0
- package/src/langs/hfs-lang-fi.json +1 -0
- package/src/langs/hfs-lang-fr.json +1 -0
- package/src/langs/hfs-lang-hu.json +1 -0
- package/src/langs/hfs-lang-it.json +1 -0
- package/src/langs/hfs-lang-ja.json +1 -0
- package/src/langs/hfs-lang-ko.json +1 -0
- package/src/langs/hfs-lang-lt.json +1 -0
- package/src/langs/hfs-lang-ms.json +1 -0
- package/src/langs/hfs-lang-nl.json +1 -0
- package/src/langs/hfs-lang-pl.json +1 -0
- package/src/langs/hfs-lang-pt-br.json +1 -0
- package/src/langs/hfs-lang-ro.json +1 -0
- package/src/langs/hfs-lang-ru.json +1 -0
- package/src/langs/hfs-lang-sr-latn.json +1 -0
- package/src/langs/hfs-lang-sr.json +1 -0
- package/src/langs/hfs-lang-th.json +1 -0
- package/src/langs/hfs-lang-tr.json +1 -0
- package/src/langs/hfs-lang-uk.json +1 -0
- package/src/langs/hfs-lang-vi.json +1 -0
- package/src/langs/hfs-lang-zh-tw.json +1 -0
- package/src/langs/hfs-lang-zh.json +1 -0
- package/src/listen.js +17 -13
- package/src/log.js +11 -2
- package/src/middlewares.js +4 -4
- package/src/misc.js +3 -3
- package/src/multipartUpload.js +1 -2
- package/src/nat.js +1 -1
- package/src/outboundProxy.js +7 -0
- package/src/perm.js +5 -3
- package/src/plugins.js +58 -36
- package/src/selfCheck.js +4 -3
- package/src/serveFile.js +3 -3
- package/src/serveGuiAndSharedFiles.js +7 -6
- package/src/serveGuiFiles.js +13 -1
- package/src/serverCode.js +27 -0
- package/src/throttler.js +3 -2
- package/src/update.js +9 -3
- package/src/upload.js +29 -11
- package/src/uploadOwners.js +95 -0
- package/src/util-files.js +4 -2
- package/src/util-http.js +3 -1
- package/src/vfs.js +28 -24
- package/src/walkDir.js +24 -11
- package/src/watchLoad.js +13 -2
- package/src/webdav.js +4 -2
- package/src/zip.js +1 -1
- package/frontend/assets/index-legacy-CmusDwvl.js +0 -1
package/src/ddns.js
CHANGED
|
@@ -73,10 +73,7 @@ async function get_dynamic_dns_error() {
|
|
|
73
73
|
if (last)
|
|
74
74
|
this.push(last); // start by sending current state
|
|
75
75
|
unsub = events_1.default.on('dynamicDnsError', x => this.push(x)); // send updates, if any. This simplified way to manage the data stream is acceptable for this case of extremely low throughput
|
|
76
|
-
|
|
77
|
-
async destroy() {
|
|
78
|
-
unsub();
|
|
79
|
-
this.push(null);
|
|
76
|
+
this.once('close', unsub);
|
|
80
77
|
}
|
|
81
78
|
});
|
|
82
79
|
}
|
package/src/events.js
CHANGED
|
@@ -19,10 +19,7 @@ class BetterEventEmitter {
|
|
|
19
19
|
this.emit(e + LISTENERS_SUFFIX, cbs, listener);
|
|
20
20
|
}
|
|
21
21
|
if (callNow)
|
|
22
|
-
|
|
23
|
-
listener();
|
|
24
|
-
}
|
|
25
|
-
catch { }
|
|
22
|
+
Promise.resolve().then(listener).catch(console.error);
|
|
26
23
|
return () => {
|
|
27
24
|
for (const e of event) {
|
|
28
25
|
const cbs = this.listeners.get(e);
|
package/src/fileAttr.js
CHANGED
|
@@ -35,7 +35,7 @@ async function storeFileAttr(path, k, v) {
|
|
|
35
35
|
return true;
|
|
36
36
|
}
|
|
37
37
|
// fallback to our kv-storage
|
|
38
|
-
return await exports.fileAttrDb.put(fileAttrKey(path, k), v)?.
|
|
38
|
+
return await exports.fileAttrDb.put(fileAttrKey(path, k), v)?.then(() => true, (e) => {
|
|
39
39
|
console.error("Couldn't store metadata on", path, String(e.message || e));
|
|
40
40
|
return false;
|
|
41
41
|
}) ?? true; // if put is undefined, the value was already there
|
package/src/frontEndApis.js
CHANGED
|
@@ -20,6 +20,7 @@ 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 uploadOwners_1 = require("./uploadOwners");
|
|
23
24
|
const config_1 = require("./config");
|
|
24
25
|
const comments_1 = require("./comments");
|
|
25
26
|
const SendList_1 = require("./SendList");
|
|
@@ -99,7 +100,7 @@ exports.frontEndApis = {
|
|
|
99
100
|
throw new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
100
101
|
if ((0, vfs_1.isRoot)(node) || !(0, util_files_1.isValidFileName)(dest))
|
|
101
102
|
return new apiMiddleware_1.ApiError(const_1.HTTP_FORBIDDEN);
|
|
102
|
-
await requestedRename(node, dest, ctx);
|
|
103
|
+
await requestedRename(node, dest, ctx, uri);
|
|
103
104
|
return {};
|
|
104
105
|
},
|
|
105
106
|
async move_files({ uri_from, uri_to }, ctx) {
|
|
@@ -126,7 +127,8 @@ exports.frontEndApis = {
|
|
|
126
127
|
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
127
128
|
if (!node.source)
|
|
128
129
|
return new apiMiddleware_1.ApiError(const_1.HTTP_FAILED_DEPENDENCY);
|
|
129
|
-
await (0, comments_1.setCommentFor)(node.source, comment)
|
|
130
|
+
if (!await (0, comments_1.setCommentFor)(node.source, comment))
|
|
131
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
130
132
|
return {};
|
|
131
133
|
},
|
|
132
134
|
async get_folder_size_partial({ id }) {
|
|
@@ -199,11 +201,12 @@ async function moveFiles(uri_from, uri_to, ctx, override) {
|
|
|
199
201
|
await (0, promises_1.copyFile)(src, dest);
|
|
200
202
|
await (0, promises_1.unlink)(src);
|
|
201
203
|
}).then(() => (0, misc_1.moveStoredFileAttrs)(src, dest))
|
|
204
|
+
.then(() => (0, uploadOwners_1.moveUploadOwner)(from1, (0, misc_1.join)(uri_to, destName)))
|
|
202
205
|
.catch(e => e.code || String(e));
|
|
203
206
|
}))
|
|
204
207
|
};
|
|
205
208
|
}
|
|
206
|
-
async function requestedRename(node, newName, ctx) {
|
|
209
|
+
async function requestedRename(node, newName, ctx, uri = ctx.path) {
|
|
207
210
|
if (!node)
|
|
208
211
|
throw new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
209
212
|
// requestedRename is exported, so keep disk rename confinement here even when callers pre-validate
|
|
@@ -223,6 +226,7 @@ async function requestedRename(node, newName, ctx) {
|
|
|
223
226
|
const destSource = (0, path_1.join)((0, path_1.dirname)(node.source), newName);
|
|
224
227
|
await (0, promises_1.rename)(node.source, destSource);
|
|
225
228
|
await (0, misc_1.moveStoredFileAttrs)(node.source, destSource);
|
|
229
|
+
await (0, uploadOwners_1.moveUploadOwner)(uri, (0, misc_1.join)((0, path_1.dirname)(uri), (0, misc_1.pathEncode)(newName)));
|
|
226
230
|
(0, comments_1.getCommentFor)(node.source).then(c => {
|
|
227
231
|
if (!c)
|
|
228
232
|
return;
|
package/src/geo.js
CHANGED
|
@@ -15,12 +15,18 @@ const enabled = (0, config_1.defineConfig)(misc_1.CFG.geo_enable, false);
|
|
|
15
15
|
const allow = (0, config_1.defineConfig)(misc_1.CFG.geo_allow, null);
|
|
16
16
|
const list = (0, config_1.defineConfig)(misc_1.CFG.geo_list, []);
|
|
17
17
|
const allowUnknown = (0, config_1.defineConfig)(misc_1.CFG.geo_allow_unknown, false);
|
|
18
|
-
|
|
18
|
+
const ignoreNet = (0, config_1.defineConfig)(misc_1.CFG.geo_ignore_net, '', v => (0, misc_1.makeNetMatcher)(v));
|
|
19
|
+
let filesCheck = Promise.resolve();
|
|
20
|
+
enabled.sub(() => {
|
|
21
|
+
filesCheck = checkFiles().catch((e) => console.error('Failed to load geo-ip db:', e?.message || String(e)));
|
|
22
|
+
});
|
|
19
23
|
setInterval(checkFiles, misc_1.DAY); // keep updated at run-time
|
|
20
24
|
// benchmark: memoize can make this 44x faster
|
|
21
25
|
exports.ip2country = lodash_1.default.memoize((ip) => ip2location.getCountryShortAsync(ip).then(v => v === '-' ? '' : v, () => ''));
|
|
22
26
|
const geoFilter = async (ctx, next) => {
|
|
23
|
-
if (enabled.get() && !(0, misc_1.isLocalHost)(ctx) && !(0, misc_1.isIpLan)(ctx.ip)) {
|
|
27
|
+
if (enabled.get() && !(0, misc_1.isLocalHost)(ctx) && !(0, misc_1.isIpLan)(ctx.ip) && !ignoreNet.compiled()(ctx.ip)) {
|
|
28
|
+
if (!isOpen()) // keep startup independent of the geo db download, but don't classify external requests before the db had a chance to load
|
|
29
|
+
await filesCheck;
|
|
24
30
|
const { connection } = ctx.state;
|
|
25
31
|
const country = connection.country ??= await (0, exports.ip2country)(ctx.ip);
|
|
26
32
|
if (country)
|
package/src/github.js
CHANGED
|
@@ -122,18 +122,19 @@ async function downloadPlugin(repo, { branch = '', overwrite = false } = {}) {
|
|
|
122
122
|
if (wasRunning)
|
|
123
123
|
await (0, plugins_1.stopPlugin)(folder); // stop old
|
|
124
124
|
// move data, and consider late release of the resource, up to a few seconds
|
|
125
|
-
await (0, misc_1.retry)(() => (0, promises_1.rename)((0, path_1.join)(installPath, plugins_1.STORAGE_FOLDER), (0, path_1.join)(tempInstallPath, plugins_1.STORAGE_FOLDER))
|
|
126
|
-
|
|
125
|
+
await (0, misc_1.retry)(() => (0, promises_1.rename)((0, path_1.join)(installPath, plugins_1.STORAGE_FOLDER), (0, path_1.join)(tempInstallPath, plugins_1.STORAGE_FOLDER)).catch(e => {
|
|
126
|
+
if (e.code !== 'ENOENT')
|
|
127
|
+
throw e;
|
|
128
|
+
}));
|
|
127
129
|
// delete old folder (if any), but it may fail in the presence of .node files, so we rename it first as a precaution (clearing require.cache doesn't help). Especially on Windows, it may be impossible to delete dll files until our process is terminated (in which case, retrying is useless).
|
|
128
130
|
const deleteMe = installPath + plugins_1.DELETE_ME_SUFFIX;
|
|
129
|
-
await (0, misc_1.retry)(() => (0, promises_1.rename)(installPath, deleteMe).
|
|
130
|
-
if (e.code
|
|
131
|
-
|
|
132
|
-
console.warn("Error renaming old plugin folder:", String(e));
|
|
133
|
-
}));
|
|
134
|
-
await (0, misc_1.retry)(() => (0, promises_1.rm)(deleteMe, { recursive: true, force: true /*ignore ENOENT*/ }).then(() => 1, e => {
|
|
135
|
-
console.warn("Error deleting old plugin folder:", String(e));
|
|
131
|
+
await (0, misc_1.retry)(() => (0, promises_1.rename)(installPath, deleteMe).catch(e => {
|
|
132
|
+
if (e.code !== 'ENOENT')
|
|
133
|
+
throw e;
|
|
136
134
|
}));
|
|
135
|
+
// a disabled leftover cannot block replacement and will be cleaned at startup
|
|
136
|
+
await (0, misc_1.retry)(() => (0, promises_1.rm)(deleteMe, { recursive: true, force: true /*ignore ENOENT*/ }))
|
|
137
|
+
.catch(e => console.warn("Error deleting old plugin folder:", String(e)));
|
|
137
138
|
// final replace
|
|
138
139
|
await (0, promises_1.rename)(tempInstallPath, installPath)
|
|
139
140
|
.catch(e => { throw e.code !== 'ENOENT' ? e : new apiMiddleware_1.ApiError(const_1.HTTP_NOT_ACCEPTABLE, "missing main file"); });
|
package/src/index.js
CHANGED
|
@@ -86,7 +86,7 @@ process.on('uncaughtException', (err) => {
|
|
|
86
86
|
// this warning is scaring users, and has been removed in node 20.12.0 https://github.com/nodejs/node/pull/51204
|
|
87
87
|
const original = process.emitWarning;
|
|
88
88
|
process.emitWarning = warn => String(warn).startsWith('An error event has already been emitted') || original.call(process, warn);
|
|
89
|
-
(0, config_1.defineConfig)(
|
|
89
|
+
(0, config_1.defineConfig)(misc_1.CFG.proxies, 0).sub(n => {
|
|
90
90
|
exports.app.proxy = n > 0;
|
|
91
91
|
exports.app.maxIpsCount = n;
|
|
92
92
|
});
|
package/src/ips.js
CHANGED
|
@@ -14,9 +14,30 @@ exports.ips = new kvstorage_1.KvStorage({
|
|
|
14
14
|
});
|
|
15
15
|
(0, first_1.onProcessExit)(() => exports.ips.close());
|
|
16
16
|
const trackIpsMw = async (ctx, next) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const tracking = exports.ips.isOpen() && !(0, misc_1.isLocalHost)(ctx);
|
|
18
|
+
const ts = new Date;
|
|
19
|
+
const country = ctx.state.connection.country;
|
|
20
|
+
let failed = false;
|
|
21
|
+
// defer storage update until downstream middlewares have assigned status or thrown
|
|
22
|
+
try {
|
|
23
|
+
await next();
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
failed = true;
|
|
27
|
+
throw e;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
if (tracking) {
|
|
31
|
+
// keep the counter update here so failures from downstream middlewares are counted with the final status
|
|
32
|
+
const was = exports.ips.getSync(ctx.ip);
|
|
33
|
+
void exports.ips.put(ctx.ip, {
|
|
34
|
+
ts,
|
|
35
|
+
country,
|
|
36
|
+
served: (was?.served || 0) + (failed || ctx.status >= 400 ? 0 : 1),
|
|
37
|
+
failed: (was?.failed || 0) + (failed || ctx.status >= 400 ? 1 : 0),
|
|
38
|
+
}).catch(e => console.error("Couldn't track IP", ctx.ip, String(e)));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
20
41
|
};
|
|
21
42
|
exports.trackIpsMw = trackIpsMw;
|
|
22
43
|
trackIps.sub(v => {
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} تم رفعه ({size})",
|
|
97
97
|
"upload_errors": "{n} فشلوا",
|
|
98
98
|
"upload_file_rejected": "بعض الملفات لم تُقبل",
|
|
99
|
+
"delete_unfinished_upload": "هل تريد إزالة الرفع غير المكتمل؟",
|
|
99
100
|
"File menu": "قائمة الملف",
|
|
100
101
|
"Folder menu": "قائمة المجلد",
|
|
101
102
|
"Name": "الاسم",
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"upload_finished": "{n} завършени ({size})",
|
|
95
95
|
"upload_errors": "{n} неуспешни",
|
|
96
96
|
"upload_file_rejected": "Някои файлове не бяха приети",
|
|
97
|
+
"delete_unfinished_upload": "Премахване на незавършеното качване?",
|
|
97
98
|
"File menu": "Меню на файл",
|
|
98
99
|
"Folder menu": "Меню на папка",
|
|
99
100
|
"Name": "Име",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} fertig ({size})",
|
|
97
97
|
"upload_errors": "{n} fehlgeschlagen",
|
|
98
98
|
"upload_file_rejected": "Einige Dateien wurden nicht akzeptiert",
|
|
99
|
+
"delete_unfinished_upload": "Unvollständigen Upload entfernen?",
|
|
99
100
|
"File menu": "Dateimenü",
|
|
100
101
|
"Folder menu": "Ordnermenü",
|
|
101
102
|
"Name": "Name",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} ολοκληρώθηκαν ({size})",
|
|
97
97
|
"upload_errors": "{n} απέτυχαν",
|
|
98
98
|
"upload_file_rejected": "Κάποια αρχεία δεν γίνονται δεκτά",
|
|
99
|
+
"delete_unfinished_upload": "Να αφαιρεθεί η ημιτελής μεταφόρτωση;",
|
|
99
100
|
"File menu": "Μενού αρχείου",
|
|
100
101
|
"Folder menu": "Μενού φακέλου",
|
|
101
102
|
"Name": "Όνομα",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} completado ({size})",
|
|
97
97
|
"upload_errors": "{n} fallido",
|
|
98
98
|
"upload_file_rejected": "Algunos archivos no fueron aceptados",
|
|
99
|
+
"delete_unfinished_upload": "¿Eliminar la subida sin terminar?",
|
|
99
100
|
"File menu": "Archivo",
|
|
100
101
|
"Folder menu": "Carpeta",
|
|
101
102
|
"Name": "Nombre",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} tiedostoa tai kansiota lähetetty onnistuneesti ({size})",
|
|
97
97
|
"upload_errors": "{n} epäonnistui",
|
|
98
98
|
"upload_file_rejected": "Joitakin tiedostoja ei hyväksytty",
|
|
99
|
+
"delete_unfinished_upload": "Poistetaanko keskeneräinen lähetys?",
|
|
99
100
|
"File menu": "Tiedostovalikko",
|
|
100
101
|
"Folder menu": "Kansiovalikko",
|
|
101
102
|
"Name": "Nimi",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} terminé(s) ({size})",
|
|
97
97
|
"upload_errors": "{n} échoués",
|
|
98
98
|
"upload_file_rejected": "Certains fichiers ont été refusés",
|
|
99
|
+
"delete_unfinished_upload": "Supprimer l'envoi inachevé ?",
|
|
99
100
|
"File menu": "Menu du fichier",
|
|
100
101
|
"Folder menu": "Menu du dossier",
|
|
101
102
|
"Name": "Nom",
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
"upload_finished": "{n} kész ({size})",
|
|
98
98
|
"upload_errors": "{n} sikertelen",
|
|
99
99
|
"upload_file_rejected": "Egyes fájlokat nem sikerült feltölteni",
|
|
100
|
+
"delete_unfinished_upload": "Eltávolítja a befejezetlen feltöltést?",
|
|
100
101
|
"download counter": "letöltés számláló",
|
|
101
102
|
"File menu": "Fájl menü",
|
|
102
103
|
"Folder menu": "Mappa menü",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"upload_finished": "{n,plural, one{# riuscito} other{# riusciti}} ({size})",
|
|
90
90
|
"upload_errors": "{n,plural, one{# fallito} other{# falliti}}",
|
|
91
91
|
"upload_file_rejected": "Alcuni file non sono stati accettati",
|
|
92
|
+
"delete_unfinished_upload": "Rimuovere l'upload incompleto?",
|
|
92
93
|
"File menu": "Menu file",
|
|
93
94
|
"Folder menu": "Menu cartella",
|
|
94
95
|
"Name": "Nome",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"upload_finished": "{n} baigta ({size})",
|
|
96
96
|
"upload_errors": "{n} nepavyko",
|
|
97
97
|
"upload_file_rejected": "Kai kurie failai nebuvo priimti",
|
|
98
|
+
"delete_unfinished_upload": "Pašalinti nebaigtą įkėlimą?",
|
|
98
99
|
"File menu": "Failo meniu",
|
|
99
100
|
"Folder menu": "Aplanko meniu",
|
|
100
101
|
"Name": "Pavadinimas",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"upload_finished": "{n} selesai ({size})",
|
|
60
60
|
"upload_errors": "{n} gagal",
|
|
61
61
|
"upload_file_rejected": "Beberapa fail tidak diterima",
|
|
62
|
+
"delete_unfinished_upload": "Alih keluar muat naik yang belum selesai?",
|
|
62
63
|
"ready_to_upload": "{n,plural,one{# fail} other{# fail}}, {size}, sedia untuk dimuat naik",
|
|
63
64
|
"Send": "Hantar",
|
|
64
65
|
"download counter": "pengira muat turun",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"upload_finished": "{n} voltooid ({size})",
|
|
96
96
|
"upload_errors": "{n} niet voltooid",
|
|
97
97
|
"upload_file_rejected": "Sommige bestanden zijn niet geaccepteerd",
|
|
98
|
+
"delete_unfinished_upload": "Onvoltooide upload verwijderen?",
|
|
98
99
|
"File menu": "Bestand menu",
|
|
99
100
|
"Folder menu": "Map menu",
|
|
100
101
|
"Name": "Naam",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"upload_finished": "{n} zakończonych ({size})",
|
|
96
96
|
"upload_errors": "{n} nieudanych",
|
|
97
97
|
"upload_file_rejected": "Niektóre pliki nie zostały zaakceptowane",
|
|
98
|
+
"delete_unfinished_upload": "Usunąć niedokończone przesyłanie?",
|
|
98
99
|
"File menu": "Menu pliku",
|
|
99
100
|
"Folder menu": "Menu folderu",
|
|
100
101
|
"Name": "Nazwa",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"upload_finished": "{n} finalizado ({size})",
|
|
96
96
|
"upload_errors": "{n} faliu",
|
|
97
97
|
"upload_file_rejected": "Alguns arquivos não foram aceitos",
|
|
98
|
+
"delete_unfinished_upload": "Remover o envio inacabado?",
|
|
98
99
|
"File menu": "Menu de arquivo",
|
|
99
100
|
"Folder menu": "Menu de Pasta",
|
|
100
101
|
"Name": "Nome",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} terminat ({size})",
|
|
97
97
|
"upload_errors": "{n} eșuat",
|
|
98
98
|
"upload_file_rejected": "Unele fișiere nu au fost acceptate",
|
|
99
|
+
"delete_unfinished_upload": "Eliminați încărcarea neterminată?",
|
|
99
100
|
"File menu": "Meniu fișier",
|
|
100
101
|
"Folder menu": "Meniu folder",
|
|
101
102
|
"Name": "Nume",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n,plural, one{# файл загружен} few{# файла загружено} many{# файлов загружено}} ({size})",
|
|
97
97
|
"upload_errors": "{n,plural, one{# файл} few{# файла} many{# файлов}} неуспешно",
|
|
98
98
|
"upload_file_rejected": "Некоторые файлы не были приняты",
|
|
99
|
+
"delete_unfinished_upload": "Удалить незавершённую загрузку?",
|
|
99
100
|
"File menu": "Меню файла",
|
|
100
101
|
"Folder menu": "Меню папки",
|
|
101
102
|
"Name": "Имя",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"upload_finished": "{n} završeno ({size})",
|
|
96
96
|
"upload_errors": "{n,plural, one{# nije uspeo} other{# neuspešna}}",
|
|
97
97
|
"upload_file_rejected": "Neke datoteke nisu prihvaćene",
|
|
98
|
+
"delete_unfinished_upload": "Ukloniti nedovršeno otpremanje?",
|
|
98
99
|
"File menu": "Meni datoteke",
|
|
99
100
|
"Folder menu": "Meni fascikle",
|
|
100
101
|
"Name": "Ime",
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
"upload_finished": "{n} пребачен(о) ({size})",
|
|
99
99
|
"upload_errors": "{n} неуспешно пребачен(их)",
|
|
100
100
|
"upload_file_rejected": "Нека документа нису прихваћена",
|
|
101
|
+
"delete_unfinished_upload": "Уклонити недовршено отпремање?",
|
|
101
102
|
"download counter": "бројач преузимања",
|
|
102
103
|
"File menu": "Мени документа",
|
|
103
104
|
"Folder menu": "Мени фолдера",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} เสร็จสิ้น ({size})",
|
|
97
97
|
"upload_errors": "{n} ล้มเหลว",
|
|
98
98
|
"upload_file_rejected": "บางไฟล์ไม่ได้รับการยอมรับ",
|
|
99
|
+
"delete_unfinished_upload": "ลบการอัปโหลดที่ยังไม่เสร็จหรือไม่?",
|
|
99
100
|
"File menu": "เมนูไฟล์",
|
|
100
101
|
"Folder menu": "เมนูโฟลเดอร์",
|
|
101
102
|
"Name": "ชื่อ",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n} tamamlandı ({size})",
|
|
97
97
|
"upload_errors": "{n} başarısız",
|
|
98
98
|
"upload_file_rejected": "Bazı dosyalar kabul edilmiyor",
|
|
99
|
+
"delete_unfinished_upload": "Tamamlanmamış yüklemeyi kaldır?",
|
|
99
100
|
"File menu": "Dosya Menüsü",
|
|
100
101
|
"Folder menu": "Klasör Menüsü",
|
|
101
102
|
"Name": "İsim",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"upload_finished": "{n,plural, one{# файл завантажено} few{# файли завантажено} many{# файлів завантажено}} ({size})",
|
|
97
97
|
"upload_errors": "{n,plural, one{# файл} few{# файли} many{# файлів}} неуспішно",
|
|
98
98
|
"upload_file_rejected": "Деякі файли не були прийняті",
|
|
99
|
+
"delete_unfinished_upload": "Видалити незавершене завантаження?",
|
|
99
100
|
"File menu": "Меню файлу",
|
|
100
101
|
"Folder menu": "Меню теки",
|
|
101
102
|
"Name": "Назва",
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
"upload_finished": "{n} thành công ({size})",
|
|
98
98
|
"upload_errors": "{n} thất bại",
|
|
99
99
|
"upload_file_rejected": "Một số file bị cấm...",
|
|
100
|
+
"delete_unfinished_upload": "Xóa bản upload chưa hoàn tất?",
|
|
100
101
|
"Download counter": "Bộ đếm download",
|
|
101
102
|
"File menu": "Menu",
|
|
102
103
|
"Folder menu": "Menu",
|
package/src/listen.js
CHANGED
|
@@ -69,11 +69,12 @@ const argv_1 = require("./argv");
|
|
|
69
69
|
const consoleLog_1 = require("./consoleLog");
|
|
70
70
|
const first_1 = require("./first");
|
|
71
71
|
const fileAttr_1 = require("./fileAttr");
|
|
72
|
+
const uploadOwners_1 = require("./uploadOwners");
|
|
72
73
|
let httpSrv;
|
|
73
74
|
let httpsSrv;
|
|
74
75
|
// the update relaunch can keep a bridge process alive, so we proactively close listeners here to release ports before the next binary binds; do it before (5) the storage file is closed, because sockets write there
|
|
75
76
|
(0, first_1.onProcessExit)(() => Promise.all([stopServer(httpSrv), stopServer(httpsSrv)]), 5);
|
|
76
|
-
const openBrowserAtStart = (0, config_1.defineConfig)(
|
|
77
|
+
const openBrowserAtStart = (0, config_1.defineConfig)(misc_1.CFG.open_browser_at_start, true);
|
|
77
78
|
exports.baseUrl = (0, config_1.defineConfig)(misc_1.CFG.base_url, '', x => /(?<=\/\/)[^\/]+/.exec(x)?.[0]); // compiled is host only
|
|
78
79
|
async function getBaseUrlOrDefault() {
|
|
79
80
|
return exports.baseUrl.get() || await nat_1.defaultBaseUrl.get();
|
|
@@ -87,7 +88,7 @@ const commonServerOptions = {
|
|
|
87
88
|
};
|
|
88
89
|
// these are properties that can be assigned to the server object
|
|
89
90
|
const commonServerAssign = { headersTimeout: 30_000, timeout: misc_1.MINUTE }; // 'headersTimeout' is not recognized by type lib, and 'timeout' is not effective when passed in parameters
|
|
90
|
-
const readyToListen = Promise.all([persistence_1.storedMap.isOpening(), fileAttr_1.fileAttrDb.isOpening(), events_1.default.once('app')]);
|
|
91
|
+
const readyToListen = Promise.all([persistence_1.storedMap.isOpening(), fileAttr_1.fileAttrDb.isOpening(), uploadOwners_1.uploadOwners.isOpening(), events_1.default.once('app')]);
|
|
91
92
|
const considerHttp = (0, misc_1.debounceAsync)(async () => {
|
|
92
93
|
await readyToListen;
|
|
93
94
|
void stopServer(httpSrv);
|
|
@@ -109,8 +110,8 @@ const considerHttp = (0, misc_1.debounceAsync)(async () => {
|
|
|
109
110
|
}
|
|
110
111
|
});
|
|
111
112
|
let openOnce = true;
|
|
112
|
-
exports.portCfg = (0, config_1.defineConfig)(
|
|
113
|
-
const listenInterface = (0, config_1.defineConfig)(
|
|
113
|
+
exports.portCfg = (0, config_1.defineConfig)(misc_1.CFG.port, 80);
|
|
114
|
+
const listenInterface = (0, config_1.defineConfig)(misc_1.CFG.listen_interface, '');
|
|
114
115
|
(0, config_1.subMultipleConfigs)(considerHttp, [exports.portCfg, listenInterface]);
|
|
115
116
|
function openAdmin() {
|
|
116
117
|
for (const srv of [httpSrv, httpsSrv]) {
|
|
@@ -123,7 +124,7 @@ function openAdmin() {
|
|
|
123
124
|
const baseUrl = `${srv.name}://${hostname}:${a.port}`;
|
|
124
125
|
(0, open_1.default)(baseUrl + const_1.ADMIN_URI, { wait: true }).catch(async (e) => {
|
|
125
126
|
console.debug(String(e));
|
|
126
|
-
console.warn("Cannot launch browser on this machine
|
|
127
|
+
console.warn("Cannot launch browser on this machine – open your browser and reach one of these (you may need a different address)", ...Object.values(await getUrls()).flat().map(x => '\n - ' + x + const_1.ADMIN_URI));
|
|
127
128
|
if (!(0, adminApis_1.anyAccountCanLoginAdmin)())
|
|
128
129
|
(0, consoleLog_1.consoleHint)(`you can enter this command: create-admin YOUR_PASSWORD`);
|
|
129
130
|
});
|
|
@@ -138,7 +139,8 @@ function getCertObject() {
|
|
|
138
139
|
const all = new crypto_1.X509Certificate(c);
|
|
139
140
|
const some = lodash_1.default.pick(all, ['subject', 'issuer', 'validFrom', 'validTo']);
|
|
140
141
|
const ret = lodash_1.default.mapValues(some, v => v?.includes('=') ? Object.fromEntries(v.split('\n').map(x => x.split('='))) : v);
|
|
141
|
-
return Object.assign(ret, { altNames: all.subjectAltName?.
|
|
142
|
+
return Object.assign(ret, { altNames: all.subjectAltName?.split(/, */)
|
|
143
|
+
.map(x => x.replace(/^(?:DNS:|IP Address:)/, '')) });
|
|
142
144
|
}
|
|
143
145
|
const considerHttps = (0, misc_1.debounceAsync)(async () => {
|
|
144
146
|
await readyToListen;
|
|
@@ -205,8 +207,8 @@ const considerHttps = (0, misc_1.debounceAsync)(async () => {
|
|
|
205
207
|
nat_1.defaultBaseUrl.proto = 'https';
|
|
206
208
|
nat_1.defaultBaseUrl.port = getCurrentPort(httpsSrv) ?? 0;
|
|
207
209
|
}, { wait: 200 }); // give time to have key and cert ready
|
|
208
|
-
exports.cert = (0, config_1.defineConfig)(
|
|
209
|
-
exports.privateKey = (0, config_1.defineConfig)(
|
|
210
|
+
exports.cert = (0, config_1.defineConfig)(misc_1.CFG.cert, '', load);
|
|
211
|
+
exports.privateKey = (0, config_1.defineConfig)(misc_1.CFG.private_key, '', load);
|
|
210
212
|
const httpsNeeds = [exports.cert, exports.privateKey];
|
|
211
213
|
function load(v, { object }) {
|
|
212
214
|
object.watcher?.unwatch();
|
|
@@ -216,7 +218,7 @@ function load(v, { object }) {
|
|
|
216
218
|
object.watcher = (0, watchLoad_1.watchLoad)(v, x => object.setCompiled(x), { immediateFirst: true });
|
|
217
219
|
return '';
|
|
218
220
|
}
|
|
219
|
-
exports.httpsPortCfg = (0, config_1.defineConfig)(
|
|
221
|
+
exports.httpsPortCfg = (0, config_1.defineConfig)(misc_1.CFG.https_port, const_1.PORT_DISABLED);
|
|
220
222
|
(0, config_1.subMultipleConfigs)(considerHttps, [exports.httpsPortCfg, listenInterface, ...httpsNeeds]);
|
|
221
223
|
const genericInterfaceNames = {
|
|
222
224
|
'0.0.0.0': "any IPv4",
|
|
@@ -273,12 +275,14 @@ function startServer(srv, { port, host }) {
|
|
|
273
275
|
srv.error = String(e);
|
|
274
276
|
srv.busy = undefined;
|
|
275
277
|
const { code } = e;
|
|
276
|
-
|
|
278
|
+
// share the lookup with status readers, but classify the error from its resolved result
|
|
279
|
+
if (code === 'EADDRINUSE' || code === 'EACCES')
|
|
277
280
|
srv.busy = (0, find_process_1.default)('port', port).then(res => res?.map(x => (0, misc_1.prefix)("Service", x.name === 'svchost.exe' && x.cmd.split(x.name)[1]?.trim()) || x.name).join(' + '), () => '');
|
|
278
|
-
|
|
281
|
+
const busy = await srv.busy;
|
|
282
|
+
if (code === 'EACCES' && port < 1024 && !busy) // on Windows, when port is used by a service, we get EACCES
|
|
279
283
|
srv.error = `lacking permission on port ${port}, try with permission (${const_1.IS_WINDOWS ? 'administrator' : 'sudo'}) or port > 1024`;
|
|
280
|
-
if (code === 'EADDRINUSE' ||
|
|
281
|
-
srv.error = `port ${port} busy: ${
|
|
284
|
+
if (code === 'EADDRINUSE' || busy)
|
|
285
|
+
srv.error = `port ${port} busy: ${busy || "unknown process"}`;
|
|
282
286
|
if (!silence)
|
|
283
287
|
console.error(srv.name, srv.error);
|
|
284
288
|
resolve(0);
|
package/src/log.js
CHANGED
|
@@ -82,8 +82,14 @@ class Logger {
|
|
|
82
82
|
this.reopen();
|
|
83
83
|
}
|
|
84
84
|
reopen() {
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
const { path } = this;
|
|
86
|
+
const s = this.stream = (0, util_files_1.createFileWithPath)(path, { flags: 'a' });
|
|
87
|
+
s?.on('error', e => {
|
|
88
|
+
if (this.stream === s) // a late error from an old stream must not detach its replacement
|
|
89
|
+
this.stream = undefined;
|
|
90
|
+
console.error("Cannot write log file", path, String(e));
|
|
91
|
+
});
|
|
92
|
+
return s;
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
95
|
// we'll have names same as config keys. These are used also by the get_log api.
|
|
@@ -103,6 +109,7 @@ const logRotation = (0, config_1.defineConfig)(misc_1.CFG.log_rotation, 'weekly'
|
|
|
103
109
|
const dontLogNet = (0, config_1.defineConfig)(misc_1.CFG.dont_log_net, '127.0.0.1|::1', v => (0, misc_1.makeNetMatcher)(v));
|
|
104
110
|
const logUA = (0, config_1.defineConfig)(misc_1.CFG.log_ua, false);
|
|
105
111
|
const logSpam = (0, config_1.defineConfig)(misc_1.CFG.log_spam, false);
|
|
112
|
+
const logHost = (0, config_1.defineConfig)(misc_1.CFG.log_host, false);
|
|
106
113
|
const debounce = lodash_1.default.debounce(cb => cb(), 1000); // with this technique, i'll be able to debounce some code respecting the references in its closure
|
|
107
114
|
const logMw = async (ctx, next) => {
|
|
108
115
|
const reqStart = new Date(); // request start
|
|
@@ -176,6 +183,8 @@ const logMw = async (ctx, next) => {
|
|
|
176
183
|
ctx.logExtra({ country: conn.country });
|
|
177
184
|
if (logUA.get())
|
|
178
185
|
ctx.logExtra({ ua: ctx.get('user-agent') || undefined });
|
|
186
|
+
if (logHost.get())
|
|
187
|
+
ctx.logExtra({ host: ctx.get('host') || undefined });
|
|
179
188
|
const extra = ctx.state.logExtra;
|
|
180
189
|
if (events_2.default.anyListener(logger.name)) // small optimization: this event can happen often, while most times there's no listener, and the parameters object is constructed pointlessly. A benchmark measured it 20% faster (just the line), while maybe it was not necessary.
|
|
181
190
|
events_2.default.emit(logger.name, { ctx, length, user, ts: reqEnd, uri, extra });
|
package/src/middlewares.js
CHANGED
|
@@ -21,10 +21,10 @@ const config_1 = require("./config");
|
|
|
21
21
|
const koa_session_1 = __importDefault(require("koa-session"));
|
|
22
22
|
const index_1 = require("./index");
|
|
23
23
|
const events_1 = __importDefault(require("./events"));
|
|
24
|
-
const forceHttps = (0, config_1.defineConfig)(
|
|
25
|
-
(0, config_1.defineConfig)(
|
|
26
|
-
const allowAuthorizationHeader = (0, config_1.defineConfig)(
|
|
27
|
-
exports.sessionDuration = (0, config_1.defineConfig)(
|
|
24
|
+
const forceHttps = (0, config_1.defineConfig)(misc_1.CFG.force_https, true);
|
|
25
|
+
(0, config_1.defineConfig)(misc_1.CFG.ignore_proxies, false);
|
|
26
|
+
const allowAuthorizationHeader = (0, config_1.defineConfig)(misc_1.CFG.authorization_header, true);
|
|
27
|
+
exports.sessionDuration = (0, config_1.defineConfig)(misc_1.CFG.session_duration, Number(process.env.SESSION_DURATION) || misc_1.DAY / 1000, v => v * 1000);
|
|
28
28
|
exports.gzipper = (0, koa_compress_1.default)({
|
|
29
29
|
threshold: 2048,
|
|
30
30
|
gzip: { flush: zlib_1.constants.Z_SYNC_FLUSH }, // flush is necessary for SSE, at least in Chrome145
|
package/src/misc.js
CHANGED
|
@@ -120,15 +120,15 @@ function asyncGeneratorToReadable(generator) {
|
|
|
120
120
|
const iterator = generator[Symbol.asyncIterator]();
|
|
121
121
|
return new stream_1.Readable({
|
|
122
122
|
objectMode: true,
|
|
123
|
-
destroy() {
|
|
124
|
-
|
|
123
|
+
destroy(error, callback) {
|
|
124
|
+
Promise.resolve(iterator.return?.()).then(() => callback(error), callback);
|
|
125
125
|
},
|
|
126
126
|
read() {
|
|
127
127
|
iterator.next().then(it => {
|
|
128
128
|
if (it.done)
|
|
129
129
|
this.emit('ending');
|
|
130
130
|
return this.push(it.done ? null : it.value);
|
|
131
|
-
});
|
|
131
|
+
}, e => this.destroy(e));
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
}
|
package/src/multipartUpload.js
CHANGED
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.handleMultipartUpload = handleMultipartUpload;
|
|
7
7
|
const busboy_1 = __importDefault(require("busboy"));
|
|
8
|
-
const events_1 = require("events");
|
|
9
8
|
const vfs_1 = require("./vfs");
|
|
10
9
|
const path_1 = require("path");
|
|
11
10
|
const upload_1 = require("./upload");
|
|
@@ -46,7 +45,7 @@ async function handleMultipartUpload(ctx, node) {
|
|
|
46
45
|
ctx.status = cross_const_1.HTTP_BAD_REQUEST;
|
|
47
46
|
});
|
|
48
47
|
ctx.req.pipe(bb);
|
|
49
|
-
await (0,
|
|
48
|
+
await new Promise(res => (0, first_1.onFirstEvent)(bb, ['finish', 'error'], res)); // parser errors are handled above as 400 and must complete the request without rejecting
|
|
50
49
|
await Promise.all(fileJobs);
|
|
51
50
|
if (!ctx.state.uploads?.length) {
|
|
52
51
|
if (!errors.length)
|
package/src/nat.js
CHANGED
|
@@ -33,7 +33,7 @@ exports.defaultBaseUrl = (0, valtio_1.proxy)({
|
|
|
33
33
|
return `${this.proto}://${(0, cross_1.ipForUrl)(ip || 'localhost')}${!port || port === defPort ? '' : ':' + port}`;
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
-
exports.mappedPort = (0, config_1.defineConfig)(
|
|
36
|
+
exports.mappedPort = (0, config_1.defineConfig)(cross_1.CFG.mapped_port, 0);
|
|
37
37
|
exports.upnpEnabled = (0, config_1.defineConfig)(cross_1.CFG.upnp_enabled, true);
|
|
38
38
|
let upnpClient;
|
|
39
39
|
// poll external ip – when UPnP is enabled, asking the modem is inexpensive, so it can be done often
|