hfs 0.46.1 → 0.47.0-alpha6
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 +4 -4
- package/admin/assets/{index-35f6e3dc.css → index-20dd43f3.css} +1 -1
- package/admin/assets/index-d55dfed9.js +518 -0
- package/{frontend/assets/sha512-d9635c9d.js → admin/assets/sha512-9867267f.js} +1 -1
- package/admin/index.html +2 -2
- package/frontend/assets/index-3a32a9b9.css +1 -0
- package/frontend/assets/index-ad78cbad.js +116 -0
- package/{admin/assets/sha512-3412b98f.js → frontend/assets/sha512-4c1cbf45.js} +1 -1
- package/frontend/fontello.css +5 -2
- package/frontend/fontello.woff2 +0 -0
- package/frontend/index.html +2 -3
- package/package.json +2 -2
- package/plugins/download-counter/plugin.js +15 -7
- package/plugins/download-counter/public/main.js +1 -1
- package/plugins/list-uploader/plugin.js +1 -1
- package/plugins/list-uploader/public/main.js +9 -10
- package/plugins/vhosting/plugin.js +5 -2
- package/src/QuickZipStream.js +3 -0
- package/src/adminApis.js +20 -5
- package/src/api.auth.js +0 -3
- package/src/api.file_list.js +3 -2
- package/src/api.monitor.js +36 -33
- package/src/api.vfs.js +37 -34
- package/src/apiMiddleware.js +44 -15
- package/src/commands.js +2 -2
- package/src/config.js +16 -13
- package/src/connections.js +3 -4
- package/src/consoleLog.js +17 -0
- package/src/const.js +4 -3
- package/src/frontEndApis.js +17 -10
- package/src/github.js +1 -1
- package/src/index.js +3 -1
- package/src/langs/embedded.js +3 -1
- package/src/langs/hfs-lang-es.json +118 -0
- package/src/langs/hfs-lang-it.json +7 -5
- package/src/langs/hfs-lang-nl.json +118 -0
- package/src/langs/hfs-lang-ru.json +3 -3
- package/src/langs/hfs-lang-zh.json +25 -5
- package/src/log.js +5 -3
- package/src/middlewares.js +2 -2
- package/src/misc.js +5 -1
- package/src/perm.js +1 -1
- package/src/serveFile.js +3 -1
- package/src/throttler.js +2 -1
- package/src/update.js +45 -7
- package/src/util-http.js +8 -3
- package/src/vfs.js +36 -12
- package/admin/assets/index-7f1741ba.js +0 -517
- package/frontend/assets/index-b49b8a16.js +0 -94
- package/frontend/assets/index-f2f8fd6b.css +0 -1
package/src/serveFile.js
CHANGED
|
@@ -68,9 +68,10 @@ async function serveFile(ctx, source, mime, content) {
|
|
|
68
68
|
return ctx.body = content;
|
|
69
69
|
const { size } = stats;
|
|
70
70
|
const range = getRange(ctx, size);
|
|
71
|
-
ctx.body = (0, fs_1.createReadStream)(source, range);
|
|
71
|
+
ctx.body = (0, fs_1.createReadStream)(source, range).on('end', () => (0, connections_1.updateConnection)(ctx.state.connection, { opProgress: 1 }));
|
|
72
72
|
if (ctx.vfsNode)
|
|
73
73
|
(0, connections_1.updateConnection)(ctx.state.connection, {
|
|
74
|
+
ctx,
|
|
74
75
|
op: 'download',
|
|
75
76
|
opTotal: stats.size,
|
|
76
77
|
opOffset: range && (range.start / size),
|
|
@@ -106,6 +107,7 @@ function getRange(ctx, totalSize) {
|
|
|
106
107
|
ctx.body = 'Requested Range Not Satisfiable';
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
110
|
+
ctx.state.includesLastByte = end === max;
|
|
109
111
|
ctx.status = const_1.HTTP_PARTIAL_CONTENT;
|
|
110
112
|
ctx.set('Content-Range', `bytes ${start}-${isNaN(end) ? '' : end}/${isNaN(totalSize) ? '*' : totalSize}`);
|
|
111
113
|
ctx.response.length = end - start + 1;
|
package/src/throttler.js
CHANGED
|
@@ -44,7 +44,7 @@ const throttler = async (ctx, next) => {
|
|
|
44
44
|
(0, connections_1.updateConnection)(conn, {
|
|
45
45
|
outSpeed,
|
|
46
46
|
sent: conn.socket.bytesWritten,
|
|
47
|
-
opProgress: (conn.opOffset || 0) + ts.getBytesSent() / conn.opTotal,
|
|
47
|
+
opProgress: conn.opTotal && ((conn.opOffset || 0) + (ts.getBytesSent() - offset) / conn.opTotal),
|
|
48
48
|
});
|
|
49
49
|
/* in case this stream stands still for a while (before the end), we'll have neither 'sent' or 'close' events,
|
|
50
50
|
* so who will take care to updateConnection? This artificial next-call will ensure just that */
|
|
@@ -67,6 +67,7 @@ const throttler = async (ctx, next) => {
|
|
|
67
67
|
delete ip2group[ctx.ip];
|
|
68
68
|
});
|
|
69
69
|
const downloadTotal = ctx.response.length;
|
|
70
|
+
ctx.state.originalStream = ctx.body;
|
|
70
71
|
ctx.body = ctx.body.pipe(ts);
|
|
71
72
|
if (downloadTotal) // preserve this info
|
|
72
73
|
ctx.response.length = downloadTotal;
|
package/src/update.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.update = exports.updateSupported = exports.localUpdateAvailable = exports.
|
|
7
|
+
exports.update = exports.updateSupported = exports.localUpdateAvailable = exports.getUpdates = void 0;
|
|
8
8
|
const github_1 = require("./github");
|
|
9
9
|
const const_1 = require("./const");
|
|
10
10
|
const path_1 = require("path");
|
|
@@ -14,10 +14,45 @@ const fs_1 = require("fs");
|
|
|
14
14
|
const plugins_1 = require("./plugins");
|
|
15
15
|
const promises_1 = require("fs/promises");
|
|
16
16
|
const open_1 = __importDefault(require("open"));
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
const config_1 = require("./config");
|
|
18
|
+
const updateToBeta = (0, config_1.defineConfig)('update_to_beta', false);
|
|
19
|
+
async function getUpdates() {
|
|
20
|
+
const stable = await (0, github_1.getRepoInfo)(const_1.HFS_REPO + '/releases/latest');
|
|
21
|
+
const verStable = ver(stable);
|
|
22
|
+
const ret = await getBetas();
|
|
23
|
+
if (stable && (config_1.currentVersion.olderThan(stable.tag_name) || const_1.RUNNING_BETA)) // if we are running a beta, also offer the latest stable
|
|
24
|
+
ret.push(stable);
|
|
25
|
+
return ret;
|
|
26
|
+
function ver(x) {
|
|
27
|
+
return (0, config_1.versionToScalar)(x.name);
|
|
28
|
+
}
|
|
29
|
+
async function getBetas() {
|
|
30
|
+
if (!updateToBeta.get() && !const_1.RUNNING_BETA)
|
|
31
|
+
return [];
|
|
32
|
+
let page = 1;
|
|
33
|
+
const ret = [];
|
|
34
|
+
while (1) {
|
|
35
|
+
const per = 100;
|
|
36
|
+
const res = await (0, github_1.getRepoInfo)(const_1.HFS_REPO + `/releases?per_page=${per}&page=${page++}`);
|
|
37
|
+
if (!res.length)
|
|
38
|
+
break;
|
|
39
|
+
const curV = config_1.currentVersion.getScalar();
|
|
40
|
+
for (const x of res) {
|
|
41
|
+
if (!x.prerelease)
|
|
42
|
+
continue; // prerelease are all the end
|
|
43
|
+
const v = ver(x);
|
|
44
|
+
if (v <= verStable) // prerelease-s are locally ordered, so as soon as we reach verStable we are done
|
|
45
|
+
return ret;
|
|
46
|
+
if (v === curV)
|
|
47
|
+
continue; // skip current
|
|
48
|
+
x.isNewer = v > curV; // make easy to know what's newer
|
|
49
|
+
ret.push(x);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return ret;
|
|
53
|
+
}
|
|
19
54
|
}
|
|
20
|
-
exports.
|
|
55
|
+
exports.getUpdates = getUpdates;
|
|
21
56
|
const LOCAL_UPDATE = 'hfs-update.zip'; // update from file takes precedence over net
|
|
22
57
|
function localUpdateAvailable() {
|
|
23
58
|
return (0, promises_1.access)(LOCAL_UPDATE).then(() => true, () => false);
|
|
@@ -27,12 +62,15 @@ function updateSupported() {
|
|
|
27
62
|
return const_1.IS_BINARY;
|
|
28
63
|
}
|
|
29
64
|
exports.updateSupported = updateSupported;
|
|
30
|
-
async function update() {
|
|
65
|
+
async function update(tag) {
|
|
31
66
|
if (!updateSupported())
|
|
32
67
|
throw "only binary versions are supported for now";
|
|
33
68
|
let updateSource = await localUpdateAvailable() && (0, fs_1.createReadStream)(LOCAL_UPDATE);
|
|
34
69
|
if (!updateSource) {
|
|
35
|
-
const update = await
|
|
70
|
+
const update = !tag ? (await getUpdates())[0]
|
|
71
|
+
: await (0, github_1.getRepoInfo)(const_1.HFS_REPO + '/releases/tags/' + tag);
|
|
72
|
+
if (!update)
|
|
73
|
+
throw "no update found";
|
|
36
74
|
const assetSearch = { win32: 'windows', darwin: 'mac', linux: 'linux' }[process.platform];
|
|
37
75
|
if (!assetSearch)
|
|
38
76
|
throw "this feature doesn't support your platform: " + process.platform;
|
|
@@ -45,7 +83,7 @@ async function update() {
|
|
|
45
83
|
}
|
|
46
84
|
const bin = process.execPath;
|
|
47
85
|
const binPath = (0, path_1.dirname)(bin);
|
|
48
|
-
const binFile = (
|
|
86
|
+
const binFile = 'hfs' + (const_1.IS_WINDOWS ? '.exe' : ''); // currently running bin could have been renamed
|
|
49
87
|
const newBinFile = 'new-' + binFile;
|
|
50
88
|
plugins_1.pluginsWatcher.pause();
|
|
51
89
|
try {
|
package/src/util-http.js
CHANGED
|
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.httpsStream = exports.httpsString = void 0;
|
|
8
8
|
const node_https_1 = __importDefault(require("node:https"));
|
|
9
9
|
const const_1 = require("./const");
|
|
10
|
-
function httpsString(url, options
|
|
10
|
+
function httpsString(url, options) {
|
|
11
11
|
return httpsStream(url, options).then(res => new Promise(resolve => {
|
|
12
12
|
let buf = '';
|
|
13
13
|
res.on('data', chunk => buf += chunk.toString());
|
|
@@ -18,8 +18,10 @@ function httpsString(url, options = {}) {
|
|
|
18
18
|
}));
|
|
19
19
|
}
|
|
20
20
|
exports.httpsString = httpsString;
|
|
21
|
-
function httpsStream(url, options = {}) {
|
|
21
|
+
function httpsStream(url, { body, ...options } = {}) {
|
|
22
22
|
return new Promise((resolve, reject) => {
|
|
23
|
+
if (body)
|
|
24
|
+
options.method || (options.method = 'POST');
|
|
23
25
|
const req = node_https_1.default.request(url, options, res => {
|
|
24
26
|
if (!res.statusCode || res.statusCode >= 400)
|
|
25
27
|
return reject(new Error(String(res.statusCode), { cause: res }));
|
|
@@ -28,7 +30,10 @@ function httpsStream(url, options = {}) {
|
|
|
28
30
|
resolve(res);
|
|
29
31
|
}).on('error', e => {
|
|
30
32
|
reject(req.res || e);
|
|
31
|
-
})
|
|
33
|
+
});
|
|
34
|
+
if (body)
|
|
35
|
+
req.write(body);
|
|
36
|
+
req.end();
|
|
32
37
|
});
|
|
33
38
|
}
|
|
34
39
|
exports.httpsStream = httpsStream;
|
package/src/vfs.js
CHANGED
|
@@ -26,22 +26,33 @@ exports.defaultPerms = {
|
|
|
26
26
|
exports.PERM_KEYS = (0, misc_1.typedKeys)(exports.defaultPerms);
|
|
27
27
|
exports.MIME_AUTO = 'auto';
|
|
28
28
|
function inheritFromParent(parent, child) {
|
|
29
|
-
var _a, _b, _c
|
|
29
|
+
var _a, _b, _c;
|
|
30
30
|
for (const k of (0, misc_1.typedKeys)(exports.defaultPerms)) {
|
|
31
|
-
let
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
let p = parent;
|
|
32
|
+
let inheritedPerm;
|
|
33
|
+
while (p) {
|
|
34
|
+
inheritedPerm = p[k];
|
|
35
|
+
// // in case of object without children, parent is skipped in favor of the parent's parent
|
|
36
|
+
if (!isWhoObject(inheritedPerm))
|
|
37
|
+
break;
|
|
38
|
+
inheritedPerm = inheritedPerm.children;
|
|
39
|
+
if (inheritedPerm !== undefined)
|
|
40
|
+
break;
|
|
41
|
+
p = p.parent;
|
|
42
|
+
}
|
|
43
|
+
if (inheritedPerm !== undefined) // small optimization: don't expand the object
|
|
44
|
+
(_a = child[k]) !== null && _a !== void 0 ? _a : (child[k] = inheritedPerm);
|
|
37
45
|
}
|
|
38
46
|
if (typeof parent.mime === 'object' && typeof child.mime === 'object')
|
|
39
47
|
lodash_1.default.defaults(child.mime, parent.mime);
|
|
40
48
|
else
|
|
41
|
-
(
|
|
42
|
-
(
|
|
49
|
+
(_b = child.mime) !== null && _b !== void 0 ? _b : (child.mime = parent.mime);
|
|
50
|
+
(_c = child.accept) !== null && _c !== void 0 ? _c : (child.accept = parent.accept);
|
|
43
51
|
return child;
|
|
44
52
|
}
|
|
53
|
+
function isWhoObject(v) {
|
|
54
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
55
|
+
}
|
|
45
56
|
function isSameFilenameAs(name) {
|
|
46
57
|
const lc = name.toLowerCase();
|
|
47
58
|
return (other) => lc === (typeof other === 'string' ? other : getNodeName(other)).toLowerCase();
|
|
@@ -114,7 +125,18 @@ async function urlToNode(url, ctx, parent = exports.vfs, getRest) {
|
|
|
114
125
|
}
|
|
115
126
|
exports.urlToNode = urlToNode;
|
|
116
127
|
exports.vfs = {};
|
|
117
|
-
(0, config_1.defineConfig)('vfs', {}).sub(data => exports.vfs =
|
|
128
|
+
(0, config_1.defineConfig)('vfs', {}).sub(data => exports.vfs = (function recur(node) {
|
|
129
|
+
if (node.propagate) { // legacy pre-0.47
|
|
130
|
+
for (const [k, v] of (0, misc_1.typedEntries)(node.propagate))
|
|
131
|
+
if (v === false)
|
|
132
|
+
node[k] = { this: node[k] };
|
|
133
|
+
delete node.propagate;
|
|
134
|
+
}
|
|
135
|
+
if (node.children)
|
|
136
|
+
for (const c of node.children)
|
|
137
|
+
recur(c);
|
|
138
|
+
return node;
|
|
139
|
+
})(data));
|
|
118
140
|
function saveVfs() {
|
|
119
141
|
return (0, config_1.setConfig)({ vfs: lodash_1.default.cloneDeep(exports.vfs) }, true);
|
|
120
142
|
}
|
|
@@ -157,14 +179,16 @@ function statusCodeForMissingPerm(node, perm, ctx, assign = true) {
|
|
|
157
179
|
ctx.status = ret;
|
|
158
180
|
return ret;
|
|
159
181
|
function getCode() {
|
|
160
|
-
var _a;
|
|
161
182
|
if (!node.source && perm === 'can_upload') // Upload possible only if we know where to store. First check node.source because is supposedly faster.
|
|
162
183
|
return const_1.HTTP_FORBIDDEN;
|
|
163
184
|
// calculate value of permission resolving references to other permissions, avoiding infinite loop
|
|
164
185
|
let who;
|
|
165
186
|
let max = exports.PERM_KEYS.length;
|
|
166
187
|
do {
|
|
167
|
-
who =
|
|
188
|
+
who = node[perm];
|
|
189
|
+
if (isWhoObject(who))
|
|
190
|
+
who = who.this;
|
|
191
|
+
who !== null && who !== void 0 ? who : (who = exports.defaultPerms[perm]);
|
|
168
192
|
if (!max-- || typeof who !== 'string' || who === exports.WHO_ANY_ACCOUNT)
|
|
169
193
|
break;
|
|
170
194
|
perm = who;
|