hfs 3.0.7 → 3.1.0-alpha2
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/README.md +1 -1
- package/admin/assets/index-CDiYkO8j.css +1 -0
- package/admin/assets/index-Dm5BN1iZ.js +1 -0
- package/admin/assets/index-P5i8LyWl.js +822 -0
- package/admin/assets/{sha512-gDcjPgJS.js → sha512-DG-ElrDe.js} +1 -1
- package/admin/flags/freakflags.css +284 -0
- package/admin/flags/sprite.png +0 -0
- package/admin/index.html +3 -2
- package/frontend/assets/index-legacy-CG_og8xL.js +1 -0
- package/frontend/assets/index-legacy-DDLKWGcm.js +9 -0
- package/frontend/assets/{sha512-legacy-BBwwadDl.js → sha512-legacy-D1zEZzDe.js} +1 -1
- package/frontend/fontello.css +3 -1
- package/frontend/fontello.woff2 +0 -0
- package/frontend/index.html +1 -1
- package/npm-shrinkwrap.json +16409 -0
- package/package.json +12 -11
- package/plugins/antibrute/plugin.js +14 -3
- package/src/AsapStream.js +49 -0
- package/src/ThrottledStream.js +1 -1
- package/src/adminApis.js +16 -5
- package/src/api.accounts.js +1 -6
- package/src/api.auth.js +103 -100
- package/src/api.get_file_list.js +7 -0
- package/src/api.lang.js +1 -0
- package/src/api.log.js +5 -3
- package/src/api.monitor.js +5 -0
- package/src/api.net.js +5 -0
- package/src/api.plugins.js +13 -2
- package/src/api.vfs.js +41 -28
- package/src/apiMiddleware.js +5 -4
- package/src/auth.js +39 -6
- package/src/commands.js +16 -27
- package/src/comments.js +4 -4
- package/src/config.js +5 -2
- package/src/const.js +2 -16
- package/src/cross-const.js +5 -2
- package/src/cross.js +21 -15
- package/src/expiringCache.js +16 -5
- package/src/fileAttr.js +1 -1
- package/src/first.js +7 -4
- package/src/frontEndApis.js +88 -102
- package/src/github.js +32 -21
- package/src/ips.js +1 -1
- package/src/log.js +5 -3
- package/src/middlewares.js +2 -1
- package/src/misc.js +2 -20
- package/src/perm.js +27 -12
- package/src/persistence.js +1 -1
- package/src/plugins.js +12 -6
- package/src/serveFile.js +3 -3
- package/src/serveGuiAndSharedFiles.js +3 -0
- package/src/serveGuiFiles.js +2 -1
- package/src/srp.js +5 -6
- package/src/stat.js +4 -1
- package/src/update.js +18 -25
- package/src/upload.js +4 -3
- package/src/util-files.js +2 -1
- package/src/util-http.js +3 -3
- package/src/vfs.js +4 -2
- package/src/webdav.js +297 -0
- package/admin/assets/index-Bj9Dk3JN.js +0 -822
- package/admin/assets/index-Byv1_NxP.css +0 -1
- package/admin/flags/ad.png +0 -0
- package/admin/flags/ae.png +0 -0
- package/admin/flags/af.png +0 -0
- package/admin/flags/ag.png +0 -0
- package/admin/flags/ai.png +0 -0
- package/admin/flags/al.png +0 -0
- package/admin/flags/am.png +0 -0
- package/admin/flags/ao.png +0 -0
- package/admin/flags/aq.png +0 -0
- package/admin/flags/ar.png +0 -0
- package/admin/flags/as.png +0 -0
- package/admin/flags/at.png +0 -0
- package/admin/flags/au.png +0 -0
- package/admin/flags/aw.png +0 -0
- package/admin/flags/ax.png +0 -0
- package/admin/flags/az.png +0 -0
- package/admin/flags/ba.png +0 -0
- package/admin/flags/bb.png +0 -0
- package/admin/flags/bd.png +0 -0
- package/admin/flags/be.png +0 -0
- package/admin/flags/bf.png +0 -0
- package/admin/flags/bg.png +0 -0
- package/admin/flags/bh.png +0 -0
- package/admin/flags/bi.png +0 -0
- package/admin/flags/bj.png +0 -0
- package/admin/flags/bl.png +0 -0
- package/admin/flags/bm.png +0 -0
- package/admin/flags/bn.png +0 -0
- package/admin/flags/bo.png +0 -0
- package/admin/flags/bq.png +0 -0
- package/admin/flags/br.png +0 -0
- package/admin/flags/bs.png +0 -0
- package/admin/flags/bt.png +0 -0
- package/admin/flags/bv.png +0 -0
- package/admin/flags/bw.png +0 -0
- package/admin/flags/by.png +0 -0
- package/admin/flags/bz.png +0 -0
- package/admin/flags/ca.png +0 -0
- package/admin/flags/cc.png +0 -0
- package/admin/flags/cd.png +0 -0
- package/admin/flags/cf.png +0 -0
- package/admin/flags/cg.png +0 -0
- package/admin/flags/ch.png +0 -0
- package/admin/flags/ci.png +0 -0
- package/admin/flags/ck.png +0 -0
- package/admin/flags/cl.png +0 -0
- package/admin/flags/cm.png +0 -0
- package/admin/flags/cn.png +0 -0
- package/admin/flags/co.png +0 -0
- package/admin/flags/cr.png +0 -0
- package/admin/flags/cu.png +0 -0
- package/admin/flags/cv.png +0 -0
- package/admin/flags/cw.png +0 -0
- package/admin/flags/cx.png +0 -0
- package/admin/flags/cy.png +0 -0
- package/admin/flags/cz.png +0 -0
- package/admin/flags/de.png +0 -0
- package/admin/flags/dj.png +0 -0
- package/admin/flags/dk.png +0 -0
- package/admin/flags/dm.png +0 -0
- package/admin/flags/do.png +0 -0
- package/admin/flags/dz.png +0 -0
- package/admin/flags/ec.png +0 -0
- package/admin/flags/ee.png +0 -0
- package/admin/flags/eg.png +0 -0
- package/admin/flags/eh.png +0 -0
- package/admin/flags/er.png +0 -0
- package/admin/flags/es.png +0 -0
- package/admin/flags/et.png +0 -0
- package/admin/flags/fi.png +0 -0
- package/admin/flags/fj.png +0 -0
- package/admin/flags/fk.png +0 -0
- package/admin/flags/fm.png +0 -0
- package/admin/flags/fo.png +0 -0
- package/admin/flags/fr.png +0 -0
- package/admin/flags/ga.png +0 -0
- package/admin/flags/gb-eng.png +0 -0
- package/admin/flags/gb-nir.png +0 -0
- package/admin/flags/gb-sct.png +0 -0
- package/admin/flags/gb-wls.png +0 -0
- package/admin/flags/gb.png +0 -0
- package/admin/flags/gd.png +0 -0
- package/admin/flags/ge.png +0 -0
- package/admin/flags/gf.png +0 -0
- package/admin/flags/gg.png +0 -0
- package/admin/flags/gh.png +0 -0
- package/admin/flags/gi.png +0 -0
- package/admin/flags/gl.png +0 -0
- package/admin/flags/gm.png +0 -0
- package/admin/flags/gn.png +0 -0
- package/admin/flags/gp.png +0 -0
- package/admin/flags/gq.png +0 -0
- package/admin/flags/gr.png +0 -0
- package/admin/flags/gs.png +0 -0
- package/admin/flags/gt.png +0 -0
- package/admin/flags/gu.png +0 -0
- package/admin/flags/gw.png +0 -0
- package/admin/flags/gy.png +0 -0
- package/admin/flags/hk.png +0 -0
- package/admin/flags/hm.png +0 -0
- package/admin/flags/hn.png +0 -0
- package/admin/flags/hr.png +0 -0
- package/admin/flags/ht.png +0 -0
- package/admin/flags/hu.png +0 -0
- package/admin/flags/id.png +0 -0
- package/admin/flags/ie.png +0 -0
- package/admin/flags/il.png +0 -0
- package/admin/flags/im.png +0 -0
- package/admin/flags/in.png +0 -0
- package/admin/flags/io.png +0 -0
- package/admin/flags/iq.png +0 -0
- package/admin/flags/ir.png +0 -0
- package/admin/flags/is.png +0 -0
- package/admin/flags/it.png +0 -0
- package/admin/flags/je.png +0 -0
- package/admin/flags/jm.png +0 -0
- package/admin/flags/jo.png +0 -0
- package/admin/flags/jp.png +0 -0
- package/admin/flags/ke.png +0 -0
- package/admin/flags/kg.png +0 -0
- package/admin/flags/kh.png +0 -0
- package/admin/flags/ki.png +0 -0
- package/admin/flags/km.png +0 -0
- package/admin/flags/kn.png +0 -0
- package/admin/flags/kp.png +0 -0
- package/admin/flags/kr.png +0 -0
- package/admin/flags/kw.png +0 -0
- package/admin/flags/ky.png +0 -0
- package/admin/flags/kz.png +0 -0
- package/admin/flags/la.png +0 -0
- package/admin/flags/lb.png +0 -0
- package/admin/flags/lc.png +0 -0
- package/admin/flags/li.png +0 -0
- package/admin/flags/lk.png +0 -0
- package/admin/flags/lr.png +0 -0
- package/admin/flags/ls.png +0 -0
- package/admin/flags/lt.png +0 -0
- package/admin/flags/lu.png +0 -0
- package/admin/flags/lv.png +0 -0
- package/admin/flags/ly.png +0 -0
- package/admin/flags/ma.png +0 -0
- package/admin/flags/mc.png +0 -0
- package/admin/flags/md.png +0 -0
- package/admin/flags/me.png +0 -0
- package/admin/flags/mf.png +0 -0
- package/admin/flags/mg.png +0 -0
- package/admin/flags/mh.png +0 -0
- package/admin/flags/mk.png +0 -0
- package/admin/flags/ml.png +0 -0
- package/admin/flags/mm.png +0 -0
- package/admin/flags/mn.png +0 -0
- package/admin/flags/mo.png +0 -0
- package/admin/flags/mp.png +0 -0
- package/admin/flags/mq.png +0 -0
- package/admin/flags/mr.png +0 -0
- package/admin/flags/ms.png +0 -0
- package/admin/flags/mt.png +0 -0
- package/admin/flags/mu.png +0 -0
- package/admin/flags/mv.png +0 -0
- package/admin/flags/mw.png +0 -0
- package/admin/flags/mx.png +0 -0
- package/admin/flags/my.png +0 -0
- package/admin/flags/mz.png +0 -0
- package/admin/flags/na.png +0 -0
- package/admin/flags/nc.png +0 -0
- package/admin/flags/ne.png +0 -0
- package/admin/flags/nf.png +0 -0
- package/admin/flags/ng.png +0 -0
- package/admin/flags/ni.png +0 -0
- package/admin/flags/nl.png +0 -0
- package/admin/flags/no.png +0 -0
- package/admin/flags/np.png +0 -0
- package/admin/flags/nr.png +0 -0
- package/admin/flags/nu.png +0 -0
- package/admin/flags/nz.png +0 -0
- package/admin/flags/om.png +0 -0
- package/admin/flags/pa.png +0 -0
- package/admin/flags/pe.png +0 -0
- package/admin/flags/pf.png +0 -0
- package/admin/flags/pg.png +0 -0
- package/admin/flags/ph.png +0 -0
- package/admin/flags/pk.png +0 -0
- package/admin/flags/pl.png +0 -0
- package/admin/flags/pm.png +0 -0
- package/admin/flags/pn.png +0 -0
- package/admin/flags/pr.png +0 -0
- package/admin/flags/ps.png +0 -0
- package/admin/flags/pt.png +0 -0
- package/admin/flags/pw.png +0 -0
- package/admin/flags/py.png +0 -0
- package/admin/flags/qa.png +0 -0
- package/admin/flags/re.png +0 -0
- package/admin/flags/ro.png +0 -0
- package/admin/flags/rs.png +0 -0
- package/admin/flags/ru.png +0 -0
- package/admin/flags/rw.png +0 -0
- package/admin/flags/sa.png +0 -0
- package/admin/flags/sb.png +0 -0
- package/admin/flags/sc.png +0 -0
- package/admin/flags/sd.png +0 -0
- package/admin/flags/se.png +0 -0
- package/admin/flags/sg.png +0 -0
- package/admin/flags/sh.png +0 -0
- package/admin/flags/si.png +0 -0
- package/admin/flags/sj.png +0 -0
- package/admin/flags/sk.png +0 -0
- package/admin/flags/sl.png +0 -0
- package/admin/flags/sm.png +0 -0
- package/admin/flags/sn.png +0 -0
- package/admin/flags/so.png +0 -0
- package/admin/flags/sr.png +0 -0
- package/admin/flags/ss.png +0 -0
- package/admin/flags/st.png +0 -0
- package/admin/flags/sv.png +0 -0
- package/admin/flags/sx.png +0 -0
- package/admin/flags/sy.png +0 -0
- package/admin/flags/sz.png +0 -0
- package/admin/flags/tc.png +0 -0
- package/admin/flags/td.png +0 -0
- package/admin/flags/tf.png +0 -0
- package/admin/flags/tg.png +0 -0
- package/admin/flags/th.png +0 -0
- package/admin/flags/tj.png +0 -0
- package/admin/flags/tk.png +0 -0
- package/admin/flags/tl.png +0 -0
- package/admin/flags/tm.png +0 -0
- package/admin/flags/tn.png +0 -0
- package/admin/flags/to.png +0 -0
- package/admin/flags/tr.png +0 -0
- package/admin/flags/tt.png +0 -0
- package/admin/flags/tv.png +0 -0
- package/admin/flags/tw.png +0 -0
- package/admin/flags/tz.png +0 -0
- package/admin/flags/ua.png +0 -0
- package/admin/flags/ug.png +0 -0
- package/admin/flags/um.png +0 -0
- package/admin/flags/us.png +0 -0
- package/admin/flags/uy.png +0 -0
- package/admin/flags/uz.png +0 -0
- package/admin/flags/va.png +0 -0
- package/admin/flags/vc.png +0 -0
- package/admin/flags/ve.png +0 -0
- package/admin/flags/vg.png +0 -0
- package/admin/flags/vi.png +0 -0
- package/admin/flags/vn.png +0 -0
- package/admin/flags/vu.png +0 -0
- package/admin/flags/wf.png +0 -0
- package/admin/flags/ws.png +0 -0
- package/admin/flags/xk.png +0 -0
- package/admin/flags/ye.png +0 -0
- package/admin/flags/yt.png +0 -0
- package/admin/flags/za.png +0 -0
- package/admin/flags/zm.png +0 -0
- package/admin/flags/zw.png +0 -0
- package/frontend/assets/index-legacy-COBT1YmS.js +0 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hfs",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0-alpha2",
|
|
4
4
|
"description": "HTTP File Server",
|
|
5
5
|
"keywords": ["file server", "http server"],
|
|
6
6
|
"homepage": "https://rejetto.com/hfs",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"watch-server-full": "npm run start --workspace=frontend & npm run start --workspace=admin & cross-env FRONTEND_PROXY=3005 ADMIN_PROXY=3006 npm run watch-server",
|
|
14
14
|
"start-frontend": "npm run start --workspace=frontend",
|
|
15
15
|
"start-admin": "npm run start --workspace=admin",
|
|
16
|
-
"build-all": "rm -rf dist && npm run build-server &&
|
|
17
|
-
"build-server": "rm -rf dist/src dist/plugins && npm i && tsc && touch package.json && cp -v -r package.json central.json README* LICENSE* hfs.ico plugins dist && find dist -name .DS_Store -o -name storage -exec rm -rf {} + && node afterbuild.js",
|
|
16
|
+
"build-all": "rm -rf dist && npm run build-server && (npm run build-frontend & npm run build-admin) && echo COMPLETED",
|
|
17
|
+
"build-server": "rm -rf dist/src dist/plugins && npm i && tsc && touch package.json && cp -v -r package.json central.json README* LICENSE* hfs.ico plugins dist && find dist -name .DS_Store -o -name storage -exec rm -rf {} + && node scripts/afterbuild.js",
|
|
18
18
|
"build-frontend": "npm run build --workspace=frontend",
|
|
19
19
|
"build-admin": "npm run build --workspace=admin",
|
|
20
20
|
"server-for-test": "node dist/src --cwd tests/work --config tests --debug",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"test": "node --import tsx --test tests/test.ts",
|
|
23
23
|
"test-with-server": "sh -c 'npm run port-is-free && tsc && rm -rf tests/work tests/tmp && (node dist/src --cwd tests/work --config tests & echo $! > .server_pid) && sleep 2 && node --import tsx --test \"$@\" tests/test.ts; _exit=$?; if [ -f ./.server_pid ]; then SERVER_PID=$(cat ./.server_pid); kill \"$SERVER_PID\" 2>/dev/null || true; rm -f ./.server_pid; fi; exit $_exit' --",
|
|
24
24
|
"port-is-free": "node -e \"const port=process.argv[1]||8081;process.exit(await fetch('http://localhost:'+port).then(() => console.log('BUSY')||1, () => 0))\" --",
|
|
25
|
-
"test-ui": "npx playwright test frontend && npx playwright test serial",
|
|
26
|
-
"test-with-ui": "sh -c 'npm run port-is-free -- 3005 && npm run start-frontend & npm run port-is-free -- 3006 && npm run start-admin & cross-env TEST_WITH_UI=1 npx playwright test --ui'",
|
|
25
|
+
"test-ui": "npx playwright test frontend && npx playwright test serial && npx playwright test admin-vfs",
|
|
26
|
+
"test-with-ui": "sh -c 'npm run port-is-free -- 3005 && npm run start-frontend & npm run port-is-free -- 3006 && npm run start-admin & cross-env TEST_WITH_UI=1 npx playwright test --ui \"$@\"' --",
|
|
27
27
|
"pub": "cd dist && npm publish",
|
|
28
28
|
"dist": "STASHED=; if ! git diff-index --quiet HEAD --; then git stash push -m 'dist' && STASHED=1; fi; CI=1 FORCE_COLOR=1 npm run dist-uncommitted || (EXIT_CODE=$?; [ -n \"$STASHED\" ] && git stash pop; exit $EXIT_CODE); [ -n \"$STASHED\" ] && git stash pop",
|
|
29
|
-
"dist-uncommitted": "npm audit --omit=dev --audit-level=moderate && npm run build-
|
|
29
|
+
"dist-uncommitted": "npm audit --omit=dev --audit-level=moderate && rm -rf dist && npm run build-server && npm run test-with-server && (npm run build-frontend & npm run build-admin) && npm run test-ui && npm run dist-bin",
|
|
30
30
|
"dist-bin": "npm run dist-modules && npm run dist-bin-win && npm run dist-bin-linux && npm run dist-bin-linux-arm && npm run dist-bin-mac && npm run dist-bin-mac-arm",
|
|
31
|
-
"dist-modules": "cp package*.json central.json README.md dist && cd dist && npm ci --omit=dev && cd .. && node prune_modules",
|
|
31
|
+
"dist-modules": "cp package*.json central.json README.md dist && cd dist && npm ci --omit=dev && npm shrinkwrap && cd .. && node scripts/prune_modules.js",
|
|
32
32
|
"dist-bin-win": "cd dist && pkg . --public -C gzip -t node20-win-x64 && npx resedit-cli --in hfs.exe --icon 1,../hfs.ico --out hfs.exe && zip hfs-windows-x64-$(jq -r .version ../package.json).zip hfs.exe -r plugins && cd ..",
|
|
33
33
|
"dist-bin-mac-arm": "cd dist && pkg . --public -C gzip -t node20-macos-arm64 && zip hfs-mac-arm64-$(jq -r .version ../package.json).zip hfs -r plugins && cd ..",
|
|
34
34
|
"dist-bin-mac": "cd dist && pkg . --public -C gzip -t node20-macos-x64 && zip hfs-mac-x64-$(jq -r .version ../package.json).zip hfs -r plugins && cd ..",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"files": [
|
|
47
47
|
"central.json",
|
|
48
|
+
"npm-shrinkwrap.json",
|
|
48
49
|
"src/*",
|
|
49
50
|
"admin/*",
|
|
50
51
|
"frontend/*",
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
},
|
|
80
81
|
"dependencies": {
|
|
81
82
|
"@gregoranders/csv": "^0.0.13",
|
|
82
|
-
"@rejetto/kvstorage": "^0.
|
|
83
|
+
"@rejetto/kvstorage": "^0.17.1",
|
|
83
84
|
"acme-client": "^5.4.0",
|
|
84
85
|
"busboy": "^1.6.0",
|
|
85
86
|
"crc-32": "^1.2.2",
|
|
@@ -90,8 +91,8 @@
|
|
|
90
91
|
"iconv-lite": "^0.7.0",
|
|
91
92
|
"immer": "^10.1.3",
|
|
92
93
|
"ip2location-nodejs": "^9.7.0",
|
|
93
|
-
"koa": "^3.1.
|
|
94
|
-
"koa-compress": "^5.
|
|
94
|
+
"koa": "^3.1.2",
|
|
95
|
+
"koa-compress": "^5.2.0",
|
|
95
96
|
"koa-mount": "^4.2.0",
|
|
96
97
|
"koa-session": "^7.0.2",
|
|
97
98
|
"limiter": "^3.0.0",
|
|
@@ -122,7 +123,7 @@
|
|
|
122
123
|
"@types/node": "^20.17.30",
|
|
123
124
|
"@types/node-forge": "^1.3.14",
|
|
124
125
|
"@types/picomatch": "^4.0.2",
|
|
125
|
-
"@yao-pkg/pkg": "6.
|
|
126
|
+
"@yao-pkg/pkg": "6.14.1",
|
|
126
127
|
"cross-env": "^10.0.0",
|
|
127
128
|
"koa-better-http-proxy": "^0.2.10",
|
|
128
129
|
"nm-prune": "^5.0.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
exports.version = 3
|
|
1
|
+
exports.version = 3.1
|
|
2
2
|
exports.description = "Introduce increasing delays between login attempts."
|
|
3
3
|
exports.apiRequired = 9.6 // addBlock
|
|
4
4
|
|
|
@@ -7,6 +7,7 @@ exports.config = {
|
|
|
7
7
|
max: { type: 'number', min: 1, defaultValue: 60, label: "Max delay", unit: "seconds", helperText: "Max seconds to delay before next login is allowed" },
|
|
8
8
|
blockAfter: { type: 'number', xs: 6, min: 1, max: 9999, defaultValue: 100, label: "Block IP after", unit: "attempts", helperText: "localhost excluded" },
|
|
9
9
|
blockForHours: { type: 'number', xs: 6, min: 0, defaultValue: 24, label: "Block for", unit: "hours" },
|
|
10
|
+
exclude: { type: 'string', defaultValue: '', label: "Exclude IPs", helperText: "Net mask syntax" },
|
|
10
11
|
}
|
|
11
12
|
exports.configDialog = {
|
|
12
13
|
maxWidth: 'xs',
|
|
@@ -15,7 +16,7 @@ exports.configDialog = {
|
|
|
15
16
|
const byIp = {}
|
|
16
17
|
|
|
17
18
|
exports.init = api => {
|
|
18
|
-
const { isLocalHost, HOUR } = api.misc
|
|
19
|
+
const { isLocalHost, HOUR, netMatches } = api.misc
|
|
19
20
|
api.events.multi({
|
|
20
21
|
async attemptingLogin({ ctx }) {
|
|
21
22
|
const { ip } = ctx
|
|
@@ -25,7 +26,7 @@ exports.init = api => {
|
|
|
25
26
|
const delay = Math.min(max, 1000 * api.getConfig('increment') * ++rec.attempts)
|
|
26
27
|
const wait = rec.next - now
|
|
27
28
|
rec.next = new Date(+rec.next + delay)
|
|
28
|
-
if (rec.attempts > api.getConfig('blockAfter') && !isLocalHost(ctx)) {
|
|
29
|
+
if (rec.attempts > api.getConfig('blockAfter') && !isLocalHost(ctx) && !isExcluded(ip)) {
|
|
29
30
|
const hours = api.getConfig('blockForHours')
|
|
30
31
|
api.addBlock({ ip, comment: "From antibrute plugin", expire: hours ? new Date(now.getTime() + hours * HOUR) : undefined })
|
|
31
32
|
}
|
|
@@ -42,4 +43,14 @@ exports.init = api => {
|
|
|
42
43
|
delete byIp[ctx.ip] // reset if login was successful
|
|
43
44
|
}
|
|
44
45
|
})
|
|
46
|
+
|
|
47
|
+
function isExcluded(ip) {
|
|
48
|
+
const mask = api.getConfig('exclude')
|
|
49
|
+
if (!mask) return false
|
|
50
|
+
try { return netMatches(ip, mask) }
|
|
51
|
+
catch (e) {
|
|
52
|
+
api.log("bad exclude mask:", String(e))
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
45
56
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AsapStream = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
const cross_1 = require("./cross");
|
|
6
|
+
// produces as promises resolve, not sequentially
|
|
7
|
+
class AsapStream extends stream_1.Readable {
|
|
8
|
+
promises;
|
|
9
|
+
finished = false;
|
|
10
|
+
constructor(promises) {
|
|
11
|
+
super({ objectMode: true });
|
|
12
|
+
this.promises = promises;
|
|
13
|
+
}
|
|
14
|
+
_read() {
|
|
15
|
+
if (this.finished)
|
|
16
|
+
return;
|
|
17
|
+
this.finished = true;
|
|
18
|
+
void (async () => {
|
|
19
|
+
const pending = [];
|
|
20
|
+
try {
|
|
21
|
+
if ((0, cross_1.isAsyncIterable)(this.promises)) {
|
|
22
|
+
const iterator = this.promises[Symbol.asyncIterator]();
|
|
23
|
+
while (true) {
|
|
24
|
+
const { value, done } = await iterator.next();
|
|
25
|
+
if (done)
|
|
26
|
+
break;
|
|
27
|
+
const promise = Promise.resolve(value);
|
|
28
|
+
pending.push(promise);
|
|
29
|
+
promise.then(x => x !== undefined && this.push(x), e => this.emit('error', e));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
for (const p of this.promises) {
|
|
34
|
+
const promise = Promise.resolve(p);
|
|
35
|
+
pending.push(promise);
|
|
36
|
+
promise.then(x => x !== undefined && this.push(x), e => this.emit('error', e));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
await Promise.allSettled(pending);
|
|
40
|
+
this.push(null);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
this.emit('error', e);
|
|
44
|
+
this.push(null);
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.AsapStream = AsapStream;
|
package/src/ThrottledStream.js
CHANGED
package/src/adminApis.js
CHANGED
|
@@ -71,10 +71,16 @@ exports.adminApis = {
|
|
|
71
71
|
customHtml: customHtml_1.customHtml.getText(),
|
|
72
72
|
};
|
|
73
73
|
},
|
|
74
|
-
set_config_text: ({ text }) =>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
74
|
+
set_config_text: ({ text }) => {
|
|
75
|
+
(0, misc_1.apiAssertTypes)({ string: { text } });
|
|
76
|
+
return config_1.configFile.save(text, { reparse: true });
|
|
77
|
+
},
|
|
78
|
+
update: ({ tag }) => {
|
|
79
|
+
(0, misc_1.apiAssertTypes)({ string_undefined: { tag } });
|
|
80
|
+
return (0, update_1.update)(tag).catch(e => {
|
|
81
|
+
throw e.cause?.statusCode ? new apiMiddleware_1.ApiError(e.cause?.statusCode) : e;
|
|
82
|
+
});
|
|
83
|
+
},
|
|
78
84
|
async check_update() {
|
|
79
85
|
return { options: await (0, update_1.getUpdates)() };
|
|
80
86
|
},
|
|
@@ -88,6 +94,10 @@ exports.adminApis = {
|
|
|
88
94
|
return {};
|
|
89
95
|
},
|
|
90
96
|
async ip_country({ ips }) {
|
|
97
|
+
(0, misc_1.apiAssertTypes)({
|
|
98
|
+
array: { ips },
|
|
99
|
+
string: { ips0: ips[0] }
|
|
100
|
+
});
|
|
91
101
|
const res = await Promise.allSettled(ips.map(geo_1.ip2country));
|
|
92
102
|
return {
|
|
93
103
|
codes: res.map(x => x.status === 'rejected' || x.value === '-' ? '' : x.value)
|
|
@@ -110,6 +120,7 @@ exports.adminApis = {
|
|
|
110
120
|
};
|
|
111
121
|
},
|
|
112
122
|
async set_custom_html({ sections }) {
|
|
123
|
+
(0, misc_1.apiAssertTypes)({ object: { sections } });
|
|
113
124
|
await (0, customHtml_1.saveCustomHtml)(sections);
|
|
114
125
|
return {};
|
|
115
126
|
},
|
|
@@ -196,7 +207,7 @@ const frpDebounced = (0, misc_1.debounceAsync)(async () => {
|
|
|
196
207
|
}
|
|
197
208
|
}, { retain: 10_000 });
|
|
198
209
|
function anyAccountCanLoginAdmin() {
|
|
199
|
-
return
|
|
210
|
+
return lodash_1.default.some(perm_1.accounts.get(), perm_1.accountCanLoginAdmin);
|
|
200
211
|
}
|
|
201
212
|
function preventAdminAccess(ctx) {
|
|
202
213
|
return !(0, misc_1.isLocalHost)(ctx) && !exports.adminNet.compiled()(ctx.ip);
|
package/src/api.accounts.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.default = {
|
|
|
40
40
|
return { list: Object.keys(perm_1.accounts.get()) };
|
|
41
41
|
},
|
|
42
42
|
get_account({ username }, ctx) {
|
|
43
|
+
(0, misc_1.apiAssertTypes)({ string: { username } });
|
|
43
44
|
return prepareAccount((0, perm_1.getAccount)(username || (0, auth_1.getCurrentUsername)(ctx)))
|
|
44
45
|
|| new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
45
46
|
},
|
|
@@ -85,10 +86,4 @@ exports.default = {
|
|
|
85
86
|
auth_1.invalidateSessionBefore.set((0, perm_1.normalizeUsername)(username), Date.now());
|
|
86
87
|
return {};
|
|
87
88
|
},
|
|
88
|
-
async change_srp({ username, salt, verifier }) {
|
|
89
|
-
(0, misc_1.apiAssertTypes)({ string: { username, salt, verifier } });
|
|
90
|
-
const a = (0, perm_1.getAccount)(username);
|
|
91
|
-
return a ? (0, perm_1.changeSrpHelper)(a, salt, verifier)
|
|
92
|
-
: new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
93
|
-
}
|
|
94
89
|
};
|
package/src/api.auth.js
CHANGED
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
7
|
+
exports.authApis = void 0;
|
|
8
8
|
const perm_1 = require("./perm");
|
|
9
9
|
const apiMiddleware_1 = require("./apiMiddleware");
|
|
10
10
|
const const_1 = require("./const");
|
|
@@ -13,103 +13,14 @@ const middlewares_1 = require("./middlewares");
|
|
|
13
13
|
const auth_1 = require("./auth");
|
|
14
14
|
const config_1 = require("./config");
|
|
15
15
|
const events_1 = __importDefault(require("./events"));
|
|
16
|
+
const misc_1 = require("./misc");
|
|
16
17
|
const ongoingLogins = {}; // store data that doesn't fit session object
|
|
17
18
|
const keepSessionAlive = (0, config_1.defineConfig)('keep_session_alive', true);
|
|
18
|
-
const login = async ({ username, password }, ctx) => {
|
|
19
|
-
if (!username)
|
|
20
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
|
21
|
-
if (!ctx.session)
|
|
22
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
23
|
-
try {
|
|
24
|
-
const account = await (0, auth_1.clearTextLogin)(ctx, username, password, 'api');
|
|
25
|
-
if (!account)
|
|
26
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
27
|
-
await (0, auth_1.setLoggedIn)(ctx, account.username);
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED, String(e));
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
redirect: ctx.state.account?.redirect,
|
|
34
|
-
...await (0, exports.refresh_session)({}, ctx)
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
exports.login = login;
|
|
38
|
-
const loginSrp1 = async ({ username }, ctx) => {
|
|
39
|
-
if (!username)
|
|
40
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
|
41
|
-
const account = (0, perm_1.getAccount)(username);
|
|
42
|
-
if (!ctx.session)
|
|
43
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
44
|
-
if (account?.plugin?.auth) // tell client to do clear-text login, before firing attemptingLogin, before triggering anti-brute
|
|
45
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_METHOD_NOT_ALLOWED);
|
|
46
|
-
if ((await events_1.default.emitAsync('attemptingLogin', { ctx, username }))?.isDefaultPrevented())
|
|
47
|
-
return;
|
|
48
|
-
if (!account || !(0, perm_1.accountCanLogin)(account)) { // TODO simulate fake account to prevent knowing valid usernames
|
|
49
|
-
ctx.logExtra({ u: username });
|
|
50
|
-
ctx.state.dontLog = false; // log even if log_api is false
|
|
51
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED, account && (0, perm_1.accountIsDisabled)(account) ? 'Account disabled' : undefined);
|
|
52
|
-
}
|
|
53
|
-
if ((0, middlewares_1.failAllowNet)(ctx, account))
|
|
54
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
55
|
-
try {
|
|
56
|
-
const { srpServer, ...rest } = await (0, auth_1.srpServerStep1)(account);
|
|
57
|
-
const sid = Math.random();
|
|
58
|
-
ongoingLogins[sid] = srpServer;
|
|
59
|
-
setTimeout(() => delete ongoingLogins[sid], 60_000);
|
|
60
|
-
ctx.session.loggingIn = { username, sid }; // temporarily store until process is complete
|
|
61
|
-
return rest;
|
|
62
|
-
}
|
|
63
|
-
catch (code) {
|
|
64
|
-
return new apiMiddleware_1.ApiError(code);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
exports.loginSrp1 = loginSrp1;
|
|
68
|
-
const loginSrp2 = async ({ pubKey, proof }, ctx) => {
|
|
69
|
-
if (!ctx.session)
|
|
70
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
71
|
-
if (!ctx.session.loggingIn)
|
|
72
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT);
|
|
73
|
-
const { username, sid } = ctx.session.loggingIn;
|
|
74
|
-
delete ctx.session.loggingIn;
|
|
75
|
-
const step1 = ongoingLogins[sid];
|
|
76
|
-
if (!step1)
|
|
77
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
78
|
-
try {
|
|
79
|
-
const M2 = await step1.step2(BigInt(pubKey), BigInt(proof))
|
|
80
|
-
.catch(() => { throw ''; });
|
|
81
|
-
await (0, auth_1.setLoggedIn)(ctx, username);
|
|
82
|
-
return {
|
|
83
|
-
proof: String(M2),
|
|
84
|
-
redirect: ctx.state.account?.redirect,
|
|
85
|
-
...await (0, exports.refresh_session)({}, ctx)
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
catch (e) {
|
|
89
|
-
ctx.logExtra({ u: username });
|
|
90
|
-
ctx.state.dontLog = false; // log even if log_api is false
|
|
91
|
-
events_1.default.emit('failedLogin', { ctx, username });
|
|
92
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED, e ? String(e) : undefined);
|
|
93
|
-
}
|
|
94
|
-
finally {
|
|
95
|
-
delete ongoingLogins[sid];
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
exports.loginSrp2 = loginSrp2;
|
|
99
|
-
// this api is here for consistency, but frontend is actually using
|
|
100
|
-
const logout = async ({}, ctx) => {
|
|
101
|
-
if (!ctx.session)
|
|
102
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
103
|
-
await (0, auth_1.setLoggedIn)(ctx, false);
|
|
104
|
-
// 401 is a convenient code for OK: the browser clears a possible http authentication (hopefully), and Admin automatically triggers login dialog
|
|
105
|
-
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
106
|
-
};
|
|
107
|
-
exports.logout = logout;
|
|
108
19
|
const refresh_session = async ({}, ctx) => {
|
|
109
20
|
const username = (0, auth_1.getCurrentUsername)(ctx);
|
|
110
21
|
return !ctx.session ? new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR) : {
|
|
111
22
|
username,
|
|
112
|
-
expandedUsername: (0, perm_1.expandUsername)(username),
|
|
23
|
+
expandedUsername: Array.from((0, perm_1.expandUsername)(username)),
|
|
113
24
|
adminUrl: (0, adminApis_1.ctxAdminAccess)(ctx) ? ctx.state.revProxyPath + const_1.ADMIN_URI : undefined,
|
|
114
25
|
canChangePassword: (0, perm_1.accountCanChangePassword)(ctx.state.account),
|
|
115
26
|
requireChangePassword: ctx.state.account?.require_password_change,
|
|
@@ -117,12 +28,104 @@ const refresh_session = async ({}, ctx) => {
|
|
|
117
28
|
accountExp: ctx.state.account?.expire,
|
|
118
29
|
};
|
|
119
30
|
};
|
|
120
|
-
exports.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
31
|
+
exports.authApis = {
|
|
32
|
+
async login({ username, password }, ctx) {
|
|
33
|
+
if (!username)
|
|
34
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
|
35
|
+
if (!ctx.session)
|
|
36
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
37
|
+
try {
|
|
38
|
+
const account = await (0, auth_1.clearTextLogin)(ctx, username, password, 'api');
|
|
39
|
+
if (!account)
|
|
40
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
41
|
+
await (0, auth_1.setLoggedIn)(ctx, account.username);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED, String(e));
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
redirect: ctx.state.account?.redirect,
|
|
48
|
+
...await refresh_session({}, ctx)
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
async loginSrp1({ username }, ctx) {
|
|
52
|
+
(0, misc_1.apiAssertTypes)({ string: { username } });
|
|
53
|
+
if (!username)
|
|
54
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
|
|
55
|
+
const account = (0, perm_1.getAccount)(username);
|
|
56
|
+
if (!ctx.session)
|
|
57
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
58
|
+
if (account?.plugin?.auth) // tell client to do clear-text login, before firing attemptingLogin, before triggering anti-brute
|
|
59
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_METHOD_NOT_ALLOWED);
|
|
60
|
+
if ((await events_1.default.emitAsync('attemptingLogin', { ctx, username }))?.isDefaultPrevented())
|
|
61
|
+
return;
|
|
62
|
+
if (!account || !(0, perm_1.accountCanLogin)(account)) { // TODO simulate fake account to prevent knowing valid usernames
|
|
63
|
+
ctx.logExtra({ u: username });
|
|
64
|
+
ctx.state.dontLog = false; // log even if log_api is false
|
|
65
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED, account && (0, perm_1.accountIsDisabled)(account) ? 'Account disabled' : undefined);
|
|
66
|
+
}
|
|
67
|
+
if ((0, middlewares_1.failAllowNet)(ctx, account))
|
|
68
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
69
|
+
try {
|
|
70
|
+
const { srpServer, ...rest } = await (0, auth_1.srpServerStep1)(account);
|
|
71
|
+
const sid = Math.random();
|
|
72
|
+
ongoingLogins[sid] = srpServer;
|
|
73
|
+
setTimeout(() => delete ongoingLogins[sid], 60_000);
|
|
74
|
+
ctx.session.loggingIn = { username, sid }; // temporarily store until process is complete
|
|
75
|
+
return rest;
|
|
76
|
+
}
|
|
77
|
+
catch (code) {
|
|
78
|
+
return new apiMiddleware_1.ApiError(code);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
async loginSrp2({ pubKey, proof }, ctx) {
|
|
82
|
+
if (!ctx.session)
|
|
83
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
84
|
+
if (!ctx.session.loggingIn)
|
|
85
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT);
|
|
86
|
+
const { username, sid } = ctx.session.loggingIn;
|
|
87
|
+
delete ctx.session.loggingIn;
|
|
88
|
+
const step1 = ongoingLogins[sid];
|
|
89
|
+
if (!step1)
|
|
90
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND);
|
|
91
|
+
try {
|
|
92
|
+
const M2 = await step1.step2(BigInt(pubKey), BigInt(proof))
|
|
93
|
+
.catch(() => { throw ''; });
|
|
94
|
+
await (0, auth_1.setLoggedIn)(ctx, username);
|
|
95
|
+
return {
|
|
96
|
+
proof: String(M2),
|
|
97
|
+
redirect: ctx.state.account?.redirect,
|
|
98
|
+
...await refresh_session({}, ctx)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
ctx.logExtra({ u: username });
|
|
103
|
+
ctx.state.dontLog = false; // log even if log_api is false
|
|
104
|
+
events_1.default.emit('failedLogin', { ctx, username });
|
|
105
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED, e ? String(e) : undefined);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
delete ongoingLogins[sid];
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
// this api is here for consistency, but frontend is actually using
|
|
112
|
+
async logout({}, ctx) {
|
|
113
|
+
if (!ctx.session)
|
|
114
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR);
|
|
115
|
+
await (0, auth_1.setLoggedIn)(ctx, false);
|
|
116
|
+
// 401 is a convenient code for OK: the browser clears a possible http authentication (hopefully), and Admin automatically triggers login dialog
|
|
117
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
118
|
+
},
|
|
119
|
+
refresh_session,
|
|
120
|
+
async change_srp({ username, salt, verifier }, ctx) {
|
|
121
|
+
const a = username && (0, perm_1.getAccount)(username);
|
|
122
|
+
const can = a && ((0, adminApis_1.ctxAdminAccess)(ctx) || username === (0, auth_1.getCurrentUsername)(ctx) && (0, perm_1.accountCanChangePassword)(a));
|
|
123
|
+
if (!can)
|
|
124
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_UNAUTHORIZED);
|
|
125
|
+
if (!salt || !verifier)
|
|
126
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'missing parameters');
|
|
127
|
+
await (0, perm_1.updateAccount)(a, a => (0, perm_1.saveSrpInfo)(a, salt, verifier));
|
|
128
|
+
delete a.require_password_change;
|
|
129
|
+
return {};
|
|
130
|
+
}
|
|
127
131
|
};
|
|
128
|
-
exports.change_my_srp = change_my_srp;
|
package/src/api.get_file_list.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
7
|
exports.get_file_list = void 0;
|
|
5
8
|
exports.paramsToFilter = paramsToFilter;
|
|
@@ -14,6 +17,7 @@ const connections_1 = require("./connections");
|
|
|
14
17
|
const adminApis_1 = require("./adminApis");
|
|
15
18
|
const upload_1 = require("./upload");
|
|
16
19
|
const SendList_1 = require("./SendList");
|
|
20
|
+
const events_1 = __importDefault(require("./events"));
|
|
17
21
|
function paramsToFilter({ search, wild, searchComment, fileMask }) {
|
|
18
22
|
search = String(search || '').toLocaleLowerCase();
|
|
19
23
|
searchComment = String(searchComment || '').toLocaleLowerCase();
|
|
@@ -25,6 +29,7 @@ function paramsToFilter({ search, wild, searchComment, fileMask }) {
|
|
|
25
29
|
};
|
|
26
30
|
}
|
|
27
31
|
const get_file_list = async ({ uri = '/', offset, limit, c, onlyFolders, onlyFiles, admin, ...rest }, ctx) => {
|
|
32
|
+
(0, misc_1.apiAssertTypes)({ string: { uri } });
|
|
28
33
|
const node = await (0, vfs_1.urlToNode)(uri, ctx);
|
|
29
34
|
const list = ctx.get('accept') === 'text/event-stream' ? new SendList_1.SendListReadable() : undefined;
|
|
30
35
|
if (!node)
|
|
@@ -81,6 +86,8 @@ const get_file_list = async ({ uri = '/', offset, limit, c, onlyFolders, onlyFil
|
|
|
81
86
|
const res = await Promise.all(onDirEntryHandlers.map(cb => cb(cbParams)));
|
|
82
87
|
if (res.some(x => x === false))
|
|
83
88
|
continue;
|
|
89
|
+
if ((await events_1.default.emitAsync('dirEntry', cbParams))?.isDefaultPrevented())
|
|
90
|
+
continue;
|
|
84
91
|
}
|
|
85
92
|
catch (e) {
|
|
86
93
|
console.log("a plugin with onDirEntry is causing problems:", e);
|
package/src/api.lang.js
CHANGED
package/src/api.log.js
CHANGED
|
@@ -19,6 +19,7 @@ exports.default = {
|
|
|
19
19
|
return { current, rotated: await (0, log_1.getRotatedFiles)() };
|
|
20
20
|
},
|
|
21
21
|
async get_log_file({ file = 'log', range = '' }, ctx) {
|
|
22
|
+
(0, misc_1.apiAssertTypes)({ string: { file, range } });
|
|
22
23
|
const log = lodash_1.default.find(log_1.loggers, { name: file });
|
|
23
24
|
if (!log)
|
|
24
25
|
throw cross_1.HTTP_NOT_FOUND;
|
|
@@ -33,7 +34,8 @@ exports.default = {
|
|
|
33
34
|
return null;
|
|
34
35
|
},
|
|
35
36
|
get_log({ file = 'log' }, ctx) {
|
|
36
|
-
|
|
37
|
+
(0, misc_1.apiAssertTypes)({ string: { file } });
|
|
38
|
+
const files = file.split('|'); // potentially more than one
|
|
37
39
|
return new SendList_1.SendListReadable({
|
|
38
40
|
bufferTime: 10,
|
|
39
41
|
async doAtStart(list) {
|
|
@@ -58,10 +60,10 @@ exports.default = {
|
|
|
58
60
|
return list.ready();
|
|
59
61
|
}
|
|
60
62
|
// for other logs we only provide updates. Use get_log_file to download past content
|
|
61
|
-
if (lodash_1.default.some(files, x => !lodash_1.default.
|
|
63
|
+
if (lodash_1.default.some(files, x => !lodash_1.default.some(log_1.loggers, { name: x })))
|
|
62
64
|
return list.error(cross_1.HTTP_NOT_FOUND, true);
|
|
63
65
|
list.ready();
|
|
64
|
-
// unsubscribe when connection is interrupted
|
|
66
|
+
// unsubscribe when the connection is interrupted
|
|
65
67
|
ctx.res.once('close', events_1.default.on(files, x => list.add(Object.assign(lodash_1.default.pick(x.ctx, ['ip', 'method', 'status']), x, { ctx: undefined }))));
|
|
66
68
|
}
|
|
67
69
|
});
|
package/src/api.monitor.js
CHANGED
|
@@ -13,6 +13,11 @@ const SendList_1 = require("./SendList");
|
|
|
13
13
|
const persistence_1 = require("./persistence");
|
|
14
14
|
exports.default = {
|
|
15
15
|
async disconnect({ ip, port, allButLocalhost }) {
|
|
16
|
+
(0, misc_1.apiAssertTypes)({
|
|
17
|
+
string_undefined: { ip },
|
|
18
|
+
number_undefined: { port },
|
|
19
|
+
boolean_undefined: { allButLocalhost },
|
|
20
|
+
});
|
|
16
21
|
const match = allButLocalhost ? ((x) => !(0, misc_1.isLocalHost)(x.ip))
|
|
17
22
|
: lodash_1.default.matches({ ip, port });
|
|
18
23
|
const found = (0, connections_1.getConnections)().filter(c => match(getConnAddress(c)));
|
package/src/api.net.js
CHANGED
|
@@ -44,6 +44,7 @@ exports.default = {
|
|
|
44
44
|
return {};
|
|
45
45
|
},
|
|
46
46
|
async map_port({ external, internal }) {
|
|
47
|
+
(0, misc_1.apiAssertTypes)({ number_undefined: { external, internal } });
|
|
47
48
|
const { upnp, externalPort, internalPort } = await (0, nat_1.getNatInfo)();
|
|
48
49
|
if (!upnp)
|
|
49
50
|
return new apiMiddleware_1.ApiError(const_1.HTTP_SERVICE_UNAVAILABLE, "upnp failed");
|
|
@@ -64,6 +65,7 @@ exports.default = {
|
|
|
64
65
|
return {};
|
|
65
66
|
},
|
|
66
67
|
async self_check({ url }) {
|
|
68
|
+
(0, misc_1.apiAssertTypes)({ string_undefined: { url } });
|
|
67
69
|
if (url)
|
|
68
70
|
return await (0, selfCheck_1.selfCheck)(url)
|
|
69
71
|
|| new apiMiddleware_1.ApiError(const_1.HTTP_SERVICE_UNAVAILABLE);
|
|
@@ -79,6 +81,9 @@ exports.default = {
|
|
|
79
81
|
return results.length ? results : new apiMiddleware_1.ApiError(const_1.HTTP_SERVICE_UNAVAILABLE);
|
|
80
82
|
},
|
|
81
83
|
async make_cert({ domain, email, altNames }) {
|
|
84
|
+
(0, misc_1.apiAssertTypes)({ string: { domain }, string_undefined: { email }, array_undefined: { altNames } });
|
|
85
|
+
if (altNames?.some((name) => typeof name !== 'string'))
|
|
86
|
+
return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'bad altNames');
|
|
82
87
|
await (0, acme_1.makeCert)(domain, email, altNames).catch(e => {
|
|
83
88
|
throw new apiMiddleware_1.ApiError(const_1.HTTP_SERVER_ERROR, e.message || String(e));
|
|
84
89
|
});
|