hfs 0.26.9 → 0.27.2
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 +15 -2
- package/admin/assets/index-509bb1d6.js +415 -0
- package/admin/assets/index-60a380a7.css +1 -0
- package/{frontend/assets/sha512.6af42937.js → admin/assets/sha512-738f0943.js} +2 -2
- package/admin/index.html +2 -2
- package/frontend/assets/index-6e178dfd.css +1 -0
- package/frontend/assets/index-aea7654e.js +85 -0
- package/{admin/assets/sha512.9dfe82e1.js → frontend/assets/sha512-bf915587.js} +2 -2
- package/frontend/index.html +3 -3
- package/package.json +2 -6
- package/plugins/vhosting/plugin.js +23 -20
- package/src/QuickZipStream.js +1 -1
- package/src/ThrottledStream.js +1 -1
- package/src/adminApis.js +5 -5
- package/src/api.accounts.js +10 -10
- package/src/api.auth.js +17 -17
- package/src/api.file_list.js +13 -6
- package/src/api.helpers.js +6 -6
- package/src/api.monitor.js +2 -0
- package/src/api.plugins.js +1 -0
- package/src/api.vfs.js +15 -12
- package/src/apiMiddleware.js +7 -4
- package/src/block.js +1 -0
- package/src/commands.js +1 -0
- package/src/config.js +1 -1
- package/src/connections.js +1 -1
- package/src/const.js +18 -7
- package/src/crypt.js +1 -1
- package/src/debounceAsync.js +1 -0
- package/src/events.js +1 -1
- package/src/frontEndApis.js +1 -1
- package/src/github.js +3 -1
- package/src/index.js +3 -2
- package/src/listen.js +1 -1
- package/src/log.js +4 -4
- package/src/middlewares.js +30 -10
- package/src/misc.js +1 -1
- package/src/perm.js +31 -29
- package/src/plugins.js +1 -1
- package/src/serveFile.js +11 -11
- package/src/serveGuiFiles.js +4 -4
- package/src/sse.js +3 -2
- package/src/throttler.js +1 -1
- package/src/update.js +1 -0
- package/src/util-files.js +17 -2
- package/src/util-generators.js +1 -0
- package/src/util-http.js +3 -1
- package/src/vfs.js +29 -27
- package/src/watchLoad.js +1 -1
- package/src/zip.js +3 -2
- package/admin/assets/index.bb5198ec.js +0 -281
- package/admin/assets/index.dcc78777.css +0 -1
- package/frontend/assets/index.27a78796.js +0 -85
- package/frontend/assets/index.93366732.css +0 -1
package/src/util-files.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
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
|
|
2
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
5
|
};
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.unzip = exports.run = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
|
|
7
|
+
exports.prepareFolder = exports.unzip = exports.run = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
|
|
7
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
9
|
const misc_1 = require("./misc");
|
|
9
10
|
const fs_1 = require("fs");
|
|
@@ -140,9 +141,23 @@ async function unzip(stream, cb) {
|
|
|
140
141
|
return entry.autodrain();
|
|
141
142
|
await pending; // don't overlap writings
|
|
142
143
|
console.debug('unzip', dest);
|
|
143
|
-
|
|
144
|
+
await prepareFolder(dest);
|
|
144
145
|
const thisFile = entry.pipe((0, fs_1.createWriteStream)(dest));
|
|
145
146
|
pending = (0, stream_1.once)(thisFile, 'finish');
|
|
146
147
|
}));
|
|
147
148
|
}
|
|
148
149
|
exports.unzip = unzip;
|
|
150
|
+
async function prepareFolder(path, dirnameIt = true) {
|
|
151
|
+
if (dirnameIt)
|
|
152
|
+
path = (0, path_1.dirname)(path);
|
|
153
|
+
if (isWindowsDrive(path))
|
|
154
|
+
return;
|
|
155
|
+
try {
|
|
156
|
+
await promises_1.default.mkdir(path, { recursive: true });
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
catch (_a) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.prepareFolder = prepareFolder;
|
package/src/util-generators.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
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
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.asyncGeneratorToReadable = exports.asyncGeneratorToArray = exports.filterMapGenerator = void 0;
|
|
4
5
|
// callback can return undefined to skip element
|
package/src/util-http.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
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
|
|
2
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
5
|
};
|
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
7
|
exports.httpsStream = exports.httpsString = void 0;
|
|
7
8
|
const node_https_1 = __importDefault(require("node:https"));
|
|
9
|
+
const const_1 = require("./const");
|
|
8
10
|
function httpsString(url, options = {}) {
|
|
9
11
|
return httpsStream(url, options).then(res => new Promise(resolve => {
|
|
10
12
|
let buf = '';
|
|
@@ -21,7 +23,7 @@ function httpsStream(url, options = {}) {
|
|
|
21
23
|
node_https_1.default.request(url, options, res => {
|
|
22
24
|
if (!res.statusCode || res.statusCode >= 400)
|
|
23
25
|
throw res;
|
|
24
|
-
if (res.statusCode ===
|
|
26
|
+
if (res.statusCode === const_1.HTTP_TEMPORARY_REDIRECT && res.headers.location)
|
|
25
27
|
return resolve(httpsStream(res.headers.location, options));
|
|
26
28
|
resolve(res);
|
|
27
29
|
}).on('error', reject).end();
|
package/src/vfs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// This file is part of HFS - Copyright 2021-
|
|
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
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
@@ -21,6 +21,7 @@ const WHO_ANY_ACCOUNT = '*';
|
|
|
21
21
|
exports.defaultPerms = {
|
|
22
22
|
can_see: WHO_ANYONE,
|
|
23
23
|
can_read: WHO_ANYONE,
|
|
24
|
+
can_upload: WHO_NO_ONE,
|
|
24
25
|
};
|
|
25
26
|
exports.MIME_AUTO = 'auto';
|
|
26
27
|
function inheritFromParent(parent, child) {
|
|
@@ -36,7 +37,7 @@ function inheritFromParent(parent, child) {
|
|
|
36
37
|
child.mime || (child.mime = parent.mime);
|
|
37
38
|
return child;
|
|
38
39
|
}
|
|
39
|
-
async function urlToNode(url, ctx, parent = exports.vfs) {
|
|
40
|
+
async function urlToNode(url, ctx, parent = exports.vfs, getRest) {
|
|
40
41
|
var _a;
|
|
41
42
|
let initialSlashes = 0;
|
|
42
43
|
while (url[initialSlashes] === '/')
|
|
@@ -48,25 +49,23 @@ async function urlToNode(url, ctx, parent = exports.vfs) {
|
|
|
48
49
|
const rest = nextSlash < 0 ? '' : url.slice(nextSlash + 1, url.endsWith('/') ? -1 : undefined);
|
|
49
50
|
if ((0, misc_1.dirTraversal)(name) || /[\/]/.test(name)) {
|
|
50
51
|
if (ctx)
|
|
51
|
-
ctx.status =
|
|
52
|
+
ctx.status = const_1.HTTP_FOOL;
|
|
52
53
|
return;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
// does the tree node have a child that goes by this name?
|
|
56
|
+
const sameName = !const_1.IS_WINDOWS ? (x) => x === name // easy
|
|
57
|
+
: (0, misc_2.with_)(name.toLowerCase(), lc => (x) => x.toLowerCase() === lc);
|
|
58
|
+
const child = (_a = parent.children) === null || _a === void 0 ? void 0 : _a.find(x => sameName(getNodeName(x)));
|
|
55
59
|
const ret = {
|
|
60
|
+
...child,
|
|
61
|
+
original: child,
|
|
56
62
|
isTemp: true,
|
|
57
|
-
url: (0, misc_1.enforceFinal)('/', parent.url || '') + name,
|
|
58
|
-
parents,
|
|
59
63
|
};
|
|
60
|
-
parents.push(parent);
|
|
61
64
|
inheritFromParent(parent, ret);
|
|
62
65
|
inheritMasks(ret, parent, name);
|
|
63
66
|
applyMasks(ret, parent, name);
|
|
64
|
-
// does the tree node have a child that goes by this name?
|
|
65
|
-
const sameName = !const_1.IS_WINDOWS ? (x) => x === name // easy
|
|
66
|
-
: (0, misc_2.with_)(name.toLowerCase(), lc => (x) => x.toLowerCase() === lc);
|
|
67
|
-
const child = (_a = parent.children) === null || _a === void 0 ? void 0 : _a.find(x => sameName(getNodeName(x)));
|
|
68
67
|
if (child) // yes
|
|
69
|
-
return urlToNode(rest, ctx,
|
|
68
|
+
return urlToNode(rest, ctx, ret, getRest);
|
|
70
69
|
// not in the tree, we can see consider continuing on the disk
|
|
71
70
|
if (!parent.source)
|
|
72
71
|
return; // but then we need the current node to be linked to the disk, otherwise, we give up
|
|
@@ -83,13 +82,16 @@ async function urlToNode(url, ctx, parent = exports.vfs) {
|
|
|
83
82
|
if (parent.default)
|
|
84
83
|
inheritFromParent({ mime: { '*': exports.MIME_AUTO } }, ret);
|
|
85
84
|
if (rest)
|
|
86
|
-
return urlToNode(rest, ctx, ret);
|
|
85
|
+
return urlToNode(rest, ctx, ret, getRest);
|
|
87
86
|
if (ret.source)
|
|
88
87
|
try {
|
|
89
88
|
await promises_1.default.stat(ret.source);
|
|
90
89
|
} // check existence
|
|
91
90
|
catch (_b) {
|
|
92
|
-
|
|
91
|
+
if (!getRest)
|
|
92
|
+
return;
|
|
93
|
+
getRest(onDisk);
|
|
94
|
+
return parent;
|
|
93
95
|
}
|
|
94
96
|
return ret;
|
|
95
97
|
}
|
|
@@ -115,18 +117,21 @@ exports.nodeIsDirectory = nodeIsDirectory;
|
|
|
115
117
|
function hasPermission(node, perm, ctx) {
|
|
116
118
|
var _a;
|
|
117
119
|
return matchWho((_a = node[perm]) !== null && _a !== void 0 ? _a : exports.defaultPerms[perm], ctx)
|
|
118
|
-
&& (perm !== 'can_see' || hasPermission(node, 'can_read', ctx)); //
|
|
120
|
+
&& (perm !== 'can_see' || hasPermission(node, 'can_read', ctx)); // can_see is used to hide something you nonetheless can_read, so you MUST also can_read
|
|
119
121
|
}
|
|
120
122
|
exports.hasPermission = hasPermission;
|
|
121
123
|
async function* walkNode(parent, ctx, depth = 0, prefixPath = '') {
|
|
122
124
|
var _a;
|
|
123
125
|
const { children, source } = parent;
|
|
126
|
+
const took = prefixPath ? undefined : new Set();
|
|
124
127
|
if (children)
|
|
125
128
|
for (let idx = 0; idx < children.length; idx++) {
|
|
126
129
|
const child = children[idx];
|
|
130
|
+
const name = prefixPath + getNodeName(child);
|
|
131
|
+
took === null || took === void 0 ? void 0 : took.add(name);
|
|
127
132
|
yield* workItem({
|
|
128
133
|
...child,
|
|
129
|
-
name
|
|
134
|
+
name,
|
|
130
135
|
}, depth > 0 && await nodeIsDirectory(child).catch(() => false));
|
|
131
136
|
}
|
|
132
137
|
if (!source)
|
|
@@ -135,9 +140,11 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '') {
|
|
|
135
140
|
for await (const path of (0, misc_1.dirStream)(source, depth)) {
|
|
136
141
|
if (ctx === null || ctx === void 0 ? void 0 : ctx.req.aborted)
|
|
137
142
|
return;
|
|
138
|
-
const
|
|
143
|
+
const name = prefixPath + (((_a = parent.rename) === null || _a === void 0 ? void 0 : _a[path]) || path);
|
|
144
|
+
if (took === null || took === void 0 ? void 0 : took.has(name))
|
|
145
|
+
continue;
|
|
139
146
|
yield* workItem({
|
|
140
|
-
name
|
|
147
|
+
name,
|
|
141
148
|
source: (0, path_1.join)(source, path),
|
|
142
149
|
rename: renameUnderPath(parent.rename, path),
|
|
143
150
|
});
|
|
@@ -151,12 +158,7 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '') {
|
|
|
151
158
|
const name = getNodeName(item);
|
|
152
159
|
// we basename for depth>0 where we already have the rest of the path in the parent's url, and would be duplicated
|
|
153
160
|
const virtualBasename = (0, path_1.basename)(name);
|
|
154
|
-
|
|
155
|
-
Object.assign(item, {
|
|
156
|
-
isTemp: true,
|
|
157
|
-
url,
|
|
158
|
-
parents: [...parent.parents || [], parent],
|
|
159
|
-
});
|
|
161
|
+
item.isTemp = true;
|
|
160
162
|
inheritFromParent(parent, item);
|
|
161
163
|
applyMasks(item, parent, virtualBasename);
|
|
162
164
|
if (ctx && !hasPermission(item, 'can_see', ctx))
|
|
@@ -206,7 +208,7 @@ function matchWho(who, ctx) {
|
|
|
206
208
|
(0, misc_1.getOrSet)(ctx.state, 'usernames', () => (0, perm_1.getCurrentUsernameExpanded)(ctx)).some((u) => who.includes(u)))();
|
|
207
209
|
}
|
|
208
210
|
function cantReadStatusCode(node) {
|
|
209
|
-
return node.can_read === false ? const_1.
|
|
211
|
+
return node.can_read === false ? const_1.HTTP_FORBIDDEN : const_1.HTTP_UNAUTHORIZED;
|
|
210
212
|
}
|
|
211
213
|
exports.cantReadStatusCode = cantReadStatusCode;
|
|
212
214
|
events_1.default.on('accountRenamed', (from, to) => {
|
|
@@ -214,8 +216,8 @@ events_1.default.on('accountRenamed', (from, to) => {
|
|
|
214
216
|
saveVfs();
|
|
215
217
|
function recur(n) {
|
|
216
218
|
var _a;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
for (const k of (0, misc_1.typedKeys)(exports.defaultPerms))
|
|
220
|
+
replace(n[k]);
|
|
219
221
|
if (n.masks)
|
|
220
222
|
Object.values(n.masks).forEach(recur);
|
|
221
223
|
(_a = n.children) === null || _a === void 0 ? void 0 : _a.forEach(recur);
|
package/src/watchLoad.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// This file is part of HFS - Copyright 2021-
|
|
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
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
package/src/zip.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// This file is part of HFS - Copyright 2021-
|
|
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
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
@@ -13,8 +13,9 @@ const promises_1 = __importDefault(require("fs/promises"));
|
|
|
13
13
|
const config_1 = require("./config");
|
|
14
14
|
const path_1 = require("path");
|
|
15
15
|
const serveFile_1 = require("./serveFile");
|
|
16
|
+
const const_1 = require("./const");
|
|
16
17
|
async function zipStreamFromFolder(node, ctx) {
|
|
17
|
-
ctx.status =
|
|
18
|
+
ctx.status = const_1.HTTP_OK;
|
|
18
19
|
ctx.mime = 'zip';
|
|
19
20
|
const name = (0, vfs_1.getNodeName)(node);
|
|
20
21
|
ctx.attachment((name || 'archive') + '.zip');
|