hfs 3.1.5 → 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-DWEYq388.js +1 -0
- package/admin/assets/am-DgLbAgj6.js +1 -0
- package/admin/assets/ar-DgEWkO74.js +1 -0
- package/admin/assets/ar-dz-DHq--Sr8.js +1 -0
- package/admin/assets/ar-iq-D1r3nsb9.js +1 -0
- package/admin/assets/ar-kw-C85fGHwp.js +1 -0
- package/admin/assets/ar-ly-Bq6pjGjs.js +1 -0
- package/admin/assets/ar-ma-SGvmh6Mj.js +1 -0
- package/admin/assets/ar-sa-Bv8hiFi6.js +1 -0
- package/admin/assets/ar-tn-Bdvo77v3.js +1 -0
- package/admin/assets/az-7fPndoov.js +1 -0
- package/admin/assets/be-wjXeIeAK.js +1 -0
- package/admin/assets/bg-DZwBvjzH.js +1 -0
- package/admin/assets/bi-qCtxvMhO.js +1 -0
- package/admin/assets/bm-BVPWvreb.js +1 -0
- package/admin/assets/bn-CdWvye7d.js +1 -0
- package/admin/assets/bn-bd-B5-3blmz.js +1 -0
- package/admin/assets/bo-BEVcgyN2.js +1 -0
- package/admin/assets/br-DGQD6fFs.js +1 -0
- package/admin/assets/bs-So4MoRua.js +1 -0
- package/admin/assets/ca-Bk5ytG4g.js +1 -0
- package/admin/assets/cs-C4NU8eW-.js +1 -0
- package/admin/assets/cv-Ct-s-zrW.js +1 -0
- package/admin/assets/cy-ojtDPj8_.js +1 -0
- package/admin/assets/da-CYGin6vm.js +1 -0
- package/admin/assets/de-BEbJ01zH.js +1 -0
- package/admin/assets/de-at-C7UwE1rJ.js +1 -0
- package/admin/assets/de-ch-CsZ7YQc_.js +1 -0
- package/admin/assets/dv-DaVliwLd.js +1 -0
- package/admin/assets/el-DM_KqKEP.js +1 -0
- package/admin/assets/en-DedtOfaf.js +1 -0
- package/admin/assets/en-au-52Bzk5D9.js +1 -0
- package/admin/assets/en-ca-3pzEPK2N.js +1 -0
- package/admin/assets/en-gb-BrwDQS2G.js +1 -0
- package/admin/assets/en-ie-BUXSHrkL.js +1 -0
- package/admin/assets/en-il-a22drDCn.js +1 -0
- package/admin/assets/en-in-BUjecjkp.js +1 -0
- package/admin/assets/en-nz-Bbo7tnB_.js +1 -0
- package/admin/assets/en-sg-CZVDddmd.js +1 -0
- package/admin/assets/en-tt-DmSGwRia.js +1 -0
- package/admin/assets/eo-B71nkHZU.js +1 -0
- package/admin/assets/es-Dk6VCuuk.js +1 -0
- package/admin/assets/es-do-DMErY8ol.js +1 -0
- package/admin/assets/es-mx-BMRmqa3u.js +1 -0
- package/admin/assets/es-pr-CtBQz48p.js +1 -0
- package/admin/assets/es-us-CrDl5pnO.js +1 -0
- package/admin/assets/et-CO9OHqio.js +1 -0
- package/admin/assets/eu-Bip44atW.js +1 -0
- package/admin/assets/fa-CHbJ_dTM.js +1 -0
- package/admin/assets/fi-DKfoLmaQ.js +1 -0
- package/admin/assets/fo-DG1kOEfw.js +1 -0
- package/admin/assets/fr-DV73GZR4.js +1 -0
- package/admin/assets/fr-ca-BK-RoZiC.js +1 -0
- package/admin/assets/fr-ch-DjqEC5E_.js +1 -0
- package/admin/assets/fy-znrRQdeC.js +1 -0
- package/admin/assets/ga-BlZeKu0N.js +1 -0
- package/admin/assets/gd-BmrycMnC.js +1 -0
- package/admin/assets/gl-CuT8e5mi.js +1 -0
- package/admin/assets/gom-latn-BSWVd0A6.js +1 -0
- package/admin/assets/gu-BHK6LfvD.js +1 -0
- package/admin/assets/he-DPoTUevR.js +1 -0
- package/admin/assets/hi-BRuLafoW.js +1 -0
- package/admin/assets/hr-Bzge-10P.js +1 -0
- package/admin/assets/ht-Ck9BCna1.js +1 -0
- package/admin/assets/hu-CzqqbYmU.js +1 -0
- package/admin/assets/hy-am-C-eV4E8v.js +1 -0
- package/admin/assets/id-Dv8GZQvB.js +1 -0
- package/admin/assets/{index-DTxjaflW.js → index-BPIX0qPj.js} +1 -1
- package/admin/assets/index-CFWd-FDo.css +1 -0
- package/admin/assets/index-D3HviM6x.js +889 -0
- package/admin/assets/is-CK6VY3M_.js +1 -0
- package/admin/assets/it-1gtki4a5.js +1 -0
- package/admin/assets/it-ch-C0Mj3-pC.js +1 -0
- package/admin/assets/ja-Dl3AfnM1.js +1 -0
- package/admin/assets/jv-CznX-tGV.js +1 -0
- package/admin/assets/ka-BNjZxCug.js +1 -0
- package/admin/assets/kk-80J_xldf.js +1 -0
- package/admin/assets/km-CuWChDRB.js +1 -0
- package/admin/assets/kn-BZp_PBdl.js +1 -0
- package/admin/assets/ko-RirpyUl_.js +1 -0
- package/admin/assets/ku-Dz8ACD5w.js +1 -0
- package/admin/assets/ky-BN3ylOhj.js +1 -0
- package/admin/assets/lb-D7h_YoEn.js +1 -0
- package/admin/assets/lo-BrlbTUPD.js +1 -0
- package/admin/assets/lt-cXuHFdTa.js +1 -0
- package/admin/assets/lv-CjIpv13Q.js +1 -0
- package/admin/assets/me-B-jTh39Z.js +1 -0
- package/admin/assets/mi-D06xdVmt.js +1 -0
- package/admin/assets/mk-iLbuxyOf.js +1 -0
- package/admin/assets/ml-2W0y6Zb2.js +1 -0
- package/admin/assets/mn-6zbvKjeb.js +1 -0
- package/admin/assets/mr-7-jrgLyw.js +1 -0
- package/admin/assets/ms-CRH6rEXt.js +1 -0
- package/admin/assets/ms-my-BIJmu2S-.js +1 -0
- package/admin/assets/mt-CbXmxK-D.js +1 -0
- package/admin/assets/my-BvMUsxU8.js +1 -0
- package/admin/assets/nb-DvKHgF7L.js +1 -0
- package/admin/assets/ne-DiZZ3Lm6.js +1 -0
- package/admin/assets/nl-be-Dy7PYRbC.js +1 -0
- package/admin/assets/nl-t_2A_VAT.js +1 -0
- package/admin/assets/nn-Cw7EwosO.js +1 -0
- package/admin/assets/oc-lnc-CuFfB75K.js +1 -0
- package/admin/assets/pa-in-DOFyZ-Ft.js +1 -0
- package/admin/assets/pl-BD7FyCJj.js +1 -0
- package/admin/assets/pt-DSKLLE_u.js +1 -0
- package/admin/assets/pt-br-BhL4gb5Z.js +1 -0
- package/admin/assets/rn-DoHoZZPd.js +1 -0
- package/admin/assets/ro-B0v-_lH0.js +1 -0
- package/admin/assets/ru-BMVOk5eA.js +1 -0
- package/admin/assets/rw-CWF0w6eL.js +1 -0
- package/admin/assets/sd-DO2rrjch.js +1 -0
- package/admin/assets/se-CAolO9WQ.js +1 -0
- package/admin/assets/{sha512-D936QW8l.js → sha512-ZlUYj4Hr.js} +1 -1
- package/admin/assets/si-D03dHfb5.js +1 -0
- package/admin/assets/sk-_GcZGaN3.js +1 -0
- package/admin/assets/sl-Cb1lUGab.js +1 -0
- package/admin/assets/sq-Czzt23Tr.js +1 -0
- package/admin/assets/sr-D76dVqKJ.js +1 -0
- package/admin/assets/sr-cyrl-CuoFbJjW.js +1 -0
- package/admin/assets/ss-g-fGaM29.js +1 -0
- package/admin/assets/sv-CZxc8I45.js +1 -0
- package/admin/assets/sv-fi-D8REJeLz.js +1 -0
- package/admin/assets/sw-B1n3PjWG.js +1 -0
- package/admin/assets/ta-K5mexJNT.js +1 -0
- package/admin/assets/te-DT6dj5B6.js +1 -0
- package/admin/assets/tet-DXwYNm_H.js +1 -0
- package/admin/assets/tg-BCcZKcE2.js +1 -0
- package/admin/assets/th-CeeeseFX.js +1 -0
- package/admin/assets/tk-CJ6KW44d.js +1 -0
- package/admin/assets/tl-ph-DzE8lDmm.js +1 -0
- package/admin/assets/tlh-ER6KiMxG.js +1 -0
- package/admin/assets/tr-D48NGNpr.js +1 -0
- package/admin/assets/tzl-5AsmDTYM.js +1 -0
- package/admin/assets/tzm-2AzZ1YPf.js +1 -0
- package/admin/assets/tzm-latn-Cd5hPQuT.js +1 -0
- package/admin/assets/ug-cn-DU-MZ9Vx.js +1 -0
- package/admin/assets/uk-hn6vcOkn.js +1 -0
- package/admin/assets/ur-jOObtqB6.js +1 -0
- package/admin/assets/uz-BlftYfHF.js +1 -0
- package/admin/assets/uz-latn-BpuI0ccM.js +1 -0
- package/admin/assets/vi-DVo3LusT.js +1 -0
- package/admin/assets/x-pseudo-BuVzNhqi.js +1 -0
- package/admin/assets/yo-BvWGwb4m.js +1 -0
- package/admin/assets/zh-D9-tfba1.js +1 -0
- package/admin/assets/zh-cn-CFL5sbIW.js +1 -0
- package/admin/assets/zh-hk-DRP8u65r.js +1 -0
- package/admin/assets/zh-tw-CtVs1ihI.js +1 -0
- package/admin/index.html +2 -2
- package/frontend/assets/index-legacy-D3BTBYs5.js +9 -0
- package/frontend/assets/{index-legacy-vmpqwZZf.js → index-legacy-DcrWtKxQ.js} +1 -1
- package/frontend/assets/{sha512-legacy-wI89-UHR.js → sha512-legacy-DJvEwScE.js} +1 -1
- package/frontend/index.html +1 -1
- package/npm-shrinkwrap.json +144 -71
- package/package.json +9 -9
- package/plugins/antibrute/plugin.js +150 -19
- package/plugins/list-uploader/public/main.js +1 -1
- package/src/acme.js +11 -7
- package/src/api.accounts.js +3 -3
- package/src/api.auth.js +3 -1
- package/src/api.get_file_list.js +17 -13
- package/src/api.monitor.js +47 -43
- package/src/api.net.js +4 -3
- package/src/api.vfs.js +1 -1
- package/src/basicWeb.js +1 -1
- package/src/commands.js +54 -1
- package/src/comments.js +7 -4
- package/src/config.js +9 -5
- package/src/consoleLog.js +39 -1
- package/src/const.js +4 -0
- package/src/cross.js +33 -6
- package/src/errorPages.js +20 -10
- package/src/events.js +3 -3
- package/src/expiringCache.js +8 -7
- package/src/fileAttr.js +73 -15
- package/src/frontEndApis.js +20 -15
- package/src/index.js +2 -1
- package/src/langs/hfs-lang-ar.json +2 -1
- package/src/langs/hfs-lang-bg.json +2 -1
- package/src/langs/hfs-lang-de.json +2 -1
- package/src/langs/hfs-lang-el.json +2 -1
- package/src/langs/hfs-lang-es.json +2 -1
- package/src/langs/hfs-lang-fi.json +2 -1
- package/src/langs/hfs-lang-fr.json +2 -1
- package/src/langs/hfs-lang-hu.json +2 -1
- package/src/langs/hfs-lang-it.json +2 -1
- package/src/langs/hfs-lang-ja.json +2 -1
- package/src/langs/hfs-lang-ko.json +2 -1
- package/src/langs/hfs-lang-lt.json +2 -1
- package/src/langs/hfs-lang-ms.json +2 -0
- package/src/langs/hfs-lang-nl.json +2 -1
- package/src/langs/hfs-lang-pt-br.json +2 -1
- package/src/langs/hfs-lang-ro.json +2 -1
- package/src/langs/hfs-lang-ru.json +2 -1
- package/src/langs/hfs-lang-sr-latn.json +2 -1
- package/src/langs/hfs-lang-sr.json +2 -1
- package/src/langs/hfs-lang-th.json +2 -1
- package/src/langs/hfs-lang-tr.json +2 -1
- package/src/langs/hfs-lang-uk.json +2 -1
- package/src/langs/hfs-lang-vi.json +2 -1
- package/src/langs/hfs-lang-zh-tw.json +2 -1
- package/src/langs/hfs-lang-zh.json +2 -1
- package/src/listen.js +2 -1
- package/src/log.js +27 -2
- package/src/middlewares.js +8 -2
- package/src/misc.js +14 -0
- package/src/nat.js +61 -21
- package/src/outboundProxy.js +1 -1
- package/src/perm.js +5 -1
- package/src/plugins.js +34 -5
- package/src/roots.js +1 -1
- package/src/selfCheck.js +2 -1
- package/src/serveGuiAndSharedFiles.js +18 -7
- package/src/serveGuiFiles.js +2 -1
- package/src/update.js +10 -18
- package/src/urlList.js +32 -0
- package/src/util-files.js +24 -9
- package/src/util-http.js +4 -0
- package/src/vfs.js +21 -9
- package/src/walkDir.js +7 -1
- package/src/webdav.js +4 -1
- package/src/zip.js +3 -2
- package/admin/assets/index-B66w-a0v.css +0 -1
- package/admin/assets/index-Df6vYR7s.js +0 -822
- package/frontend/assets/index-legacy-emBsvICj.js +0 -9
package/src/urlList.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.encodeUrlList = encodeUrlList;
|
|
5
|
+
exports.decodeUrlList = decodeUrlList;
|
|
6
|
+
// utilities to pass a list of files via url
|
|
7
|
+
// not easy to find chars that are not allowed in file names both for windows and unix
|
|
8
|
+
const URL_LIST_SEPARATOR = '//';
|
|
9
|
+
const URL_LIST_SAME_FOLDER = '\0'; // nul cannot be a valid file name char, and query encoding carries it as %00 without conflicting with path slashes
|
|
10
|
+
function encodeUrlList(entries) {
|
|
11
|
+
let previousFolder = '';
|
|
12
|
+
return entries.map(entry => {
|
|
13
|
+
const slash = entry.lastIndexOf('/');
|
|
14
|
+
const folder = slash < 0 ? '' : entry.slice(0, slash + 1);
|
|
15
|
+
const name = slash < 0 ? entry : entry.slice(slash + 1);
|
|
16
|
+
if (folder && folder === previousFolder)
|
|
17
|
+
return URL_LIST_SAME_FOLDER + name;
|
|
18
|
+
previousFolder = folder;
|
|
19
|
+
return entry;
|
|
20
|
+
}).join(URL_LIST_SEPARATOR);
|
|
21
|
+
}
|
|
22
|
+
function decodeUrlList(list) {
|
|
23
|
+
let previousFolder = '';
|
|
24
|
+
return list?.split(URL_LIST_SEPARATOR).map(entry => {
|
|
25
|
+
const sameFolder = entry.startsWith(URL_LIST_SAME_FOLDER);
|
|
26
|
+
if (sameFolder && previousFolder)
|
|
27
|
+
entry = previousFolder + entry.slice(URL_LIST_SAME_FOLDER.length);
|
|
28
|
+
const slash = entry.lastIndexOf('/');
|
|
29
|
+
previousFolder = slash < 0 ? '' : entry.slice(0, slash + 1);
|
|
30
|
+
return entry;
|
|
31
|
+
});
|
|
32
|
+
}
|
package/src/util-files.js
CHANGED
|
@@ -29,8 +29,7 @@ const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
|
29
29
|
const const_1 = require("./const");
|
|
30
30
|
const promises_2 = require("stream/promises");
|
|
31
31
|
const stat_1 = require("./stat");
|
|
32
|
-
|
|
33
|
-
const unzip_stream_1 = __importDefault(require("unzip-stream"));
|
|
32
|
+
const unzipper_1 = __importDefault(require("unzipper"));
|
|
34
33
|
const fileTimeout = (0, config_1.defineConfig)('file_timeout', 3, x => x * 1000);
|
|
35
34
|
// a smart (and a bit arbitrary) way to decide if we need the stat-workers functionality. Without it, we may be a bit faster. We'll see with experience if we need a dedicated configuration.
|
|
36
35
|
const disableStatWorkers = Number(process.env.UV_THREADPOOL_SIZE) >= 10;
|
|
@@ -104,18 +103,29 @@ function escapeGlobPath(path) {
|
|
|
104
103
|
return fast_glob_1.default.escapePath(path.replace(/\\/g, '/'));
|
|
105
104
|
}
|
|
106
105
|
async function unzip(stream, cb) {
|
|
106
|
+
const extracted = new Map();
|
|
107
107
|
let chain = Promise.resolve();
|
|
108
|
-
return new Promise((resolve, reject) => stream.pipe(
|
|
109
|
-
.on('
|
|
108
|
+
return new Promise((resolve, reject) => stream.pipe(unzipper_1.default.Parse())
|
|
109
|
+
.on('close', () => chain.then(resolve, reject))
|
|
110
110
|
.on('error', reject)
|
|
111
111
|
.on('entry', (entry) => chain = chain.then(async () => {
|
|
112
112
|
const { path, type } = entry;
|
|
113
113
|
const dest = await (0, cross_1.try_)(() => cb(path), e => console.warn(String(e)));
|
|
114
114
|
if (!dest || type !== 'File')
|
|
115
|
-
return entry.autodrain();
|
|
115
|
+
return entry.autodrain().promise();
|
|
116
|
+
extracted.set(path, dest);
|
|
116
117
|
console.debug('Unzip', dest);
|
|
118
|
+
// keep writes serialized so archive entries can't race while callers map paths asynchronously
|
|
117
119
|
const thisFile = entry.pipe(await createSafeWriteStream(dest));
|
|
118
120
|
await (0, promises_2.finished)(thisFile);
|
|
121
|
+
}))
|
|
122
|
+
// unix modes live in the central directory, so we reapply them after the file stream has been written
|
|
123
|
+
.on('entryInCentral', (entry) => chain = chain.then(async () => {
|
|
124
|
+
if (entry.type !== 'File')
|
|
125
|
+
return;
|
|
126
|
+
const dest = extracted.get(entry.path);
|
|
127
|
+
if (dest && entry.unixAttrs)
|
|
128
|
+
await (0, promises_1.chmod)(dest, entry.unixAttrs).catch(() => { });
|
|
119
129
|
})));
|
|
120
130
|
}
|
|
121
131
|
async function ensureParentFolder(path, dirnameIt = true) {
|
|
@@ -172,19 +182,24 @@ function exists(path) {
|
|
|
172
182
|
}
|
|
173
183
|
// parse a file, caching unless timestamp has changed
|
|
174
184
|
exports.parseFileCache = new Map();
|
|
175
|
-
async function loadFileCached(path, loader) {
|
|
185
|
+
async function loadFileCached(path, loader, minInterval = 0) {
|
|
176
186
|
const cached = exports.parseFileCache.get(path);
|
|
187
|
+
const now = Date.now();
|
|
188
|
+
if (cached && now - cached.lastCheck < minInterval)
|
|
189
|
+
return cached.parsed;
|
|
177
190
|
const ts = await statWithTimeout(path).then(x => x.mtime, e => {
|
|
178
191
|
if (e?.message !== 'timeout')
|
|
179
192
|
throw e;
|
|
180
193
|
return cached?.ts || new Date(0); // on timeout (e.g. thread pool saturated), serve cache if any, or attempt the loader
|
|
181
194
|
});
|
|
195
|
+
if (cached)
|
|
196
|
+
cached.lastCheck = now;
|
|
182
197
|
if (cached && Number(ts) === Number(cached.ts))
|
|
183
198
|
return cached.parsed;
|
|
184
199
|
const parsed = loader(path);
|
|
185
|
-
exports.parseFileCache.set(path, { ts, parsed });
|
|
200
|
+
exports.parseFileCache.set(path, { ts, parsed, lastCheck: now });
|
|
186
201
|
return parsed;
|
|
187
202
|
}
|
|
188
|
-
async function parseFile(path, parse) {
|
|
189
|
-
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);
|
|
190
205
|
}
|
package/src/util-http.js
CHANGED
|
@@ -67,6 +67,8 @@ function httpStream(url, { body, proxy, jar, noRedirect, httpThrow = true, ...op
|
|
|
67
67
|
return Object.assign(new Promise(async (resolve, reject) => {
|
|
68
68
|
proxy ??= httpStream.defaultProxy;
|
|
69
69
|
options.headers ??= {};
|
|
70
|
+
if (httpStream.defaultUA && !Object.keys(options.headers).find(k => k.toLowerCase() === 'user-agent'))
|
|
71
|
+
options.headers['user-agent'] = httpStream.defaultUA;
|
|
70
72
|
if (body) {
|
|
71
73
|
options.method ||= 'POST';
|
|
72
74
|
if (lodash_1.default.isPlainObject(body)) {
|
|
@@ -135,6 +137,8 @@ function httpStream(url, { body, proxy, jar, noRedirect, httpThrow = true, ...op
|
|
|
135
137
|
e.cause ??= req; // enrich the error
|
|
136
138
|
reject(e);
|
|
137
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' })));
|
|
138
142
|
if (body && body instanceof node_stream_1.Readable)
|
|
139
143
|
body.pipe(req).on('end', () => req.end());
|
|
140
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;
|
|
@@ -337,7 +349,7 @@ async function* walkNode(parent, { ctx, depth = Infinity, prefixPath = '', requi
|
|
|
337
349
|
const name = prefixPath + (renamed || path);
|
|
338
350
|
if (taken?.has(normalizeFilename(name))) // taken by vfs node above
|
|
339
351
|
return false; // false just in case it's a folder
|
|
340
|
-
const item = { name, isFolder, source: (0, path_1.join)(source, path), parent };
|
|
352
|
+
const item = { name, isFolder, source: (0, path_1.join)(source, path), parent, stats: entry.stats };
|
|
341
353
|
// masks containing '/' must be matched against the relative path while keeping walkDir recursion enabled
|
|
342
354
|
await pathMaskApplier(item, renamed || path);
|
|
343
355
|
if (await cantSee(item)) // can't see: don't produce and don't recur
|
package/src/walkDir.js
CHANGED
|
@@ -56,7 +56,13 @@ function walkDir(path, { depth = 0, hidden = true, parallelizeRecursion = false,
|
|
|
56
56
|
work(Object.assign(Object.create(direntMethods), {
|
|
57
57
|
isDir: f.IS_DIRECTORY,
|
|
58
58
|
name: f.LONG_NAME,
|
|
59
|
-
stats: {
|
|
59
|
+
stats: {
|
|
60
|
+
size: f.SIZE,
|
|
61
|
+
birthtime: f.CREATION_TIME, birthtimeMs: f.CREATION_TIME.getTime(),
|
|
62
|
+
mtime: f.LAST_WRITE_TIME, mtimeMs: f.LAST_WRITE_TIME.getTime(),
|
|
63
|
+
isFile: () => !f.IS_DIRECTORY,
|
|
64
|
+
isDirectory: () => f.IS_DIRECTORY,
|
|
65
|
+
}
|
|
60
66
|
}));
|
|
61
67
|
}, true));
|
|
62
68
|
}
|
package/src/webdav.js
CHANGED
|
@@ -23,6 +23,7 @@ const config_1 = require("./config");
|
|
|
23
23
|
const expiringCache_1 = require("./expiringCache");
|
|
24
24
|
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
25
25
|
const lodash_1 = __importDefault(require("lodash"));
|
|
26
|
+
const fileAttr_1 = require("./fileAttr");
|
|
26
27
|
const forceWebdavLogin = (0, config_1.defineConfig)(cross_1.CFG.force_webdav_login, true, compileWebdavAgentRegex);
|
|
27
28
|
const webdavInitialAuth = (0, config_1.defineConfig)(cross_1.CFG.webdav_initial_auth, 'WebDAVFS', compileWebdavAgentRegex);
|
|
28
29
|
const webdavPrompted = (0, expiringCache_1.expiringCache)(cross_1.DAY);
|
|
@@ -148,7 +149,9 @@ const webdav = async (ctx, next) => {
|
|
|
148
149
|
canOverwrite.delete(overwriteGraceKey);
|
|
149
150
|
const node = await (0, vfs_1.urlToNode)(path, ctx);
|
|
150
151
|
if (node?.source)
|
|
151
|
-
await (0, promises_1.rm)(node.source)
|
|
152
|
+
await (0, promises_1.rm)(node.source)
|
|
153
|
+
.then(() => (0, fileAttr_1.deleteStoredFileAttrs)(node.source))
|
|
154
|
+
.catch(() => { });
|
|
152
155
|
}
|
|
153
156
|
if (x && ctx.length === undefined) // missing length can make PUT fail
|
|
154
157
|
ctx.req.headers['content-length'] = x;
|
package/src/zip.js
CHANGED
|
@@ -12,9 +12,10 @@ const serveFile_1 = require("./serveFile");
|
|
|
12
12
|
const const_1 = require("./const");
|
|
13
13
|
const api_get_file_list_1 = require("./api.get_file_list");
|
|
14
14
|
const comments_1 = require("./comments");
|
|
15
|
+
const urlList_1 = require("./urlList");
|
|
15
16
|
// expects 'node' to have had permissions checked by caller
|
|
16
17
|
async function zipStreamFromFolder(node, ctx) {
|
|
17
|
-
const list = (0, misc_1.wantArray)(ctx.query.list)[0]
|
|
18
|
+
const list = (0, urlList_1.decodeUrlList)((0, misc_1.wantArray)(ctx.query.list)[0]);
|
|
18
19
|
if (!list && (0, vfs_1.statusCodeForMissingPerm)(node, 'can_archive', ctx))
|
|
19
20
|
return;
|
|
20
21
|
ctx.status = const_1.HTTP_OK;
|
|
@@ -39,7 +40,7 @@ async function zipStreamFromFolder(node, ctx) {
|
|
|
39
40
|
if ((0, vfs_1.nodeIsFolder)(subNode)) { // a directory needs to be walked
|
|
40
41
|
if ((0, vfs_1.hasPermission)(subNode, 'can_list', ctx) && (0, vfs_1.hasPermission)(subNode, 'can_archive', ctx)) {
|
|
41
42
|
yield subNode; // it could be empty
|
|
42
|
-
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' });
|
|
43
44
|
}
|
|
44
45
|
continue;
|
|
45
46
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.ariaOnly{position:absolute;clip-path:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.icon{font-size:1.2em;height:1.2em;width:1.4em;display:inline-block;text-align:center}@keyframes blink{0%{opacity:1}50%{opacity:.3}}:root{height:100dvh;--success: #5c5}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;height:100vh;background:#000}#root{min-height:100%;display:flex}main{word-break:break-word}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}img.flag{width:1.5em;height:1em;vertical-align:text-top;margin-top:1px}.icon-w-text{margin-right:.5em}form{max-width:100%}.MuiSvgIcon-root{vertical-align:bottom}div.MuiTreeItem-content{padding:0}.MuiDataGrid-columnHeaders{background-color:#8882}.MuiDataGrid-cell{line-height:1.2em}.MuiDataGrid-filterForm{flex-wrap:wrap;justify-content:space-evenly;row-gap:1em}.wrap[role=cell]{white-space:normal!important}ol,ul{margin-top:.2em;margin-bottom:.2em;padding-left:1.5em}h2.MuiDialogTitle-root{padding-top:2px;padding-bottom:2px}.dialog-alert .MuiDialogContent-root{max-width:45em;padding:.5em 1em;white-space:pre-wrap}.release code{font-size:95%;background-color:#8883;padding:0 .2em;border-radius:.2em}.MuiAppBar-root .MuiAlert-standardInfo .MuiAlert-icon{color:#fff8!important}.MuiAppBar-root .MuiAlert-standardInfo .MuiAlert-message{color:#fffa!important}.MuiAppBar-root .MuiAlert-colorWarning .MuiAlert-icon{color:#ff08!important}.MuiAppBar-root .MuiAlert-colorWarning .MuiAlert-message{color:#ff0a!important}.animated-dashed-line{width:100%;height:2px;background-image:linear-gradient(to right,currentColor 50%,transparent 50%);background-size:10px 100%;animation:animate-dash 1s alternate linear infinite}@keyframes animate-dash{to{background-position:20px 0}}@keyframes success{50%{transform:scale(1.3);color:var(--success)}to{transform:inherit;color:inherit}}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-thumb{background:#8888}::-webkit-scrollbar-track{background:#8882}.token.operator{background:unset!important}.fflag{width:26px;height:17px;vertical-align:text-bottom;border:none}.dialog-backdrop{position:fixed;inset:0;background:#8886;backdrop-filter:blur(2px);display:flex;justify-content:center;align-items:center;z-index:1000}.dialog{background:#fff;background:var(--bg);padding:.5em;padding:max(.5em,1vw,2vh);padding-top:0;border-radius:1em;position:relative;margin:0 3vw;overflow:hidden;max-height:calc(100vh - 2em);display:flex;flex-direction:column;justify-content:center}.dialog-icon{color:#fff;background-color:var(--color);position:absolute;top:0;width:2em;height:1.8em;text-align:center;border-radius:.8em 0}.dialog-icon-text{display:flex;align-items:center;justify-content:center}.dialog-title{font-size:120%;font-weight:400;margin:.3em 0;padding:0 .5em;min-height:1.2em}.dialog-closer~.dialog-title{margin-right:2em}.dialog-type~.dialog-title{margin-left:2em}.dialog-icon~.dialog-title{text-align:center}.dialog-closer{border-radius:0 .8em;right:0;padding:0;background-color:#c88}.dialog-icon~.dialog-content{margin-top:1em}.dialog-type{left:0;top:0;overflow:hidden;opacity:.7}.dialog-content{overflow:auto;max-height:calc(100vh - 4.5em)}.dialog-content p{white-space:pre-wrap;margin:.5em 0}.dialog-confirm .dialog-content button{margin-top:1em}.dialog-alert-info{--color: #282 }.dialog-alert-warning{--color: #c91 }.dialog-alert-error{--color: #822}@media (max-width: 42em){.dialog-icon{font-size:120%}.dialog-icon~.dialog-content{margin-top:1.5em}}.dialog-prompt label{display:block;margin:.5em .1em}.toasts{position:fixed;right:0;display:flex;flex-direction:column;margin-top:.5em;gap:.5em;z-index:1001}.toast{background:var(--faint-contrast);color:var(--text-high-contrast);transition:all .5s ease-in;position:relative;left:-.5em;overflow:hidden;display:flex;align-items:center;padding:.3em .6em;border-radius:.5em;box-shadow:0 0 .3em .3em #8883;box-sizing:border-box}.toast .toast-icon{margin-right:.3em;animation:zoomRotating 1.5s}.toast.toast-success{background-color:var(--success)}.toast.toast-warning{background-color:var(--warning)}.toast.toast-error{background-color:var(--error)}.toast.before{left:100%;transform:scale(.1);padding-top:0;padding-bottom:0}.toast.after{height:0!important;padding-top:0;padding-bottom:0;transition-duration:.2s;transform:scale(0)}@keyframes zoomRotating{0%{transform:scale(0)}to{transform:scale(1) rotate(360deg)}}code[class*=language-],pre[class*=language-]{color:#657b83;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,code[class*=language-] ::-moz-selection{background:#073642}pre[class*=language-]::selection,pre[class*=language-] ::selection,code[class*=language-]::selection,code[class*=language-] ::selection{background:#073642}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background-color:#fdf6e3}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:#93a1a1}.token.punctuation{color:#586e75}.token.namespace{opacity:.7}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:#268bd2}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.url,.token.inserted{color:#2aa198}.token.entity{color:#657b83;background:#eee8d5}.token.atrule,.token.attr-value,.token.keyword{color:#859900}.token.function,.token.class-name{color:#b58900}.token.regex,.token.important,.token.variable{color:#cb4b16}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|